Source Code
Overview
ETH Balance
ETH Value
$0.00Latest 25 from a total of 324 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Do Forced Withdr... | 1306033 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1306033 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1306033 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1306032 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1306032 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1306032 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1306032 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1306032 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1306032 | 174 days ago | IN | 0 ETH | 0.00000241 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1305956 | 174 days ago | IN | 0 ETH | 0.00000214 | ||||
| Do Forced Withdr... | 1305952 | 174 days ago | IN | 0 ETH | 0.00000118 | ||||
| Do Forced Withdr... | 1305952 | 174 days ago | IN | 0 ETH | 0.00000118 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 1306033 | 174 days ago | 0 ETH | |||||
| 1306033 | 174 days ago | 0 ETH | |||||
| 1306033 | 174 days ago | 0 ETH | |||||
| 1306032 | 174 days ago | 0 ETH | |||||
| 1306032 | 174 days ago | 0 ETH | |||||
| 1306032 | 174 days ago | 0 ETH | |||||
| 1306032 | 174 days ago | 0 ETH | |||||
| 1306032 | 174 days ago | 0 ETH | |||||
| 1306032 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305956 | 174 days ago | 0 ETH | |||||
| 1305952 | 174 days ago | 0 ETH | |||||
| 1305952 | 174 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x248c4BfD...428Ec4D55 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
ForcedWithdrawalAgent
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import "../../core/iface/IExchangeV3.sol"; import "../../lib/ReentrancyGuard.sol"; import "../../lib/OwnerManagable.sol"; import "../../lib/AddressUtil.sol"; import "../../lib/Drainable.sol"; /// @author Kongliang Zhong - <[email protected]> contract ForcedWithdrawalAgent is ReentrancyGuard, OwnerManagable, Drainable { using AddressUtil for address; function canDrain(address /*drainer*/, address /*token*/) public override view returns (bool) { return msg.sender == owner || isManager(msg.sender); } function doForcedWithdrawalFor( address exchangeAddress, address owner, address token, uint32 accountID ) external payable nonReentrant onlyOwnerOrManager { IExchangeV3(exchangeAddress).forceWithdraw{value: msg.value}(owner, token, accountID); if (address(this).balance > 0) { drain(msg.sender, address(0)); } } receive() external payable { } }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import "./IAgentRegistry.sol"; import "./IBlockVerifier.sol"; import "./IDepositContract.sol"; import "./ILoopringV3.sol"; /// @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; } }
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
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);
}// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import "../../lib/Claimable.sol"; /// @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); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; /// @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); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import "../../lib/Claimable.sol"; import "./ExchangeData.sol"; /// @title IExchangeV3 /// @dev Note that Claimable and RentrancyGuard are inherited here to /// ensure all data members are declared on IExchangeV3 to make it /// easy to support upgradability through proxies. /// /// Subclasses of this contract must NOT define constructor to /// initialize data. /// /// @author Brecht Devos - <[email protected]> /// @author Daniel Wang - <[email protected]> abstract contract IExchangeV3 is Claimable { // -- Events -- event ExchangeCloned( address exchangeAddress, address owner, bytes32 genesisMerkleRoot ); event TokenRegistered( address token, uint16 tokenId ); event Shutdown( uint timestamp ); event WithdrawalModeActivated( uint timestamp ); event BlockSubmitted( uint indexed blockIdx, bytes32 merkleRoot, bytes32 publicDataHash ); 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 ); event ForcedWithdrawalRequested( address owner, uint16 tokenID, uint32 accountID ); event WithdrawalCompleted( uint8 category, address from, address to, address token, uint amount ); event WithdrawalFailed( uint8 category, address from, address to, address token, uint amount ); event NftWithdrawalCompleted( uint8 category, address from, address to, uint16 tokenID, address token, uint256 nftID, uint amount ); event NftWithdrawalFailed( uint8 category, address from, address to, uint16 tokenID, address token, uint256 nftID, uint amount ); event ProtocolFeesUpdated( uint8 takerFeeBips, uint8 makerFeeBips, uint8 previousTakerFeeBips, uint8 previousMakerFeeBips ); event TransactionApproved( address owner, bytes32 transactionHash ); // -- Initialization -- /// @dev Initializes this exchange. This method can only be called once. /// @param loopring The LoopringV3 contract address. /// @param owner The owner of this exchange. /// @param genesisMerkleRoot The initial Merkle tree state. function initialize( address loopring, address owner, bytes32 genesisMerkleRoot ) virtual external; /// @dev Initialized the agent registry contract used by the exchange. /// Can only be called by the exchange owner once. /// @param agentRegistry The agent registry contract to be used function setAgentRegistry(address agentRegistry) external virtual; /// @dev Gets the agent registry contract used by the exchange. /// @return the agent registry contract function getAgentRegistry() external virtual view returns (IAgentRegistry); /// Can only be called by the exchange owner once. /// @param depositContract The deposit contract to be used function setDepositContract(address depositContract) external virtual; /// @dev refresh the blockVerifier contract which maybe changed in loopringV3 contract. function refreshBlockVerifier() external virtual; /// @dev Gets the deposit contract used by the exchange. /// @return the deposit contract function getDepositContract() external virtual view returns (IDepositContract); // @dev Exchange owner withdraws fees from the exchange. // @param token Fee token address // @param feeRecipient Fee recipient address function withdrawExchangeFees( address token, address feeRecipient ) external virtual; // -- Constants -- /// @dev Returns a list of constants used by the exchange. /// @return constants The list of constants. function getConstants() external virtual pure returns(ExchangeData.Constants memory); // -- Mode -- /// @dev Returns hether the exchange is in withdrawal mode. /// @return Returns true if the exchange is in withdrawal mode, else false. function isInWithdrawalMode() external virtual view returns (bool); /// @dev Returns whether the exchange is shutdown. /// @return Returns true if the exchange is shutdown, else false. function isShutdown() external virtual view returns (bool); // -- Tokens -- /// @dev Registers an ERC20 token for a token id. Note that different exchanges may have /// different ids for the same ERC20 token. /// /// Please note that 1 is reserved for Ether (ETH), 2 is reserved for Wrapped Ether (ETH), /// and 3 is reserved for Loopring Token (LRC). /// /// This function is only callable by the exchange owner. /// /// @param tokenAddress The token's address /// @return tokenID The token's ID in this exchanges. function registerToken( address tokenAddress ) external virtual returns (uint16 tokenID); /// @dev Returns the id of a registered token. /// @param tokenAddress The token's address /// @return tokenID The token's ID in this exchanges. function getTokenID( address tokenAddress ) external virtual view returns (uint16 tokenID); /// @dev Returns the address of a registered token. /// @param tokenID The token's ID in this exchanges. /// @return tokenAddress The token's address function getTokenAddress( uint16 tokenID ) external virtual view returns (address tokenAddress); // -- Stakes -- /// @dev Gets the amount of LRC the owner has staked onchain for this exchange. /// The stake will be burned if the exchange does not fulfill its duty by /// processing user requests in time. Please note that order matching may potentially /// performed by another party and is not part of the exchange's duty. /// /// @return The amount of LRC staked function getExchangeStake() external virtual view returns (uint); /// @dev Withdraws the amount staked for this exchange. /// This can only be done if the exchange has been correctly shutdown: /// - The exchange owner has shutdown the exchange /// - All deposit requests are processed /// - All funds are returned to the users (merkle root is reset to initial state) /// /// Can only be called by the exchange owner. /// /// @return amountLRC The amount of LRC withdrawn function withdrawExchangeStake( address recipient ) external virtual returns (uint amountLRC); /// @dev Can by called by anyone to burn the stake of the exchange when certain /// conditions are fulfilled. /// /// Currently this will only burn the stake of the exchange if /// the exchange is in withdrawal mode. function burnExchangeStake() external virtual; // -- Blocks -- /// @dev Gets the current Merkle root of this exchange's virtual blockchain. /// @return The current Merkle root. function getMerkleRoot() external virtual view returns (bytes32); /// @dev Gets the height of this exchange's virtual blockchain. The block height for a /// new exchange is 1. /// @return The virtual blockchain height which is the index of the last block. function getBlockHeight() external virtual view returns (uint); /// @dev Gets some minimal info of a previously submitted block that's kept onchain. /// A DEX can use this function to implement a payment receipt verification /// contract with a challange-response scheme. /// @param blockIdx The block index. function getBlockInfo(uint blockIdx) external virtual view returns (ExchangeData.BlockInfo memory); /// @dev Sumbits new blocks to the rollup blockchain. /// /// This function can only be called by the exchange operator. /// /// @param blocks The blocks being submitted /// - blockType: The type of the new block /// - blockSize: The number of onchain or offchain requests/settlements /// that have been processed in this block /// - blockVersion: The circuit version to use for verifying the block /// - storeBlockInfoOnchain: If the block info for this block needs to be stored on-chain /// - data: The data for this block /// - offchainData: Arbitrary data, mainly for off-chain data-availability, i.e., /// the multihash of the IPFS file that contains the block data. function submitBlocks(ExchangeData.Block[] calldata blocks) external virtual; /// @dev Gets the number of available forced request slots. /// @return The number of available slots. function getNumAvailableForcedSlots() external virtual view returns (uint); // -- Deposits -- /// @dev Deposits Ether or ERC20 tokens to the specified account. /// /// This function is only callable by an agent of 'from'. /// /// The operator is not forced to do the deposit. /// /// @param from The address that deposits the funds to the exchange /// @param to The account owner's address receiving the funds /// @param tokenAddress The address of the token, use `0x0` for Ether. /// @param amount The amount of tokens to deposit /// @param extraData Optional extra data used by the deposit contract function deposit( address from, address to, address tokenAddress, uint96 amount, bytes calldata extraData ) external virtual payable; /// @dev Deposits an NFT to the specified account. /// /// This function is only callable by an agent of 'from'. /// /// The operator is not forced to do the deposit. /// /// @param from The address that deposits the funds to the exchange /// @param to The account owner's address receiving the funds /// @param nftType The type of NFT contract address (ERC721/ERC1155/...) /// @param tokenAddress The address of the token, use `0x0` for Ether. /// @param nftID The token type 'id`. /// @param amount The amount of tokens to deposit. /// @param extraData Optional extra data used by the deposit contract. function depositNFT( address from, address to, ExchangeData.NftType nftType, address tokenAddress, uint256 nftID, uint96 amount, bytes calldata extraData ) external virtual; /// @dev Gets the amount of tokens that may be added to the owner's account. /// @param owner The destination address for the amount deposited. /// @param tokenAddress The address of the token, use `0x0` for Ether. /// @return The amount of tokens pending. function getPendingDepositAmount( address owner, address tokenAddress ) public virtual view returns (uint96); /// @dev Gets the amount of tokens that may be added to the owner's account. /// @param owner The destination address for the amount deposited. /// @param tokenAddress The address of the token, use `0x0` for Ether. /// @param nftType The type of NFT contract address (ERC721/ERC1155/...) /// @param nftID The token type 'id`. /// @return The amount of tokens pending. function getPendingNFTDepositAmount( address owner, address tokenAddress, ExchangeData.NftType nftType, uint256 nftID ) public virtual view returns (uint96); // -- Withdrawals -- /// @dev Submits an onchain request to force withdraw Ether, ERC20 and NFT tokens. /// This request always withdraws the full balance. /// /// This function is only callable by an agent of the account. /// /// The total fee in ETH that the user needs to pay is 'withdrawalFee'. /// If the user sends too much ETH the surplus is sent back immediately. /// /// Note that after such an operation, it will take the owner some /// time (no more than MAX_AGE_FORCED_REQUEST_UNTIL_WITHDRAW_MODE) to process the request /// and create the deposit to the offchain account. /// /// @param owner The expected owner of the account /// @param tokenID The tokenID to withdraw from /// @param accountID The address the account in the Merkle tree. function forceWithdrawByTokenID( address owner, uint16 tokenID, uint32 accountID ) external virtual payable; /// @dev Submits an onchain request to force withdraw Ether or ERC20 tokens. /// This request always withdraws the full balance. /// /// This function is only callable by an agent of the account. /// /// The total fee in ETH that the user needs to pay is 'withdrawalFee'. /// If the user sends too much ETH the surplus is sent back immediately. /// /// Note that after such an operation, it will take the owner some /// time (no more than MAX_AGE_FORCED_REQUEST_UNTIL_WITHDRAW_MODE) to process the request /// and create the deposit to the offchain account. /// /// @param owner The expected owner of the account /// @param tokenAddress The address of the token, use `0x0` for Ether. /// @param accountID The address the account in the Merkle tree. function forceWithdraw( address owner, address tokenAddress, uint32 accountID ) external virtual payable; /// @dev Checks if a forced withdrawal is pending for an account balance. /// @param accountID The accountID of the account to check. /// @param token The token address /// @return True if a request is pending, false otherwise function isForcedWithdrawalPending( uint32 accountID, address token ) external virtual view returns (bool); /// @dev Submits an onchain request to withdraw Ether or ERC20 tokens from the /// protocol fees account. The complete balance is always withdrawn. /// /// Anyone can request a withdrawal of the protocol fees. /// /// Note that after such an operation, it will take the owner some /// time (no more than MAX_AGE_FORCED_REQUEST_UNTIL_WITHDRAW_MODE) to process the request /// and create the deposit to the offchain account. /// /// @param tokenAddress The address of the token, use `0x0` for Ether. function withdrawProtocolFees( address tokenAddress ) external virtual payable; /// @dev Gets the time the protocol fee for a token was last withdrawn. /// @param tokenAddress The address of the token, use `0x0` for Ether. /// @return The time the protocol fee was last withdrawn. function getProtocolFeeLastWithdrawnTime( address tokenAddress ) external virtual view returns (uint); /// @dev Allows anyone to withdraw funds for a specified user using the balances stored /// in the Merkle tree. The funds will be sent to the owner of the acount. /// /// Can only be used in withdrawal mode (i.e. when the owner has stopped /// committing blocks and is not able to commit any more blocks). /// /// This will NOT modify the onchain merkle root! The merkle root stored /// onchain will remain the same after the withdrawal. We store if the user /// has withdrawn the balance in State.withdrawnInWithdrawMode. /// /// @param merkleProof The Merkle inclusion proof function withdrawFromMerkleTree( ExchangeData.MerkleProof calldata merkleProof ) external virtual; /// @dev Checks if the balance for the account was withdrawn with `withdrawFromMerkleTree`. /// @param accountID The accountID of the balance to check. /// @param token The token address /// @return True if it was already withdrawn, false otherwise function isWithdrawnInWithdrawalMode( uint32 accountID, address token ) external virtual view returns (bool); /// @dev Allows withdrawing funds deposited to the contract in a deposit request when /// it was never processed by the owner within the maximum time allowed. /// /// Can be called by anyone. The deposited tokens will be sent back to /// the owner of the account they were deposited in. /// /// @param owner The address of the account the withdrawal was done for. /// @param token The token address function withdrawFromDepositRequest( address owner, address token ) external virtual; /// @dev Allows withdrawing funds deposited to the contract in a deposit request when /// it was never processed by the owner within the maximum time allowed. /// /// Can be called by anyone. The deposited tokens will be sent back to /// the owner of the account they were deposited in. /// /// @param owner The address of the account the withdrawal was done for. /// @param token The token address /// @param nftType The type of NFT contract address (ERC721/ERC1155/...) /// @param nftID The token type 'id`. function withdrawFromNFTDepositRequest( address owner, address token, ExchangeData.NftType nftType, uint256 nftID ) external virtual; /// @dev Allows withdrawing funds after a withdrawal request (either onchain /// or offchain) was submitted in a block by the operator. /// /// Can be called by anyone. The withdrawn tokens will be sent to /// the owner of the account they were withdrawn out. /// /// Normally it is should not be needed for users to call this manually. /// Funds from withdrawal requests will be sent to the account owner /// immediately by the owner when the block is submitted. /// The user will however need to call this manually if the transfer failed. /// /// Tokens and owners must have the same size. /// /// @param owners The addresses of the account the withdrawal was done for. /// @param tokens The token addresses function withdrawFromApprovedWithdrawals( address[] calldata owners, address[] calldata tokens ) external virtual; /// @dev Allows withdrawing funds after an NFT withdrawal request (either onchain /// or offchain) was submitted in a block by the operator. /// /// Can be called by anyone. The withdrawn tokens will be sent to /// the owner of the account they were withdrawn out. /// /// Normally it is should not be needed for users to call this manually. /// Funds from withdrawal requests will be sent to the account owner /// immediately by the owner when the block is submitted. /// The user will however need to call this manually if the transfer failed. /// /// All input arrays must have the same size. /// /// @param owners The addresses of the accounts the withdrawal was done for. /// @param minters The addresses of the minters. /// @param nftTypes The NFT token addresses types /// @param tokens The token addresses /// @param nftIDs The token ids function withdrawFromApprovedWithdrawalsNFT( address[] memory owners, address[] memory minters, ExchangeData.NftType[] memory nftTypes, address[] memory tokens, uint256[] memory nftIDs ) external virtual; /// @dev Gets the amount that can be withdrawn immediately with `withdrawFromApprovedWithdrawals`. /// @param owner The address of the account the withdrawal was done for. /// @param token The token address /// @return The amount withdrawable function getAmountWithdrawable( address owner, address token ) external virtual view returns (uint); /// @dev Gets the amount that can be withdrawn immediately with `withdrawFromApprovedWithdrawalsNFT`. /// @param owner The address of the account the withdrawal was done for. /// @param token The token address /// @param nftType The NFT token address types /// @param nftID The token id /// @param minter The NFT minter /// @return The amount withdrawable function getAmountWithdrawableNFT( address owner, address token, ExchangeData.NftType nftType, uint256 nftID, address minter ) external virtual view returns (uint); /// @dev Notifies the exchange that the owner did not process a forced request. /// If this is indeed the case, the exchange will enter withdrawal mode. /// /// Can be called by anyone. /// /// @param accountID The accountID the forced request was made for /// @param tokenID The tokenID of the the forced request function notifyForcedRequestTooOld( uint32 accountID, uint16 tokenID ) external virtual; /// @dev Allows a withdrawal to be done to an adddresss that is different /// than initialy specified in the withdrawal request. This can be used to /// implement functionality like fast withdrawals. /// /// This function can only be called by an agent. /// /// @param from The address of the account that does the withdrawal. /// @param to The address to which 'amount' tokens were going to be withdrawn. /// @param token The address of the token that is withdrawn ('0x0' for ETH). /// @param amount The amount of tokens that are going to be withdrawn. /// @param storageID The storageID of the withdrawal request. /// @param newRecipient The new recipient address of the withdrawal. function setWithdrawalRecipient( address from, address to, address token, uint96 amount, uint32 storageID, address newRecipient ) external virtual; /// @dev Gets the withdrawal recipient. /// /// @param from The address of the account that does the withdrawal. /// @param to The address to which 'amount' tokens were going to be withdrawn. /// @param token The address of the token that is withdrawn ('0x0' for ETH). /// @param amount The amount of tokens that are going to be withdrawn. /// @param storageID The storageID of the withdrawal request. function getWithdrawalRecipient( address from, address to, address token, uint96 amount, uint32 storageID ) external virtual view returns (address); /// @dev Allows an agent to transfer ERC-20 tokens for a user using the allowance /// the user has set for the exchange. This way the user only needs to approve a single exchange contract /// for all exchange/agent features, which allows for a more seamless user experience. /// /// This function can only be called by an agent. /// /// @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 onchainTransferFrom( address from, address to, address token, uint amount ) external virtual; /// @dev Allows an agent to approve a rollup tx. /// /// This function can only be called by an agent. /// /// @param owner The owner of the account /// @param txHash The hash of the transaction function approveTransaction( address owner, bytes32 txHash ) external virtual; /// @dev Allows an agent to approve multiple rollup txs. /// /// This function can only be called by an agent. /// /// @param owners The account owners /// @param txHashes The hashes of the transactions function approveTransactions( address[] calldata owners, bytes32[] calldata txHashes ) external virtual; /// @dev Checks if a rollup tx is approved using the tx's hash. /// /// @param owner The owner of the account that needs to authorize the tx /// @param txHash The hash of the transaction /// @return True if the tx is approved, else false function isTransactionApproved( address owner, bytes32 txHash ) external virtual view returns (bool); // -- Admins -- /// @dev Sets the max time deposits have to wait before becoming withdrawable. /// @param newValue The new value. /// @return The old value. function setMaxAgeDepositUntilWithdrawable( uint32 newValue ) external virtual returns (uint32); /// @dev Returns the max time deposits have to wait before becoming withdrawable. /// @return The value. function getMaxAgeDepositUntilWithdrawable() external virtual view returns (uint32); /// @dev Shuts down the exchange. /// Once the exchange is shutdown all onchain requests are permanently disabled. /// When all requirements are fulfilled the exchange owner can withdraw /// the exchange stake with withdrawStake. /// /// Note that the exchange can still enter the withdrawal mode after this function /// has been invoked successfully. To prevent entering the withdrawal mode before the /// the echange stake can be withdrawn, all withdrawal requests still need to be handled /// for at least MIN_TIME_IN_SHUTDOWN seconds. /// /// Can only be called by the exchange owner. /// /// @return success True if the exchange is shutdown, else False function shutdown() external virtual returns (bool success); /// @dev Gets the protocol fees for this exchange. /// @return syncedAt The timestamp the protocol fees were last updated /// @return takerFeeBips The protocol taker fee /// @return makerFeeBips The protocol maker fee /// @return previousTakerFeeBips The previous protocol taker fee /// @return previousMakerFeeBips The previous protocol maker fee function getProtocolFeeValues() external virtual view returns ( uint32 syncedAt, uint8 takerFeeBips, uint8 makerFeeBips, uint8 previousTakerFeeBips, uint8 previousMakerFeeBips ); /// @dev Gets the domain separator used in this exchange. function getDomainSeparator() external virtual view returns (bytes32); /// @dev set amm pool feeBips value. function setAmmFeeBips(uint8 _feeBips) external virtual; /// @dev get amm pool feeBips value. function getAmmFeeBips() external virtual view returns (uint8); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; import "../../lib/Claimable.sol"; /// @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 ); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; /// @title AddressSet /// @author Daniel Wang - <[email protected]> contract AddressSet { struct Set { address[] addresses; mapping (address => uint) positions; uint count; } mapping (bytes32 => Set) private sets; function addAddressToSet( bytes32 key, address addr, bool maintainList ) internal { Set storage set = sets[key]; require(set.positions[addr] == 0, "ALREADY_IN_SET"); if (maintainList) { require(set.addresses.length == set.count, "PREVIOUSLY_NOT_MAINTAILED"); set.addresses.push(addr); } else { require(set.addresses.length == 0, "MUST_MAINTAIN"); } set.count += 1; set.positions[addr] = set.count; } function removeAddressFromSet( bytes32 key, address addr ) internal { Set storage set = sets[key]; uint pos = set.positions[addr]; require(pos != 0, "NOT_IN_SET"); delete set.positions[addr]; set.count -= 1; if (set.addresses.length > 0) { address lastAddr = set.addresses[set.count]; if (lastAddr != addr) { set.addresses[pos - 1] = lastAddr; set.positions[lastAddr] = pos; } set.addresses.pop(); } } function removeSet(bytes32 key) internal { delete sets[key]; } function isAddressInSet( bytes32 key, address addr ) internal view returns (bool) { return sets[key].positions[addr] != 0; } function numAddressesInSet(bytes32 key) internal view returns (uint) { Set storage set = sets[key]; return set.count; } function addressesInSet(bytes32 key) internal view returns (address[] memory) { Set storage set = sets[key]; require(set.count == set.addresses.length, "NOT_MAINTAINED"); return sets[key].addresses; } }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; /// @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)) } } } }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; import "./Ownable.sol"; /// @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); } }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; import "./AddressUtil.sol"; import "./ERC20.sol"; import "./ERC20SafeTransfer.sol"; /// @title Drainable /// @author Brecht Devos - <[email protected]> /// @dev Standard functionality to allow draining funds from a contract. abstract contract Drainable { using AddressUtil for address; using ERC20SafeTransfer for address; event Drained( address to, address token, uint amount ); function drain( address to, address token ) public returns (uint amount) { require(canDrain(msg.sender, token), "UNAUTHORIZED"); if (token == address(0)) { amount = address(this).balance; to.sendETHAndVerify(amount, gasleft()); // ETH } else { amount = ERC20(token).balanceOf(address(this)); token.safeTransferAndVerify(to, amount); // ERC20 token } emit Drained(to, token, amount); } // Needs to return if the address is authorized to call drain. function canDrain(address drainer, address token) public virtual view returns (bool); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; /// @title ERC20 Token Interface /// @dev see https://github.com/ethereum/EIPs/issues/20 /// @author Daniel Wang - <[email protected]> abstract contract ERC20 { function totalSupply() public virtual view returns (uint); function balanceOf( address who ) public virtual view returns (uint); function allowance( address owner, address spender ) public virtual view returns (uint); function transfer( address to, uint value ) public virtual returns (bool); function transferFrom( address from, address to, uint value ) public virtual returns (bool); function approve( address spender, uint value ) public virtual returns (bool); }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; /// @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; } }
// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; /// @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); } }
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
import "./AddressSet.sol";
import "./Claimable.sol";
contract OwnerManagable is Claimable, AddressSet
{
bytes32 internal constant MANAGER = keccak256("__MANAGED__");
event ManagerAdded (address indexed manager);
event ManagerRemoved(address indexed manager);
modifier onlyManager(address addr)
{
require(isManager(addr), "NOT_MANAGER");
_;
}
modifier onlyFromManager
{
require(isManager(msg.sender), "NOT_MANAGER");
_;
}
modifier onlyOwnerOrManager
{
require(msg.sender == owner || isManager(msg.sender), "NOT_OWNER_OR_MANAGER");
_;
}
constructor() Claimable() {}
/// @dev Gets the managers.
/// @return The list of managers.
function managers()
public
view
returns (address[] memory)
{
return addressesInSet(MANAGER);
}
/// @dev Gets the number of managers.
/// @return The numer of managers.
function numManagers()
public
view
returns (uint)
{
return numAddressesInSet(MANAGER);
}
/// @dev Checks if an address is a manger.
/// @param addr The address to check.
/// @return True if the address is a manager, False otherwise.
function isManager(address addr)
public
view
returns (bool)
{
return isAddressInSet(MANAGER, addr);
}
/// @dev Adds a new manager.
/// @param manager The new address to add.
function addManager(address manager)
public
virtual
onlyOwner
{
addManagerInternal(manager);
}
/// @dev Removes a manager.
/// @param manager The manager to remove.
function removeManager(address manager)
public
virtual
onlyOwner
{
removeAddressFromSet(MANAGER, manager);
emit ManagerRemoved(manager);
}
function addManagerInternal(address manager)
internal
{
addAddressToSet(MANAGER, manager, true);
emit ManagerAdded(manager);
}
}// SPDX-License-Identifier: Apache-2.0 // Copyright 2017 Loopring Technology Limited. pragma solidity ^0.7.0; /// @title ReentrancyGuard /// @author Brecht Devos - <[email protected]> /// @dev Exposes a modifier that guards a function against reentrancy /// Changing the value of the same storage value multiple times in a transaction /// is cheap (starting from Istanbul) so there is no need to minimize /// the number of times the value is changed contract ReentrancyGuard { //The default value must be 0 in order to work behind a proxy. uint private _guardValue; // Use this modifier on a function to prevent reentrancy modifier nonReentrant() { // Check if the guard value has its original value require(_guardValue == 0, "REENTRANCY"); // Set the value to something else _guardValue = 1; // Function body _; // Set the value back _guardValue = 0; } }
{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Drained","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"ManagerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"ManagerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"addManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"canDrain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"exchangeAddress","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"accountID","type":"uint32"}],"name":"doForcedWithdrawalFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"drain","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numManagers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"removeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
0x608060405234801561001057600080fd5b50600180546001600160a01b031916331790556110d9806100326000396000f3fe6080604052600436106100c65760003560e01c8063907d985b1161007f578063e30c397811610059578063e30c3978146101f8578063e68777d71461020d578063f2fde38b14610222578063f3ae241514610242576100cd565b8063907d985b14610198578063ac18de43146101c5578063ad065e88146101e5576100cd565b80632d06177a146100d25780634e71e0c8146100f4578063715018a614610109578063723117051461011e578063837971e4146101495780638da5cb5b14610176576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f26100ed366004610f48565b610262565b005b34801561010057600080fd5b506100f26102bc565b34801561011557600080fd5b506100f2610370565b34801561012a57600080fd5b50610133610408565b604051610140919061102e565b60405180910390f35b34801561015557600080fd5b50610169610164366004610f62565b610426565b604051610140919061107a565b34801561018257600080fd5b5061018b610576565b6040516101409190610ff1565b3480156101a457600080fd5b506101b86101b3366004610f62565b610585565b604051610140919061106f565b3480156101d157600080fd5b506100f26101e0366004610f48565b6105ac565b6100f26101f3366004610f94565b610649565b34801561020457600080fd5b5061018b610779565b34801561021957600080fd5b50610169610788565b34801561022e57600080fd5b506100f261023d366004610f48565b6107a1565b34801561024e57600080fd5b506101b861025d366004610f48565b61087a565b6001546001600160a01b031633146102b0576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6102b98161089c565b50565b6002546001600160a01b0316331461030a576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6002546001546040516001600160a01b0392831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360028054600180546001600160a01b03199081166001600160a01b03841617909155169055565b6001546001600160a01b031633146103be576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b60606104216000805160206110848339815191526108ed565b905090565b60006104323383610585565b610472576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6001600160a01b03821661049e575047610498815a6001600160a01b03861691906109b4565b50610526565b604080516370a0823160e01b815230600482015290516001600160a01b038416916370a08231916024808301926020929190829003018186803b1580156104e457600080fd5b505afa1580156104f8573d6000803e3d6000fd5b505050506040513d602081101561050e57600080fd5b505190506105266001600160a01b0383168483610a11565b604080516001600160a01b0380861682528416602082015280820183905290517fbfd2431e6c719bec0308db4f4ed0afc39712d368867354c711a1ea1e384fa7819181900360600190a192915050565b6001546001600160a01b031681565b6001546000906001600160a01b03163314806105a557506105a53361087a565b9392505050565b6001546001600160a01b031633146105fa576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b61061260008051602061108483398151915282610a22565b6040516001600160a01b038216907fef69f7d97228658c92417be1b16b19058315de71fecb435d07b7d23728b6bd3190600090a250565b6000541561068b576040805162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015290519081900360640190fd5b60016000819055546001600160a01b03163314806106ad57506106ad3361087a565b6106f5576040805162461bcd60e51b81526020600482015260146024820152732727aa2fa7aba722a92fa7a92fa6a0a720a3a2a960611b604482015290519081900360640190fd5b6040516347b67d0560e01b81526001600160a01b038516906347b67d0590349061072790879087908790600401611005565b6000604051808303818588803b15801561074057600080fd5b505af1158015610754573d6000803e3d6000fd5b5050505050600047111561076f5761076d336000610426565b505b5050600080555050565b6002546001600160a01b031681565b6000610421600080516020611084833981519152610b71565b6001546001600160a01b031633146107ef576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6001600160a01b0381161580159061081557506001546001600160a01b03828116911614155b610858576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b600061089460008051602061108483398151915283610b86565b90505b919050565b6108b6600080516020611084833981519152826001610bb4565b6040516001600160a01b038216907f3b4a40cccf2058c593542587329dd385be4f0b588db5471fbd9598e56dd7093a90600090a250565b6000818152600360205260409020805460028201546060929114610949576040805162461bcd60e51b815260206004820152600e60248201526d1393d517d350525395105253915160921b604482015290519081900360640190fd5b600083815260036020908152604091829020805483518184028101840190945280845290918301828280156109a757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610989575b5050505050915050919050565b60006109ca6001600160a01b0385168484610d24565b9050806105a5576040805162461bcd60e51b815260206004820152601060248201526f5452414e534645525f4641494c55524560801b604482015290519081900360640190fd5b610a1d8383835a610da7565b505050565b60008281526003602090815260408083206001600160a01b0385168452600181019092529091205480610a89576040805162461bcd60e51b815260206004820152600a6024820152691393d517d25397d4d15560b21b604482015290519081900360640190fd5b6001600160a01b0383166000908152600183016020526040812055600282018054600019019055815415610b6b57600082600001836002015481548110610acc57fe5b6000918252602090912001546001600160a01b03908116915084168114610b3c5780836000016001840381548110610b0057fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260018501909152604090208290555b8254839080610b4757fe5b600082815260209020810160001990810180546001600160a01b0319169055019055505b50505050565b60009081526003602052604090206002015490565b60008281526003602090815260408083206001600160a01b0385168452600101909152902054151592915050565b60008381526003602090815260408083206001600160a01b0386168452600181019092529091205415610c1f576040805162461bcd60e51b815260206004820152600e60248201526d1053149150511657d25397d4d15560921b604482015290519081900360640190fd5b8115610cae576002810154815414610c7e576040805162461bcd60e51b815260206004820152601960248201527f50524556494f55534c595f4e4f545f4d41494e5441494c454400000000000000604482015290519081900360640190fd5b80546001810182556000828152602090200180546001600160a01b0319166001600160a01b038516179055610cf2565b805415610cf2576040805162461bcd60e51b815260206004820152600d60248201526c26aaa9aa2fa6a0a4a72a20a4a760991b604482015290519081900360640190fd5b6002810180546001908101918290556001600160a01b0390941660009081529190930160205260409020919091555050565b600082610d33575060016105a5565b6000610d47856001600160a01b0316610df7565b6040519091506001600160a01b03821690849086906000818181858888f193505050503d8060008114610d96576040519150601f19603f3d011682016040523d82523d6000602084013e610d9b565b606091505b50909695505050505050565b610db384848484610dfa565b610b6b576040805162461bcd60e51b815260206004820152601060248201526f5452414e534645525f4641494c55524560801b604482015290519081900360640190fd5b90565b604080516001600160a01b038086166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485938a16928792869282918083835b60208310610e765780518252601f199092019160209182019101610e57565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d8060008114610ed9576040519150601f19603f3d011682016040523d82523d6000602084013e610ede565b606091505b50509050610eeb81610ef6565b979650505050505050565b60008115610f2d573d8015610f165760208114610f1f5760009250610f2b565b60019250610f2b565b60206000803e60005192505b505b5090565b80356001600160a01b038116811461089757600080fd5b600060208284031215610f59578081fd5b6105a582610f31565b60008060408385031215610f74578081fd5b610f7d83610f31565b9150610f8b60208401610f31565b90509250929050565b60008060008060808587031215610fa9578182fd5b610fb285610f31565b9350610fc060208601610f31565b9250610fce60408601610f31565b9150606085013563ffffffff81168114610fe6578182fd5b939692955090935050565b6001600160a01b0391909116815260200190565b6001600160a01b03938416815291909216602082015263ffffffff909116604082015260600190565b6020808252825182820181905260009190848201906040850190845b81811015610d9b5783516001600160a01b03168352928401929184019160010161104a565b901515815260200190565b9081526020019056feae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f8a2646970667358221220e7ae725d0ce63c87411fd305a11b72b974ee9b58ac6982fa24417ae46db271db64736f6c63430007060033
Deployed Bytecode
0x6080604052600436106100c65760003560e01c8063907d985b1161007f578063e30c397811610059578063e30c3978146101f8578063e68777d71461020d578063f2fde38b14610222578063f3ae241514610242576100cd565b8063907d985b14610198578063ac18de43146101c5578063ad065e88146101e5576100cd565b80632d06177a146100d25780634e71e0c8146100f4578063715018a614610109578063723117051461011e578063837971e4146101495780638da5cb5b14610176576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f26100ed366004610f48565b610262565b005b34801561010057600080fd5b506100f26102bc565b34801561011557600080fd5b506100f2610370565b34801561012a57600080fd5b50610133610408565b604051610140919061102e565b60405180910390f35b34801561015557600080fd5b50610169610164366004610f62565b610426565b604051610140919061107a565b34801561018257600080fd5b5061018b610576565b6040516101409190610ff1565b3480156101a457600080fd5b506101b86101b3366004610f62565b610585565b604051610140919061106f565b3480156101d157600080fd5b506100f26101e0366004610f48565b6105ac565b6100f26101f3366004610f94565b610649565b34801561020457600080fd5b5061018b610779565b34801561021957600080fd5b50610169610788565b34801561022e57600080fd5b506100f261023d366004610f48565b6107a1565b34801561024e57600080fd5b506101b861025d366004610f48565b61087a565b6001546001600160a01b031633146102b0576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6102b98161089c565b50565b6002546001600160a01b0316331461030a576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6002546001546040516001600160a01b0392831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360028054600180546001600160a01b03199081166001600160a01b03841617909155169055565b6001546001600160a01b031633146103be576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b60606104216000805160206110848339815191526108ed565b905090565b60006104323383610585565b610472576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6001600160a01b03821661049e575047610498815a6001600160a01b03861691906109b4565b50610526565b604080516370a0823160e01b815230600482015290516001600160a01b038416916370a08231916024808301926020929190829003018186803b1580156104e457600080fd5b505afa1580156104f8573d6000803e3d6000fd5b505050506040513d602081101561050e57600080fd5b505190506105266001600160a01b0383168483610a11565b604080516001600160a01b0380861682528416602082015280820183905290517fbfd2431e6c719bec0308db4f4ed0afc39712d368867354c711a1ea1e384fa7819181900360600190a192915050565b6001546001600160a01b031681565b6001546000906001600160a01b03163314806105a557506105a53361087a565b9392505050565b6001546001600160a01b031633146105fa576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b61061260008051602061108483398151915282610a22565b6040516001600160a01b038216907fef69f7d97228658c92417be1b16b19058315de71fecb435d07b7d23728b6bd3190600090a250565b6000541561068b576040805162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015290519081900360640190fd5b60016000819055546001600160a01b03163314806106ad57506106ad3361087a565b6106f5576040805162461bcd60e51b81526020600482015260146024820152732727aa2fa7aba722a92fa7a92fa6a0a720a3a2a960611b604482015290519081900360640190fd5b6040516347b67d0560e01b81526001600160a01b038516906347b67d0590349061072790879087908790600401611005565b6000604051808303818588803b15801561074057600080fd5b505af1158015610754573d6000803e3d6000fd5b5050505050600047111561076f5761076d336000610426565b505b5050600080555050565b6002546001600160a01b031681565b6000610421600080516020611084833981519152610b71565b6001546001600160a01b031633146107ef576040805162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b604482015290519081900360640190fd5b6001600160a01b0381161580159061081557506001546001600160a01b03828116911614155b610858576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c49445f4144445245535360881b604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b600061089460008051602061108483398151915283610b86565b90505b919050565b6108b6600080516020611084833981519152826001610bb4565b6040516001600160a01b038216907f3b4a40cccf2058c593542587329dd385be4f0b588db5471fbd9598e56dd7093a90600090a250565b6000818152600360205260409020805460028201546060929114610949576040805162461bcd60e51b815260206004820152600e60248201526d1393d517d350525395105253915160921b604482015290519081900360640190fd5b600083815260036020908152604091829020805483518184028101840190945280845290918301828280156109a757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610989575b5050505050915050919050565b60006109ca6001600160a01b0385168484610d24565b9050806105a5576040805162461bcd60e51b815260206004820152601060248201526f5452414e534645525f4641494c55524560801b604482015290519081900360640190fd5b610a1d8383835a610da7565b505050565b60008281526003602090815260408083206001600160a01b0385168452600181019092529091205480610a89576040805162461bcd60e51b815260206004820152600a6024820152691393d517d25397d4d15560b21b604482015290519081900360640190fd5b6001600160a01b0383166000908152600183016020526040812055600282018054600019019055815415610b6b57600082600001836002015481548110610acc57fe5b6000918252602090912001546001600160a01b03908116915084168114610b3c5780836000016001840381548110610b0057fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260018501909152604090208290555b8254839080610b4757fe5b600082815260209020810160001990810180546001600160a01b0319169055019055505b50505050565b60009081526003602052604090206002015490565b60008281526003602090815260408083206001600160a01b0385168452600101909152902054151592915050565b60008381526003602090815260408083206001600160a01b0386168452600181019092529091205415610c1f576040805162461bcd60e51b815260206004820152600e60248201526d1053149150511657d25397d4d15560921b604482015290519081900360640190fd5b8115610cae576002810154815414610c7e576040805162461bcd60e51b815260206004820152601960248201527f50524556494f55534c595f4e4f545f4d41494e5441494c454400000000000000604482015290519081900360640190fd5b80546001810182556000828152602090200180546001600160a01b0319166001600160a01b038516179055610cf2565b805415610cf2576040805162461bcd60e51b815260206004820152600d60248201526c26aaa9aa2fa6a0a4a72a20a4a760991b604482015290519081900360640190fd5b6002810180546001908101918290556001600160a01b0390941660009081529190930160205260409020919091555050565b600082610d33575060016105a5565b6000610d47856001600160a01b0316610df7565b6040519091506001600160a01b03821690849086906000818181858888f193505050503d8060008114610d96576040519150601f19603f3d011682016040523d82523d6000602084013e610d9b565b606091505b50909695505050505050565b610db384848484610dfa565b610b6b576040805162461bcd60e51b815260206004820152601060248201526f5452414e534645525f4641494c55524560801b604482015290519081900360640190fd5b90565b604080516001600160a01b038086166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485938a16928792869282918083835b60208310610e765780518252601f199092019160209182019101610e57565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038160008787f1925050503d8060008114610ed9576040519150601f19603f3d011682016040523d82523d6000602084013e610ede565b606091505b50509050610eeb81610ef6565b979650505050505050565b60008115610f2d573d8015610f165760208114610f1f5760009250610f2b565b60019250610f2b565b60206000803e60005192505b505b5090565b80356001600160a01b038116811461089757600080fd5b600060208284031215610f59578081fd5b6105a582610f31565b60008060408385031215610f74578081fd5b610f7d83610f31565b9150610f8b60208401610f31565b90509250929050565b60008060008060808587031215610fa9578182fd5b610fb285610f31565b9350610fc060208601610f31565b9250610fce60408601610f31565b9150606085013563ffffffff81168114610fe6578182fd5b939692955090935050565b6001600160a01b0391909116815260200190565b6001600160a01b03938416815291909216602082015263ffffffff909116604082015260600190565b6020808252825182820181905260009190848201906040850190845b81811015610d9b5783516001600160a01b03168352928401929184019160010161104a565b901515815260200190565b9081526020019056feae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f8a2646970667358221220e7ae725d0ce63c87411fd305a11b72b974ee9b58ac6982fa24417ae46db271db64736f6c63430007060033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.