Spend less on fees, more on crypto. Buy crypto easily with MoonPay Balance. 20M+ users trust MoonPay worldwide.
Ready to onboard to Ethereum? With MetaMask Portfolio, you're in control.
Don’t invest unless you’re prepared to lose all the money you invest.
Ready to simplify your web3 experience? Try the all-in-one web3 app trusted by millions worldwide.
Available on 9 networks: Ethereum mainnet, Linea, Polygon, Optimism, BNB Chain, zkSync Era, Base, Avalanche.
Everyday giveaways up to 100 ETH, Lucky Spins. Deposit BONUS 300% and Cashbacks!
5000+ Slots & Live Casino Games, 50+cryptos. Register with Etherscan and get 760% deposit bonus. Win Big$, withdraw it fast.
Slots, Roulette, Poker & more - Proud sponsors of UFC, Everton & StakeF1 team!
5000+ Slots & Live Casino Games, 50+cryptos. Register with Etherscan and get 760% deposit bonus. Win Big$, withdraw it fast.
Anonymous play on awesome games - sign up now for 25 free jackpot spins - worth $100s!
100s of games, generous bonuses, 20+ years of trusted gaming. Join CryptoWins & start winning today!
Overview
ETH Balance
Eth Value
$13.03 (@ $3,385.06/ETH)Token Holdings
Could not find any matches!
- ERC-20 Tokens (20)787.29482151 1INCH1INCH Token (1INCH)$314.60@0.3996131.87657022 APEApeCoin (APE)$160.89@1.22232.23936396 LINKChainLink To... (LINK)$5,587.68@24.06155.99863497 LDOLido DAO Tok... (LDO)$282.36@1.811,026,862,294.99239 PEPEPepe (PEPE)$18,760.77@0.000.03450522 imBTCThe Tokenize... (imBTC)$3,406.67@98,729.00637.72766941 UNIUniswap (UNI)$8,966.45@14.0617,700.20533278 DAIDai Stableco... (DAI)$17,717.91@1.00133,636.753254 USDTTether USD (USDT)$33,613.27@0.9993112.775504 USDCUSDC (USDC)$112.89@1.0010.00296089 WBTCWrapped BTC (WBTC)$278.60@94,095.004,000 Earn $UNI airdrops at https://www.uniswaplabs.comERC-20: # un... (Earn $...)48,000 Earn $TUSD airdrops at https://www.tenorusd.orgERC-20: $ te... (Earn $...)12,394,453.0166 CHKNChickencoin$0.92@0.002,797.604281 DUSDERC-20: DCST... (DUSD)1.2 TokenERC-20 TOKEN*[Suspicious]245.44 TokenERC-20 TOKEN*[Suspicious]0.7 TokenERC-20 TOKEN*[Suspicious]1.7 TokenERC-20 TOKEN*[Suspicious]132.84 TokenERC-20 TOKEN*[Spam]NFT Tokens (26)claim rewards on apylink.comapylink.comERC-1155claim rewards on apyusd.netapyusd.netERC-1155ether-origin.comether-origin.comERC-1155claim rewards on get-clink.netget-clink.netERC-1155claim rewards on pepetoken.netpepetoken.netERC-1155claim rewards on univ3portal.netuniv3portal.netERC-1155claim rewards on univ4labs.orguniv4labs.orgERC-1155Withdrawal NFT originethers.commWithdrawal NFT originethers.comERC-1155ERC-1155 TOKEN*[Suspicious]ERC-1155 TOKEN*[Suspicious]ERC-1155 TOKEN*[Suspicious]ERC-1155 TOKEN*[Suspicious]ERC-1155 TOKEN*[Suspicious]ERC-1155 TOKEN*[Suspicious]ERC-1155 TOKEN*[Suspicious]ERC-1155 TOKEN*[Spam]ERC-1155 TOKEN*[Spam]ERC-1155 TOKEN*[Spam]
More Info
Private Name Tags
ContractCreator
Multichain Info
1 address found via- Transactions
- Internal Transactions
- Token Transfers (ERC-20)
- NFT Transfers
- Contract
- Events
- Analytics
- Multichain Portfolio
- Cards New
Transaction Hash MethodBlockFromToLatest 25 internal transactions (View All)
Advanced mode:Parent Transaction Hash Block FromTo20611183 2024-08-26 7:09:47 119 days ago 1724656187 2.92 ETH$9,884.38 20611183 2024-08-26 7:09:47 119 days ago 1724656187 2.92 ETH$9,884.38 20610654 2024-08-26 5:23:47 119 days ago 1724649827 0.3413 ETH$1,155.32 20610654 2024-08-26 5:23:47 119 days ago 1724649827 0.3413 ETH$1,155.32 20610611 2024-08-26 5:15:11 119 days ago 1724649311 1.0091 ETH$3,415.87 20610611 2024-08-26 5:15:11 119 days ago 1724649311 1.0091 ETH$3,415.87 20610486 2024-08-26 4:50:11 119 days ago 1724647811 27.5 ETH$93,089.21 20610486 2024-08-26 4:50:11 119 days ago 1724647811 27.5 ETH$93,089.21 20610399 2024-08-26 4:32:23 119 days ago 1724646743 0.353 ETH$1,194.93 20610399 2024-08-26 4:32:23 119 days ago 1724646743 0.353 ETH$1,194.93 20610388 2024-08-26 4:30:11 119 days ago 1724646611 0.35173549 ETH$1,190.65 20610388 2024-08-26 4:30:11 119 days ago 1724646611 0.35286466 ETH$1,194.47 20610376 2024-08-26 4:27:35 119 days ago 1724646455 0.3537 ETH$1,197.30 20610376 2024-08-26 4:27:35 119 days ago 1724646455 0.3537 ETH$1,197.30 20610371 2024-08-26 4:26:35 119 days ago 1724646395 0.02355831 ETH$79.75 20610371 2024-08-26 4:26:35 119 days ago 1724646395 0.02399502 ETH$81.22 20610363 2024-08-26 4:24:59 119 days ago 1724646299 0.3577154 ETH$1,210.89 20610363 2024-08-26 4:24:59 119 days ago 1724646299 0.35886377 ETH$1,214.78 20610282 2024-08-26 4:08:47 119 days ago 1724645327 0.2 ETH$677.01 20610282 2024-08-26 4:08:47 119 days ago 1724645327 0.2 ETH$677.01 20610264 2024-08-26 4:05:11 119 days ago 1724645111 0.115 ETH$389.28 20610264 2024-08-26 4:05:11 119 days ago 1724645111 0.115 ETH$389.28 20610231 2024-08-26 3:58:23 119 days ago 1724644703 0.36484195 ETH$1,235.01 20610231 2024-08-26 3:58:23 119 days ago 1724644703 0.36597648 ETH$1,238.85 20610213 2024-08-26 3:54:47 119 days ago 1724644487 0.1696 ETH$574.11 Loading...LoadingContract Name:RFQv2
Compiler Versionv0.7.6+commit.7338295f
Optimization Enabled:Yes with 1000 runs
Other Settings:istanbul EvmVersionContract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { TokenCollector } from "./utils/TokenCollector.sol"; import { BaseLibEIP712 } from "./utils/BaseLibEIP712.sol"; import { Asset } from "./utils/Asset.sol"; import { Offer } from "./utils/Offer.sol"; import { RFQOrder, getRFQOrderHash } from "./utils/RFQOrder.sol"; import { LibConstant } from "./utils/LibConstant.sol"; import { SignatureValidator } from "./utils/SignatureValidator.sol"; import { StrategyBase } from "./utils/StrategyBase.sol"; import { IRFQv2 } from "./interfaces/IRFQv2.sol"; /// @title RFQv2 Contract /// @author imToken Labs contract RFQv2 is IRFQv2, StrategyBase, TokenCollector, SignatureValidator, BaseLibEIP712 { using SafeMath for uint256; using Asset for address; address payable public feeCollector; /// @notice Emitted when fee collector address is updated /// @param newFeeCollector The address of the new fee collector event SetFeeCollector(address newFeeCollector); receive() external payable {} constructor( address _owner, address _userProxy, address _weth, address _permStorage, address _spender, address _uniswapPermit2, address payable _feeCollector ) StrategyBase(_owner, _userProxy, _weth, _permStorage, _spender) TokenCollector(_uniswapPermit2, _spender) { feeCollector = _feeCollector; } /// @notice Set fee collector /// @notice Only owner can call /// @param _newFeeCollector The address of the new fee collector function setFeeCollector(address payable _newFeeCollector) external onlyOwner { require(_newFeeCollector != address(0), "zero address"); feeCollector = _newFeeCollector; emit SetFeeCollector(_newFeeCollector); } /// @inheritdoc IRFQv2 function fillRFQ( RFQOrder calldata order, bytes calldata makerSignature, bytes calldata makerTokenPermit, bytes calldata takerSignature, bytes calldata takerTokenPermit ) external payable override onlyUserProxy { Offer calldata _offer = order.offer; // check the offer deadline and fee factor require(_offer.expiry > block.timestamp, "offer expired"); require(_offer.feeFactor < LibConstant.BPS_MAX, "invalid fee factor"); require(order.recipient != address(0), "zero recipient"); // check if the offer is available to be filled (bytes32 offerHash, bytes32 rfqOrderHash) = getRFQOrderHash(order); // check and set permStorage.setRFQOfferFilled(offerHash); // check maker signature require(isValidSignature(_offer.maker, getEIP712Hash(offerHash), bytes(""), makerSignature), "invalid signature"); // check taker signature if needed if (_offer.taker != msg.sender) { require(isValidSignature(_offer.taker, getEIP712Hash(rfqOrderHash), bytes(""), takerSignature), "invalid signature"); } // transfer takerToken to maker if (_offer.takerToken.isETH()) { require(msg.value == _offer.takerTokenAmount, "invalid msg value"); weth.deposit{ value: msg.value }(); weth.transfer(_offer.maker, msg.value); } else { require(msg.value == 0, "invalid msg value"); _collect(_offer.takerToken, _offer.taker, _offer.maker, _offer.takerTokenAmount, takerTokenPermit); } // collect makerToken from maker to this _collect(_offer.makerToken, _offer.maker, address(this), _offer.makerTokenAmount, makerTokenPermit); // transfer makerToken to recipient (sub fee) uint256 fee = _offer.makerTokenAmount.mul(_offer.feeFactor).div(LibConstant.BPS_MAX); uint256 makerTokenToTaker = _offer.makerTokenAmount.sub(fee); { // determine if WETH unwrap is needed, send out ETH if makerToken is WETH address makerToken = _offer.makerToken; if (makerToken == address(weth)) { weth.withdraw(_offer.makerTokenAmount); makerToken = LibConstant.ETH_ADDRESS; } // collect fee if present if (fee > 0) { makerToken.transferTo(feeCollector, fee); } makerToken.transferTo(order.recipient, makerTokenToTaker); } _emitFilledRFQEvent(offerHash, order, makerTokenToTaker); } function _emitFilledRFQEvent( bytes32 _offerHash, RFQOrder calldata _rfqOrder, uint256 _makerTokenToTaker ) internal { emit FilledRFQ( _offerHash, _rfqOrder.offer.taker, _rfqOrder.offer.maker, _rfqOrder.offer.takerToken, _rfqOrder.offer.takerTokenAmount, _rfqOrder.offer.makerToken, _rfqOrder.offer.makerTokenAmount, _rfqOrder.recipient, _makerTokenToTaker, _rfqOrder.offer.feeFactor ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.6; pragma abicoder v2; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { IUniswapPermit2 } from "../interfaces/IUniswapPermit2.sol"; import { ISpender } from "../interfaces/ISpender.sol"; import { IERC20Permit } from "../interfaces/IERC20Permit.sol"; abstract contract TokenCollector { using SafeERC20 for IERC20; enum Source { TokenlonSpender, Token, TokenPermit, Permit2AllowanceTransfer, Permit2SignatureTransfer } address public immutable permit2; address public immutable tokenlonSpender; constructor(address _permit2, address _tokenlonSpender) { permit2 = _permit2; tokenlonSpender = _tokenlonSpender; } function _collect( address token, address from, address to, uint256 amount, bytes calldata data ) internal { Source src = Source(uint8(data[0])); if (src == Source.TokenlonSpender) { ISpender(tokenlonSpender).spendFromUser(from, token, amount); if (to != address(this)) { IERC20(token).safeTransfer(to, amount); } return; } else if (src == Source.Token) { return IERC20(token).safeTransferFrom(from, to, amount); } else if (src == Source.TokenPermit) { (bool success, bytes memory result) = token.call(abi.encodePacked(IERC20Permit.permit.selector, data[1:])); if (!success) { assembly { revert(add(result, 32), returndatasize()) } } return IERC20(token).safeTransferFrom(from, to, amount); } else if (src == Source.Permit2AllowanceTransfer) { bytes memory permit2Data = data[1:]; if (permit2Data.length > 0) { (bool success, bytes memory result) = permit2.call(abi.encodePacked(IUniswapPermit2.permit.selector, permit2Data)); if (!success) { assembly { revert(add(result, 32), returndatasize()) } } } return IUniswapPermit2(permit2).transferFrom(from, to, uint160(amount), token); } else if (src == Source.Permit2SignatureTransfer) { bytes memory permit2Data = data[1:]; require(permit2Data.length != 0, "empty permit2 data"); (uint256 nonce, uint256 deadline, bytes memory permitSig) = abi.decode(permit2Data, (uint256, uint256, bytes)); IUniswapPermit2.PermitTransferFrom memory permit = IUniswapPermit2.PermitTransferFrom({ permitted: IUniswapPermit2.TokenPermissions({ token: token, amount: amount }), nonce: nonce, deadline: deadline }); IUniswapPermit2.SignatureTransferDetails memory detail = IUniswapPermit2.SignatureTransferDetails({ to: to, requestedAmount: amount }); return IUniswapPermit2(permit2).permitTransferFrom(permit, detail, from, permitSig); } // won't be reached revert(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.6; abstract contract BaseLibEIP712 { // EIP-191 Header string public constant EIP191_HEADER = "\x19\x01"; // EIP712Domain string public constant EIP712_DOMAIN_NAME = "Tokenlon"; string public constant EIP712_DOMAIN_VERSION = "v5"; // EIP712Domain Separator bytes32 public immutable originalEIP712DomainSeparator; uint256 public immutable originalChainId; constructor() { originalEIP712DomainSeparator = _buildDomainSeparator(); originalChainId = getChainID(); } /** * @dev Return `chainId` */ function getChainID() internal pure returns (uint256) { uint256 chainId; assembly { chainId := chainid() } return chainId; } function _buildDomainSeparator() private view returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(EIP712_DOMAIN_NAME)), keccak256(bytes(EIP712_DOMAIN_VERSION)), getChainID(), address(this) ) ); } function _getDomainSeparator() private view returns (bytes32) { if (getChainID() == originalChainId) { return originalEIP712DomainSeparator; } else { return _buildDomainSeparator(); } } function getEIP712Hash(bytes32 structHash) internal view returns (bytes32) { return keccak256(abi.encodePacked(EIP191_HEADER, _getDomainSeparator(), structHash)); } function EIP712_DOMAIN_SEPARATOR() external view returns (bytes32) { return _getDomainSeparator(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { LibConstant } from "./LibConstant.sol"; library Asset { using SafeERC20 for IERC20; function isETH(address addr) internal pure returns (bool) { return (addr == LibConstant.ETH_ADDRESS || addr == LibConstant.ZERO_ADDRESS); } function transferTo( address asset, address payable to, uint256 amount ) internal { if (to == address(this)) { return; } if (isETH(asset)) { // @dev forward all available gas and may cause reentrancy require(address(this).balance >= amount, "insufficient balance"); (bool success, ) = to.call{ value: amount }(""); require(success, "unable to send ETH"); } else { IERC20(asset).safeTransfer(to, amount); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.6; string constant OFFER_TYPESTRING = "Offer(address taker,address maker,address takerToken,uint256 takerTokenAmount,address makerToken,uint256 makerTokenAmount,uint256 feeFactor,uint256 expiry,uint256 salt)"; bytes32 constant OFFER_DATA_TYPEHASH = keccak256(bytes(OFFER_TYPESTRING)); struct Offer { address taker; address payable maker; address takerToken; uint256 takerTokenAmount; address makerToken; uint256 makerTokenAmount; uint256 feeFactor; uint256 expiry; uint256 salt; } // solhint-disable-next-line func-visibility function getOfferHash(Offer memory offer) pure returns (bytes32) { return keccak256( abi.encode( OFFER_DATA_TYPEHASH, offer.taker, offer.maker, offer.takerToken, offer.takerTokenAmount, offer.makerToken, offer.makerTokenAmount, offer.feeFactor, offer.expiry, offer.salt ) ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.6; import { Offer, getOfferHash, OFFER_TYPESTRING } from "./Offer.sol"; string constant RFQ_ORDER_TYPESTRING = string(abi.encodePacked("RFQOrder(Offer offer,address recipient)", OFFER_TYPESTRING)); bytes32 constant RFQ_ORDER_TYPEHASH = keccak256(bytes(RFQ_ORDER_TYPESTRING)); struct RFQOrder { Offer offer; address payable recipient; } // solhint-disable-next-line func-visibility function getRFQOrderHash(RFQOrder memory rfqOrder) pure returns (bytes32 offerHash, bytes32 orderHash) { offerHash = getOfferHash(rfqOrder.offer); orderHash = keccak256(abi.encode(RFQ_ORDER_TYPEHASH, offerHash, rfqOrder.recipient)); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.6; library LibConstant { int256 internal constant MAX_INT = 2**255 - 1; uint256 internal constant MAX_UINT = 2**256 - 1; uint16 internal constant BPS_MAX = 10000; address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address internal constant ZERO_ADDRESS = address(0); }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import "../interfaces/IERC1271Wallet.sol"; import "./LibBytes.sol"; interface IWallet { /// @dev Verifies that a signature is valid. /// @param hash Message hash that is signed. /// @param signature Proof of signing. /// @return isValid Validity of order signature. function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bool isValid); } /** * @dev Contains logic for signature validation. * Signatures from wallet contracts assume ERC-1271 support (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md) * Notes: Methods are strongly inspired by contracts in https://github.com/0xProject/0x-monorepo/blob/development/ */ contract SignatureValidator { using LibBytes for bytes; /***********************************| | Variables | |__________________________________*/ // bytes4(keccak256("isValidSignature(bytes,bytes)")) bytes4 internal constant ERC1271_MAGICVALUE = 0x20c13b0b; // bytes4(keccak256("isValidSignature(bytes32,bytes)")) bytes4 internal constant ERC1271_MAGICVALUE_BYTES32 = 0x1626ba7e; // Allowed signature types. enum SignatureType { Illegal, // 0x00, default value Invalid, // 0x01 EIP712, // 0x02 EthSign, // 0x03 WalletBytes, // 0x04 standard 1271 wallet type WalletBytes32, // 0x05 standard 1271 wallet type Wallet, // 0x06 0x wallet type for signature compatibility NSignatureTypes // 0x07, number of signature types. Always leave at end. } /***********************************| | Signature Functions | |__________________________________*/ /** * @dev Verifies that a hash has been signed by the given signer. * @param _signerAddress Address that should have signed the given hash. * @param _hash Hash of the EIP-712 encoded data * @param _data Full EIP-712 data structure that was hashed and signed * @param _sig Proof that the hash has been signed by signer. * For non wallet signatures, _sig is expected to be an array tightly encoded as * (bytes32 r, bytes32 s, uint8 v, uint256 nonce, SignatureType sigType) * @return isValid True if the address recovered from the provided signature matches the input signer address. */ function isValidSignature( address _signerAddress, bytes32 _hash, bytes memory _data, bytes memory _sig ) public view returns (bool isValid) { require(_sig.length > 0, "SignatureValidator#isValidSignature: length greater than 0 required"); require(_signerAddress != address(0x0), "SignatureValidator#isValidSignature: invalid signer"); // Pop last byte off of signature byte array. uint8 signatureTypeRaw = uint8(_sig.popLastByte()); // Ensure signature is supported require(signatureTypeRaw < uint8(SignatureType.NSignatureTypes), "SignatureValidator#isValidSignature: unsupported signature"); // Extract signature type SignatureType signatureType = SignatureType(signatureTypeRaw); // Variables are not scoped in Solidity. uint8 v; bytes32 r; bytes32 s; address recovered; // Always illegal signature. // This is always an implicit option since a signer can create a // signature array with invalid type or length. We may as well make // it an explicit option. This aids testing and analysis. It is // also the initialization value for the enum type. if (signatureType == SignatureType.Illegal) { revert("SignatureValidator#isValidSignature: illegal signature"); // Signature using EIP712 } else if (signatureType == SignatureType.EIP712) { require(_sig.length == 65 || _sig.length == 97, "SignatureValidator#isValidSignature: length 65 or 97 required"); r = _sig.readBytes32(0); s = _sig.readBytes32(32); v = uint8(_sig[64]); recovered = ecrecover(_hash, v, r, s); isValid = _signerAddress == recovered; return isValid; // Signed using web3.eth_sign() or Ethers wallet.signMessage() } else if (signatureType == SignatureType.EthSign) { require(_sig.length == 65 || _sig.length == 97, "SignatureValidator#isValidSignature: length 65 or 97 required"); r = _sig.readBytes32(0); s = _sig.readBytes32(32); v = uint8(_sig[64]); recovered = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)), v, r, s); isValid = _signerAddress == recovered; return isValid; // Signature verified by wallet contract with data validation. } else if (signatureType == SignatureType.WalletBytes) { isValid = ERC1271_MAGICVALUE == IERC1271Wallet(_signerAddress).isValidSignature(_data, _sig); return isValid; // Signature verified by wallet contract without data validation. } else if (signatureType == SignatureType.WalletBytes32) { isValid = ERC1271_MAGICVALUE_BYTES32 == IERC1271Wallet(_signerAddress).isValidSignature(_hash, _sig); return isValid; } else if (signatureType == SignatureType.Wallet) { isValid = isValidWalletSignature(_hash, _signerAddress, _sig); return isValid; } // Anything else is illegal (We do not return false because // the signature may actually be valid, just not in a format // that we currently support. In this case returning false // may lead the caller to incorrectly believe that the // signature was invalid.) revert("SignatureValidator#isValidSignature: unsupported signature"); } /// @dev Verifies signature using logic defined by Wallet contract. /// @param hash Any 32 byte hash. /// @param walletAddress Address that should have signed the given hash /// and defines its own signature verification method. /// @param signature Proof that the hash has been signed by signer. /// @return isValid True if signature is valid for given wallet.. function isValidWalletSignature( bytes32 hash, address walletAddress, bytes memory signature ) internal view returns (bool isValid) { bytes memory _calldata = abi.encodeWithSelector(IWallet(walletAddress).isValidSignature.selector, hash, signature); bytes32 magic_salt = bytes32(bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)"))); assembly { if iszero(extcodesize(walletAddress)) { // Revert with `Error("WALLET_ERROR")` mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000) mstore(96, 0) revert(0, 100) } let cdStart := add(_calldata, 32) let success := staticcall( gas(), // forward all gas walletAddress, // address of Wallet contract cdStart, // pointer to start of input mload(_calldata), // length of input cdStart, // write output over input 32 // output size is 32 bytes ) if iszero(eq(returndatasize(), 32)) { // Revert with `Error("WALLET_ERROR")` mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000) mstore(96, 0) revert(0, 100) } switch success case 0 { // Revert with `Error("WALLET_ERROR")` mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000) mstore(96, 0) revert(0, 100) } case 1 { // Signature is valid if call did not revert and returned true isValid := eq( and(mload(cdStart), 0xffffffff00000000000000000000000000000000000000000000000000000000), and(magic_salt, 0xffffffff00000000000000000000000000000000000000000000000000000000) ) } } return isValid; } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "./Ownable.sol"; import "./LibConstant.sol"; import "../interfaces/IWETH.sol"; import "../interfaces/IStrategyBase.sol"; import "../interfaces/ISpender.sol"; import "../interfaces/IPermanentStorage.sol"; /// @title StrategyBase Abstract Contract /// @author imToken Labs /// @dev This contract is shared by every Tokenlon strategy contracts abstract contract StrategyBase is IStrategyBase, Ownable { using SafeERC20 for IERC20; address public immutable userProxy; IWETH public immutable weth; IPermanentStorage public immutable permStorage; ISpender public spender; constructor( address _owner, address _userProxy, address _weth, address _permStorage, address _spender ) Ownable(_owner) { userProxy = _userProxy; weth = IWETH(_weth); permStorage = IPermanentStorage(_permStorage); spender = ISpender(_spender); } modifier onlyUserProxy() { require(address(userProxy) == msg.sender, "Strategy: not from UserProxy contract"); _; } /// @inheritdoc IStrategyBase function upgradeSpender(address _newSpender) external override onlyOwner { require(_newSpender != address(0), "Strategy: spender can not be zero address"); spender = ISpender(_newSpender); emit UpgradeSpender(_newSpender); } /// @inheritdoc IStrategyBase function setAllowance(address[] calldata _tokenList, address _spender) external override onlyOwner { for (uint256 i = 0; i < _tokenList.length; ++i) { IERC20(_tokenList[i]).safeApprove(_spender, LibConstant.MAX_UINT); emit AllowTransfer(_spender, _tokenList[i]); } } /// @inheritdoc IStrategyBase function closeAllowance(address[] calldata _tokenList, address _spender) external override onlyOwner { for (uint256 i = 0; i < _tokenList.length; ++i) { IERC20(_tokenList[i]).safeApprove(_spender, 0); emit DisallowTransfer(_spender, _tokenList[i]); } } /// @inheritdoc IStrategyBase function depositETH() external override onlyOwner { uint256 balance = address(this).balance; if (balance > 0) { weth.deposit{ value: balance }(); emit DepositETH(balance); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0; pragma abicoder v2; import { RFQOrder } from "../utils/RFQOrder.sol"; /// @title IRFQv2 Interface /// @author imToken Labs interface IRFQv2 { /// @notice Emitted when an order is settled /// @param offerHash The hash of the offer to be filled /// @param user The address of the user /// @param maker The address of the offer maker /// @param takerToken The address of taker token /// @param takerTokenAmount The amount of taker token /// @param makerToken The address of maker token /// @param makerTokenAmount The amount of maker token /// @param recipient The address of recipient that will receive the maker token /// @param settleAmount The actual amount that recipient will receive (after fee, if any) /// @param feeFactor The fee factor of this settlement event FilledRFQ( bytes32 indexed offerHash, address indexed user, address indexed maker, address takerToken, uint256 takerTokenAmount, address makerToken, uint256 makerTokenAmount, address recipient, uint256 settleAmount, uint256 feeFactor ); /// @notice Settle a RFQ order /// @notice Signature from maker and user should be both provided /// @param rfqOrder The order that is going to be filled /// @param makerSignature The signature of the offer /// @param makerTokenPermit The token permit data of the maker /// @param takerSignature The signature of the whole order /// @param takerTokenPermit The token permit data of the taker function fillRFQ( RFQOrder calldata rfqOrder, bytes calldata makerSignature, bytes calldata makerTokenPermit, bytes calldata takerSignature, bytes calldata takerTokenPermit ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0; pragma abicoder v2; interface IUniswapPermit2 { /* * Allowance Transfer */ /// @notice The permit data for a token struct PermitDetails { // ERC20 token address address token; // the maximum amount allowed to spend uint160 amount; // timestamp at which a spender's token allowances become invalid uint48 expiration; // an incrementing value indexed per owner,token,and spender for each signature uint48 nonce; } /// @notice The permit message signed for a single token allownce struct PermitSingle { // the permit data for a single token alownce PermitDetails details; // address permissioned on the allowed tokens address spender; // deadline on the permit signature uint256 sigDeadline; } /// @notice Returns the domain separator for the current chain. /// @dev Uses cached version if chainid and address are unchanged from construction. function DOMAIN_SEPARATOR() external view returns (bytes32); /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval. /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress] /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals. function allowance( address user, address token, address spender ) external view returns ( uint160 amount, uint48 expiration, uint48 nonce ); /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce /// @param owner The owner of the tokens being approved /// @param permitSingle Data signed over by the owner specifying the terms of approval /// @param signature The owner's signature over the permit data function permit( address owner, PermitSingle memory permitSingle, bytes calldata signature ) external; /// @notice Transfer approved tokens from one address to another /// @param from The address to transfer from /// @param to The address of the recipient /// @param amount The amount of the token to transfer /// @param token The token address to transfer /// @dev Requires the from address to have approved at least the desired amount /// of tokens to msg.sender. function transferFrom( address from, address to, uint160 amount, address token ) external; /// @notice Approves the spender to use up to amount of the specified token up until the expiration /// @param token The token to approve /// @param spender The spender address to approve /// @param amount The approved amount of the token /// @param expiration The timestamp at which the approval is no longer valid /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve /// @dev Setting amount to type(uint160).max sets an unlimited approval function approve( address token, address spender, uint160 amount, uint48 expiration ) external; /* * Signature Transfer */ /// @notice The token and amount details for a transfer signed in the permit transfer signature struct TokenPermissions { // ERC20 token address address token; // the maximum amount that can be spent uint256 amount; } /// @notice The signed permit message for a single token transfer struct PermitTransferFrom { TokenPermissions permitted; // a unique value for every token owner's signature to prevent signature replays uint256 nonce; // deadline on the permit signature uint256 deadline; } /// @notice Specifies the recipient address and amount for batched transfers. /// @dev Recipients and amounts correspond to the index of the signed token permissions array. /// @dev Reverts if the requested amount is greater than the permitted signed amount. struct SignatureTransferDetails { // recipient address address to; // spender requested amount uint256 requestedAmount; } /// @notice Transfers a token using a signed permit message /// @dev Reverts if the requested amount is greater than the permitted signed amount /// @param permit The permit data signed over by the owner /// @param owner The owner of the tokens to transfer /// @param transferDetails The spender's requested transfer details for the permitted token /// @param signature The signature to verify function permitTransferFrom( PermitTransferFrom memory permit, SignatureTransferDetails calldata transferDetails, address owner, bytes calldata signature ) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0; interface ISpender { // System events event TimeLockActivated(uint256 activatedTimeStamp); // Owner events event SetAllowanceTarget(address allowanceTarget); event SetNewSpender(address newSpender); event SetConsumeGasERC20Token(address token); event TearDownAllowanceTarget(uint256 tearDownTimeStamp); event BlackListToken(address token, bool isBlacklisted); event AuthorizeSpender(address spender, bool isAuthorized); function spendFromUser( address _user, address _tokenAddr, uint256 _amount ) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0; interface IERC20Permit { function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0; interface IERC1271Wallet { /** * @notice Verifies whether the provided signature is valid with respect to the provided data * @dev MUST return the correct magic value if the signature provided is valid for the provided data * > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)") * > This function MAY modify Ethereum's state * @param _data Arbitrary length data signed on the behalf of address(this) * @param _signature Signature byte array associated with _data * @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise * */ function isValidSignature(bytes calldata _data, bytes calldata _signature) external view returns (bytes4 magicValue); /** * @notice Verifies whether the provided signature is valid with respect to the provided hash * @dev MUST return the correct magic value if the signature provided is valid for the provided hash * > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)") * > This function MAY modify Ethereum's state * @param _hash keccak256 hash that was signed * @param _signature Signature byte array associated with _data * @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise */ function isValidSignature(bytes32 _hash, bytes calldata _signature) external view returns (bytes4 magicValue); }
/* Copyright 2018 ZeroEx Intl. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This is a truncated version of the original LibBytes.sol library from ZeroEx. */ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.7.6; library LibBytes { using LibBytes for bytes; /***********************************| | Pop Bytes Functions | |__________________________________*/ /** * @dev Pops the last byte off of a byte array by modifying its length. * @param b Byte array that will be modified. * @return result The byte that was popped off. */ function popLastByte(bytes memory b) internal pure returns (bytes1 result) { require(b.length > 0, "LibBytes#popLastByte: greater than zero length required"); // Store last byte. result = b[b.length - 1]; assembly { // Decrement length of byte array. let newLen := sub(mload(b), 1) mstore(b, newLen) } return result; } /// @dev Reads an address from a position in a byte array. /// @param b Byte array containing an address. /// @param index Index in byte array of address. /// @return result address from byte array. function readAddress(bytes memory b, uint256 index) internal pure returns (address result) { require( b.length >= index + 20, // 20 is length of address "LibBytes#readAddress greater or equal to 20 length required" ); // Add offset to index: // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) index += 20; // Read address from array memory assembly { // 1. Add index to address of bytes array // 2. Load 32-byte word from memory // 3. Apply 20-byte mask to obtain address result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff) } return result; } /***********************************| | Read Bytes Functions | |__________________________________*/ /** * @dev Reads a bytes32 value from a position in a byte array. * @param b Byte array containing a bytes32 value. * @param index Index in byte array of bytes32 value. * @return result bytes32 value from byte array. */ function readBytes32(bytes memory b, uint256 index) internal pure returns (bytes32 result) { require(b.length >= index + 32, "LibBytes#readBytes32 greater or equal to 32 length required"); // Arrays are prefixed by a 256 bit length parameter index += 32; // Read the bytes32 from array memory assembly { result := mload(add(b, index)) } return result; } /// @dev Reads an unpadded bytes4 value from a position in a byte array. /// @param b Byte array containing a bytes4 value. /// @param index Index in byte array of bytes4 value. /// @return result bytes4 value from byte array. function readBytes4(bytes memory b, uint256 index) internal pure returns (bytes4 result) { require(b.length >= index + 4, "LibBytes#readBytes4 greater or equal to 4 length required"); // Arrays are prefixed by a 32 byte length field index += 32; // Read the bytes4 from array memory assembly { result := mload(add(b, index)) // Solidity does not require us to clean the trailing bytes. // We do it anyway result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000) } return result; } function readBytes2(bytes memory b, uint256 index) internal pure returns (bytes2 result) { require(b.length >= index + 2, "LibBytes#readBytes2 greater or equal to 2 length required"); // Arrays are prefixed by a 32 byte length field index += 32; // Read the bytes4 from array memory assembly { result := mload(add(b, index)) // Solidity does not require us to clean the trailing bytes. // We do it anyway result := and(result, 0xFFFF000000000000000000000000000000000000000000000000000000000000) } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.6; /// @title Ownable Contract /// @author imToken Labs abstract contract Ownable { address public owner; address public nominatedOwner; event OwnerNominated(address indexed newOwner); event OwnerChanged(address indexed oldOwner, address indexed newOwner); constructor(address _owner) { require(_owner != address(0), "owner should not be 0"); owner = _owner; } modifier onlyOwner() { require(msg.sender == owner, "not owner"); _; } /// @notice Activate new ownership /// @notice Only nominated owner can call function acceptOwnership() external { require(msg.sender == nominatedOwner, "not nominated"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } /// @notice Give up the ownership /// @notice Only owner can call /// @notice Ownership cannot be recovered function renounceOwnership() external onlyOwner { require(nominatedOwner == address(0), "pending nomination exists"); emit OwnerChanged(owner, address(0)); owner = address(0); } /// @notice Nominate new owner /// @notice Only owner can call /// @param newOwner The address of the new owner function nominateNewOwner(address newOwner) external onlyOwner { nominatedOwner = newOwner; emit OwnerNominated(newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0; interface IWETH { function balanceOf(address account) external view returns (uint256); function deposit() external payable; function withdraw(uint256 amount) external; function transfer(address dst, uint256 wad) external returns (bool); function transferFrom( address src, address dst, uint256 wad ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0; /// @title IStrategyBase Interface /// @author imToken Labs interface IStrategyBase { /// @notice Emitted when Tokenlon spender address is updated /// @param newSpender The address of the new Tokenlon spender event UpgradeSpender(address newSpender); /// @notice Emitted when allowing another account to spend assets /// @param spender The address that is allowed to transfer tokens event AllowTransfer(address indexed spender, address token); /// @notice Emitted when disallowing an account to spend assets /// @param spender The address that is removed from allow list event DisallowTransfer(address indexed spender, address token); /// @notice Emitted when ETH converted to WETH /// @param amount The amount of converted ETH event DepositETH(uint256 amount); /// @notice Update the address of Tokenlon spender /// @notice Only owner can call /// @param _newSpender The address of the new spender function upgradeSpender(address _newSpender) external; /// @notice Set allowance of tokens to an address /// @notice Only owner can call /// @param _tokenList The list of tokens /// @param _spender The address that will be allowed function setAllowance(address[] calldata _tokenList, address _spender) external; /// @notice Clear allowance of tokens to an address /// @notice Only owner can call /// @param _tokenList The list of tokens /// @param _spender The address that will be cleared function closeAllowance(address[] calldata _tokenList, address _spender) external; /// @notice Convert ETH in this contract to WETH /// @notice Only owner can call function depositETH() external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0; interface IPermanentStorage { // Operator events event OperatorNominated(address indexed newOperator); event OperatorChanged(address indexed oldOperator, address indexed newOperator); event SetPermission(bytes32 storageId, address role, bool enabled); event UpgradeAMMWrapper(address newAMMWrapper); event UpgradePMM(address newPMM); event UpgradeRFQ(address newRFQ); event UpgradeRFQv2(address newRFQv2); event UpgradeLimitOrder(address newLimitOrder); event UpgradeWETH(address newWETH); event SetCurvePoolInfo(address makerAddr, address[] underlyingCoins, address[] coins, bool supportGetD); event SetRelayerValid(address relayer, bool valid); function hasPermission(bytes32 _storageId, address _role) external view returns (bool); function ammWrapperAddr() external view returns (address); function pmmAddr() external view returns (address); function rfqAddr() external view returns (address); function rfqv2Addr() external view returns (address); function limitOrderAddr() external view returns (address); function wethAddr() external view returns (address); function getCurvePoolInfo( address _makerAddr, address _takerAssetAddr, address _makerAssetAddr ) external view returns ( int128 takerAssetIndex, int128 makerAssetIndex, uint16 swapMethod, bool supportGetDx ); function setCurvePoolInfo( address _makerAddr, address[] calldata _underlyingCoins, address[] calldata _coins, bool _supportGetDx ) external; function isAMMTransactionSeen(bytes32 _transactionHash) external view returns (bool); function isRFQTransactionSeen(bytes32 _transactionHash) external view returns (bool); function isRFQOfferFilled(bytes32 _offerHash) external view returns (bool); function isLimitOrderTransactionSeen(bytes32 _transactionHash) external view returns (bool); function isLimitOrderAllowFillSeen(bytes32 _allowFillHash) external view returns (bool); function isRelayerValid(address _relayer) external view returns (bool); function setAMMTransactionSeen(bytes32 _transactionHash) external; function setRFQTransactionSeen(bytes32 _transactionHash) external; function setRFQOfferFilled(bytes32 _offerHash) external; function setLimitOrderTransactionSeen(bytes32 _transactionHash) external; function setLimitOrderAllowFillSeen(bytes32 _allowFillHash) external; function setRelayersValid(address[] memory _relayers, bool[] memory _isValids) external; }
{ "remappings": [ "@openzeppelin/=lib/openzeppelin-contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 1000 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "istanbul", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_userProxy","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_permStorage","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"address","name":"_uniswapPermit2","type":"address"},{"internalType":"address payable","name":"_feeCollector","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"AllowTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"DisallowTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"offerHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"address","name":"takerToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"takerTokenAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"makerToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"makerTokenAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"settleAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeFactor","type":"uint256"}],"name":"FilledRFQ","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"SetFeeCollector","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newSpender","type":"address"}],"name":"UpgradeSpender","type":"event"},{"inputs":[],"name":"EIP191_HEADER","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokenList","type":"address[]"},{"internalType":"address","name":"_spender","type":"address"}],"name":"closeAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address payable","name":"maker","type":"address"},{"internalType":"address","name":"takerToken","type":"address"},{"internalType":"uint256","name":"takerTokenAmount","type":"uint256"},{"internalType":"address","name":"makerToken","type":"address"},{"internalType":"uint256","name":"makerTokenAmount","type":"uint256"},{"internalType":"uint256","name":"feeFactor","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"}],"internalType":"struct Offer","name":"offer","type":"tuple"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct RFQOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"internalType":"bytes","name":"makerTokenPermit","type":"bytes"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"internalType":"bytes","name":"takerTokenPermit","type":"bytes"}],"name":"fillRFQ","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_signerAddress","type":"address"},{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_sig","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originalChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originalEIP712DomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permStorage","outputs":[{"internalType":"contract IPermanentStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokenList","type":"address[]"},{"internalType":"address","name":"_spender","type":"address"}],"name":"setAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newFeeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"spender","outputs":[{"internalType":"contract ISpender","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenlonSpender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newSpender","type":"address"}],"name":"upgradeSpender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"userProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101606040523480156200001257600080fd5b5060405162003c7e38038062003c7e83398101604081905262000035916200023d565b81838888888884846001600160a01b03811662000099576040805162461bcd60e51b815260206004820152601560248201527f6f776e65722073686f756c64206e6f7420626520300000000000000000000000604482015290519081900360640190fd5b600080546001600160a01b03199081166001600160a01b0393841617909155606095861b6001600160601b031990811660805294861b851660a05292851b841660c05260028054909316911617905593811b841660e0529190911b90911661010052506200010662000145565b610120526200011462000239565b61014052600380546001600160a01b0319166001600160a01b03929092169190911790555062000300945050505050565b60408051808201825260088152672a37b5b2b73637b760c11b60209182015281518083019092526002825261763560f01b91015260007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f4428669f887e7f6a6e361e218ee42308201bdbacbf601211fc38b8b2ec6961817f7d6f66f923317ceee1bd9447053fb8a64c76979d436a723b87aff2899feaa6c3620001e862000239565b3060405160200180868152602001858152602001848152602001838152602001826001600160a01b031681526020019550505050505060405160208183030381529060405280519060200120905090565b4690565b600080600080600080600060e0888a03121562000258578283fd5b87516200026581620002e7565b60208901519097506200027881620002e7565b60408901519096506200028b81620002e7565b60608901519095506200029e81620002e7565b6080890151909450620002b181620002e7565b60a0890151909350620002c481620002e7565b60c0890151909250620002d781620002e7565b8091505092959891949750929550565b6001600160a01b0381168114620002fd57600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c61012051610140516138da620003a4600039806104345280611a6d52508061060d5280611a9d5250806109fe5280611f9f52508061045852806121b0528061229252806123fd525080610afc52806113fd5250806106555280610baf52806115d2528061164652806117d0528061183852508061063152806112e452506138da6000f3fe60806040526004361061019a5760003560e01c806382fdaf58116100e1578063dab400f31161008a578063f6326fb311610064578063f6326fb3146103c8578063fa4e12d7146103dd578063fd0702961461040a578063ffc8fa691461041f576101a1565b8063dab400f314610389578063e0c05c241461039e578063e8edc816146103b3576101a1565b8063a42dce80116100bb578063a42dce801461033f578063c415b95c1461035f578063c49e4fd914610374576101a1565b806382fdaf58146102f5578063872001f1146103155780638da5cb5b1461032a576101a1565b80633fc8cef3116101435780635cc333211161011d5780635cc33321146102a9578063715018a6146102cb57806379ba5097146102e0576101a1565b80633fc8cef31461025f57806346920bad1461027457806353a47bb714610294576101a1565b806330db45801161017457806330db45801461021557806337be5439146102355780633ec632161461024a576101a1565b80630d788c36146101a657806312261ee7146101d15780631627540c146101f3576101a1565b366101a157005b600080fd5b3480156101b257600080fd5b506101bb610432565b6040516101c89190613267565b60405180910390f35b3480156101dd57600080fd5b506101e6610456565b6040516101c8919061319d565b3480156101ff57600080fd5b5061021361020e366004612d6f565b61047a565b005b34801561022157600080fd5b50610213610230366004612e08565b61050f565b34801561024157600080fd5b506101bb61060b565b34801561025657600080fd5b506101e661062f565b34801561026b57600080fd5b506101e6610653565b34801561028057600080fd5b5061021361028f366004612e08565b610677565b3480156102a057600080fd5b506101e6610749565b3480156102b557600080fd5b506102be610758565b6040516101c89190613270565b3480156102d757600080fd5b50610213610776565b3480156102ec57600080fd5b50610213610869565b34801561030157600080fd5b50610213610310366004612d6f565b61092c565b34801561032157600080fd5b506101e66109fc565b34801561033657600080fd5b506101e6610a20565b34801561034b57600080fd5b5061021361035a366004612d6f565b610a2f565b34801561036b57600080fd5b506101e6610aeb565b34801561038057600080fd5b506101e6610afa565b34801561039557600080fd5b506101bb610b1e565b3480156103aa57600080fd5b506102be610b2e565b3480156103bf57600080fd5b506101e6610b4c565b3480156103d457600080fd5b50610213610b5b565b3480156103e957600080fd5b506103fd6103f8366004612d8b565b610c53565b6040516101c8919061325c565b34801561041657600080fd5b506102be6112be565b61021361042d366004612ea8565b6112e2565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031633146104c5576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b6000546001600160a01b0316331461055a576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b60005b828110156106055761059c82600086868581811061057757fe5b905060200201602081019061058c9190612d6f565b6001600160a01b0316919061191f565b816001600160a01b03167f3ed6edecab5354e68e8f8fe05f9f34f99c401a17d00482311bfa561162bbc8798585848181106105d357fe5b90506020020160208101906105e89190612d6f565b6040516105f5919061319d565b60405180910390a260010161055d565b50505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031633146106c2576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b60005b82811015610605576106e08260001986868581811061057757fe5b816001600160a01b03167f9a3e46ec71da6d3ab362377a5f095af84cc1dbb1b40c5fa3ad7bb5accae2af7585858481811061071757fe5b905060200201602081019061072c9190612d6f565b604051610739919061319d565b60405180910390a26001016106c5565b6001546001600160a01b031681565b60405180604001604052806002815260200161763560f01b81525081565b6000546001600160a01b031633146107c1576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b6001546001600160a01b03161561081f576040805162461bcd60e51b815260206004820152601960248201527f70656e64696e67206e6f6d696e6174696f6e2065786973747300000000000000604482015290519081900360640190fd5b600080546040516001600160a01b03909116907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908390a3600080546001600160a01b0319169055565b6001546001600160a01b031633146108c8576040805162461bcd60e51b815260206004820152600d60248201527f6e6f74206e6f6d696e6174656400000000000000000000000000000000000000604482015290519081900360640190fd5b600154600080546040516001600160a01b0393841693909116917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b03163314610977576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b6001600160a01b0381166109a65760405162461bcd60e51b815260040161099d90613461565b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383161790556040517fbd4e916c3e5390ed2ffaf01ea6c14195c3e174811b8ad55bca06034e89bbd0bb906109f190839061319d565b60405180910390a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031681565b6000546001600160a01b03163314610a7a576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b6001600160a01b038116610aa05760405162461bcd60e51b815260040161099d90613385565b600380546001600160a01b0319166001600160a01b0383161790556040517fd649da8f6092116f86ea4e5139de0b75ad371d823918d16368ba3ff09a5cbc9f906109f190839061319d565b6003546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610b28611a69565b90505b90565b60405180604001604052806002815260200161190160f01b81525081565b6002546001600160a01b031681565b6000546001600160a01b03163314610ba6576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b478015610c50577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b50505050507ff21b64ad26683e79854b8f088d254ef4e123df84bdb91d1f7f4356d772716a39816040516109f19190613267565b50565b600080825111610c945760405162461bcd60e51b815260040180806020018281038252604381526020018061363b6043913960600191505060405180910390fd5b6001600160a01b038516610cd95760405162461bcd60e51b81526004018080602001828103825260338152602001806135c06033913960400191505060405180910390fd5b6000610ce483611ad0565b60f81c905060078110610d285760405162461bcd60e51b815260040180806020018281038252603a81526020018061367e603a913960400191505060405180910390fd5b60008160ff166007811115610d3957fe5b9050600080808080856007811115610d4d57fe5b1415610d8a5760405162461bcd60e51b81526004018080602001828103825260368152602001806136f36036913960400191505060405180910390fd5b6002856007811115610d9857fe5b1415610ea257875160411480610daf575087516061145b610dea5760405162461bcd60e51b815260040180806020018281038252603d815260200180613832603d913960400191505060405180910390fd5b610df5886000611b58565b9250610e02886020611b58565b915087604081518110610e1157fe5b602001015160f81c60f81b60f81c935060018a85858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610e7b573d6000803e3d6000fd5b5050604051601f1901516001600160a01b038d811691161497506112b69650505050505050565b6003856007811115610eb057fe5b1415610fd457875160411480610ec7575087516061145b610f025760405162461bcd60e51b815260040180806020018281038252603d815260200180613832603d913960400191505060405180910390fd5b610f0d886000611b58565b9250610f1a886020611b58565b915087604081518110610f2957fe5b01602090810151604080517f19457468657265756d205369676e6564204d6573736167653a0a33320000000081850152603c8082018f905282518083039091018152605c82018084528151918601919091206000909152607c82018084525260f89290921c609c830181905260bc830187905260dc8301869052905190965060019260fc808401939192601f1981019281900390910190855afa158015610e7b573d6000803e3d6000fd5b6004856007811115610fe257fe5b141561114357604080516320c13b0b60e01b8152600481019182528a5160448201528a516001600160a01b038e16926320c13b0b928d928d92918291602482019160640190602087019080838360005b8381101561104a578181015183820152602001611032565b50505050905090810190601f1680156110775780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b838110156110aa578181015183820152602001611092565b50505050905090810190601f1680156110d75780820380516001836020036101000a031916815260200191505b5094505050505060206040518083038186803b1580156110f657600080fd5b505afa15801561110a573d6000803e3d6000fd5b505050506040513d602081101561112057600080fd5b50516001600160e01b0319166320c13b0b60e01b1496506112b695505050505050565b600585600781111561115157fe5b14156112535760408051630b135d3f60e11b8152600481018c8152602482019283528a5160448301528a516001600160a01b038f1693631626ba7e938f938e9390929160640190602085019080838360005b838110156111bb5781810151838201526020016111a3565b50505050905090810190601f1680156111e85780820380516001836020036101000a031916815260200191505b50935050505060206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d602081101561123057600080fd5b50516001600160e01b031916630b135d3f60e11b1496506112b695505050505050565b600685600781111561126157fe5b141561127f576112728a8c8a611bb0565b96505050505050506112b6565b60405162461bcd60e51b815260040180806020018281038252603a81526020018061367e603a913960400191505060405180910390fd5b949350505050565b604051806040016040528060088152602001672a37b5b2b73637b760c11b81525081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316331461132a5760405162461bcd60e51b815260040161099d906132f1565b884260e08201351161134e5760405162461bcd60e51b815260040161099d9061342a565b61271060c0820135106113735760405162461bcd60e51b815260040161099d906133f3565b60006113876101408c016101208d01612d6f565b6001600160a01b031614156113ae5760405162461bcd60e51b815260040161099d906133bc565b6000806113c86113c3368e90038e018e612f86565b611d77565b6040517f8caa276d00000000000000000000000000000000000000000000000000000000815291935091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638caa276d90611432908590600401613267565b600060405180830381600087803b15801561144c57600080fd5b505af1158015611460573d6000803e3d6000fd5b506114ce92506114799150506040850160208601612d6f565b61148284611e63565b604051806020016040528060008152508e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c5392505050565b6114ea5760405162461bcd60e51b815260040161099d90613283565b336114f86020850185612d6f565b6001600160a01b0316146115875761156b6115166020850185612d6f565b61151f83611e63565b604051806020016040528060008152508a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c5392505050565b6115875760405162461bcd60e51b815260040161099d90613283565b6115a861159a6060850160408601612d6f565b6001600160a01b0316611eff565b156116fc57826060013534146115d05760405162461bcd60e51b815260040161099d9061334e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561162b57600080fd5b505af115801561163f573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb8460200160208101906116869190612d6f565b346040518363ffffffff1660e01b81526004016116a49291906131b1565b602060405180830381600087803b1580156116be57600080fd5b505af11580156116d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f69190612e88565b50611756565b341561171a5760405162461bcd60e51b815260040161099d9061334e565b61175661172d6060850160408601612d6f565b61173a6020860186612d6f565b61174a6040870160208801612d6f565b86606001358989611f35565b61178661176960a0850160808601612d6f565b6117796040860160208701612d6f565b308660a001358d8d611f35565b60006117a66127106117a060a087013560c088013561248f565b906124e8565b905060006117b860a08601358361254f565b905060006117cc60a0870160808801612d6f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614156118bb576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d906118719060a08a013590600401613267565b600060405180830381600087803b15801561188b57600080fd5b505af115801561189f573d6000803e3d6000fd5b5050505073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90505b82156118db576003546118db906001600160a01b038381169116856125ac565b6119038f6101200160208101906118f29190612d6f565b6001600160a01b03831690846125ac565b5061190f848f836126e5565b5050505050505050505050505050565b8015806119be5750604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b15801561199057600080fd5b505afa1580156119a4573d6000803e3d6000fd5b505050506040513d60208110156119ba57600080fd5b5051155b6119f95760405162461bcd60e51b815260040180806020018281038252603681526020018061386f6036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b03167f095ea7b300000000000000000000000000000000000000000000000000000000179052611a64908490612798565b505050565b60007f0000000000000000000000000000000000000000000000000000000000000000611a94612849565b1415611ac157507f0000000000000000000000000000000000000000000000000000000000000000610b2b565b611ac961284d565b9050610b2b565b600080825111611b115760405162461bcd60e51b81526004018080602001828103825260378152602001806137296037913960400191505060405180910390fd5b81600183510381518110611b2157fe5b016020015182516000190183527fff000000000000000000000000000000000000000000000000000000000000001690505b919050565b60008160200183511015611b9d5760405162461bcd60e51b815260040180806020018281038252603b8152602001806136b8603b913960400191505060405180910390fd5b6020820191508183015190505b92915050565b600080631626ba7e60e01b85846040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611c03578181015183820152602001611beb565b50505050905090810190601f168015611c305780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990971696909617909552509293507fb067138100000000000000000000000000000000000000000000000000000000925050853b9050611cc45762461bcd60e51b600052600160e51b6020526c062ba0a62622aa2fa2a92927a960811b604052600060605260646000fd5b60208201602081845183895afa60203d14611d0a5762461bcd60e51b600052600160e51b6020526c062ba0a62622aa2fa2a92927a960811b604052600060605260646000fd5b808015611d1e5760018114611d4f57611d6a565b62461bcd60e51b600052600160e51b6020526c062ba0a62622aa2fa2a92927a960811b604052600060605260646000fd5b6001600160e01b031984166001600160e01b03198451161495505b50505050505b9392505050565b600080611d87836000015161293f565b91506040518060e0016040528060a8815260200161376060a891396040516020018060276135f3823960270182805190602001908083835b60208310611dde5780518252601f199092019160209182019101611dbf565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012082846020015160405160200180848152602001838152602001826001600160a01b031681526020019350505050604051602081830303815290604052805190602001209050915091565b600060405180604001604052806002815260200161190160f01b815250611e88611a69565b836040516020018084805190602001908083835b60208310611ebb5780518252601f199092019160209182019101611e9c565b51815160209384036101000a600019018019909216911617905292019485525083810192909252506040805180840383018152928101905281519101209392505050565b60006001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480611baa5750506001600160a01b03161590565b600082826000818110611f4457fe5b919091013560f81c90506004811115611f5957fe5b90506000816004811115611f6957fe5b1415612034576040517f3474ad1a0000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633474ad1a90611fd89089908b9089906004016131f5565b600060405180830381600087803b158015611ff257600080fd5b505af1158015612006573d6000803e3d6000fd5b505050506001600160a01b038516301461202e5761202e6001600160a01b0388168686612a1f565b50612487565b600181600481111561204257fe5b141561205d5761202e6001600160a01b038816878787612a8a565b600281600481111561206b57fe5b1415612148576000806001600160a01b0389167fd505accf000000000000000000000000000000000000000000000000000000006120ac866001818a613556565b6040516020016120be9392919061312d565b60408051601f19818403018152908290526120d891613181565b6000604051808303816000865af19150503d8060008114612115576040519150601f19603f3d011682016040523d82523d6000602084013e61211a565b606091505b50915091508161212b573d60208201fd5b6121406001600160a01b038a16898989612a8a565b505050612487565b600381600481111561215657fe5b141561230657600061216b8360018187613556565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505082519293505090159050612262576000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632b67b57060e01b846040516020016121f2929190613151565b60408051601f198184030181529082905261220c91613181565b6000604051808303816000865af19150503d8060008114612249576040519150601f19603f3d011682016040523d82523d6000602084013e61224e565b606091505b50915091508161225f573d60208201fd5b50505b6040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906336c78516906122cd908a908a908a908e906004016131ca565b600060405180830381600087803b1580156122e757600080fd5b505af11580156122fb573d6000803e3d6000fd5b505050505050612487565b600481600481111561231457fe5b14156101a15760006123298360018187613556565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508251929350505061237e5760405162461bcd60e51b815260040161099d906132ba565b6000806000838060200190518101906123979190613061565b9250925092506000604051806060016040528060405180604001604052808f6001600160a01b031681526020018c8152508152602001858152602001848152509050600060405180604001604052808c6001600160a01b031681526020018b81525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166330f28b7a83838f876040518563ffffffff1660e01b815260040161244d94939291906134be565b600060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b50505050505050505050505b505050505050565b60008261249e57506000611baa565b828202828482816124ab57fe5b0414611d705760405162461bcd60e51b815260040180806020018281038252602181526020018061361a6021913960400191505060405180910390fd5b600080821161253e576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161254757fe5b049392505050565b6000828211156125a6576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6001600160a01b0382163014156125c257611a64565b6125cb83611eff565b156126d15780471015612625576040805162461bcd60e51b815260206004820152601460248201527f696e73756666696369656e742062616c616e6365000000000000000000000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114612670576040519150601f19603f3d011682016040523d82523d6000602084013e612675565b606091505b50509050806126cb576040805162461bcd60e51b815260206004820152601260248201527f756e61626c6520746f2073656e64204554480000000000000000000000000000604482015290519081900360640190fd5b50611a64565b611a646001600160a01b0384168383612a1f565b6126f56040830160208401612d6f565b6001600160a01b031661270b6020840184612d6f565b6001600160a01b0316847ff421ece6d047e3cc8f5953db3c6a3b01544fd3288d60bdb78643565d71d163326127466060870160408801612d6f565b606087013561275b60a0890160808a01612d6f565b60a08901356127726101408b016101208c01612d6f565b60405161278b9594939291908b9060c08e013590613219565b60405180910390a4505050565b60006127ed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612afd9092919063ffffffff16565b805190915015611a645780806020019051602081101561280c57600080fd5b5051611a645760405162461bcd60e51b815260040180806020018281038252602a815260200180613808602a913960400191505060405180910390fd5b4690565b60408051808201825260088152672a37b5b2b73637b760c11b60209182015281518083019092526002825261763560f01b91015260007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f4428669f887e7f6a6e361e218ee42308201bdbacbf601211fc38b8b2ec6961817f7d6f66f923317ceee1bd9447053fb8a64c76979d436a723b87aff2899feaa6c36128ee612849565b3060405160200180868152602001858152602001848152602001838152602001826001600160a01b031681526020019550505050505060405160208183030381529060405280519060200120905090565b60006040518060e0016040528060a8815260200161376060a8913980519060200120826000015183602001518460400151856060015186608001518760a001518860c001518960e001518a6101000151604051602001808b81526020018a6001600160a01b03168152602001896001600160a01b03168152602001886001600160a01b03168152602001878152602001866001600160a01b031681526020018581526020018481526020018381526020018281526020019a5050505050505050505050604051602081830303815290604052805190602001209050919050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b03167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611a64908490612798565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03167f23b872dd00000000000000000000000000000000000000000000000000000000179052610605908590612798565b60606112b6848460008585612b1185612c22565b612b62576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310612ba05780518252601f199092019160209182019101612b81565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612c02576040519150601f19603f3d011682016040523d82523d6000602084013e612c07565b606091505b5091509150612c17828286612c28565b979650505050505050565b3b151590565b60608315612c37575081611d70565b825115612c475782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612c91578181015183820152602001612c79565b50505050905090810190601f168015612cbe5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b8035611b53816135aa565b60008083601f840112612ce8578182fd5b50813567ffffffffffffffff811115612cff578182fd5b602083019150836020828501011115612d1757600080fd5b9250929050565b600082601f830112612d2e578081fd5b8135612d41612d3c82613534565b613510565b818152846020838601011115612d55578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215612d80578081fd5b8135611d70816135aa565b60008060008060808587031215612da0578283fd5b8435612dab816135aa565b935060208501359250604085013567ffffffffffffffff80821115612dce578384fd5b612dda88838901612d1e565b93506060870135915080821115612def578283fd5b50612dfc87828801612d1e565b91505092959194509250565b600080600060408486031215612e1c578283fd5b833567ffffffffffffffff80821115612e33578485fd5b818601915086601f830112612e46578485fd5b813581811115612e54578586fd5b8760208083028501011115612e67578586fd5b60209283019550935050840135612e7d816135aa565b809150509250925092565b600060208284031215612e99578081fd5b81518015158114611d70578182fd5b6000806000806000806000806000898b036101c0811215612ec7578586fd5b61014080821215612ed6578687fd5b8b9a508a0135905067ffffffffffffffff80821115612ef3578687fd5b612eff8d838e01612cd7565b909a5098506101608c0135915080821115612f18578687fd5b612f248d838e01612cd7565b90985096506101808c0135915080821115612f3d578586fd5b612f498d838e01612cd7565b90965094506101a08c0135915080821115612f62578384fd5b50612f6f8c828d01612cd7565b915080935050809150509295985092959850929598565b6000818303610140811215612f99578182fd5b6040516040810181811067ffffffffffffffff82111715612fb657fe5b60405261012080831215612fc8578384fd5b612fd181613510565b9250612fdc85612ccc565b8352612fea60208601612ccc565b6020840152612ffb60408601612ccc565b60408401526060850135606084015261301660808601612ccc565b608084015260a085013560a084015260c085013560c084015260e085013560e0840152610100808601358185015250828252613053818601612ccc565b602083015250949350505050565b600080600060608486031215613075578283fd5b8351925060208401519150604084015167ffffffffffffffff811115613099578182fd5b8401601f810186136130a9578182fd5b80516130b7612d3c82613534565b8181528760208385010111156130cb578384fd5b6130dc82602083016020860161357e565b8093505050509250925092565b6000815180845261310181602086016020860161357e565b601f01601f19169290920160200192915050565b80516001600160a01b03168252602090810151910152565b60006001600160e01b03198516825282846004840137910160040190815292915050565b60006001600160e01b031984168252825161317381600485016020870161357e565b919091016004019392505050565b6000825161319381846020870161357e565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815292841660208401529083166040830152909116606082015260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039788168152602081019690965293861660408601526060850192909252909316608083015260a082019290925260c081019190915260e00190565b901515815260200190565b90815260200190565b600060208252611d7060208301846130e9565b60208082526011908201527f696e76616c6964207369676e6174757265000000000000000000000000000000604082015260600190565b60208082526012908201527f656d707479207065726d69743220646174610000000000000000000000000000604082015260600190565b60208082526025908201527f53747261746567793a206e6f742066726f6d205573657250726f787920636f6e60408201527f7472616374000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f696e76616c6964206d73672076616c7565000000000000000000000000000000604082015260600190565b6020808252600c908201527f7a65726f20616464726573730000000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f7a65726f20726563697069656e74000000000000000000000000000000000000604082015260600190565b60208082526012908201527f696e76616c69642066656520666163746f720000000000000000000000000000604082015260600190565b6020808252600d908201527f6f66666572206578706972656400000000000000000000000000000000000000604082015260600190565b60208082526029908201527f53747261746567793a207370656e6465722063616e206e6f74206265207a657260408201527f6f20616464726573730000000000000000000000000000000000000000000000606082015260800190565b60006101006134ce838851613115565b60208701516040840152604087015160608401526134ef6080840187613115565b6001600160a01b03851660c08401528060e0840152612c17818401856130e9565b60405181810167ffffffffffffffff8111828210171561352c57fe5b604052919050565b600067ffffffffffffffff82111561354857fe5b50601f01601f191660200190565b60008085851115613565578182fd5b83861115613571578182fd5b5050820193919092039150565b60005b83811015613599578181015183820152602001613581565b838111156106055750506000910152565b6001600160a01b0381168114610c5057600080fdfe5369676e617475726556616c696461746f7223697356616c69645369676e61747572653a20696e76616c6964207369676e65725246514f72646572284f66666572206f666665722c6164647265737320726563697069656e7429536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775369676e617475726556616c696461746f7223697356616c69645369676e61747572653a206c656e6774682067726561746572207468616e20302072657175697265645369676e617475726556616c696461746f7223697356616c69645369676e61747572653a20756e737570706f72746564207369676e61747572654c696242797465732372656164427974657333322067726561746572206f7220657175616c20746f203332206c656e6774682072657175697265645369676e617475726556616c696461746f7223697356616c69645369676e61747572653a20696c6c6567616c207369676e61747572654c6962427974657323706f704c617374427974653a2067726561746572207468616e207a65726f206c656e6774682072657175697265644f6666657228616464726573732074616b65722c61646472657373206d616b65722c616464726573732074616b6572546f6b656e2c75696e743235362074616b6572546f6b656e416d6f756e742c61646472657373206d616b6572546f6b656e2c75696e74323536206d616b6572546f6b656e416d6f756e742c75696e7432353620666565466163746f722c75696e74323536206578706972792c75696e743235362073616c74295361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645369676e617475726556616c696461746f7223697356616c69645369676e61747572653a206c656e677468203635206f722039372072657175697265645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a26469706673582212203388db445d1a2e782c8fe4db3bf36c2f9ac65683ffb93715ab7da29044ba5f7d64736f6c6343000706003300000000000000000000000063ef071b8a69c52a88dca4a844286aeff195129f00000000000000000000000003f34be1bf910116595db1b11e9d1b2ca5d59659000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006d9cc14a1d36e6ff13fc6efa9e9326fcd12e79030000000000000000000000003c68dfc45dc92c9c605d92b49858073e10b857a6000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000091c986709bb4fe0763edf8e2690ee9d5019bea4aDeployed Bytecode
0x60806040526004361061019a5760003560e01c806382fdaf58116100e1578063dab400f31161008a578063f6326fb311610064578063f6326fb3146103c8578063fa4e12d7146103dd578063fd0702961461040a578063ffc8fa691461041f576101a1565b8063dab400f314610389578063e0c05c241461039e578063e8edc816146103b3576101a1565b8063a42dce80116100bb578063a42dce801461033f578063c415b95c1461035f578063c49e4fd914610374576101a1565b806382fdaf58146102f5578063872001f1146103155780638da5cb5b1461032a576101a1565b80633fc8cef3116101435780635cc333211161011d5780635cc33321146102a9578063715018a6146102cb57806379ba5097146102e0576101a1565b80633fc8cef31461025f57806346920bad1461027457806353a47bb714610294576101a1565b806330db45801161017457806330db45801461021557806337be5439146102355780633ec632161461024a576101a1565b80630d788c36146101a657806312261ee7146101d15780631627540c146101f3576101a1565b366101a157005b600080fd5b3480156101b257600080fd5b506101bb610432565b6040516101c89190613267565b60405180910390f35b3480156101dd57600080fd5b506101e6610456565b6040516101c8919061319d565b3480156101ff57600080fd5b5061021361020e366004612d6f565b61047a565b005b34801561022157600080fd5b50610213610230366004612e08565b61050f565b34801561024157600080fd5b506101bb61060b565b34801561025657600080fd5b506101e661062f565b34801561026b57600080fd5b506101e6610653565b34801561028057600080fd5b5061021361028f366004612e08565b610677565b3480156102a057600080fd5b506101e6610749565b3480156102b557600080fd5b506102be610758565b6040516101c89190613270565b3480156102d757600080fd5b50610213610776565b3480156102ec57600080fd5b50610213610869565b34801561030157600080fd5b50610213610310366004612d6f565b61092c565b34801561032157600080fd5b506101e66109fc565b34801561033657600080fd5b506101e6610a20565b34801561034b57600080fd5b5061021361035a366004612d6f565b610a2f565b34801561036b57600080fd5b506101e6610aeb565b34801561038057600080fd5b506101e6610afa565b34801561039557600080fd5b506101bb610b1e565b3480156103aa57600080fd5b506102be610b2e565b3480156103bf57600080fd5b506101e6610b4c565b3480156103d457600080fd5b50610213610b5b565b3480156103e957600080fd5b506103fd6103f8366004612d8b565b610c53565b6040516101c8919061325c565b34801561041657600080fd5b506102be6112be565b61021361042d366004612ea8565b6112e2565b7f000000000000000000000000000000000000000000000000000000000000000181565b7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b6000546001600160a01b031633146104c5576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce2290600090a250565b6000546001600160a01b0316331461055a576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b60005b828110156106055761059c82600086868581811061057757fe5b905060200201602081019061058c9190612d6f565b6001600160a01b0316919061191f565b816001600160a01b03167f3ed6edecab5354e68e8f8fe05f9f34f99c401a17d00482311bfa561162bbc8798585848181106105d357fe5b90506020020160208101906105e89190612d6f565b6040516105f5919061319d565b60405180910390a260010161055d565b50505050565b7f8001743d62ea96bb683eb1f62c14b8f1469123c5f143a7f9095b8b9036a85e1e81565b7f00000000000000000000000003f34be1bf910116595db1b11e9d1b2ca5d5965981565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6000546001600160a01b031633146106c2576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b60005b82811015610605576106e08260001986868581811061057757fe5b816001600160a01b03167f9a3e46ec71da6d3ab362377a5f095af84cc1dbb1b40c5fa3ad7bb5accae2af7585858481811061071757fe5b905060200201602081019061072c9190612d6f565b604051610739919061319d565b60405180910390a26001016106c5565b6001546001600160a01b031681565b60405180604001604052806002815260200161763560f01b81525081565b6000546001600160a01b031633146107c1576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b6001546001600160a01b03161561081f576040805162461bcd60e51b815260206004820152601960248201527f70656e64696e67206e6f6d696e6174696f6e2065786973747300000000000000604482015290519081900360640190fd5b600080546040516001600160a01b03909116907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908390a3600080546001600160a01b0319169055565b6001546001600160a01b031633146108c8576040805162461bcd60e51b815260206004820152600d60248201527f6e6f74206e6f6d696e6174656400000000000000000000000000000000000000604482015290519081900360640190fd5b600154600080546040516001600160a01b0393841693909116917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91a360018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b03163314610977576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b6001600160a01b0381166109a65760405162461bcd60e51b815260040161099d90613461565b60405180910390fd5b600280546001600160a01b0319166001600160a01b0383161790556040517fbd4e916c3e5390ed2ffaf01ea6c14195c3e174811b8ad55bca06034e89bbd0bb906109f190839061319d565b60405180910390a150565b7f0000000000000000000000003c68dfc45dc92c9c605d92b49858073e10b857a681565b6000546001600160a01b031681565b6000546001600160a01b03163314610a7a576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b6001600160a01b038116610aa05760405162461bcd60e51b815260040161099d90613385565b600380546001600160a01b0319166001600160a01b0383161790556040517fd649da8f6092116f86ea4e5139de0b75ad371d823918d16368ba3ff09a5cbc9f906109f190839061319d565b6003546001600160a01b031681565b7f0000000000000000000000006d9cc14a1d36e6ff13fc6efa9e9326fcd12e790381565b6000610b28611a69565b90505b90565b60405180604001604052806002815260200161190160f01b81525081565b6002546001600160a01b031681565b6000546001600160a01b03163314610ba6576040805162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015290519081900360640190fd5b478015610c50577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b50505050507ff21b64ad26683e79854b8f088d254ef4e123df84bdb91d1f7f4356d772716a39816040516109f19190613267565b50565b600080825111610c945760405162461bcd60e51b815260040180806020018281038252604381526020018061363b6043913960600191505060405180910390fd5b6001600160a01b038516610cd95760405162461bcd60e51b81526004018080602001828103825260338152602001806135c06033913960400191505060405180910390fd5b6000610ce483611ad0565b60f81c905060078110610d285760405162461bcd60e51b815260040180806020018281038252603a81526020018061367e603a913960400191505060405180910390fd5b60008160ff166007811115610d3957fe5b9050600080808080856007811115610d4d57fe5b1415610d8a5760405162461bcd60e51b81526004018080602001828103825260368152602001806136f36036913960400191505060405180910390fd5b6002856007811115610d9857fe5b1415610ea257875160411480610daf575087516061145b610dea5760405162461bcd60e51b815260040180806020018281038252603d815260200180613832603d913960400191505060405180910390fd5b610df5886000611b58565b9250610e02886020611b58565b915087604081518110610e1157fe5b602001015160f81c60f81b60f81c935060018a85858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610e7b573d6000803e3d6000fd5b5050604051601f1901516001600160a01b038d811691161497506112b69650505050505050565b6003856007811115610eb057fe5b1415610fd457875160411480610ec7575087516061145b610f025760405162461bcd60e51b815260040180806020018281038252603d815260200180613832603d913960400191505060405180910390fd5b610f0d886000611b58565b9250610f1a886020611b58565b915087604081518110610f2957fe5b01602090810151604080517f19457468657265756d205369676e6564204d6573736167653a0a33320000000081850152603c8082018f905282518083039091018152605c82018084528151918601919091206000909152607c82018084525260f89290921c609c830181905260bc830187905260dc8301869052905190965060019260fc808401939192601f1981019281900390910190855afa158015610e7b573d6000803e3d6000fd5b6004856007811115610fe257fe5b141561114357604080516320c13b0b60e01b8152600481019182528a5160448201528a516001600160a01b038e16926320c13b0b928d928d92918291602482019160640190602087019080838360005b8381101561104a578181015183820152602001611032565b50505050905090810190601f1680156110775780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b838110156110aa578181015183820152602001611092565b50505050905090810190601f1680156110d75780820380516001836020036101000a031916815260200191505b5094505050505060206040518083038186803b1580156110f657600080fd5b505afa15801561110a573d6000803e3d6000fd5b505050506040513d602081101561112057600080fd5b50516001600160e01b0319166320c13b0b60e01b1496506112b695505050505050565b600585600781111561115157fe5b14156112535760408051630b135d3f60e11b8152600481018c8152602482019283528a5160448301528a516001600160a01b038f1693631626ba7e938f938e9390929160640190602085019080838360005b838110156111bb5781810151838201526020016111a3565b50505050905090810190601f1680156111e85780820380516001836020036101000a031916815260200191505b50935050505060206040518083038186803b15801561120657600080fd5b505afa15801561121a573d6000803e3d6000fd5b505050506040513d602081101561123057600080fd5b50516001600160e01b031916630b135d3f60e11b1496506112b695505050505050565b600685600781111561126157fe5b141561127f576112728a8c8a611bb0565b96505050505050506112b6565b60405162461bcd60e51b815260040180806020018281038252603a81526020018061367e603a913960400191505060405180910390fd5b949350505050565b604051806040016040528060088152602001672a37b5b2b73637b760c11b81525081565b7f00000000000000000000000003f34be1bf910116595db1b11e9d1b2ca5d596596001600160a01b0316331461132a5760405162461bcd60e51b815260040161099d906132f1565b884260e08201351161134e5760405162461bcd60e51b815260040161099d9061342a565b61271060c0820135106113735760405162461bcd60e51b815260040161099d906133f3565b60006113876101408c016101208d01612d6f565b6001600160a01b031614156113ae5760405162461bcd60e51b815260040161099d906133bc565b6000806113c86113c3368e90038e018e612f86565b611d77565b6040517f8caa276d00000000000000000000000000000000000000000000000000000000815291935091506001600160a01b037f0000000000000000000000006d9cc14a1d36e6ff13fc6efa9e9326fcd12e79031690638caa276d90611432908590600401613267565b600060405180830381600087803b15801561144c57600080fd5b505af1158015611460573d6000803e3d6000fd5b506114ce92506114799150506040850160208601612d6f565b61148284611e63565b604051806020016040528060008152508e8e8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c5392505050565b6114ea5760405162461bcd60e51b815260040161099d90613283565b336114f86020850185612d6f565b6001600160a01b0316146115875761156b6115166020850185612d6f565b61151f83611e63565b604051806020016040528060008152508a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c5392505050565b6115875760405162461bcd60e51b815260040161099d90613283565b6115a861159a6060850160408601612d6f565b6001600160a01b0316611eff565b156116fc57826060013534146115d05760405162461bcd60e51b815260040161099d9061334e565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561162b57600080fd5b505af115801561163f573d6000803e3d6000fd5b50505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663a9059cbb8460200160208101906116869190612d6f565b346040518363ffffffff1660e01b81526004016116a49291906131b1565b602060405180830381600087803b1580156116be57600080fd5b505af11580156116d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f69190612e88565b50611756565b341561171a5760405162461bcd60e51b815260040161099d9061334e565b61175661172d6060850160408601612d6f565b61173a6020860186612d6f565b61174a6040870160208801612d6f565b86606001358989611f35565b61178661176960a0850160808601612d6f565b6117796040860160208701612d6f565b308660a001358d8d611f35565b60006117a66127106117a060a087013560c088013561248f565b906124e8565b905060006117b860a08601358361254f565b905060006117cc60a0870160808801612d6f565b90507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316816001600160a01b031614156118bb576040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21690632e1a7d4d906118719060a08a013590600401613267565b600060405180830381600087803b15801561188b57600080fd5b505af115801561189f573d6000803e3d6000fd5b5050505073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90505b82156118db576003546118db906001600160a01b038381169116856125ac565b6119038f6101200160208101906118f29190612d6f565b6001600160a01b03831690846125ac565b5061190f848f836126e5565b5050505050505050505050505050565b8015806119be5750604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b15801561199057600080fd5b505afa1580156119a4573d6000803e3d6000fd5b505050506040513d60208110156119ba57600080fd5b5051155b6119f95760405162461bcd60e51b815260040180806020018281038252603681526020018061386f6036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b03167f095ea7b300000000000000000000000000000000000000000000000000000000179052611a64908490612798565b505050565b60007f0000000000000000000000000000000000000000000000000000000000000001611a94612849565b1415611ac157507f8001743d62ea96bb683eb1f62c14b8f1469123c5f143a7f9095b8b9036a85e1e610b2b565b611ac961284d565b9050610b2b565b600080825111611b115760405162461bcd60e51b81526004018080602001828103825260378152602001806137296037913960400191505060405180910390fd5b81600183510381518110611b2157fe5b016020015182516000190183527fff000000000000000000000000000000000000000000000000000000000000001690505b919050565b60008160200183511015611b9d5760405162461bcd60e51b815260040180806020018281038252603b8152602001806136b8603b913960400191505060405180910390fd5b6020820191508183015190505b92915050565b600080631626ba7e60e01b85846040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611c03578181015183820152602001611beb565b50505050905090810190601f168015611c305780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990971696909617909552509293507fb067138100000000000000000000000000000000000000000000000000000000925050853b9050611cc45762461bcd60e51b600052600160e51b6020526c062ba0a62622aa2fa2a92927a960811b604052600060605260646000fd5b60208201602081845183895afa60203d14611d0a5762461bcd60e51b600052600160e51b6020526c062ba0a62622aa2fa2a92927a960811b604052600060605260646000fd5b808015611d1e5760018114611d4f57611d6a565b62461bcd60e51b600052600160e51b6020526c062ba0a62622aa2fa2a92927a960811b604052600060605260646000fd5b6001600160e01b031984166001600160e01b03198451161495505b50505050505b9392505050565b600080611d87836000015161293f565b91506040518060e0016040528060a8815260200161376060a891396040516020018060276135f3823960270182805190602001908083835b60208310611dde5780518252601f199092019160209182019101611dbf565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012082846020015160405160200180848152602001838152602001826001600160a01b031681526020019350505050604051602081830303815290604052805190602001209050915091565b600060405180604001604052806002815260200161190160f01b815250611e88611a69565b836040516020018084805190602001908083835b60208310611ebb5780518252601f199092019160209182019101611e9c565b51815160209384036101000a600019018019909216911617905292019485525083810192909252506040805180840383018152928101905281519101209392505050565b60006001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480611baa5750506001600160a01b03161590565b600082826000818110611f4457fe5b919091013560f81c90506004811115611f5957fe5b90506000816004811115611f6957fe5b1415612034576040517f3474ad1a0000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000003c68dfc45dc92c9c605d92b49858073e10b857a61690633474ad1a90611fd89089908b9089906004016131f5565b600060405180830381600087803b158015611ff257600080fd5b505af1158015612006573d6000803e3d6000fd5b505050506001600160a01b038516301461202e5761202e6001600160a01b0388168686612a1f565b50612487565b600181600481111561204257fe5b141561205d5761202e6001600160a01b038816878787612a8a565b600281600481111561206b57fe5b1415612148576000806001600160a01b0389167fd505accf000000000000000000000000000000000000000000000000000000006120ac866001818a613556565b6040516020016120be9392919061312d565b60408051601f19818403018152908290526120d891613181565b6000604051808303816000865af19150503d8060008114612115576040519150601f19603f3d011682016040523d82523d6000602084013e61211a565b606091505b50915091508161212b573d60208201fd5b6121406001600160a01b038a16898989612a8a565b505050612487565b600381600481111561215657fe5b141561230657600061216b8360018187613556565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505082519293505090159050612262576000807f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b0316632b67b57060e01b846040516020016121f2929190613151565b60408051601f198184030181529082905261220c91613181565b6000604051808303816000865af19150503d8060008114612249576040519150601f19603f3d011682016040523d82523d6000602084013e61224e565b606091505b50915091508161225f573d60208201fd5b50505b6040517f36c785160000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316906336c78516906122cd908a908a908a908e906004016131ca565b600060405180830381600087803b1580156122e757600080fd5b505af11580156122fb573d6000803e3d6000fd5b505050505050612487565b600481600481111561231457fe5b14156101a15760006123298360018187613556565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250508251929350505061237e5760405162461bcd60e51b815260040161099d906132ba565b6000806000838060200190518101906123979190613061565b9250925092506000604051806060016040528060405180604001604052808f6001600160a01b031681526020018c8152508152602001858152602001848152509050600060405180604001604052808c6001600160a01b031681526020018b81525090507f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b03166330f28b7a83838f876040518563ffffffff1660e01b815260040161244d94939291906134be565b600060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b50505050505050505050505b505050505050565b60008261249e57506000611baa565b828202828482816124ab57fe5b0414611d705760405162461bcd60e51b815260040180806020018281038252602181526020018061361a6021913960400191505060405180910390fd5b600080821161253e576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161254757fe5b049392505050565b6000828211156125a6576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6001600160a01b0382163014156125c257611a64565b6125cb83611eff565b156126d15780471015612625576040805162461bcd60e51b815260206004820152601460248201527f696e73756666696369656e742062616c616e6365000000000000000000000000604482015290519081900360640190fd5b6040516000906001600160a01b0384169083908381818185875af1925050503d8060008114612670576040519150601f19603f3d011682016040523d82523d6000602084013e612675565b606091505b50509050806126cb576040805162461bcd60e51b815260206004820152601260248201527f756e61626c6520746f2073656e64204554480000000000000000000000000000604482015290519081900360640190fd5b50611a64565b611a646001600160a01b0384168383612a1f565b6126f56040830160208401612d6f565b6001600160a01b031661270b6020840184612d6f565b6001600160a01b0316847ff421ece6d047e3cc8f5953db3c6a3b01544fd3288d60bdb78643565d71d163326127466060870160408801612d6f565b606087013561275b60a0890160808a01612d6f565b60a08901356127726101408b016101208c01612d6f565b60405161278b9594939291908b9060c08e013590613219565b60405180910390a4505050565b60006127ed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612afd9092919063ffffffff16565b805190915015611a645780806020019051602081101561280c57600080fd5b5051611a645760405162461bcd60e51b815260040180806020018281038252602a815260200180613808602a913960400191505060405180910390fd5b4690565b60408051808201825260088152672a37b5b2b73637b760c11b60209182015281518083019092526002825261763560f01b91015260007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f4428669f887e7f6a6e361e218ee42308201bdbacbf601211fc38b8b2ec6961817f7d6f66f923317ceee1bd9447053fb8a64c76979d436a723b87aff2899feaa6c36128ee612849565b3060405160200180868152602001858152602001848152602001838152602001826001600160a01b031681526020019550505050505060405160208183030381529060405280519060200120905090565b60006040518060e0016040528060a8815260200161376060a8913980519060200120826000015183602001518460400151856060015186608001518760a001518860c001518960e001518a6101000151604051602001808b81526020018a6001600160a01b03168152602001896001600160a01b03168152602001886001600160a01b03168152602001878152602001866001600160a01b031681526020018581526020018481526020018381526020018281526020019a5050505050505050505050604051602081830303815290604052805190602001209050919050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b03167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611a64908490612798565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03167f23b872dd00000000000000000000000000000000000000000000000000000000179052610605908590612798565b60606112b6848460008585612b1185612c22565b612b62576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310612ba05780518252601f199092019160209182019101612b81565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612c02576040519150601f19603f3d011682016040523d82523d6000602084013e612c07565b606091505b5091509150612c17828286612c28565b979650505050505050565b3b151590565b60608315612c37575081611d70565b825115612c475782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612c91578181015183820152602001612c79565b50505050905090810190601f168015612cbe5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b8035611b53816135aa565b60008083601f840112612ce8578182fd5b50813567ffffffffffffffff811115612cff578182fd5b602083019150836020828501011115612d1757600080fd5b9250929050565b600082601f830112612d2e578081fd5b8135612d41612d3c82613534565b613510565b818152846020838601011115612d55578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215612d80578081fd5b8135611d70816135aa565b60008060008060808587031215612da0578283fd5b8435612dab816135aa565b935060208501359250604085013567ffffffffffffffff80821115612dce578384fd5b612dda88838901612d1e565b93506060870135915080821115612def578283fd5b50612dfc87828801612d1e565b91505092959194509250565b600080600060408486031215612e1c578283fd5b833567ffffffffffffffff80821115612e33578485fd5b818601915086601f830112612e46578485fd5b813581811115612e54578586fd5b8760208083028501011115612e67578586fd5b60209283019550935050840135612e7d816135aa565b809150509250925092565b600060208284031215612e99578081fd5b81518015158114611d70578182fd5b6000806000806000806000806000898b036101c0811215612ec7578586fd5b61014080821215612ed6578687fd5b8b9a508a0135905067ffffffffffffffff80821115612ef3578687fd5b612eff8d838e01612cd7565b909a5098506101608c0135915080821115612f18578687fd5b612f248d838e01612cd7565b90985096506101808c0135915080821115612f3d578586fd5b612f498d838e01612cd7565b90965094506101a08c0135915080821115612f62578384fd5b50612f6f8c828d01612cd7565b915080935050809150509295985092959850929598565b6000818303610140811215612f99578182fd5b6040516040810181811067ffffffffffffffff82111715612fb657fe5b60405261012080831215612fc8578384fd5b612fd181613510565b9250612fdc85612ccc565b8352612fea60208601612ccc565b6020840152612ffb60408601612ccc565b60408401526060850135606084015261301660808601612ccc565b608084015260a085013560a084015260c085013560c084015260e085013560e0840152610100808601358185015250828252613053818601612ccc565b602083015250949350505050565b600080600060608486031215613075578283fd5b8351925060208401519150604084015167ffffffffffffffff811115613099578182fd5b8401601f810186136130a9578182fd5b80516130b7612d3c82613534565b8181528760208385010111156130cb578384fd5b6130dc82602083016020860161357e565b8093505050509250925092565b6000815180845261310181602086016020860161357e565b601f01601f19169290920160200192915050565b80516001600160a01b03168252602090810151910152565b60006001600160e01b03198516825282846004840137910160040190815292915050565b60006001600160e01b031984168252825161317381600485016020870161357e565b919091016004019392505050565b6000825161319381846020870161357e565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815292841660208401529083166040830152909116606082015260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039788168152602081019690965293861660408601526060850192909252909316608083015260a082019290925260c081019190915260e00190565b901515815260200190565b90815260200190565b600060208252611d7060208301846130e9565b60208082526011908201527f696e76616c6964207369676e6174757265000000000000000000000000000000604082015260600190565b60208082526012908201527f656d707479207065726d69743220646174610000000000000000000000000000604082015260600190565b60208082526025908201527f53747261746567793a206e6f742066726f6d205573657250726f787920636f6e60408201527f7472616374000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f696e76616c6964206d73672076616c7565000000000000000000000000000000604082015260600190565b6020808252600c908201527f7a65726f20616464726573730000000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f7a65726f20726563697069656e74000000000000000000000000000000000000604082015260600190565b60208082526012908201527f696e76616c69642066656520666163746f720000000000000000000000000000604082015260600190565b6020808252600d908201527f6f66666572206578706972656400000000000000000000000000000000000000604082015260600190565b60208082526029908201527f53747261746567793a207370656e6465722063616e206e6f74206265207a657260408201527f6f20616464726573730000000000000000000000000000000000000000000000606082015260800190565b60006101006134ce838851613115565b60208701516040840152604087015160608401526134ef6080840187613115565b6001600160a01b03851660c08401528060e0840152612c17818401856130e9565b60405181810167ffffffffffffffff8111828210171561352c57fe5b604052919050565b600067ffffffffffffffff82111561354857fe5b50601f01601f191660200190565b60008085851115613565578182fd5b83861115613571578182fd5b5050820193919092039150565b60005b83811015613599578181015183820152602001613581565b838111156106055750506000910152565b6001600160a01b0381168114610c5057600080fdfe5369676e617475726556616c696461746f7223697356616c69645369676e61747572653a20696e76616c6964207369676e65725246514f72646572284f66666572206f666665722c6164647265737320726563697069656e7429536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775369676e617475726556616c696461746f7223697356616c69645369676e61747572653a206c656e6774682067726561746572207468616e20302072657175697265645369676e617475726556616c696461746f7223697356616c69645369676e61747572653a20756e737570706f72746564207369676e61747572654c696242797465732372656164427974657333322067726561746572206f7220657175616c20746f203332206c656e6774682072657175697265645369676e617475726556616c696461746f7223697356616c69645369676e61747572653a20696c6c6567616c207369676e61747572654c6962427974657323706f704c617374427974653a2067726561746572207468616e207a65726f206c656e6774682072657175697265644f6666657228616464726573732074616b65722c61646472657373206d616b65722c616464726573732074616b6572546f6b656e2c75696e743235362074616b6572546f6b656e416d6f756e742c61646472657373206d616b6572546f6b656e2c75696e74323536206d616b6572546f6b656e416d6f756e742c75696e7432353620666565466163746f722c75696e74323536206578706972792c75696e743235362073616c74295361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645369676e617475726556616c696461746f7223697356616c69645369676e61747572653a206c656e677468203635206f722039372072657175697265645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a26469706673582212203388db445d1a2e782c8fe4db3bf36c2f9ac65683ffb93715ab7da29044ba5f7d64736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000063ef071b8a69c52a88dca4a844286aeff195129f00000000000000000000000003f34be1bf910116595db1b11e9d1b2ca5d59659000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006d9cc14a1d36e6ff13fc6efa9e9326fcd12e79030000000000000000000000003c68dfc45dc92c9c605d92b49858073e10b857a6000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000091c986709bb4fe0763edf8e2690ee9d5019bea4a
-----Decoded View---------------
Arg [0] : _owner (address): 0x63Ef071b8A69C52a88dCA4A844286Aeff195129F
Arg [1] : _userProxy (address): 0x03f34bE1BF910116595dB1b11E9d1B2cA5D59659
Arg [2] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [3] : _permStorage (address): 0x6D9Cc14a1d36E6fF13fc6efA9e9326FcD12E7903
Arg [4] : _spender (address): 0x3c68dfc45dc92C9c605d92B49858073e10b857A6
Arg [5] : _uniswapPermit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
Arg [6] : _feeCollector (address): 0x91C986709Bb4fE0763edF8E2690EE9d5019Bea4a
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 00000000000000000000000063ef071b8a69c52a88dca4a844286aeff195129f
Arg [1] : 00000000000000000000000003f34be1bf910116595db1b11e9d1b2ca5d59659
Arg [2] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [3] : 0000000000000000000000006d9cc14a1d36e6ff13fc6efa9e9326fcd12e7903
Arg [4] : 0000000000000000000000003c68dfc45dc92c9c605d92b49858073e10b857a6
Arg [5] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [6] : 00000000000000000000000091c986709bb4fe0763edf8e2690ee9d5019bea4aLoading...LoadingLoading...Loading
Loading...Loading
Loading...LoadingLoading...LoadingLoading...LoadingLoading...LoadingLoading...LoadingLoading...LoadingMultichain Portfolio | 30 Chains
Chain Token Portfolio % Price Amount Value ETH 37.67% $0.999302 33,636.7533 $33,613.27 ETH 21.03% $0.000018 1,026,862,294.9924 $18,760.77 ETH 19.86% $1 17,700.2053 $17,717.91 ETH 10.05% $14.06 637.7277 $8,966.45 ETH 6.26% $24.06 232.2394 $5,587.68 ETH 3.82% $98,729 0.0345 $3,406.67 ETH 0.35% $0.399593 787.2948 $314.6 ETH 0.32% $1.81 155.9986 $282.36 ETH 0.31% $94,095 0.00296089 $278.6 ETH 0.18% $1.22 131.8766 $160.89 ETH 0.13% $1 112.7755 $112.89 ETH Ether (ETH)0.01% $3,385.06 0.00384877 $13.03 ETH <0.01% <$0.000001 12,394,453.0166 $0.9246 BSC 0.01% $0.000016 804,828 $12.91 POL <0.01% $0.0003 500 $0.1498 POL <0.01% $0.498614 0.0011 $0.000548 Loading...Loading[ 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.
Address QR Code
My Address - Private Name Tag or Note
My Name Tag:
Private Name Tags (up to 35 characters) can be used for easy identification of addressesPrivate Note:
A private note (up to 500 characters) can be attached to this address.
Please DO NOT store any passwords or private keys here.Compiler specific version warnings:
The compiled contract might be susceptible to FullInlinerNonExpressionSplitArgumentEvaluationOrder (low-severity), MissingSideEffectsOnSelectorAccess (low-severity), AbiReencodingHeadOverflowWithStaticArrayCleanup (medium-severity), DirtyBytesArrayToStorage (low-severity), DataLocationChangeInInternalOverride (very low-severity), NestedCalldataArrayAbiReencodingSizeValidation (very low-severity), SignedImmutables (very low-severity), ABIDecodeTwoDimensionalArrayMemory (very low-severity), KeccakCaching (medium-severity) Solidity Compiler Bugs.
Connect a Wallet
Connecting wallet for read function is optional, useful if you want to call certain functions or simply use your wallet's node.Connect a Wallet
Connecting wallet for read function is optional, useful if you want to call certain functions or simply use your wallet's node.Connect a Wallet
Connecting wallet for read function is optional, useful if you want to call certain functions or simply use your wallet's node.SignIn
Address Cards
To use this feature, please login to your Etherscan account and return to this page.Before You Copy
Transaction Private Note
This website uses cookies to improve your experience. By continuing to use this website, you agree to its Terms and Privacy Policy.