CELO Price: $1.24 (-4.02%)
Gas: 5 GWei

Contract

0x42F5c7839Bf00FAea6ca09517E96E82e7364384D

Overview

CELO Balance

Celo Chain LogoCelo Chain LogoCelo Chain Logo0 CELO

CELO Value

$0.00

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Value
0x60806040182422202023-03-15 11:20:58380 days ago1678879258IN
 Create: UnlockSwapPurchaser
0 CELO0.0239979525

Parent Txn Hash Block From To Value
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UnlockSwapPurchaser

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 80 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 9 : UnlockSwapPurchaser.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol';
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
import "../interfaces/IMintableERC20.sol";
import "../interfaces/IPermit2.sol";
import "../interfaces/IPublicLock.sol";
import "../interfaces/IUnlock.sol";

contract UnlockSwapPurchaser {

  // Unlock address on current chain
  address public unlockAddress;
  
  // required by Uniswap Universal Router
  address public permit2;

  mapping (address => bool) uniswapRouters;

  // events
  event SwapCall(
    address lock,
    address tokenAddress,
    uint amountSpent
  );

  // errors
  error SwapFailed(address uniswapRouter, address tokenIn, address tokenOut, uint amountInMax, bytes callData);
  error LockDoesntExist(address lockAddress);
  error InsufficientBalance();
  error UnauthorizedBalanceChange();
  error LockCallFailed();
  error WithdrawFailed();
  error UnautorizedRouter(address routerAddress);

  /**
   * Set the address of Uniswap Permit2 helper contract
   * @param _unlockAddress the address of Unlock contract  
   * @param _permit2Address the address of Uniswap PERMIT2 contract  
   */
  constructor(address _unlockAddress, address _permit2Address, address[] memory _uniswapRouters) {
    unlockAddress = _unlockAddress;
    permit2 = _permit2Address;
    for (uint i = 0; i < _uniswapRouters.length; i++) {
     uniswapRouters[_uniswapRouters[i]] = true;
    }
  }


  /**
   * Simple helper to retrieve balance in ERC20 or native tokens
   * @param token the address of the token (address(0) for native token)
   */
  function getBalance(address token) internal view returns (uint) {
    return token == address(0) ?
      address(this).balance 
      :
      IMintableERC20(token).balanceOf(address(this));
  }

  /**
   * Swap tokens and call a function a lock contract.
   * 
   * Calling this function will 1) swap the token sent by the user into the token (ERCC20 or native) used by
   * the lock contract using Uniswap Universal Router and 2) call the lock contract with the specified calldata
   * 
   * @param lock the address of the lock
   * @param srcToken the address of the token sent by the user (ERC20 or address(0) for native)
   * @param amountInMax the maximum amount the user want to spend in the swap
   * @param uniswapRouter the address of the uniswap router
   * @param swapCalldata the Uniswap quote calldata returned by the SDK, to be sent to the router contract
   * @param callData the encoded instructions to be executed by the lock
   *
   * @return the bytes as returned by the execution on the lock
   * 
   * @notice If the actual amount spent is less than the specified maximum amount, the remaining tokens will 
   * be held by the Unlock contract
   */
  function swapAndCall(
    address lock,
    address srcToken,
    uint amountInMax,
    address uniswapRouter, 
    bytes memory swapCalldata,
    bytes memory callData
  ) public payable returns(bytes memory) {
    // check if lock exists
    (bool lockExists,,) = IUnlock(unlockAddress).locks(lock);
    if(!lockExists) {
      revert LockDoesntExist(lock);
    }

    // make sure 
    if(uniswapRouters[uniswapRouter] != true) {
      revert UnautorizedRouter(uniswapRouter);
    }

    // get lock pricing 
    address destToken = IPublicLock(lock).tokenAddress();

    // get balances of UnlockSwapPurchaser before
    // if payments in ETH, substract the value sent by user to get actual balance
    uint balanceTokenDestBefore = destToken == address(0) ? 
      getBalance(destToken) - msg.value 
            :
      getBalance(destToken);

    uint balanceTokenSrcBefore = 
        srcToken == address(0) ? 
          getBalance(srcToken) - msg.value 
          :
          getBalance(srcToken);

    if(srcToken != address(0)) {
      // Transfer the specified amount of src ERC20 to this contract
      TransferHelper.safeTransferFrom(srcToken, msg.sender, address(this), amountInMax);

      // Approve the router to spend src ERC20
      TransferHelper.safeApprove(srcToken, uniswapRouter, amountInMax);

      // approve PERMIT2 to manipulate the token
      IERC20(srcToken).approve(permit2, amountInMax);
    }

    // issue PERMIT2 Allowance
    IPermit2(permit2).approve(
      srcToken,
      uniswapRouter,
      uint160(amountInMax),
      uint48(block.timestamp + 60) // expires after 1min
    );

    // executes the swap
    (bool success, ) = uniswapRouter.call{ 
      value: srcToken == address(0) ? msg.value : 0 
    }(swapCalldata);

    // make sure to catch Uniswap revert
    if(success == false) {
      revert SwapFailed(uniswapRouter, srcToken, destToken, amountInMax, swapCalldata);
    }

    // make sure balance is enough to buy key
    if((
      destToken == address(0) ? 
      getBalance(destToken) - msg.value 
            :
      getBalance(destToken)
    ) < balanceTokenDestBefore + IPublicLock(lock).keyPrice()) {
      revert InsufficientBalance();
    }

    // approve ERC20 to call the lock
    if(destToken != address(0)) {
      IMintableERC20(destToken).approve(lock, IPublicLock(lock).keyPrice());
    }

    // call the lock
    (bool lockCallSuccess, bytes memory returnData) = lock.call{
      value: destToken == address(0) ? IPublicLock(lock).keyPrice() : 0
    }(
      callData
    );

    if(lockCallSuccess == false) {
      revert LockCallFailed();
    }

    // check that Unlock did not spend more than it received
    if(
      getBalance(srcToken) - balanceTokenSrcBefore < 0
      ||
      getBalance(destToken) - balanceTokenDestBefore < 0
    ) {
      // balance too low
      revert UnauthorizedBalanceChange();
    }

    // returns whatever the lock returned
    return returnData;
  }

  /**
   * This is used to send remaining tokens from swaps to the main unlock contract
   * @param tokenAddress the ERC20 contract address of the token to withdraw
   * or address(0) for native tokens
   */
  function withdrawToUnlock(address tokenAddress) public {
    uint balance = getBalance(tokenAddress);
    if(tokenAddress != address(0)) {
      IERC20(tokenAddress).transfer(unlockAddress, balance);
    } else {
      (bool sent,) = payable(unlockAddress).call{value: balance}("");
      if(sent == false) {
        revert WithdrawFailed();
      }
    }
  }

  // required to withdraw WETH
  receive() external payable {}
}

File 2 of 9 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 3 of 9 : IUniswapV3SwapCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
    /// @dev In the implementation you must pay the pool tokens owed for the swap.
    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external;
}

File 4 of 9 : ISwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol';

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}

File 5 of 9 : TransferHelper.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

library TransferHelper {
    /// @notice Transfers tokens from the targeted address to the given destination
    /// @notice Errors with 'STF' if transfer fails
    /// @param token The contract address of the token to be transferred
    /// @param from The originating address from which the tokens will be transferred
    /// @param to The destination address of the transfer
    /// @param value The amount to be transferred
    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) =
            token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
    }

    /// @notice Transfers tokens from msg.sender to a recipient
    /// @dev Errors with ST if transfer fails
    /// @param token The contract address of the token which will be transferred
    /// @param to The recipient of the transfer
    /// @param value The value of the transfer
    function safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
    }

    /// @notice Approves the stipulated contract to spend the given allowance in the given token
    /// @dev Errors with 'SA' if transfer fails
    /// @param token The contract address of the token to be approved
    /// @param to The target of the approval
    /// @param value The amount of the given token the target will be allowed to spend
    function safeApprove(
        address token,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
    }

    /// @notice Transfers ETH to the recipient address
    /// @dev Fails with `STE`
    /// @param to The destination of the transfer
    /// @param value The value to be transferred
    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'STE');
    }
}

File 6 of 9 : IMintableERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.17 <0.9.0;

interface IMintableERC20 {
  function mint(address account, uint256 amount) external returns (bool);

  function transfer(address recipient, uint256 amount) external returns (bool);

  function totalSupply() external view returns (uint256);

  function balanceOf(address account) external view returns (uint256);

  function approve(address spender, uint256 amount) external returns (bool);
}

File 7 of 9 : IPermit2.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.17 <0.9.0;

interface IPermit2 {
  function approve(address token, address spender, uint160 amount, uint48 expiration) external;
}

File 8 of 9 : IPublicLock.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.17 <0.9.0;
pragma experimental ABIEncoderV2;

/**
 * @title The PublicLock Interface
 */

interface IPublicLock {
  /// Functions
  function initialize(
    address _lockCreator,
    uint _expirationDuration,
    address _tokenAddress,
    uint _keyPrice,
    uint _maxNumberOfKeys,
    string calldata _lockName
  ) external;

  // default role from OpenZeppelin
  function DEFAULT_ADMIN_ROLE()
    external
    view
    returns (bytes32 role);

  /**
   * @notice The version number of the current implementation on this network.
   * @return The current version number.
   */
  function publicLockVersion()
    external
    pure
    returns (uint16);

  /**
   * @dev Called by lock manager to withdraw all funds from the lock
   * @param _tokenAddress specifies the token address to withdraw or 0 for ETH. This is usually
   * the same as `tokenAddress` in MixinFunds.
   * @param _recipient specifies the address that will receive the tokens
   * @param _amount specifies the max amount to withdraw, which may be reduced when
   * considering the available balance. Set to 0 or MAX_UINT to withdraw everything.
   * -- however be wary of draining funds as it breaks the `cancelAndRefund` and `expireAndRefundFor` use cases.
   */
  function withdraw(
    address _tokenAddress,
    address payable _recipient,
    uint _amount
  ) external;

  /**
   * A function which lets a Lock manager of the lock to change the price for future purchases.
   * @dev Throws if called by other than a Lock manager
   * @dev Throws if lock has been disabled
   * @dev Throws if _tokenAddress is not a valid token
   * @param _keyPrice The new price to set for keys
   * @param _tokenAddress The address of the erc20 token to use for pricing the keys,
   * or 0 to use ETH
   */
  function updateKeyPricing(
    uint _keyPrice,
    address _tokenAddress
  ) external;

  /**
   * Update the main key properties for the entire lock:
   *
   * - default duration of each key
   * - the maximum number of keys the lock can edit
   * - the maximum number of keys a single address can hold
   *
   * @notice keys previously bought are unaffected by this changes in expiration duration (i.e.
   * existing keys timestamps are not recalculated/updated)
   * @param _newExpirationDuration the new amount of time for each key purchased or type(uint).max for a non-expiring key
   * @param _maxKeysPerAcccount the maximum amount of key a single user can own
   * @param _maxNumberOfKeys uint the maximum number of keys
   * @dev _maxNumberOfKeys Can't be smaller than the existing supply
   */
  function updateLockConfig(
    uint _newExpirationDuration,
    uint _maxNumberOfKeys,
    uint _maxKeysPerAcccount
  ) external;

  /**
   * Checks if the user has a non-expired key.
   * @param _user The address of the key owner
   */
  function getHasValidKey(
    address _user
  ) external view returns (bool);

  /**
   * @dev Returns the key's ExpirationTimestamp field for a given owner.
   * @param _tokenId the id of the key
   * @dev Returns 0 if the owner has never owned a key for this lock
   */
  function keyExpirationTimestampFor(
    uint _tokenId
  ) external view returns (uint timestamp);

  /**
   * Public function which returns the total number of unique owners (both expired
   * and valid).  This may be larger than totalSupply.
   */
  function numberOfOwners() external view returns (uint);

  /**
   * Allows the Lock owner to assign
   * @param _lockName a descriptive name for this Lock.
   * @param _lockSymbol a Symbol for this Lock (default to KEY).
   * @param _baseTokenURI the baseTokenURI for this Lock
   */
  function setLockMetadata(
    string calldata _lockName,
    string calldata _lockSymbol,
    string calldata _baseTokenURI
  ) external;

  /**
   * @dev Gets the token symbol
   * @return string representing the token symbol
   */
  function symbol() external view returns (string memory);

  /**  @notice A distinct Uniform Resource Identifier (URI) for a given asset.
   * @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
   *  3986. The URI may point to a JSON file that conforms to the "ERC721
   *  Metadata JSON Schema".
   * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
   * @param _tokenId The tokenID we're inquiring about
   * @return String representing the URI for the requested token
   */
  function tokenURI(
    uint256 _tokenId
  ) external view returns (string memory);

  /**
   * Allows a Lock manager to add or remove an event hook
   * @param _onKeyPurchaseHook Hook called when the `purchase` function is called
   * @param _onKeyCancelHook Hook called when the internal `_cancelAndRefund` function is called
   * @param _onValidKeyHook Hook called to determine if the contract should overide the status for a given address
   * @param _onTokenURIHook Hook called to generate a data URI used for NFT metadata
   * @param _onKeyTransferHook Hook called when a key is transfered
   * @param _onKeyExtendHook Hook called when a key is extended or renewed
   * @param _onKeyGrantHook Hook called when a key is granted
   */
  function setEventHooks(
    address _onKeyPurchaseHook,
    address _onKeyCancelHook,
    address _onValidKeyHook,
    address _onTokenURIHook,
    address _onKeyTransferHook,
    address _onKeyExtendHook,
    address _onKeyGrantHook
  ) external;

  /**
   * Allows a Lock manager to give a collection of users a key with no charge.
   * Each key may be assigned a different expiration date.
   * @dev Throws if called by other than a Lock manager
   * @param _recipients An array of receiving addresses
   * @param _expirationTimestamps An array of expiration Timestamps for the keys being granted
   * @return the ids of the granted tokens
   */
  function grantKeys(
    address[] calldata _recipients,
    uint[] calldata _expirationTimestamps,
    address[] calldata _keyManagers
  ) external returns (uint256[] memory);

  /**
   * Allows the Lock owner to extend an existing keys with no charge.
   * @param _tokenId The id of the token to extend
   * @param _duration The duration in secondes to add ot the key
   * @dev set `_duration` to 0 to use the default duration of the lock
   */
  function grantKeyExtension(
    uint _tokenId,
    uint _duration
  ) external;

  /**
   * @dev Purchase function
   * @param _values array of tokens amount to pay for this purchase >= the current keyPrice - any applicable discount
   * (_values is ignored when using ETH)
   * @param _recipients array of addresses of the recipients of the purchased key
   * @param _referrers array of addresses of the users making the referral
   * @param _keyManagers optional array of addresses to grant managing rights to a specific address on creation
   * @param _data array of arbitrary data populated by the front-end which initiated the sale
   * @notice when called for an existing and non-expired key, the `_keyManager` param will be ignored
   * @dev Setting _value to keyPrice exactly doubles as a security feature. That way if the lock owner increases the
   * price while my transaction is pending I can't be charged more than I expected (only applicable to ERC-20 when more
   * than keyPrice is approved for spending).
   * @return tokenIds the ids of the created tokens
   */
  function purchase(
    uint256[] calldata _values,
    address[] calldata _recipients,
    address[] calldata _referrers,
    address[] calldata _keyManagers,
    bytes[] calldata _data
  ) external payable returns (uint256[] memory tokenIds);

  /**
   * @dev Extend function
   * @param _value the number of tokens to pay for this purchase >= the current keyPrice - any applicable discount
   * (_value is ignored when using ETH)
   * @param _tokenId the id of the key to extend
   * @param _referrer address of the user making the referral
   * @param _data arbitrary data populated by the front-end which initiated the sale
   * @dev Throws if lock is disabled or key does not exist for _recipient. Throws if _recipient == address(0).
   */
  function extend(
    uint _value,
    uint _tokenId,
    address _referrer,
    bytes calldata _data
  ) external payable;

  /**
   * Returns the percentage of the keyPrice to be sent to the referrer (in basis points)
   * @param _referrer the address of the referrer
   * @return referrerFee the percentage of the keyPrice to be sent to the referrer (in basis points)
   */
  function referrerFees(
    address _referrer
  ) external view returns (uint referrerFee);

  /**
   * Set a specific percentage of the keyPrice to be sent to the referrer while purchasing,
   * extending or renewing a key.
   * @param _referrer the address of the referrer
   * @param _feeBasisPoint the percentage of the price to be used for this
   * specific referrer (in basis points)
   * @dev To send a fixed percentage of the key price to all referrers, sett a percentage to `address(0)`
   */
  function setReferrerFee(
    address _referrer,
    uint _feeBasisPoint
  ) external;

  /**
   * Merge existing keys
   * @param _tokenIdFrom the id of the token to substract time from
   * @param _tokenIdTo the id of the destination token  to add time
   * @param _amount the amount of time to transfer (in seconds)
   */
  function mergeKeys(
    uint _tokenIdFrom,
    uint _tokenIdTo,
    uint _amount
  ) external;

  /**
   * Deactivate an existing key
   * @param _tokenId the id of token to burn
   * @notice the key will be expired and ownership records will be destroyed
   */
  function burn(uint _tokenId) external;

  /**
   * @param _gasRefundValue price in wei or token in smallest price unit
   * @dev Set the value to be refunded to the sender on purchase
   */
  function setGasRefundValue(
    uint256 _gasRefundValue
  ) external;

  /**
   * _gasRefundValue price in wei or token in smallest price unit
   * @dev Returns the value/rpice to be refunded to the sender on purchase
   */
  function gasRefundValue()
    external
    view
    returns (uint256 _gasRefundValue);

  /**
   * @notice returns the minimum price paid for a purchase with these params.
   * @dev this considers any discount from Unlock or the OnKeyPurchase hook.
   */
  function purchasePriceFor(
    address _recipient,
    address _referrer,
    bytes calldata _data
  ) external view returns (uint);

  /**
   * Allow a Lock manager to change the transfer fee.
   * @dev Throws if called by other than a Lock manager
   * @param _transferFeeBasisPoints The new transfer fee in basis-points(bps).
   * Ex: 200 bps = 2%
   */
  function updateTransferFee(
    uint _transferFeeBasisPoints
  ) external;

  /**
   * Determines how much of a fee would need to be paid in order to
   * transfer to another account.  This is pro-rated so the fee goes
   * down overtime.
   * @dev Throws if _tokenId does not have a valid key
   * @param _tokenId The id of the key check the transfer fee for.
   * @param _time The amount of time to calculate the fee for.
   * @return The transfer fee in seconds.
   */
  function getTransferFee(
    uint _tokenId,
    uint _time
  ) external view returns (uint);

  /**
   * @dev Invoked by a Lock manager to expire the user's key
   * and perform a refund and cancellation of the key
   * @param _tokenId The key id we wish to refund to
   * @param _amount The amount to refund to the key-owner
   * @dev Throws if called by other than a Lock manager
   * @dev Throws if _keyOwner does not have a valid key
   */
  function expireAndRefundFor(
    uint _tokenId,
    uint _amount
  ) external;

  /**
   * @dev allows the key manager to expire a given tokenId
   * and send a refund to the keyOwner based on the amount of time remaining.
   * @param _tokenId The id of the key to cancel.
   */
  function cancelAndRefund(uint _tokenId) external;

  /**
   * Allow a Lock manager to change the refund penalty.
   * @dev Throws if called by other than a Lock manager
   * @param _freeTrialLength The new duration of free trials for this lock
   * @param _refundPenaltyBasisPoints The new refund penaly in basis-points(bps)
   */
  function updateRefundPenalty(
    uint _freeTrialLength,
    uint _refundPenaltyBasisPoints
  ) external;

  /**
   * @dev Determines how much of a refund a key owner would receive if they issued
   * @param _tokenId the id of the token to get the refund value for.
   * @notice Due to the time required to mine a tx, the actual refund amount will be lower
   * than what the user reads from this call.
   * @return refund the amount of tokens refunded
   */
  function getCancelAndRefundValue(
    uint _tokenId
  ) external view returns (uint refund);

  function addLockManager(address account) external;

  function isLockManager(
    address account
  ) external view returns (bool);

  /**
   * Returns the address of the `onKeyPurchaseHook` hook.
   * @return hookAddress address of the hook
   */
  function onKeyPurchaseHook()
    external
    view
    returns (address hookAddress);

  /**
   * Returns the address of the `onKeyCancelHook` hook.
   * @return hookAddress address of the hook
   */
  function onKeyCancelHook()
    external
    view
    returns (address hookAddress);

  /**
   * Returns the address of the `onValidKeyHook` hook.
   * @return hookAddress address of the hook
   */
  function onValidKeyHook()
    external
    view
    returns (address hookAddress);

  /**
   * Returns the address of the `onTokenURIHook` hook.
   * @return hookAddress address of the hook
   */
  function onTokenURIHook()
    external
    view
    returns (address hookAddress);

  /**
   * Returns the address of the `onKeyTransferHook` hook.
   * @return hookAddress address of the hook
   */
  function onKeyTransferHook()
    external
    view
    returns (address hookAddress);

  /**
   * Returns the address of the `onKeyExtendHook` hook.
   * @return hookAddress the address ok the hook
   */
  function onKeyExtendHook()
    external
    view
    returns (address hookAddress);

  /**
   * Returns the address of the `onKeyGrantHook` hook.
   * @return hookAddress the address ok the hook
   */
  function onKeyGrantHook()
    external
    view
    returns (address hookAddress);

  function renounceLockManager() external;

  /**
   * @return the maximum number of key allowed for a single address
   */
  function maxKeysPerAddress() external view returns (uint);

  function expirationDuration()
    external
    view
    returns (uint256);

  function freeTrialLength()
    external
    view
    returns (uint256);

  function keyPrice() external view returns (uint256);

  function maxNumberOfKeys()
    external
    view
    returns (uint256);

  function refundPenaltyBasisPoints()
    external
    view
    returns (uint256);

  function tokenAddress() external view returns (address);

  function transferFeeBasisPoints()
    external
    view
    returns (uint256);

  function unlockProtocol() external view returns (address);

  function keyManagerOf(
    uint
  ) external view returns (address);

  ///===================================================================

  /**
   * @notice Allows the key owner to safely share their key (parent key) by
   * transferring a portion of the remaining time to a new key (child key).
   * @dev Throws if key is not valid.
   * @dev Throws if `_to` is the zero address
   * @param _to The recipient of the shared key
   * @param _tokenId the key to share
   * @param _timeShared The amount of time shared
   * checks if `_to` is a smart contract (code size > 0). If so, it calls
   * `onERC721Received` on `_to` and throws if the return value is not
   * `bytes4(keccak256('onERC721Received(address,address,uint,bytes)'))`.
   * @dev Emit Transfer event
   */
  function shareKey(
    address _to,
    uint _tokenId,
    uint _timeShared
  ) external;

  /**
   * @notice Update transfer and cancel rights for a given key
   * @param _tokenId The id of the key to assign rights for
   * @param _keyManager The address to assign the rights to for the given key
   */
  function setKeyManagerOf(
    uint _tokenId,
    address _keyManager
  ) external;

  /**
   * Check if a certain key is valid
   * @param _tokenId the id of the key to check validity
   * @notice this makes use of the onValidKeyHook if it is set
   */
  function isValidKey(
    uint _tokenId
  ) external view returns (bool);

  /**
   * Returns the number of keys owned by `_keyOwner` (expired or not)
   * @param _keyOwner address for which we are retrieving the total number of keys
   * @return numberOfKeys total number of keys owned by the address
   */
  function totalKeys(
    address _keyOwner
  ) external view returns (uint numberOfKeys);

  /// @notice A descriptive name for a collection of NFTs in this contract
  function name()
    external
    view
    returns (string memory _name);

  ///===================================================================

  /// From ERC165.sol
  function supportsInterface(
    bytes4 interfaceId
  ) external view returns (bool);

  ///===================================================================

  /// From ERC-721
  /**
   * In the specific case of a Lock, `balanceOf` returns only the tokens with a valid expiration timerange
   * @return balance The number of valid keys owned by `_keyOwner`
   */
  function balanceOf(
    address _owner
  ) external view returns (uint256 balance);

  /**
   * @dev Returns the owner of the NFT specified by `tokenId`.
   */
  function ownerOf(
    uint256 tokenId
  ) external view returns (address _owner);

  /**
   * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
   * another (`to`).
   *
   * Requirements:
   * - `from`, `to` cannot be zero.
   * - `tokenId` must be owned by `from`.
   * - If the caller is not `from`, it must be have been allowed to move this
   * NFT by either {approve} or {setApprovalForAll}.
   */
  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId
  ) external;

  /**
   * an ERC721-like function to transfer a token from one account to another.
   * @param from the owner of token to transfer
   * @param to the address that will receive the token
   * @param tokenId the id of the token
   * @dev Requirements: if the caller is not `from`, it must be approved to move this token by
   * either {approve} or {setApprovalForAll}.
   * The key manager will be reset to address zero after the transfer
   */
  function transferFrom(
    address from,
    address to,
    uint256 tokenId
  ) external;

  /**
   * Lending a key allows you to transfer the token while retaining the
   * ownerships right by setting yourself as a key manager first.
   * @param from the owner of token to transfer
   * @param to the address that will receive the token
   * @param tokenId the id of the token
   * @notice This function can only be called by 1) the key owner when no key manager is set or 2) the key manager.
   * After calling the function, the `_recipent` will be the new owner, and the sender of the tx
   * will become the key manager.
   */
  function lendKey(
    address from,
    address to,
    uint tokenId
  ) external;

  /**
   * Unlend is called when you have lent a key and want to claim its full ownership back.
   * @param _recipient the address that will receive the token ownership
   * @param _tokenId the id of the token
   * @dev Only the key manager of the token can call this function
   */
  function unlendKey(
    address _recipient,
    uint _tokenId
  ) external;

  function approve(address to, uint256 tokenId) external;

  /**
   * @notice Get the approved address for a single NFT
   * @dev Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId The NFT to find the approved address for
   * @return operator The approved address for this NFT, or the zero address if there is none
   */
  function getApproved(
    uint256 _tokenId
  ) external view returns (address operator);

  /**
   * @dev Sets or unsets the approval of a given operator
   * An operator is allowed to transfer all tokens of the sender on their behalf
   * @param _operator operator address to set the approval
   * @param _approved representing the status of the approval to be set
   * @notice disabled when transfers are disabled
   */
  function setApprovalForAll(
    address _operator,
    bool _approved
  ) external;

  /**
   * @dev Tells whether an operator is approved by a given keyManager
   * @param _owner owner address which you want to query the approval of
   * @param _operator operator address which you want to query the approval of
   * @return bool whether the given operator is approved by the given owner
   */
  function isApprovedForAll(
    address _owner,
    address _operator
  ) external view returns (bool);

  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes calldata data
  ) external;

  function totalSupply() external view returns (uint256);

  function tokenOfOwnerByIndex(
    address _owner,
    uint256 index
  ) external view returns (uint256 tokenId);

  function tokenByIndex(
    uint256 index
  ) external view returns (uint256);

  /**
   * Innherited from Open Zeppelin AccessControl.sol
   */
  function getRoleAdmin(
    bytes32 role
  ) external view returns (bytes32);

  function grantRole(
    bytes32 role,
    address account
  ) external;

  function revokeRole(
    bytes32 role,
    address account
  ) external;

  function renounceRole(
    bytes32 role,
    address account
  ) external;

  function hasRole(
    bytes32 role,
    address account
  ) external view returns (bool);

  /**
   * @param _tokenId the id of the token to transfer time from
   * @param _to the recipient of the new token with time
   * @param _value sends a token with _value * expirationDuration (the amount of time remaining on a standard purchase).
   * @dev The typical use case would be to call this with _value 1, which is on par with calling `transferFrom`. If the user
   * has more than `expirationDuration` time remaining this may use the `shareKey` function to send some but not all of the token.
   * @return success the result of the transfer operation
   */
  function transfer(
    uint _tokenId,
    address _to,
    uint _value
  ) external returns (bool success);

  /** `owner()` is provided as an helper to mimick the `Ownable` contract ABI.
   * The `Ownable` logic is used by many 3rd party services to determine
   * contract ownership - e.g. who is allowed to edit metadata on Opensea.
   *
   * @notice This logic is NOT used internally by the Unlock Protocol and is made
   * available only as a convenience helper.
   */
  function owner() external view returns (address owner);

  function setOwner(address account) external;

  function isOwner(
    address account
  ) external view returns (bool isOwner);

  /**
   * Migrate data from the previous single owner => key mapping to
   * the new data structure w multiple tokens.
   * @param _calldata an ABI-encoded representation of the params (v10: the number of records to migrate as `uint`)
   * @dev when all record schemas are sucessfully upgraded, this function will update the `schemaVersion`
   * variable to the latest/current lock version
   */
  function migrate(bytes calldata _calldata) external;

  /**
   * Returns the version number of the data schema currently used by the lock
   * @notice if this is different from `publicLockVersion`, then the ability to purchase, grant
   * or extend keys is disabled.
   * @dev will return 0 if no ;igration has ever been run
   */
  function schemaVersion() external view returns (uint);

  /**
   * Set the schema version to the latest
   * @notice only lock manager call call this
   */
  function updateSchemaVersion() external;

  /**
   * Renew a given token
   * @notice only works for non-free, expiring, ERC20 locks
   * @param _tokenId the ID fo the token to renew
   * @param _referrer the address of the person to be granted UDT
   */
  function renewMembershipFor(
    uint _tokenId,
    address _referrer
  ) external;
}

File 9 of 9 : IUnlock.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.17 <0.9.0;

/**
 * @title The Unlock Interface
 **/

interface IUnlock {
  // Use initialize instead of a constructor to support proxies(for upgradeability via zos).
  function initialize(address _unlockOwner) external;

  /**
   * @dev deploy a ProxyAdmin contract used to upgrade locks
   */
  function initializeProxyAdmin() external;

  /**
   * Retrieve the contract address of the proxy admin that manages the locks
   * @return the address of the ProxyAdmin instance
   */
  function proxyAdminAddress()
    external
    view
    returns (address);

  /**
   * @notice Create lock (legacy)
   * This deploys a lock for a creator. It also keeps track of the deployed lock.
   * @param _expirationDuration the duration of the lock (pass 0 for unlimited duration)
   * @param _tokenAddress set to the ERC20 token address, or 0 for ETH.
   * @param _keyPrice the price of each key
   * @param _maxNumberOfKeys the maximum nimbers of keys to be edited
   * @param _lockName the name of the lock
   * param _salt [deprec] -- kept only for backwards copatibility
   * This may be implemented as a sequence ID or with RNG. It's used with `create2`
   * to know the lock's address before the transaction is mined.
   * @dev internally call `createUpgradeableLock`
   */
  function createLock(
    uint _expirationDuration,
    address _tokenAddress,
    uint _keyPrice,
    uint _maxNumberOfKeys,
    string calldata _lockName,
    bytes12 // _salt
  ) external returns (address);

  /**
   * @notice Create lock (default)
   * This deploys a lock for a creator. It also keeps track of the deployed lock.
   * @param data bytes containing the call to initialize the lock template
   * @dev this call is passed as encoded function - for instance:
   *  bytes memory data = abi.encodeWithSignature(
   *    'initialize(address,uint256,address,uint256,uint256,string)',
   *    msg.sender,
   *    _expirationDuration,
   *    _tokenAddress,
   *    _keyPrice,
   *    _maxNumberOfKeys,
   *    _lockName
   *  );
   * @return address of the create lock
   */
  function createUpgradeableLock(
    bytes memory data
  ) external returns (address);

  /**
   * Create an upgradeable lock using a specific PublicLock version
   * @param data bytes containing the call to initialize the lock template
   * (refer to createUpgradeableLock for more details)
   * @param _lockVersion the version of the lock to use
   */
  function createUpgradeableLockAtVersion(
    bytes memory data,
    uint16 _lockVersion
  ) external returns (address);

  /**
   * @notice Upgrade a lock to a specific version
   * @dev only available for publicLockVersion > 10 (proxyAdmin /required)
   * @param lockAddress the existing lock address
   * @param version the version number you are targeting
   * Likely implemented with OpenZeppelin TransparentProxy contract
   */
  function upgradeLock(
    address payable lockAddress,
    uint16 version
  ) external returns (address);

  /**
   * This function keeps track of the added GDP, as well as grants of discount tokens
   * to the referrer, if applicable.
   * The number of discount tokens granted is based on the value of the referal,
   * the current growth rate and the lock's discount token distribution rate
   * This function is invoked by a previously deployed lock only.
   */
  function recordKeyPurchase(
    uint _value,
    address _referrer // solhint-disable-line no-unused-vars
  ) external;

  /**
   * @notice [DEPRECATED] Call to this function has been removed from PublicLock > v9.
   * @dev [DEPRECATED] Kept for backwards compatibility
   * This function will keep track of consumed discounts by a given user.
   * It will also grant discount tokens to the creator who is granting the discount based on the
   * amount of discount and compensation rate.
   * This function is invoked by a previously deployed lock only.
   */
  function recordConsumedDiscount(
    uint _discount,
    uint _tokens // solhint-disable-line no-unused-vars
  ) external view;

  /**
   * @notice [DEPRECATED] Call to this function has been removed from PublicLock > v9.
   * @dev [DEPRECATED] Kept for backwards compatibility
   * This function returns the discount available for a user, when purchasing a
   * a key from a lock.
   * This does not modify the state. It returns both the discount and the number of tokens
   * consumed to grant that discount.
   */
  function computeAvailableDiscountFor(
    address _purchaser, // solhint-disable-line no-unused-vars
    uint _keyPrice // solhint-disable-line no-unused-vars
  ) external pure returns (uint discount, uint tokens);

  // Function to read the globalTokenURI field.
  function globalBaseTokenURI()
    external
    view
    returns (string memory);

  /**
   * @dev Redundant with globalBaseTokenURI() for backwards compatibility with v3 & v4 locks.
   */
  function getGlobalBaseTokenURI()
    external
    view
    returns (string memory);

  // Function to read the globalTokenSymbol field.
  function globalTokenSymbol()
    external
    view
    returns (string memory);

  // Function to read the chainId field.
  function chainId() external view returns (uint);

  /**
   * @dev Redundant with globalTokenSymbol() for backwards compatibility with v3 & v4 locks.
   */
  function getGlobalTokenSymbol()
    external
    view
    returns (string memory);

  /**
   * @notice Allows the owner to update configuration variables
   */
  function configUnlock(
    address _udt,
    address _weth,
    uint _estimatedGasForPurchase,
    string calldata _symbol,
    string calldata _URI,
    uint _chainId
  ) external;

  /**
   * @notice Add a PublicLock template to be used for future calls to `createLock`.
   * @dev This is used to upgrade conytract per version number
   */
  function addLockTemplate(
    address impl,
    uint16 version
  ) external;

  /**
   * Match lock templates addresses with version numbers
   * @param _version the number of the version of the template
   * @return address of the lock templates
   */
  function publicLockImpls(
    uint16 _version
  ) external view returns (address);

  /**
   * Match version numbers with lock templates addresses
   * @param _impl the address of the deployed template contract (PublicLock)
   * @return number of the version corresponding to this address
   */
  function publicLockVersions(
    address _impl
  ) external view returns (uint16);

  /**
   * Retrive the latest existing lock template version
   * @return the version number of the latest template (used to deploy contracts)
   */
  function publicLockLatestVersion()
    external
    view
    returns (uint16);

  /**
   * @notice Upgrade the PublicLock template used for future calls to `createLock`.
   * @dev This will initialize the template and revokeOwnership.
   */
  function setLockTemplate(
    address payable _publicLockAddress
  ) external;

  // Allows the owner to change the value tracking variables as needed.
  function resetTrackedValue(
    uint _grossNetworkProduct,
    uint _totalDiscountGranted
  ) external;

  function grossNetworkProduct()
    external
    view
    returns (uint);

  function totalDiscountGranted()
    external
    view
    returns (uint);

  function locks(
    address
  )
    external
    view
    returns (
      bool deployed,
      uint totalSales,
      uint yieldedDiscountTokens
    );

  // The address of the public lock template, used when `createLock` is called
  function publicLockAddress()
    external
    view
    returns (address);

  // Map token address to exchange contract address if the token is supported
  // Used for GDP calculations
  function uniswapOracles(
    address
  ) external view returns (address);

  // The WETH token address, used for value calculations
  function weth() external view returns (address);

  // The UDT token address, used to mint tokens on referral
  function udt() external view returns (address);

  // The approx amount of gas required to purchase a key
  function estimatedGasForPurchase()
    external
    view
    returns (uint);

  /**
   * Helper to get the network mining basefee as introduced in EIP-1559
   * @dev this helper can be wrapped in try/catch statement to avoid
   * revert in networks where EIP-1559 is not implemented
   */
  function networkBaseFee() external view returns (uint);

  // The version number of the current Unlock implementation on this network
  function unlockVersion() external pure returns (uint16);

  /**
   * @notice allows the owner to set the oracle address to use for value conversions
   * setting the _oracleAddress to address(0) removes support for the token
   * @dev This will also call update to ensure at least one datapoint has been recorded.
   */
  function setOracle(
    address _tokenAddress,
    address _oracleAddress
  ) external;

  // Initialize the Ownable contract, granting contract ownership to the specified sender
  function __initializeOwnable(address sender) external;

  /**
   * @dev Returns true if the caller is the current owner.
   */
  function isOwner() external view returns (bool);

  /**
   * @dev Returns the address of the current owner.
   */
  function owner() external view returns (address);

  /**
   * @dev Leaves the contract without owner. It will not be possible to call
   * `onlyOwner` functions anymore. Can only be called by the current owner.
   *
   * NOTE: Renouncing ownership will leave the contract without an owner,
   * thereby removing any functionality that is only available to the owner.
   */
  function renounceOwnership() external;

  /**
   * @dev Transfers ownership of the contract to a new account (`newOwner`).
   * Can only be called by the current owner.
   */
  function transferOwnership(address newOwner) external;

  /**
   * Set the fee collected by the protocol
   * @param _protocolFee fee (in basis points)
   */
  function setProtocolFee(uint _protocolFee) external;

  /**
   * The fee (in basis points) collected by the protocol on each purchase / 
   extension / renewal of a key
   * @return the protocol fee in basic point
   */
  function protocolFee() external view returns (uint);

  /**
   * Call executed by a lock after its version upgrade triggred by `upgradeLock`
   * - PublicLock v12 > v13 (mainnet): migrate an existing Lock to another instance 
   * of the Unlock contract
   * @dev The `msg.sender` will be the upgraded lock
   */
  function postLockUpgrade() external;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 80
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_unlockAddress","type":"address"},{"internalType":"address","name":"_permit2Address","type":"address"},{"internalType":"address[]","name":"_uniswapRouters","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"LockCallFailed","type":"error"},{"inputs":[{"internalType":"address","name":"lockAddress","type":"address"}],"name":"LockDoesntExist","type":"error"},{"inputs":[{"internalType":"address","name":"uniswapRouter","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"SwapFailed","type":"error"},{"inputs":[],"name":"UnauthorizedBalanceChange","type":"error"},{"inputs":[{"internalType":"address","name":"routerAddress","type":"address"}],"name":"UnautorizedRouter","type":"error"},{"inputs":[],"name":"WithdrawFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"lock","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSpent","type":"uint256"}],"name":"SwapCall","type":"event"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lock","type":"address"},{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address","name":"uniswapRouter","type":"address"},{"internalType":"bytes","name":"swapCalldata","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"swapAndCall","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unlockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"withdrawToUnlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Contract Creation Code

60806040523480156200001157600080fd5b50604051620011033803806200110383398101604081905262000034916200010a565b600080546001600160a01b038086166001600160a01b031992831617835560018054918616919092161790555b8151811015620000cd5760016002600084848151811062000086576200008662000204565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620000c4816200021a565b91505062000061565b5050505062000242565b80516001600160a01b0381168114620000ef57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156200012057600080fd5b6200012b84620000d7565b925060206200013c818601620000d7565b60408601519093506001600160401b03808211156200015a57600080fd5b818701915087601f8301126200016f57600080fd5b815181811115620001845762000184620000f4565b8060051b604051601f19603f83011681018181108582111715620001ac57620001ac620000f4565b60405291825284820192508381018501918a831115620001cb57600080fd5b938501935b82851015620001f457620001e485620000d7565b84529385019392850192620001d0565b8096505050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b6000600182016200023b57634e487b7160e01b600052601160045260246000fd5b5060010190565b610eb180620002526000396000f3fe6080604052600436106100435760003560e01c806302837f7b1461004f57806312261ee7146100715780635e8f4502146100a7578063b30929cd146100c757600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610b32565b6100e7565b005b34801561007d57600080fd5b50600154610091906001600160a01b031681565b60405161009e9190610b56565b60405180910390f35b6100ba6100b5366004610c0d565b6101f9565b60405161009e9190610d0d565b3480156100d357600080fd5b50600054610091906001600160a01b031681565b60006100f28261087b565b90506001600160a01b0382161561017f5760005460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb9261013792909116908590600401610d20565b6020604051808303816000875af1158015610156573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061017a9190610d4e565b505050565b600080546040516001600160a01b039091169083908381818185875af1925050503d80600081146101cc576040519150601f19603f3d011682016040523d82523d6000602084013e6101d1565b606091505b509091505080151560000361017a57604051631d42c86760e21b815260040160405180910390fd5b60008054604051635de9a13760e01b8152606092916001600160a01b031690635de9a1379061022c908b90600401610b56565b606060405180830381865afa158015610249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026d9190610d69565b505090508061029a5787604051637421631960e11b81526004016102919190610b56565b60405180910390fd5b6001600160a01b03851660009081526002602052604090205460ff1615156001146102da578460405163f2f52fc960e01b81526004016102919190610b56565b6000886001600160a01b0316639d76ea586040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033e9190610d9e565b905060006001600160a01b0382161561035f5761035a8261087b565b610373565b346103698361087b565b6103739190610dd1565b905060006001600160a01b038a16156103945761038f8a61087b565b6103a8565b3461039e8b61087b565b6103a89190610dd1565b90506001600160a01b038a1615610449576103c58a33308c610906565b6103d08a898b610a10565b60015460405163095ea7b360e01b81526001600160a01b038c81169263095ea7b39261040492909116908d90600401610d20565b6020604051808303816000875af1158015610423573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104479190610d4e565b505b6001546001600160a01b03166387517c458b8a8c61046842603c610de8565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015292841660248401529216604482015265ffffffffffff9091166064820152608401600060405180830381600087803b1580156104c757600080fd5b505af11580156104db573d6000803e3d6000fd5b5060009250506001600160a01b03808b1691508c16156104fc5760006104fe565b345b8960405161050c9190610e00565b60006040518083038185875af1925050503d8060008114610549576040519150601f19603f3d011682016040523d82523d6000602084013e61054e565b606091505b509091505080151560000361058057888b858c8b604051637bd486e960e11b8152600401610291959493929190610e1c565b8b6001600160a01b03166310e569736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e29190610e62565b6105ec9084610de8565b6001600160a01b03851615610609576106048561087b565b61061d565b346106138661087b565b61061d9190610dd1565b101561063c57604051631e9acf1760e31b815260040160405180910390fd5b6001600160a01b0384161561071f57836001600160a01b031663095ea7b38d8e6001600160a01b03166310e569736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610699573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bd9190610e62565b6040518363ffffffff1660e01b81526004016106da929190610d20565b6020604051808303816000875af11580156106f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071d9190610d4e565b505b6000806001600160a01b03808f169087161561073c57600061079e565b8e6001600160a01b03166310e569736040518163ffffffff1660e01b8152600401602060405180830381865afa15801561077a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079e9190610e62565b8a6040516107ac9190610e00565b60006040518083038185875af1925050503d80600081146107e9576040519150601f19603f3d011682016040523d82523d6000602084013e6107ee565b606091505b50909250905081151560000361081757604051637772507160e11b815260040160405180910390fd5b6000846108238f61087b565b61082d9190610dd1565b108061084c57506000856108408861087b565b61084a9190610dd1565b105b1561086a5760405163392032cb60e21b815260040160405180910390fd5b9d9c50505050505050505050505050565b60006001600160a01b038216156108fe576040516370a0823160e01b81526001600160a01b038316906370a08231906108b8903090600401610b56565b602060405180830381865afa1580156108d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f99190610e62565b610900565b475b92915050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b179052915160009283929088169161096a9190610e00565b6000604051808303816000865af19150503d80600081146109a7576040519150601f19603f3d011682016040523d82523d6000602084013e6109ac565b606091505b50915091508180156109d65750805115806109d65750808060200190518101906109d69190610d4e565b610a085760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b6044820152606401610291565b505050505050565b600080846001600160a01b031663095ea7b360e01b8585604051602401610a38929190610d20565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610a769190610e00565b6000604051808303816000865af19150503d8060008114610ab3576040519150601f19603f3d011682016040523d82523d6000602084013e610ab8565b606091505b5091509150818015610ae2575080511580610ae2575080806020019051810190610ae29190610d4e565b610b135760405162461bcd60e51b8152602060048201526002602482015261534160f01b6044820152606401610291565b5050505050565b6001600160a01b0381168114610b2f57600080fd5b50565b600060208284031215610b4457600080fd5b8135610b4f81610b1a565b9392505050565b6001600160a01b0391909116815260200190565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610b9157600080fd5b813567ffffffffffffffff80821115610bac57610bac610b6a565b604051601f8301601f19908116603f01168101908282118183101715610bd457610bd4610b6a565b81604052838152866020858801011115610bed57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c08789031215610c2657600080fd5b8635610c3181610b1a565b95506020870135610c4181610b1a565b9450604087013593506060870135610c5881610b1a565b9250608087013567ffffffffffffffff80821115610c7557600080fd5b610c818a838b01610b80565b935060a0890135915080821115610c9757600080fd5b50610ca489828a01610b80565b9150509295509295509295565b60005b83811015610ccc578181015183820152602001610cb4565b83811115610cdb576000848401525b50505050565b60008151808452610cf9816020860160208601610cb1565b601f01601f19169290920160200192915050565b602081526000610b4f6020830184610ce1565b6001600160a01b03929092168252602082015260400190565b80518015158114610d4957600080fd5b919050565b600060208284031215610d6057600080fd5b610b4f82610d39565b600080600060608486031215610d7e57600080fd5b610d8784610d39565b925060208401519150604084015190509250925092565b600060208284031215610db057600080fd5b8151610b4f81610b1a565b634e487b7160e01b600052601160045260246000fd5b600082821015610de357610de3610dbb565b500390565b60008219821115610dfb57610dfb610dbb565b500190565b60008251610e12818460208701610cb1565b9190910192915050565b6001600160a01b0386811682528581166020830152841660408201526060810183905260a060808201819052600090610e5790830184610ce1565b979650505050505050565b600060208284031215610e7457600080fd5b505191905056fea2646970667358221220f15885891d83577bf265f3b7f85f96639bf1fa423670362f91f4c3a5827c933b64736f6c634300080d00330000000000000000000000001ff7e338d5e582138c46044dc238543ce555c963000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c73d61d192fb994157168fb56730fdec64c9cb8f0000000000000000000000005615cdab10dc425a742d643d949a7f474c01abc4

Deployed Bytecode

0x6080604052600436106100435760003560e01c806302837f7b1461004f57806312261ee7146100715780635e8f4502146100a7578063b30929cd146100c757600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610b32565b6100e7565b005b34801561007d57600080fd5b50600154610091906001600160a01b031681565b60405161009e9190610b56565b60405180910390f35b6100ba6100b5366004610c0d565b6101f9565b60405161009e9190610d0d565b3480156100d357600080fd5b50600054610091906001600160a01b031681565b60006100f28261087b565b90506001600160a01b0382161561017f5760005460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb9261013792909116908590600401610d20565b6020604051808303816000875af1158015610156573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061017a9190610d4e565b505050565b600080546040516001600160a01b039091169083908381818185875af1925050503d80600081146101cc576040519150601f19603f3d011682016040523d82523d6000602084013e6101d1565b606091505b509091505080151560000361017a57604051631d42c86760e21b815260040160405180910390fd5b60008054604051635de9a13760e01b8152606092916001600160a01b031690635de9a1379061022c908b90600401610b56565b606060405180830381865afa158015610249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026d9190610d69565b505090508061029a5787604051637421631960e11b81526004016102919190610b56565b60405180910390fd5b6001600160a01b03851660009081526002602052604090205460ff1615156001146102da578460405163f2f52fc960e01b81526004016102919190610b56565b6000886001600160a01b0316639d76ea586040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033e9190610d9e565b905060006001600160a01b0382161561035f5761035a8261087b565b610373565b346103698361087b565b6103739190610dd1565b905060006001600160a01b038a16156103945761038f8a61087b565b6103a8565b3461039e8b61087b565b6103a89190610dd1565b90506001600160a01b038a1615610449576103c58a33308c610906565b6103d08a898b610a10565b60015460405163095ea7b360e01b81526001600160a01b038c81169263095ea7b39261040492909116908d90600401610d20565b6020604051808303816000875af1158015610423573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104479190610d4e565b505b6001546001600160a01b03166387517c458b8a8c61046842603c610de8565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015292841660248401529216604482015265ffffffffffff9091166064820152608401600060405180830381600087803b1580156104c757600080fd5b505af11580156104db573d6000803e3d6000fd5b5060009250506001600160a01b03808b1691508c16156104fc5760006104fe565b345b8960405161050c9190610e00565b60006040518083038185875af1925050503d8060008114610549576040519150601f19603f3d011682016040523d82523d6000602084013e61054e565b606091505b509091505080151560000361058057888b858c8b604051637bd486e960e11b8152600401610291959493929190610e1c565b8b6001600160a01b03166310e569736040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e29190610e62565b6105ec9084610de8565b6001600160a01b03851615610609576106048561087b565b61061d565b346106138661087b565b61061d9190610dd1565b101561063c57604051631e9acf1760e31b815260040160405180910390fd5b6001600160a01b0384161561071f57836001600160a01b031663095ea7b38d8e6001600160a01b03166310e569736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610699573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bd9190610e62565b6040518363ffffffff1660e01b81526004016106da929190610d20565b6020604051808303816000875af11580156106f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071d9190610d4e565b505b6000806001600160a01b03808f169087161561073c57600061079e565b8e6001600160a01b03166310e569736040518163ffffffff1660e01b8152600401602060405180830381865afa15801561077a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079e9190610e62565b8a6040516107ac9190610e00565b60006040518083038185875af1925050503d80600081146107e9576040519150601f19603f3d011682016040523d82523d6000602084013e6107ee565b606091505b50909250905081151560000361081757604051637772507160e11b815260040160405180910390fd5b6000846108238f61087b565b61082d9190610dd1565b108061084c57506000856108408861087b565b61084a9190610dd1565b105b1561086a5760405163392032cb60e21b815260040160405180910390fd5b9d9c50505050505050505050505050565b60006001600160a01b038216156108fe576040516370a0823160e01b81526001600160a01b038316906370a08231906108b8903090600401610b56565b602060405180830381865afa1580156108d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f99190610e62565b610900565b475b92915050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b179052915160009283929088169161096a9190610e00565b6000604051808303816000865af19150503d80600081146109a7576040519150601f19603f3d011682016040523d82523d6000602084013e6109ac565b606091505b50915091508180156109d65750805115806109d65750808060200190518101906109d69190610d4e565b610a085760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b6044820152606401610291565b505050505050565b600080846001600160a01b031663095ea7b360e01b8585604051602401610a38929190610d20565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610a769190610e00565b6000604051808303816000865af19150503d8060008114610ab3576040519150601f19603f3d011682016040523d82523d6000602084013e610ab8565b606091505b5091509150818015610ae2575080511580610ae2575080806020019051810190610ae29190610d4e565b610b135760405162461bcd60e51b8152602060048201526002602482015261534160f01b6044820152606401610291565b5050505050565b6001600160a01b0381168114610b2f57600080fd5b50565b600060208284031215610b4457600080fd5b8135610b4f81610b1a565b9392505050565b6001600160a01b0391909116815260200190565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610b9157600080fd5b813567ffffffffffffffff80821115610bac57610bac610b6a565b604051601f8301601f19908116603f01168101908282118183101715610bd457610bd4610b6a565b81604052838152866020858801011115610bed57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c08789031215610c2657600080fd5b8635610c3181610b1a565b95506020870135610c4181610b1a565b9450604087013593506060870135610c5881610b1a565b9250608087013567ffffffffffffffff80821115610c7557600080fd5b610c818a838b01610b80565b935060a0890135915080821115610c9757600080fd5b50610ca489828a01610b80565b9150509295509295509295565b60005b83811015610ccc578181015183820152602001610cb4565b83811115610cdb576000848401525b50505050565b60008151808452610cf9816020860160208601610cb1565b601f01601f19169290920160200192915050565b602081526000610b4f6020830184610ce1565b6001600160a01b03929092168252602082015260400190565b80518015158114610d4957600080fd5b919050565b600060208284031215610d6057600080fd5b610b4f82610d39565b600080600060608486031215610d7e57600080fd5b610d8784610d39565b925060208401519150604084015190509250925092565b600060208284031215610db057600080fd5b8151610b4f81610b1a565b634e487b7160e01b600052601160045260246000fd5b600082821015610de357610de3610dbb565b500390565b60008219821115610dfb57610dfb610dbb565b500190565b60008251610e12818460208701610cb1565b9190910192915050565b6001600160a01b0386811682528581166020830152841660408201526060810183905260a060808201819052600090610e5790830184610ce1565b979650505050505050565b600060208284031215610e7457600080fd5b505191905056fea2646970667358221220f15885891d83577bf265f3b7f85f96639bf1fa423670362f91f4c3a5827c933b64736f6c634300080d0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001ff7e338d5e582138c46044dc238543ce555c963000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c73d61d192fb994157168fb56730fdec64c9cb8f0000000000000000000000005615cdab10dc425a742d643d949a7f474c01abc4

-----Decoded View---------------
Arg [0] : _unlockAddress (address): 0x1FF7e338d5E582138C46044dc238543Ce555C963
Arg [1] : _permit2Address (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
Arg [2] : _uniswapRouters (address[]): 0xC73d61d192FB994157168Fb56730FdEc64C9Cb8F,0x5615CDAb10dc425a742d643d949a7F474C01abc4

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000001ff7e338d5e582138c46044dc238543ce555c963
Arg [1] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [4] : 000000000000000000000000c73d61d192fb994157168fb56730fdec64c9cb8f
Arg [5] : 0000000000000000000000005615cdab10dc425a742d643d949a7f474c01abc4


Block Transaction Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.