Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ExchangeDeposits
Compiler Version
v0.7.6+commit.7338295f
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-08-28 */ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; // File: contracts/lib/AddressUtil.sol // Copyright 2017 Loopring Technology Limited. /// @title Utility Functions for addresses /// @author Daniel Wang - <[email protected]> /// @author Brecht Devos - <[email protected]> library AddressUtil { using AddressUtil for *; function isContract( address addr ) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(addr) } return (codehash != 0x0 && codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470); } function toPayable( address addr ) internal pure returns (address payable) { return payable(addr); } // Works like address.send but with a customizable gas limit // Make sure your code is safe for reentrancy when using this function! function sendETH( address to, uint amount, uint gasLimit ) internal returns (bool success) { if (amount == 0) { return true; } address payable recipient = to.toPayable(); /* solium-disable-next-line */ (success, ) = recipient.call{value: amount, gas: gasLimit}(""); } // Works like address.transfer but with a customizable gas limit // Make sure your code is safe for reentrancy when using this function! function sendETHAndVerify( address to, uint amount, uint gasLimit ) internal returns (bool success) { success = to.sendETH(amount, gasLimit); require(success, "TRANSFER_FAILURE"); } // Works like call but is slightly more efficient when data // needs to be copied from memory to do the call. function fastCall( address to, uint gasLimit, uint value, bytes memory data ) internal returns (bool success, bytes memory returnData) { if (to != address(0)) { assembly { // Do the call success := call(gasLimit, to, value, add(data, 32), mload(data), 0, 0) // Copy the return data let size := returndatasize() returnData := mload(0x40) mstore(returnData, size) returndatacopy(add(returnData, 32), 0, size) // Update free memory pointer mstore(0x40, add(returnData, add(32, size))) } } } // Like fastCall, but throws when the call is unsuccessful. function fastCallAndVerify( address to, uint gasLimit, uint value, bytes memory data ) internal returns (bytes memory returnData) { bool success; (success, returnData) = fastCall(to, gasLimit, value, data); if (!success) { assembly { revert(add(returnData, 32), mload(returnData)) } } } } // File: contracts/lib/MathUint96.sol // Copyright 2017 Loopring Technology Limited. /// @title Utility Functions for uint /// @author Daniel Wang - <[email protected]> library MathUint96 { function add( uint96 a, uint96 b ) internal pure returns (uint96 c) { c = a + b; require(c >= a, "ADD_OVERFLOW"); } function sub( uint96 a, uint96 b ) internal pure returns (uint96 c) { require(b <= a, "SUB_UNDERFLOW"); return a - b; } } // File: contracts/core/iface/IAgentRegistry.sol // Copyright 2017 Loopring Technology Limited. interface IAgent{} abstract contract IAgentRegistry { /// @dev Returns whether an agent address is an agent of an account owner /// @param owner The account owner. /// @param agent The agent address /// @return True if the agent address is an agent for the account owner, else false function isAgent( address owner, address agent ) external virtual view returns (bool); /// @dev Returns whether an agent address is an agent of all account owners /// @param owners The account owners. /// @param agent The agent address /// @return True if the agent address is an agent for the account owner, else false function isAgent( address[] calldata owners, address agent ) external virtual view returns (bool); /// @dev Returns whether an agent address is a universal agent. /// @param agent The agent address /// @return True if the agent address is a universal agent, else false function isUniversalAgent(address agent) public virtual view returns (bool); } // File: contracts/lib/Ownable.sol // Copyright 2017 Loopring Technology Limited. /// @title Ownable /// @author Brecht Devos - <[email protected]> /// @dev The Ownable contract has an owner address, and provides basic /// authorization control functions, this simplifies the implementation of /// "user permissions". contract Ownable { address public owner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /// @dev The Ownable constructor sets the original `owner` of the contract /// to the sender. constructor() { owner = msg.sender; } /// @dev Throws if called by any account other than the owner. modifier onlyOwner() { require(msg.sender == owner, "UNAUTHORIZED"); _; } /// @dev Allows the current owner to transfer control of the contract to a /// new owner. /// @param newOwner The address to transfer ownership to. function transferOwnership( address newOwner ) public virtual onlyOwner { require(newOwner != address(0), "ZERO_ADDRESS"); emit OwnershipTransferred(owner, newOwner); owner = newOwner; } function renounceOwnership() public onlyOwner { emit OwnershipTransferred(owner, address(0)); owner = address(0); } } // File: contracts/lib/Claimable.sol // Copyright 2017 Loopring Technology Limited. /// @title Claimable /// @author Brecht Devos - <[email protected]> /// @dev Extension for the Ownable contract, where the ownership needs /// to be claimed. This allows the new owner to accept the transfer. contract Claimable is Ownable { address public pendingOwner; /// @dev Modifier throws if called by any account other than the pendingOwner. modifier onlyPendingOwner() { require(msg.sender == pendingOwner, "UNAUTHORIZED"); _; } /// @dev Allows the current owner to set the pendingOwner address. /// @param newOwner The address to transfer ownership to. function transferOwnership( address newOwner ) public override onlyOwner { require(newOwner != address(0) && newOwner != owner, "INVALID_ADDRESS"); pendingOwner = newOwner; } /// @dev Allows the pendingOwner address to finalize the transfer. function claimOwnership() public onlyPendingOwner { emit OwnershipTransferred(owner, pendingOwner); owner = pendingOwner; pendingOwner = address(0); } } // File: contracts/core/iface/IBlockVerifier.sol // Copyright 2017 Loopring Technology Limited. /// @title IBlockVerifier /// @author Brecht Devos - <[email protected]> abstract contract IBlockVerifier is Claimable { // -- Events -- event CircuitRegistered( uint8 indexed blockType, uint16 blockSize, uint8 blockVersion ); event CircuitDisabled( uint8 indexed blockType, uint16 blockSize, uint8 blockVersion ); // -- Public functions -- /// @dev Sets the verifying key for the specified circuit. /// Every block permutation needs its own circuit and thus its own set of /// verification keys. Only a limited number of block sizes per block /// type are supported. /// @param blockType The type of the block /// @param blockSize The number of requests handled in the block /// @param blockVersion The block version (i.e. which circuit version needs to be used) /// @param vk The verification key function registerCircuit( uint8 blockType, uint16 blockSize, uint8 blockVersion, uint[18] calldata vk ) external virtual; /// @dev Disables the use of the specified circuit. /// @param blockType The type of the block /// @param blockSize The number of requests handled in the block /// @param blockVersion The block version (i.e. which circuit version needs to be used) function disableCircuit( uint8 blockType, uint16 blockSize, uint8 blockVersion ) external virtual; /// @dev Verifies blocks with the given public data and proofs. /// Verifying a block makes sure all requests handled in the block /// are correctly handled by the operator. /// @param blockType The type of block /// @param blockSize The number of requests handled in the block /// @param blockVersion The block version (i.e. which circuit version needs to be used) /// @param publicInputs The hash of all the public data of the blocks /// @param proofs The ZK proofs proving that the blocks are correct /// @return True if the block is valid, false otherwise function verifyProofs( uint8 blockType, uint16 blockSize, uint8 blockVersion, uint[] calldata publicInputs, uint[] calldata proofs ) external virtual view returns (bool); /// @dev Checks if a circuit with the specified parameters is registered. /// @param blockType The type of the block /// @param blockSize The number of requests handled in the block /// @param blockVersion The block version (i.e. which circuit version needs to be used) /// @return True if the circuit is registered, false otherwise function isCircuitRegistered( uint8 blockType, uint16 blockSize, uint8 blockVersion ) external virtual view returns (bool); /// @dev Checks if a circuit can still be used to commit new blocks. /// @param blockType The type of the block /// @param blockSize The number of requests handled in the block /// @param blockVersion The block version (i.e. which circuit version needs to be used) /// @return True if the circuit is enabled, false otherwise function isCircuitEnabled( uint8 blockType, uint16 blockSize, uint8 blockVersion ) external virtual view returns (bool); } // File: contracts/core/iface/IDepositContract.sol // Copyright 2017 Loopring Technology Limited. /// @title IDepositContract. /// @dev Contract storing and transferring funds for an exchange. /// /// ERC1155 tokens can be supported by registering pseudo token addresses calculated /// as `address(keccak256(real_token_address, token_params))`. Then the custom /// deposit contract can look up the real token address and paramsters with the /// pseudo token address before doing the transfers. /// @author Brecht Devos - <[email protected]> interface IDepositContract { /// @dev Returns if a token is suppoprted by this contract. function isTokenSupported(address token) external view returns (bool); /// @dev Transfers tokens from a user to the exchange. This function will /// be called when a user deposits funds to the exchange. /// In a simple implementation the funds are simply stored inside the /// deposit contract directly. More advanced implementations may store the funds /// in some DeFi application to earn interest, so this function could directly /// call the necessary functions to store the funds there. /// /// This function needs to throw when an error occurred! /// /// This function can only be called by the exchange. /// /// @param from The address of the account that sends the tokens. /// @param token The address of the token to transfer (`0x0` for ETH). /// @param amount The amount of tokens to transfer. /// @param extraData Opaque data that can be used by the contract to handle the deposit /// @return amountReceived The amount to deposit to the user's account in the Merkle tree function deposit( address from, address token, uint96 amount, bytes calldata extraData ) external payable returns (uint96 amountReceived); /// @dev Transfers tokens from the exchange to a user. This function will /// be called when a withdrawal is done for a user on the exchange. /// In the simplest implementation the funds are simply stored inside the /// deposit contract directly so this simply transfers the requested tokens back /// to the user. More advanced implementations may store the funds /// in some DeFi application to earn interest so the function would /// need to get those tokens back from the DeFi application first before they /// can be transferred to the user. /// /// This function needs to throw when an error occurred! /// /// This function can only be called by the exchange. /// /// @param from The address from which 'amount' tokens are transferred. /// @param to The address to which 'amount' tokens are transferred. /// @param token The address of the token to transfer (`0x0` for ETH). /// @param amount The amount of tokens transferred. /// @param extraData Opaque data that can be used by the contract to handle the withdrawal function withdraw( address from, address to, address token, uint amount, bytes calldata extraData ) external payable; /// @dev Transfers tokens (ETH not supported) for a user using the allowance set /// for the exchange. This way the approval can be used for all functionality (and /// extended functionality) of the exchange. /// Should NOT be used to deposit/withdraw user funds, `deposit`/`withdraw` /// should be used for that as they will contain specialised logic for those operations. /// This function can be called by the exchange to transfer onchain funds of users /// necessary for Agent functionality. /// /// This function needs to throw when an error occurred! /// /// This function can only be called by the exchange. /// /// @param from The address of the account that sends the tokens. /// @param to The address to which 'amount' tokens are transferred. /// @param token The address of the token to transfer (ETH is and cannot be suppported). /// @param amount The amount of tokens transferred. function transfer( address from, address to, address token, uint amount ) external payable; /// @dev Checks if the given address is used for depositing ETH or not. /// Is used while depositing to send the correct ETH amount to the deposit contract. /// /// Note that 0x0 is always registered for deposting ETH when the exchange is created! /// This function allows additional addresses to be used for depositing ETH, the deposit /// contract can implement different behaviour based on the address value. /// /// @param addr The address to check /// @return True if the address is used for depositing ETH, else false. function isETH(address addr) external view returns (bool); } // File: contracts/core/iface/ILoopringV3.sol // Copyright 2017 Loopring Technology Limited. /// @title ILoopringV3 /// @author Brecht Devos - <[email protected]> /// @author Daniel Wang - <[email protected]> abstract contract ILoopringV3 is Claimable { // == Events == event ExchangeStakeDeposited(address exchangeAddr, uint amount); event ExchangeStakeWithdrawn(address exchangeAddr, uint amount); event ExchangeStakeBurned(address exchangeAddr, uint amount); event SettingsUpdated(uint time); // == Public Variables == mapping (address => uint) internal exchangeStake; uint public totalStake; address public blockVerifierAddress; uint public forcedWithdrawalFee; uint public tokenRegistrationFeeLRCBase; uint public tokenRegistrationFeeLRCDelta; uint8 public protocolTakerFeeBips; uint8 public protocolMakerFeeBips; address payable public protocolFeeVault; // == Public Functions == /// @dev Returns the LRC token address /// @return the LRC token address function lrcAddress() external view virtual returns (address); /// @dev Updates the global exchange settings. /// This function can only be called by the owner of this contract. /// /// Warning: these new values will be used by existing and /// new Loopring exchanges. function updateSettings( address payable _protocolFeeVault, // address(0) not allowed address _blockVerifierAddress, // address(0) not allowed uint _forcedWithdrawalFee ) external virtual; /// @dev Updates the global protocol fee settings. /// This function can only be called by the owner of this contract. /// /// Warning: these new values will be used by existing and /// new Loopring exchanges. function updateProtocolFeeSettings( uint8 _protocolTakerFeeBips, uint8 _protocolMakerFeeBips ) external virtual; /// @dev Gets the amount of staked LRC for an exchange. /// @param exchangeAddr The address of the exchange /// @return stakedLRC The amount of LRC function getExchangeStake( address exchangeAddr ) public virtual view returns (uint stakedLRC); /// @dev Burns a certain amount of staked LRC for a specific exchange. /// This function is meant to be called only from exchange contracts. /// @return burnedLRC The amount of LRC burned. If the amount is greater than /// the staked amount, all staked LRC will be burned. function burnExchangeStake( uint amount ) external virtual returns (uint burnedLRC); /// @dev Stakes more LRC for an exchange. /// @param exchangeAddr The address of the exchange /// @param amountLRC The amount of LRC to stake /// @return stakedLRC The total amount of LRC staked for the exchange function depositExchangeStake( address exchangeAddr, uint amountLRC ) external virtual returns (uint stakedLRC); /// @dev Withdraws a certain amount of staked LRC for an exchange to the given address. /// This function is meant to be called only from within exchange contracts. /// @param recipient The address to receive LRC /// @param requestedAmount The amount of LRC to withdraw /// @return amountLRC The amount of LRC withdrawn function withdrawExchangeStake( address recipient, uint requestedAmount ) external virtual returns (uint amountLRC); /// @dev Gets the protocol fee values for an exchange. /// @return takerFeeBips The protocol taker fee /// @return makerFeeBips The protocol maker fee function getProtocolFeeValues( ) public virtual view returns ( uint8 takerFeeBips, uint8 makerFeeBips ); } // File: contracts/core/iface/ExchangeData.sol // Copyright 2017 Loopring Technology Limited. /// @title ExchangeData /// @dev All methods in this lib are internal, therefore, there is no need /// to deploy this library independently. /// @author Daniel Wang - <[email protected]> /// @author Brecht Devos - <[email protected]> library ExchangeData { // -- Enums -- enum TransactionType { NOOP, DEPOSIT, WITHDRAWAL, TRANSFER, SPOT_TRADE, ACCOUNT_UPDATE, AMM_UPDATE, SIGNATURE_VERIFICATION, NFT_MINT, // L2 NFT mint or L1-to-L2 NFT deposit NFT_DATA } enum NftType { ERC1155, ERC721 } // -- Structs -- struct Token { address token; } struct ProtocolFeeData { uint32 syncedAt; // only valid before 2105 (85 years to go) uint8 takerFeeBips; uint8 makerFeeBips; uint8 previousTakerFeeBips; uint8 previousMakerFeeBips; } // General auxiliary data for each conditional transaction struct AuxiliaryData { uint txIndex; bool approved; bytes data; } // This is the (virtual) block the owner needs to submit onchain to maintain the // per-exchange (virtual) blockchain. struct Block { uint8 blockType; uint16 blockSize; uint8 blockVersion; bytes data; uint256[8] proof; // Whether we should store the @BlockInfo for this block on-chain. bool storeBlockInfoOnchain; // Block specific data that is only used to help process the block on-chain. // It is not used as input for the circuits and it is not necessary for data-availability. // This bytes array contains the abi encoded AuxiliaryData[] data. bytes auxiliaryData; // Arbitrary data, mainly for off-chain data-availability, i.e., // the multihash of the IPFS file that contains the block data. bytes offchainData; } struct BlockInfo { // The time the block was submitted on-chain. uint32 timestamp; // The public data hash of the block (the 28 most significant bytes). bytes28 blockDataHash; } // Represents an onchain deposit request. struct Deposit { uint96 amount; uint64 timestamp; } // A forced withdrawal request. // If the actual owner of the account initiated the request (we don't know who the owner is // at the time the request is being made) the full balance will be withdrawn. struct ForcedWithdrawal { address owner; uint64 timestamp; } struct Constants { uint SNARK_SCALAR_FIELD; uint MAX_OPEN_FORCED_REQUESTS; uint MAX_AGE_FORCED_REQUEST_UNTIL_WITHDRAW_MODE; uint TIMESTAMP_HALF_WINDOW_SIZE_IN_SECONDS; uint MAX_NUM_ACCOUNTS; uint MAX_NUM_TOKENS; uint MIN_AGE_PROTOCOL_FEES_UNTIL_UPDATED; uint MIN_TIME_IN_SHUTDOWN; uint TX_DATA_AVAILABILITY_SIZE; uint MAX_AGE_DEPOSIT_UNTIL_WITHDRAWABLE_UPPERBOUND; } // This is the prime number that is used for the alt_bn128 elliptic curve, see EIP-196. uint public constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint public constant MAX_OPEN_FORCED_REQUESTS = 4096; uint public constant MAX_AGE_FORCED_REQUEST_UNTIL_WITHDRAW_MODE = 15 days; uint public constant TIMESTAMP_HALF_WINDOW_SIZE_IN_SECONDS = 7 days; uint public constant MAX_NUM_ACCOUNTS = 2 ** 32; uint public constant MAX_NUM_TOKENS = 2 ** 16; uint public constant MIN_AGE_PROTOCOL_FEES_UNTIL_UPDATED = 7 days; uint public constant MIN_TIME_IN_SHUTDOWN = 30 days; // The amount of bytes each rollup transaction uses in the block data for data-availability. // This is the maximum amount of bytes of all different transaction types. uint32 public constant MAX_AGE_DEPOSIT_UNTIL_WITHDRAWABLE_UPPERBOUND = 15 days; uint32 public constant ACCOUNTID_PROTOCOLFEE = 0; uint public constant TX_DATA_AVAILABILITY_SIZE = 68; uint public constant TX_DATA_AVAILABILITY_SIZE_PART_1 = 29; uint public constant TX_DATA_AVAILABILITY_SIZE_PART_2 = 39; uint public constant NFT_TOKEN_ID_START = 2 ** 15; struct AccountLeaf { uint32 accountID; address owner; uint pubKeyX; uint pubKeyY; uint32 nonce; uint feeBipsAMM; } struct BalanceLeaf { uint16 tokenID; uint96 balance; uint weightAMM; uint storageRoot; } struct Nft { address minter; // Minter address for a L2 mint or // the NFT's contract address in the case of a L1-to-L2 NFT deposit. NftType nftType; address token; uint256 nftID; uint8 creatorFeeBips; } struct MerkleProof { ExchangeData.AccountLeaf accountLeaf; ExchangeData.BalanceLeaf balanceLeaf; ExchangeData.Nft nft; uint[48] accountMerkleProof; uint[24] balanceMerkleProof; } struct BlockContext { bytes32 DOMAIN_SEPARATOR; uint32 timestamp; Block block; uint txIndex; } // Represents the entire exchange state except the owner of the exchange. struct State { uint32 maxAgeDepositUntilWithdrawable; bytes32 DOMAIN_SEPARATOR; ILoopringV3 loopring; IBlockVerifier blockVerifier; IAgentRegistry agentRegistry; IDepositContract depositContract; // The merkle root of the offchain data stored in a Merkle tree. The Merkle tree // stores balances for users using an account model. bytes32 merkleRoot; // List of all blocks mapping(uint => BlockInfo) blocks; uint numBlocks; // List of all tokens Token[] tokens; // A map from a token to its tokenID + 1 mapping (address => uint16) tokenToTokenId; // A map from an accountID to a tokenID to if the balance is withdrawn mapping (uint32 => mapping (uint16 => bool)) withdrawnInWithdrawMode; // A map from an account to a token to the amount withdrawable for that account. // This is only used when the automatic distribution of the withdrawal failed. mapping (address => mapping (uint16 => uint)) amountWithdrawable; // A map from an account to a token to the forced withdrawal (always full balance) // The `uint16' represents ERC20 token ID (if < NFT_TOKEN_ID_START) or // NFT balance slot (if >= NFT_TOKEN_ID_START) mapping (uint32 => mapping (uint16 => ForcedWithdrawal)) pendingForcedWithdrawals; // A map from an address to a token to a deposit mapping (address => mapping (uint16 => Deposit)) pendingDeposits; // A map from an account owner to an approved transaction hash to if the transaction is approved or not mapping (address => mapping (bytes32 => bool)) approvedTx; // A map from an account owner to a destination address to a tokenID to an amount to a storageID to a new recipient address mapping (address => mapping (address => mapping (uint16 => mapping (uint => mapping (uint32 => address))))) withdrawalRecipient; // Counter to keep track of how many of forced requests are open so we can limit the work that needs to be done by the owner uint32 numPendingForcedTransactions; // Cached data for the protocol fee ProtocolFeeData protocolFeeData; // Time when the exchange was shutdown uint shutdownModeStartTime; // Time when the exchange has entered withdrawal mode uint withdrawalModeStartTime; // Last time the protocol fee was withdrawn for a specific token mapping (address => uint) protocolFeeLastWithdrawnTime; // Duplicated loopring address address loopringAddr; // AMM fee bips uint8 ammFeeBips; // Enable/Disable `onchainTransferFrom` bool allowOnchainTransferFrom; // owner => NFT type => token address => nftID => Deposit mapping (address => mapping (NftType => mapping (address => mapping(uint256 => Deposit)))) pendingNFTDeposits; // owner => minter => NFT type => token address => nftID => amount withdrawable // This is only used when the automatic distribution of the withdrawal failed. mapping (address => mapping (address => mapping (NftType => mapping (address => mapping(uint256 => uint))))) amountWithdrawableNFT; } } // File: contracts/lib/MathUint.sol // Copyright 2017 Loopring Technology Limited. /// @title Utility Functions for uint /// @author Daniel Wang - <[email protected]> library MathUint { using MathUint for uint; function mul( uint a, uint b ) internal pure returns (uint c) { c = a * b; require(a == 0 || c / a == b, "MUL_OVERFLOW"); } function sub( uint a, uint b ) internal pure returns (uint) { require(b <= a, "SUB_UNDERFLOW"); return a - b; } function add( uint a, uint b ) internal pure returns (uint c) { c = a + b; require(c >= a, "ADD_OVERFLOW"); } function add64( uint64 a, uint64 b ) internal pure returns (uint64 c) { c = a + b; require(c >= a, "ADD_OVERFLOW"); } } // File: contracts/core/impl/libexchange/ExchangeMode.sol // Copyright 2017 Loopring Technology Limited. /// @title ExchangeMode. /// @dev All methods in this lib are internal, therefore, there is no need /// to deploy this library independently. /// @author Brecht Devos - <[email protected]> /// @author Daniel Wang - <[email protected]> library ExchangeMode { using MathUint for uint; function isInWithdrawalMode( ExchangeData.State storage S ) internal // inline call view returns (bool result) { result = S.withdrawalModeStartTime > 0; } function isShutdown( ExchangeData.State storage S ) internal // inline call view returns (bool) { return S.shutdownModeStartTime > 0; } function getNumAvailableForcedSlots( ExchangeData.State storage S ) internal view returns (uint) { return ExchangeData.MAX_OPEN_FORCED_REQUESTS - S.numPendingForcedTransactions; } } // File: contracts/core/iface/IL2MintableNFT.sol // Copyright 2017 Loopring Technology Limited. interface IL2MintableNFT { /// @dev This function is called when an NFT minted on L2 is withdrawn from Loopring. /// That means the NFTs were burned on L2 and now need to be minted on L1. /// /// This function can only be called by the Loopring exchange. /// /// @param to The owner of the NFT /// @param tokenId The token type 'id` /// @param amount The amount of NFTs to mint /// @param minter The minter on L2, which can be used to decide if the NFT is authentic /// @param data Opaque data that can be used by the contract function mintFromL2( address to, uint256 tokenId, uint amount, address minter, bytes calldata data ) external; /// @dev Returns a list of all address that are authorized to mint NFTs on L2. /// @return The list of authorized minter on L2 function minters() external view returns (address[] memory); } // File: contracts/thirdparty/erc165/IERC165.sol /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // File: contracts/thirdparty/erc165/ERC165.sol /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ abstract contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } // File: contracts/thirdparty/erc1155/IERC1155.sol /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external; } // File: contracts/thirdparty/erc721/IERC721.sol /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; } // File: contracts/core/impl/libexchange/ExchangeNFT.sol // Copyright 2017 Loopring Technology Limited. /// @title ExchangeNFT /// @author Brecht Devos - <[email protected]> library ExchangeNFT { using ExchangeNFT for ExchangeData.State; function deposit( ExchangeData.State storage S, address from, ExchangeData.NftType nftType, address token, uint256 nftID, uint amount, bytes memory extraData ) internal { if (amount == 0) { return; } // Disable calls to certain contracts require(S.isTokenAddressAllowed(token), "TOKEN_ADDRESS_NOT_ALLOWED"); if (nftType == ExchangeData.NftType.ERC1155) { IERC1155(token).safeTransferFrom( from, address(this), nftID, amount, extraData ); } else if (nftType == ExchangeData.NftType.ERC721) { require(amount == 1, "INVALID_AMOUNT"); IERC721(token).safeTransferFrom( from, address(this), nftID, extraData ); } else { revert("UNKNOWN_NFTTYPE"); } } function withdraw( ExchangeData.State storage S, address /*from*/, address to, ExchangeData.NftType nftType, address token, uint256 nftID, uint amount, bytes memory extraData, uint gasLimit ) internal returns (bool success) { if (amount == 0) { return true; } // Disable calls to certain contracts if(!S.isTokenAddressAllowed(token)) { return false; } if (nftType == ExchangeData.NftType.ERC1155) { try IERC1155(token).safeTransferFrom{gas: gasLimit}( address(this), to, nftID, amount, extraData ) { success = true; } catch { success = false; } } else if (nftType == ExchangeData.NftType.ERC721) { try IERC721(token).safeTransferFrom{gas: gasLimit}( address(this), to, nftID, extraData ) { success = true; } catch { success = false; } } else { revert("UNKNOWN_NFTTYPE"); } } function mintFromL2( ExchangeData.State storage S, address to, address token, uint256 nftID, uint amount, address minter, bytes memory extraData, uint gasLimit ) internal returns (bool success) { if (amount == 0) { return true; } // Disable calls to certain contracts if(!S.isTokenAddressAllowed(token)) { return false; } try IL2MintableNFT(token).mintFromL2{gas: gasLimit}( to, nftID, amount, minter, extraData ) { success = true; } catch { success = false; } } function isTokenAddressAllowed( ExchangeData.State storage S, address token ) internal view returns (bool valid) { return (token != address(this) && token != address(S.depositContract)); } } // File: contracts/lib/ERC20SafeTransfer.sol // Copyright 2017 Loopring Technology Limited. /// @title ERC20 safe transfer /// @dev see https://github.com/sec-bit/badERC20Fix /// @author Brecht Devos - <[email protected]> library ERC20SafeTransfer { function safeTransferAndVerify( address token, address to, uint value ) internal { safeTransferWithGasLimitAndVerify( token, to, value, gasleft() ); } function safeTransfer( address token, address to, uint value ) internal returns (bool) { return safeTransferWithGasLimit( token, to, value, gasleft() ); } function safeTransferWithGasLimitAndVerify( address token, address to, uint value, uint gasLimit ) internal { require( safeTransferWithGasLimit(token, to, value, gasLimit), "TRANSFER_FAILURE" ); } function safeTransferWithGasLimit( address token, address to, uint value, uint gasLimit ) internal returns (bool) { // A transfer is successful when 'call' is successful and depending on the token: // - No value is returned: we assume a revert when the transfer failed (i.e. 'call' returns false) // - A single boolean is returned: this boolean needs to be true (non-zero) // bytes4(keccak256("transfer(address,uint256)")) = 0xa9059cbb bytes memory callData = abi.encodeWithSelector( bytes4(0xa9059cbb), to, value ); (bool success, ) = token.call{gas: gasLimit}(callData); return checkReturnValue(success); } function safeTransferFromAndVerify( address token, address from, address to, uint value ) internal { safeTransferFromWithGasLimitAndVerify( token, from, to, value, gasleft() ); } function safeTransferFrom( address token, address from, address to, uint value ) internal returns (bool) { return safeTransferFromWithGasLimit( token, from, to, value, gasleft() ); } function safeTransferFromWithGasLimitAndVerify( address token, address from, address to, uint value, uint gasLimit ) internal { bool result = safeTransferFromWithGasLimit( token, from, to, value, gasLimit ); require(result, "TRANSFER_FAILURE"); } function safeTransferFromWithGasLimit( address token, address from, address to, uint value, uint gasLimit ) internal returns (bool) { // A transferFrom is successful when 'call' is successful and depending on the token: // - No value is returned: we assume a revert when the transfer failed (i.e. 'call' returns false) // - A single boolean is returned: this boolean needs to be true (non-zero) // bytes4(keccak256("transferFrom(address,address,uint256)")) = 0x23b872dd bytes memory callData = abi.encodeWithSelector( bytes4(0x23b872dd), from, to, value ); (bool success, ) = token.call{gas: gasLimit}(callData); return checkReturnValue(success); } function checkReturnValue( bool success ) internal pure returns (bool) { // A transfer/transferFrom is successful when 'call' is successful and depending on the token: // - No value is returned: we assume a revert when the transfer failed (i.e. 'call' returns false) // - A single boolean is returned: this boolean needs to be true (non-zero) if (success) { assembly { switch returndatasize() // Non-standard ERC20: nothing is returned so if 'call' was successful we assume the transfer succeeded case 0 { success := 1 } // Standard ERC20: a single boolean value is returned which needs to be true case 32 { returndatacopy(0, 0, 32) success := mload(0) } // None of the above: not successful default { success := 0 } } } return success; } } // File: contracts/core/impl/libexchange/ExchangeTokens.sol // Copyright 2017 Loopring Technology Limited. /// @title ExchangeTokens. /// @author Daniel Wang - <[email protected]> /// @author Brecht Devos - <[email protected]> library ExchangeTokens { using MathUint for uint; using ERC20SafeTransfer for address; using ExchangeMode for ExchangeData.State; event TokenRegistered( address token, uint16 tokenId ); function getTokenAddress( ExchangeData.State storage S, uint16 tokenID ) public view returns (address) { require(tokenID < S.tokens.length, "INVALID_TOKEN_ID"); return S.tokens[tokenID].token; } function registerToken( ExchangeData.State storage S, address tokenAddress ) public returns (uint16 tokenID) { require(!S.isInWithdrawalMode(), "INVALID_MODE"); require(S.tokenToTokenId[tokenAddress] == 0, "TOKEN_ALREADY_EXIST"); require(S.tokens.length < ExchangeData.NFT_TOKEN_ID_START, "TOKEN_REGISTRY_FULL"); // Check if the deposit contract supports the new token if (S.depositContract != IDepositContract(0)) { require( S.depositContract.isTokenSupported(tokenAddress), "UNSUPPORTED_TOKEN" ); } // Assign a tokenID and store the token ExchangeData.Token memory token = ExchangeData.Token( tokenAddress ); tokenID = uint16(S.tokens.length); S.tokens.push(token); S.tokenToTokenId[tokenAddress] = tokenID + 1; emit TokenRegistered(tokenAddress, tokenID); } function getTokenID( ExchangeData.State storage S, address tokenAddress ) internal // inline call view returns (uint16 tokenID) { tokenID = S.tokenToTokenId[tokenAddress]; require(tokenID != 0, "TOKEN_NOT_FOUND"); tokenID = tokenID - 1; } function isNFT(uint16 tokenID) internal // inline call pure returns (bool) { return tokenID >= ExchangeData.NFT_TOKEN_ID_START; } } // File: contracts/core/impl/libexchange/ExchangeDeposits.sol // Copyright 2017 Loopring Technology Limited. /// @title ExchangeDeposits. /// @author Daniel Wang - <[email protected]> /// @author Brecht Devos - <[email protected]> library ExchangeDeposits { using AddressUtil for address payable; using MathUint96 for uint96; using ExchangeMode for ExchangeData.State; using ExchangeTokens for ExchangeData.State; event DepositRequested( address from, address to, address token, uint16 tokenId, uint96 amount ); event NFTDepositRequested( address from, address to, uint8 nftType, address token, uint256 nftID, uint96 amount ); function deposit( ExchangeData.State storage S, address from, address to, address tokenAddress, uint96 amount, // can be zero bytes memory extraData ) internal // inline call { require(to != address(0), "ZERO_ADDRESS"); // Deposits are still possible when the exchange is being shutdown, or even in withdrawal mode. // This is fine because the user can easily withdraw the deposited amounts again. // We don't want to make all deposits more expensive just to stop that from happening. // Allow depositing with amount == 0 to allow updating the deposit timestamp uint16 tokenID = S.getTokenID(tokenAddress); // Transfer the tokens to this contract uint96 amountDeposited = S.depositContract.deposit{value: msg.value}( from, tokenAddress, amount, extraData ); // Add the amount to the deposit request and reset the time the operator has to process it ExchangeData.Deposit memory _deposit = S.pendingDeposits[to][tokenID]; _deposit.timestamp = uint64(block.timestamp); _deposit.amount = _deposit.amount.add(amountDeposited); S.pendingDeposits[to][tokenID] = _deposit; emit DepositRequested( from, to, tokenAddress, tokenID, amountDeposited ); } function depositNFT( ExchangeData.State storage S, address from, address to, ExchangeData.NftType nftType, address tokenAddress, uint256 nftID, uint96 amount, // can be zero bytes memory extraData ) public { require(to != address(0), "ZERO_ADDRESS"); // Deposits are still possible when the exchange is being shutdown, or even in withdrawal mode. // This is fine because the user can easily withdraw the deposited amounts again. // We don't want to make all deposits more expensive just to stop that from happening. // Allow depositing with amount == 0 to allow updating the deposit timestamp // Transfer the tokens to this contract ExchangeNFT.deposit( S, from, nftType, tokenAddress, nftID, amount, extraData ); // Add the amount to the deposit request and reset the time the operator has to process it ExchangeData.Deposit memory _deposit = S.pendingNFTDeposits[to][nftType][tokenAddress][nftID]; _deposit.timestamp = uint64(block.timestamp); _deposit.amount = _deposit.amount.add(amount); S.pendingNFTDeposits[to][nftType][tokenAddress][nftID] = _deposit; emit NFTDepositRequested( from, to, uint8(nftType), tokenAddress, nftID, amount ); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint16","name":"tokenId","type":"uint16"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"DepositRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint8","name":"nftType","type":"uint8"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftID","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"NFTDepositRequested","type":"event"}]
Contract Creation Code
61096d610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c806374417afc1461003a575b600080fd5b81801561004657600080fd5b5061005a610055366004610612565b61005c565b005b73ffffffffffffffffffffffffffffffffffffffff86166100b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a99061085b565b60405180910390fd5b6100cf8888878787876bffffffffffffffffffffffff16876102e6565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260178901602052604081208187600181111561010357fe5b600181111561010e57fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff89168252835281812087825283528190208151808301909252546bffffffffffffffffffffffff168082524267ffffffffffffffff1692820192909252915061018190846104b6565b6bffffffffffffffffffffffff16815273ffffffffffffffffffffffffffffffffffffffff8716600090815260178a016020526040812082918860018111156101c657fe5b60018111156101d157fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff8a168252835281812088825283522082518154939092015167ffffffffffffffff166c01000000000000000000000000027fffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffff6bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090941693909317919091169190911790557f59c0422c484ae5502249fd758097d16508ef0e61b5f7f962bef8145a5870128788888860018111156102be57fe5b8888886040516102d3969594939291906107cd565b60405180910390a1505050505050505050565b816102f0576104ad565b6102fa878561050a565b610330576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a990610824565b600085600181111561033e57fe5b14156103d5576040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063f242432a9061039e908990309088908890889060040161077d565b600060405180830381600087803b1580156103b857600080fd5b505af11580156103cc573d6000803e3d6000fd5b505050506104ad565b60018560018111156103e357fe5b141561047b5781600114610423576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a990610900565b6040517fb88d4fde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063b88d4fde9061039e908990309088908790600401610734565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a990610892565b50505050505050565b8181016bffffffffffffffffffffffff8084169082161015610504576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a9906108c9565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff8216301480159061054f5750600583015473ffffffffffffffffffffffffffffffffffffffff838116911614155b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461057a57600080fd5b919050565b600082601f83011261058f578081fd5b813567ffffffffffffffff808211156105a457fe5b60405160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011682010181811083821117156105e057fe5b6040528281528483016020018610156105f7578384fd5b82602086016020830137918201602001929092529392505050565b600080600080600080600080610100898b03121561062e578384fd5b8835975061063e60208a01610556565b965061064c60408a01610556565b955060608901356002811061065f578485fd5b945061066d60808a01610556565b935060a0890135925060c08901356bffffffffffffffffffffffff81168114610694578283fd5b915060e089013567ffffffffffffffff8111156106af578182fd5b6106bb8b828c0161057f565b9150509295985092959890939650565b60008151808452815b818110156106f0576020818501810151868301820152016106d4565b818111156107015782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff80871683528086166020840152508360408301526080606083015261077360808301846106cb565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a060808301526107c260a08301846106cb565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff9687168152948616602086015260ff9390931660408501529316606083015260808201929092526bffffffffffffffffffffffff90911660a082015260c00190565b60208082526019908201527f544f4b454e5f414444524553535f4e4f545f414c4c4f57454400000000000000604082015260600190565b6020808252600c908201527f5a45524f5f414444524553530000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f554e4b4e4f574e5f4e4654545950450000000000000000000000000000000000604082015260600190565b6020808252600c908201527f4144445f4f564552464c4f570000000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f414d4f554e5400000000000000000000000000000000000060408201526060019056fea264697066735822122032c779a17601086476ad8784b85db2ddbfc11693519abd842576fef5dbb3040964736f6c63430007060033
Deployed Bytecode
0x7307f50b5a6a3f1f069c27ea11ffa62b53a20872cc30146080604052600436106100355760003560e01c806374417afc1461003a575b600080fd5b81801561004657600080fd5b5061005a610055366004610612565b61005c565b005b73ffffffffffffffffffffffffffffffffffffffff86166100b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a99061085b565b60405180910390fd5b6100cf8888878787876bffffffffffffffffffffffff16876102e6565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260178901602052604081208187600181111561010357fe5b600181111561010e57fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff89168252835281812087825283528190208151808301909252546bffffffffffffffffffffffff168082524267ffffffffffffffff1692820192909252915061018190846104b6565b6bffffffffffffffffffffffff16815273ffffffffffffffffffffffffffffffffffffffff8716600090815260178a016020526040812082918860018111156101c657fe5b60018111156101d157fe5b81526020808201929092526040908101600090812073ffffffffffffffffffffffffffffffffffffffff8a168252835281812088825283522082518154939092015167ffffffffffffffff166c01000000000000000000000000027fffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffff6bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090941693909317919091169190911790557f59c0422c484ae5502249fd758097d16508ef0e61b5f7f962bef8145a5870128788888860018111156102be57fe5b8888886040516102d3969594939291906107cd565b60405180910390a1505050505050505050565b816102f0576104ad565b6102fa878561050a565b610330576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a990610824565b600085600181111561033e57fe5b14156103d5576040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063f242432a9061039e908990309088908890889060040161077d565b600060405180830381600087803b1580156103b857600080fd5b505af11580156103cc573d6000803e3d6000fd5b505050506104ad565b60018560018111156103e357fe5b141561047b5781600114610423576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a990610900565b6040517fb88d4fde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063b88d4fde9061039e908990309088908790600401610734565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a990610892565b50505050505050565b8181016bffffffffffffffffffffffff8084169082161015610504576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100a9906108c9565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff8216301480159061054f5750600583015473ffffffffffffffffffffffffffffffffffffffff838116911614155b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461057a57600080fd5b919050565b600082601f83011261058f578081fd5b813567ffffffffffffffff808211156105a457fe5b60405160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011682010181811083821117156105e057fe5b6040528281528483016020018610156105f7578384fd5b82602086016020830137918201602001929092529392505050565b600080600080600080600080610100898b03121561062e578384fd5b8835975061063e60208a01610556565b965061064c60408a01610556565b955060608901356002811061065f578485fd5b945061066d60808a01610556565b935060a0890135925060c08901356bffffffffffffffffffffffff81168114610694578283fd5b915060e089013567ffffffffffffffff8111156106af578182fd5b6106bb8b828c0161057f565b9150509295985092959890939650565b60008151808452815b818110156106f0576020818501810151868301820152016106d4565b818111156107015782602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff80871683528086166020840152508360408301526080606083015261077360808301846106cb565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a060808301526107c260a08301846106cb565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff9687168152948616602086015260ff9390931660408501529316606083015260808201929092526bffffffffffffffffffffffff90911660a082015260c00190565b60208082526019908201527f544f4b454e5f414444524553535f4e4f545f414c4c4f57454400000000000000604082015260600190565b6020808252600c908201527f5a45524f5f414444524553530000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f554e4b4e4f574e5f4e4654545950450000000000000000000000000000000000604082015260600190565b6020808252600c908201527f4144445f4f564552464c4f570000000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f494e56414c49445f414d4f554e5400000000000000000000000000000000000060408201526060019056fea264697066735822122032c779a17601086476ad8784b85db2ddbfc11693519abd842576fef5dbb3040964736f6c63430007060033
Deployed Bytecode Sourcemap
56733:3879:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;58919:1690;;;;;;;;;;-1:-1:-1;58919:1690:0;;;;;:::i;:::-;;:::i;:::-;;;59371:16;;;59363:41;;;;;;;;;;;;:::i;:::-;;;;;;;;;59848:179;59882:1;59898:4;59917:7;59939:12;59966:5;59986:6;59848:179;;60007:9;59848:19;:179::i;:::-;60179:24;;;60140:36;60179:24;;;:20;;;:24;;;;;60140:36;60204:7;60179:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;60179:33:0;;;:47;;;;;;;;;;:54;;;;;;;;60140:93;;;;;;;;;;;;;;60272:15;60140:93;60244:44;60140:93;;;60244:44;;;;60140:93;-1:-1:-1;60317:27:0;;60337:6;60317:19;:27::i;:::-;60299:45;;;;60355:24;;;60299:15;60355:24;;;:20;;;:24;;;;;60299:8;;60380:7;60355:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;60355:33:0;;;:47;;;;;;;;;;:54;;;;;;:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60438:163;60472:4;60491:2;60514:7;60355:65;60508:14;;;;;;;60537:12;60564:5;60584:6;60438:163;;;;;;;;;;;:::i;:::-;;;;;;;;58919:1690;;;;;;;;;:::o;45246:1154::-;45615:11;45611:50;;45643:7;;45611:50;45728:30;:1;45752:5;45728:23;:30::i;:::-;45720:68;;;;;;;;;;;;:::i;:::-;45816:28;45805:7;:39;;;;;;;;;45801:592;;;45861:179;;;;;:32;;;;;;:179;;45912:4;;45943;;45967:5;;45991:6;;46016:9;;45861:179;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45801:592;;;46073:27;46062:7;:38;;;;;;;;;46058:335;;;46125:6;46135:1;46125:11;46117:38;;;;;;;;;;;;:::i;:::-;46170:153;;;;;:31;;;;;;:153;;46220:4;;46251;;46275:5;;46299:9;;46170:153;;;:::i;46058:335::-;46356:25;;;;;;;;;;:::i;46058:335::-;45246:1154;;;;;;;:::o;3804:197::-;3946:5;;;3970:6;;;;;;;;;3962:31;;;;;;;;;;;;:::i;:::-;3804:197;;;;:::o;48764:280::-;48938:10;48974:22;;;48991:4;48974:22;;;;:61;;-1:-1:-1;49017:17:0;;;;;49000:35;;;49017:17;;49000:35;;48974:61;48966:70;48764:280;-1:-1:-1;;;48764:280:0:o;14:198:1:-;84:20;;144:42;133:54;;123:65;;113:2;;202:1;199;192:12;113:2;65:147;;;:::o;217:753::-;;314:3;307:4;299:6;295:17;291:27;281:2;;336:5;329;322:20;281:2;376:6;363:20;402:18;439:2;435;432:10;429:2;;;445:9;429:2;485;479:9;620:4;550:66;543:4;539:2;535:13;531:86;523:6;519:99;515:110;675:6;663:10;660:22;655:2;643:10;640:18;637:46;634:2;;;686:9;634:2;713;706:22;737:18;;;774:15;;;791:4;770:26;767:35;-1:-1:-1;764:2:1;;;819:5;812;805:20;764:2;887;880:4;872:6;868:17;861:4;853:6;849:17;836:54;910:15;;;927:4;906:26;899:41;;;;914:6;271:699;-1:-1:-1;;;271:699:1:o;975:1097::-;;;;;;;;;1248:3;1236:9;1227:7;1223:23;1219:33;1216:2;;;1270:6;1262;1255:22;1216:2;1311:9;1298:23;1288:33;;1340:40;1376:2;1365:9;1361:18;1340:40;:::i;:::-;1330:50;;1399:40;1435:2;1424:9;1420:18;1399:40;:::i;:::-;1389:50;;1489:2;1478:9;1474:18;1461:32;1522:1;1515:5;1512:12;1502:2;;1543:6;1535;1528:22;1502:2;1571:5;-1:-1:-1;1595:41:1;1631:3;1616:19;;1595:41;:::i;:::-;1585:51;;1683:3;1672:9;1668:19;1655:33;1645:43;;1740:3;1729:9;1725:19;1712:33;1789:26;1780:7;1776:40;1767:7;1764:53;1754:2;;1836:6;1828;1821:22;1754:2;1864:7;-1:-1:-1;1922:3:1;1907:19;;1894:33;1950:18;1939:30;;1936:2;;;1987:6;1979;1972:22;1936:2;2015:51;2058:7;2049:6;2038:9;2034:22;2015:51;:::i;:::-;2005:61;;;1206:866;;;;;;;;;;;:::o;2077:536::-;;2158:5;2152:12;2185:6;2180:3;2173:19;2210:3;2222:162;2236:6;2233:1;2230:13;2222:162;;;2298:4;2354:13;;;2350:22;;2344:29;2326:11;;;2322:20;;2315:59;2251:12;2222:162;;;2402:6;2399:1;2396:13;2393:2;;;2468:3;2461:4;2452:6;2447:3;2443:16;2439:27;2432:40;2393:2;-1:-1:-1;2527:2:1;2515:15;2532:66;2511:88;2502:98;;;;2602:4;2498:109;;2128:485;-1:-1:-1;;2128:485:1:o;2618:513::-;;2841:42;2922:2;2914:6;2910:15;2899:9;2892:34;2974:2;2966:6;2962:15;2957:2;2946:9;2942:18;2935:43;;3014:6;3009:2;2998:9;2994:18;2987:34;3057:3;3052:2;3041:9;3037:18;3030:31;3078:47;3120:3;3109:9;3105:19;3097:6;3078:47;:::i;:::-;3070:55;2821:310;-1:-1:-1;;;;;;2821:310:1:o;3136:585::-;;3387:42;3468:2;3460:6;3456:15;3445:9;3438:34;3520:2;3512:6;3508:15;3503:2;3492:9;3488:18;3481:43;;3560:6;3555:2;3544:9;3540:18;3533:34;3603:6;3598:2;3587:9;3583:18;3576:34;3647:3;3641;3630:9;3626:19;3619:32;3668:47;3710:3;3699:9;3695:19;3687:6;3668:47;:::i;:::-;3660:55;3367:354;-1:-1:-1;;;;;;;3367:354:1:o;3726:661::-;4017:42;4086:15;;;4068:34;;4138:15;;;4133:2;4118:18;;4111:43;4202:4;4190:17;;;;4185:2;4170:18;;4163:45;4244:15;;4239:2;4224:18;;4217:43;4291:3;4276:19;;4269:35;;;;4353:26;4341:39;;;4335:3;4320:19;;4313:68;3994:3;3979:19;;3961:426::o;4392:349::-;4594:2;4576:21;;;4633:2;4613:18;;;4606:30;4672:27;4667:2;4652:18;;4645:55;4732:2;4717:18;;4566:175::o;4746:336::-;4948:2;4930:21;;;4987:2;4967:18;;;4960:30;5026:14;5021:2;5006:18;;4999:42;5073:2;5058:18;;4920:162::o;5087:339::-;5289:2;5271:21;;;5328:2;5308:18;;;5301:30;5367:17;5362:2;5347:18;;5340:45;5417:2;5402:18;;5261:165::o;5431:336::-;5633:2;5615:21;;;5672:2;5652:18;;;5645:30;5711:14;5706:2;5691:18;;5684:42;5758:2;5743:18;;5605:162::o;5772:338::-;5974:2;5956:21;;;6013:2;5993:18;;;5986:30;6052:16;6047:2;6032:18;;6025:44;6101:2;6086:18;;5946:164::o
Swarm Source
ipfs://32c779a17601086476ad8784b85db2ddbfc11693519abd842576fef5dbb30409
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.