Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 341 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Do Forced Withdr... | 21475684 | 20 days ago | IN | 0.02 ETH | 0.00051502 | ||||
Do Forced Withdr... | 21453002 | 23 days ago | IN | 0.02 ETH | 0.00097378 | ||||
Do Forced Withdr... | 21423877 | 27 days ago | IN | 0.02 ETH | 0.00379677 | ||||
Do Forced Withdr... | 21410299 | 29 days ago | IN | 0.02 ETH | 0.001319 | ||||
Do Forced Withdr... | 21219752 | 56 days ago | IN | 0.02 ETH | 0.00103924 | ||||
Do Forced Withdr... | 20837804 | 109 days ago | IN | 0.02 ETH | 0.00193368 | ||||
Do Forced Withdr... | 20194988 | 199 days ago | IN | 0.02 ETH | 0.0001753 | ||||
Do Forced Withdr... | 20035581 | 221 days ago | IN | 0.02 ETH | 0.00169463 | ||||
Do Forced Withdr... | 20026689 | 222 days ago | IN | 0.02 ETH | 0.00285248 | ||||
Do Forced Withdr... | 19953281 | 233 days ago | IN | 0.02 ETH | 0.00055645 | ||||
Do Forced Withdr... | 19942273 | 234 days ago | IN | 0.02 ETH | 0.00039989 | ||||
Do Forced Withdr... | 19623540 | 279 days ago | IN | 0.02 ETH | 0.00188057 | ||||
Do Forced Withdr... | 19621888 | 279 days ago | IN | 0.02 ETH | 0.00168427 | ||||
Do Forced Withdr... | 19565609 | 287 days ago | IN | 0.02 ETH | 0.00241473 | ||||
Do Forced Withdr... | 19563206 | 287 days ago | IN | 0.02 ETH | 0.00413487 | ||||
Do Forced Withdr... | 19535671 | 291 days ago | IN | 0.02 ETH | 0.00429438 | ||||
Do Forced Withdr... | 19511126 | 295 days ago | IN | 0.02 ETH | 0.00243114 | ||||
Do Forced Withdr... | 19481735 | 299 days ago | IN | 0.02 ETH | 0.00343151 | ||||
Do Forced Withdr... | 19444195 | 304 days ago | IN | 0.02 ETH | 0.00482239 | ||||
Do Forced Withdr... | 19414675 | 308 days ago | IN | 0.02 ETH | 0.00826192 | ||||
Do Forced Withdr... | 19396372 | 311 days ago | IN | 0.02 ETH | 0.00526036 | ||||
Do Forced Withdr... | 19386272 | 312 days ago | IN | 0.02 ETH | 0.00658157 | ||||
Do Forced Withdr... | 19386268 | 312 days ago | IN | 0.02 ETH | 0.00753921 | ||||
Do Forced Withdr... | 19366961 | 315 days ago | IN | 0.02 ETH | 0.00965988 | ||||
Do Forced Withdr... | 19352474 | 317 days ago | IN | 0.02 ETH | 0.0047661 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
21475684 | 20 days ago | 0.02 ETH | ||||
21453002 | 23 days ago | 0.02 ETH | ||||
21423877 | 27 days ago | 0.02 ETH | ||||
21410299 | 29 days ago | 0.02 ETH | ||||
21219752 | 56 days ago | 0.02 ETH | ||||
20837804 | 109 days ago | 0.02 ETH | ||||
20194988 | 199 days ago | 0.02 ETH | ||||
20035581 | 221 days ago | 0.02 ETH | ||||
20026689 | 222 days ago | 0.02 ETH | ||||
19953281 | 233 days ago | 0.02 ETH | ||||
19623540 | 279 days ago | 0.02 ETH | ||||
19621888 | 279 days ago | 0.02 ETH | ||||
19565609 | 287 days ago | 0.02 ETH | ||||
19563206 | 287 days ago | 0.02 ETH | ||||
19535671 | 291 days ago | 0.02 ETH | ||||
19511126 | 295 days ago | 0.02 ETH | ||||
19481735 | 299 days ago | 0.02 ETH | ||||
19444195 | 304 days ago | 0.02 ETH | ||||
19414675 | 308 days ago | 0.02 ETH | ||||
19396372 | 311 days ago | 0.02 ETH | ||||
19386272 | 312 days ago | 0.02 ETH | ||||
19386268 | 312 days ago | 0.02 ETH | ||||
19366961 | 315 days ago | 0.02 ETH | ||||
19352474 | 317 days ago | 0.02 ETH | ||||
19343334 | 318 days ago | 0.02 ETH |
Loading...
Loading
Contract Name:
ForcedWithdrawalAgent
Compiler Version
v0.7.0+commit.9e61f92b
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-03-10 */ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; // 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/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/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 } // -- 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; struct AccountLeaf { uint32 accountID; address owner; uint pubKeyX; uint pubKeyY; uint32 nonce; uint feeBipsAMM; } struct BalanceLeaf { uint16 tokenID; uint96 balance; uint96 weightAMM; uint storageRoot; } struct MerkleProof { ExchangeData.AccountLeaf accountLeaf; ExchangeData.BalanceLeaf balanceLeaf; uint[48] accountMerkleProof; uint[24] balanceMerkleProof; } struct BlockContext { bytes32 DOMAIN_SEPARATOR; uint32 timestamp; } // 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) 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; } } // File: contracts/core/iface/IExchangeV3.sol // Copyright 2017 Loopring Technology Limited. /// @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 ForcedWithdrawalRequested( address owner, address token, 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 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'. /// /// A fee to the owner is paid in ETH to process the deposit. /// The operator is not forced to do the deposit and the user can send /// any fee amount. /// /// @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 auxiliaryData Optional extra data used by the deposit contract function deposit( address from, address to, address tokenAddress, uint96 amount, bytes calldata auxiliaryData ) external virtual payable; /// @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 ) external virtual view returns (uint96); // -- Withdrawals -- /// @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 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 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 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 token The token address of the the forced request function notifyForcedRequestTooOld( uint32 accountID, address token ) 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); } // File: contracts/lib/ReentrancyGuard.sol // Copyright 2017 Loopring Technology Limited. /// @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; } } // File: contracts/lib/AddressSet.sol // Copyright 2017 Loopring Technology Limited. /// @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; } } // File: contracts/lib/OwnerManagable.sol // Copyright 2017 Loopring Technology Limited. contract OwnerManagable is Claimable, AddressSet { bytes32 internal constant MANAGER = keccak256("__MANAGED__"); event ManagerAdded (address indexed manager); event ManagerRemoved(address indexed manager); modifier onlyManager { 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 onlyOwner { addManagerInternal(manager); } /// @dev Removes a manager. /// @param manager The manager to remove. function removeManager(address manager) public onlyOwner { removeAddressFromSet(MANAGER, manager); emit ManagerRemoved(manager); } function addManagerInternal(address manager) internal { addAddressToSet(MANAGER, manager, true); emit ManagerAdded(manager); } } // 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/ERC20.sol // Copyright 2017 Loopring Technology Limited. /// @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); } // 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/lib/Drainable.sol // Copyright 2017 Loopring Technology Limited. /// @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); } // File: contracts/aux/agents/ForcedWithdrawalAgent.sol // Copyright 2017 Loopring Technology Limited. /// @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 { } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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
608060405234801561001057600080fd5b50600180546001600160a01b03191633179055611632806100326000396000f3fe6080604052600436106100d65760003560e01c8063907d985b1161007f578063e30c397811610059578063e30c397814610208578063e68777d71461021d578063f2fde38b14610232578063f3ae241514610252576100dd565b8063907d985b146101a8578063ac18de43146101d5578063ad065e88146101f5576100dd565b806372311705116100b0578063723117051461012e578063837971e4146101595780638da5cb5b14610186576100dd565b80632d06177a146100e25780634e71e0c814610104578063715018a614610119576100dd565b366100dd57005b600080fd5b3480156100ee57600080fd5b506101026100fd3660046111c6565b610272565b005b34801561011057600080fd5b506101026102d8565b34801561012557600080fd5b506101026103c1565b34801561013a57600080fd5b50610143610481565b6040516101509190611374565b60405180910390f35b34801561016557600080fd5b506101796101743660046111e1565b6104b1565b60405161015091906115f3565b34801561019257600080fd5b5061019b61063f565b60405161015091906112c6565b3480156101b457600080fd5b506101c86101c33660046111e1565b61065b565b60405161015091906113c2565b3480156101e157600080fd5b506101026101f03660046111c6565b610691565b610102610203366004611215565b610750565b34801561021457600080fd5b5061019b610899565b34801561022957600080fd5b506101796108b5565b34801561023e57600080fd5b5061010261024d3660046111c6565b6108e0565b34801561025e57600080fd5b506101c861026d3660046111c6565b6109ee565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b60405180910390fd5b6102d581610a1a565b50565b60025473ffffffffffffffffffffffffffffffffffffffff163314610329576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b60025460015460405173ffffffffffffffffffffffffffffffffffffffff92831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360028054600180547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610412576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b60015460405160009173ffffffffffffffffffffffffffffffffffffffff16907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60606104ac7fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f8610a8a565b905090565b60006104bd338361065b565b6104f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b73ffffffffffffffffffffffffffffffffffffffff8216610539575047610533815a73ffffffffffffffffffffffffffffffffffffffff86169190610b52565b506105fe565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316906370a082319061058b9030906004016112c6565b60206040518083038186803b1580156105a357600080fd5b505afa1580156105b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105db9190611275565b90506105fe73ffffffffffffffffffffffffffffffffffffffff83168483610bb5565b7fbfd2431e6c719bec0308db4f4ed0afc39712d368867354c711a1ea1e384fa781838383604051610631939291906112e7565b60405180910390a192915050565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b60015460009073ffffffffffffffffffffffffffffffffffffffff163314806106885750610688336109ee565b90505b92915050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146106e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b61070c7fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f882610bc6565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fef69f7d97228658c92417be1b16b19058315de71fecb435d07b7d23728b6bd3190600090a250565b6000541561078a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390611404565b600160008190555473ffffffffffffffffffffffffffffffffffffffff163314806107b957506107b9336109ee565b6107ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390611472565b6040517f47b67d0500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516906347b67d0590349061084790879087908790600401611318565b6000604051808303818588803b15801561086057600080fd5b505af1158015610874573d6000803e3d6000fd5b5050505050600047111561088f5761088d3360006104b1565b505b5050600080555050565b60025473ffffffffffffffffffffffffffffffffffffffff1681565b60006104ac7fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f8610dad565b60015473ffffffffffffffffffffffffffffffffffffffff163314610931576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b73ffffffffffffffffffffffffffffffffffffffff811615801590610971575060015473ffffffffffffffffffffffffffffffffffffffff828116911614155b6109a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906113cd565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600061068b7fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f883610dc2565b610a467fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f8826001610dfd565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f3b4a40cccf2058c593542587329dd385be4f0b588db5471fbd9598e56dd7093a90600090a250565b6000818152600360205260409020805460028201546060929114610ada576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906115bc565b60008381526003602090815260409182902080548351818402810184019094528084529091830182828015610b4557602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b1a575b5050505050915050919050565b6000610b7573ffffffffffffffffffffffffffffffffffffffff85168484610f7a565b905080610bae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906114a9565b9392505050565b610bc18383835a611021565b505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452600181019092529091205480610c32576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061154e565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001830160205260408120556002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055815415610da757600082600001836002015481548110610ca057fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff908116915084168114610d425780836000016001840381548110610ce157fe5b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918316815260018501909152604090208290555b8254839080610d4d57fe5b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505b50505050565b60009081526003602052604090206002015490565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452600101909152902054151592915050565b600083815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452600181019092529091205415610e69576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906114e0565b8115610f02576002810154815414610ead576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390611585565b80546001810182556000828152602090200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8516179055610f3b565b805415610f3b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390611517565b60028101805460019081019182905573ffffffffffffffffffffffffffffffffffffffff90941660009081529190930160205260409020919091555050565b600082610f8957506001610bae565b6000610faa8573ffffffffffffffffffffffffffffffffffffffff16611063565b90508073ffffffffffffffffffffffffffffffffffffffff16848490604051610fd290611063565b600060405180830381858888f193505050503d8060008114611010576040519150601f19603f3d011682016040523d82523d6000602084013e611015565b606091505b50909695505050505050565b61102d84848484611066565b610da7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906114a9565b90565b6000606063a9059cbb60e01b858560405160240161108592919061134e565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008673ffffffffffffffffffffffffffffffffffffffff16848360405161110c919061128d565b60006040518083038160008787f1925050503d806000811461114a576040519150601f19603f3d011682016040523d82523d6000602084013e61114f565b606091505b5050905061115c81611167565b979650505050505050565b6000811561119e573d80156111875760208114611190576000925061119c565b6001925061119c565b60206000803e60005192505b505b5090565b803573ffffffffffffffffffffffffffffffffffffffff8116811461068b57600080fd5b6000602082840312156111d7578081fd5b61068883836111a2565b600080604083850312156111f3578081fd5b6111fd84846111a2565b915061120c84602085016111a2565b90509250929050565b6000806000806080858703121561122a578182fd5b61123486866111a2565b935061124386602087016111a2565b925061125286604087016111a2565b9150606085013563ffffffff8116811461126a578182fd5b939692955090935050565b600060208284031215611286578081fd5b5051919050565b60008251815b818110156112ad5760208186018101518583015201611293565b818111156112bb5782828501525b509190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff938416815291909216602082015263ffffffff909116604082015260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561101557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611390565b901515815260200190565b6020808252600f908201527f494e56414c49445f414444524553530000000000000000000000000000000000604082015260600190565b6020808252600a908201527f5245454e5452414e435900000000000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f554e415554484f52495a45440000000000000000000000000000000000000000604082015260600190565b60208082526014908201527f4e4f545f4f574e45525f4f525f4d414e41474552000000000000000000000000604082015260600190565b60208082526010908201527f5452414e534645525f4641494c55524500000000000000000000000000000000604082015260600190565b6020808252600e908201527f414c52454144595f494e5f534554000000000000000000000000000000000000604082015260600190565b6020808252600d908201527f4d5553545f4d41494e5441494e00000000000000000000000000000000000000604082015260600190565b6020808252600a908201527f4e4f545f494e5f53455400000000000000000000000000000000000000000000604082015260600190565b60208082526019908201527f50524556494f55534c595f4e4f545f4d41494e5441494c454400000000000000604082015260600190565b6020808252600e908201527f4e4f545f4d41494e5441494e4544000000000000000000000000000000000000604082015260600190565b9081526020019056fea2646970667358221220cc3137f5d8e2a73a4d717fb82401ebd582d4040ff47b9b0e9c72dad7eaf0097064736f6c63430007000033
Deployed Bytecode
0x6080604052600436106100d65760003560e01c8063907d985b1161007f578063e30c397811610059578063e30c397814610208578063e68777d71461021d578063f2fde38b14610232578063f3ae241514610252576100dd565b8063907d985b146101a8578063ac18de43146101d5578063ad065e88146101f5576100dd565b806372311705116100b0578063723117051461012e578063837971e4146101595780638da5cb5b14610186576100dd565b80632d06177a146100e25780634e71e0c814610104578063715018a614610119576100dd565b366100dd57005b600080fd5b3480156100ee57600080fd5b506101026100fd3660046111c6565b610272565b005b34801561011057600080fd5b506101026102d8565b34801561012557600080fd5b506101026103c1565b34801561013a57600080fd5b50610143610481565b6040516101509190611374565b60405180910390f35b34801561016557600080fd5b506101796101743660046111e1565b6104b1565b60405161015091906115f3565b34801561019257600080fd5b5061019b61063f565b60405161015091906112c6565b3480156101b457600080fd5b506101c86101c33660046111e1565b61065b565b60405161015091906113c2565b3480156101e157600080fd5b506101026101f03660046111c6565b610691565b610102610203366004611215565b610750565b34801561021457600080fd5b5061019b610899565b34801561022957600080fd5b506101796108b5565b34801561023e57600080fd5b5061010261024d3660046111c6565b6108e0565b34801561025e57600080fd5b506101c861026d3660046111c6565b6109ee565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b60405180910390fd5b6102d581610a1a565b50565b60025473ffffffffffffffffffffffffffffffffffffffff163314610329576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b60025460015460405173ffffffffffffffffffffffffffffffffffffffff92831692909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a360028054600180547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610412576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b60015460405160009173ffffffffffffffffffffffffffffffffffffffff16907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60606104ac7fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f8610a8a565b905090565b60006104bd338361065b565b6104f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b73ffffffffffffffffffffffffffffffffffffffff8216610539575047610533815a73ffffffffffffffffffffffffffffffffffffffff86169190610b52565b506105fe565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316906370a082319061058b9030906004016112c6565b60206040518083038186803b1580156105a357600080fd5b505afa1580156105b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105db9190611275565b90506105fe73ffffffffffffffffffffffffffffffffffffffff83168483610bb5565b7fbfd2431e6c719bec0308db4f4ed0afc39712d368867354c711a1ea1e384fa781838383604051610631939291906112e7565b60405180910390a192915050565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b60015460009073ffffffffffffffffffffffffffffffffffffffff163314806106885750610688336109ee565b90505b92915050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146106e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b61070c7fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f882610bc6565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fef69f7d97228658c92417be1b16b19058315de71fecb435d07b7d23728b6bd3190600090a250565b6000541561078a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390611404565b600160008190555473ffffffffffffffffffffffffffffffffffffffff163314806107b957506107b9336109ee565b6107ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390611472565b6040517f47b67d0500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516906347b67d0590349061084790879087908790600401611318565b6000604051808303818588803b15801561086057600080fd5b505af1158015610874573d6000803e3d6000fd5b5050505050600047111561088f5761088d3360006104b1565b505b5050600080555050565b60025473ffffffffffffffffffffffffffffffffffffffff1681565b60006104ac7fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f8610dad565b60015473ffffffffffffffffffffffffffffffffffffffff163314610931576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061143b565b73ffffffffffffffffffffffffffffffffffffffff811615801590610971575060015473ffffffffffffffffffffffffffffffffffffffff828116911614155b6109a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906113cd565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600061068b7fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f883610dc2565b610a467fae79206ff8d89355a31a27bc7df0c55f5fe15ce3ae94530629cd19b6712ea1f8826001610dfd565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f3b4a40cccf2058c593542587329dd385be4f0b588db5471fbd9598e56dd7093a90600090a250565b6000818152600360205260409020805460028201546060929114610ada576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906115bc565b60008381526003602090815260409182902080548351818402810184019094528084529091830182828015610b4557602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b1a575b5050505050915050919050565b6000610b7573ffffffffffffffffffffffffffffffffffffffff85168484610f7a565b905080610bae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906114a9565b9392505050565b610bc18383835a611021565b505050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452600181019092529091205480610c32576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c39061154e565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001830160205260408120556002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055815415610da757600082600001836002015481548110610ca057fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff908116915084168114610d425780836000016001840381548110610ce157fe5b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918316815260018501909152604090208290555b8254839080610d4d57fe5b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505b50505050565b60009081526003602052604090206002015490565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452600101909152902054151592915050565b600083815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452600181019092529091205415610e69576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906114e0565b8115610f02576002810154815414610ead576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390611585565b80546001810182556000828152602090200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8516179055610f3b565b805415610f3b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c390611517565b60028101805460019081019182905573ffffffffffffffffffffffffffffffffffffffff90941660009081529190930160205260409020919091555050565b600082610f8957506001610bae565b6000610faa8573ffffffffffffffffffffffffffffffffffffffff16611063565b90508073ffffffffffffffffffffffffffffffffffffffff16848490604051610fd290611063565b600060405180830381858888f193505050503d8060008114611010576040519150601f19603f3d011682016040523d82523d6000602084013e611015565b606091505b50909695505050505050565b61102d84848484611066565b610da7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102c3906114a9565b90565b6000606063a9059cbb60e01b858560405160240161108592919061134e565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008673ffffffffffffffffffffffffffffffffffffffff16848360405161110c919061128d565b60006040518083038160008787f1925050503d806000811461114a576040519150601f19603f3d011682016040523d82523d6000602084013e61114f565b606091505b5050905061115c81611167565b979650505050505050565b6000811561119e573d80156111875760208114611190576000925061119c565b6001925061119c565b60206000803e60005192505b505b5090565b803573ffffffffffffffffffffffffffffffffffffffff8116811461068b57600080fd5b6000602082840312156111d7578081fd5b61068883836111a2565b600080604083850312156111f3578081fd5b6111fd84846111a2565b915061120c84602085016111a2565b90509250929050565b6000806000806080858703121561122a578182fd5b61123486866111a2565b935061124386602087016111a2565b925061125286604087016111a2565b9150606085013563ffffffff8116811461126a578182fd5b939692955090935050565b600060208284031215611286578081fd5b5051919050565b60008251815b818110156112ad5760208186018101518583015201611293565b818111156112bb5782828501525b509190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff938416815291909216602082015263ffffffff909116604082015260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561101557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611390565b901515815260200190565b6020808252600f908201527f494e56414c49445f414444524553530000000000000000000000000000000000604082015260600190565b6020808252600a908201527f5245454e5452414e435900000000000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f554e415554484f52495a45440000000000000000000000000000000000000000604082015260600190565b60208082526014908201527f4e4f545f4f574e45525f4f525f4d414e41474552000000000000000000000000604082015260600190565b60208082526010908201527f5452414e534645525f4641494c55524500000000000000000000000000000000604082015260600190565b6020808252600e908201527f414c52454144595f494e5f534554000000000000000000000000000000000000604082015260600190565b6020808252600d908201527f4d5553545f4d41494e5441494e00000000000000000000000000000000000000604082015260600190565b6020808252600a908201527f4e4f545f494e5f53455400000000000000000000000000000000000000000000604082015260600190565b60208082526019908201527f50524556494f55534c595f4e4f545f4d41494e5441494c454400000000000000604082015260600190565b6020808252600e908201527f4e4f545f4d41494e5441494e4544000000000000000000000000000000000000604082015260600190565b9081526020019056fea2646970667358221220cc3137f5d8e2a73a4d717fb82401ebd582d4040ff47b9b0e9c72dad7eaf0097064736f6c63430007000033
Deployed Bytecode Sourcemap
64951:816:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53313:123;;;;;;;;;;-1:-1:-1;53313:123:0;;;;;:::i;:::-;;:::i;:::-;;2627:205;;;;;;;;;;;;;:::i;1408:161::-;;;;;;;;;;;;;:::i;52544:140::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;64029:543;;;;;;;;;;-1:-1:-1;64029:543:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;468:20::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;65074:200::-;;;;;;;;;;-1:-1:-1;65074:200:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;53524:176::-;;;;;;;;;;-1:-1:-1;53524:176:0;;;;;:::i;:::-;;:::i;65282:444::-;;;;;;:::i;:::-;;:::i;1927:27::-;;;;;;;;;;;;;:::i;52775:134::-;;;;;;;;;;;;;:::i;2300:247::-;;;;;;;;;;-1:-1:-1;2300:247:0;;;;;:::i;:::-;;:::i;53076:147::-;;;;;;;;;;-1:-1:-1;53076:147:0;;;;;:::i;:::-;;:::i;53313:123::-;914:5;;;;900:10;:19;892:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;53401:27:::1;53420:7;53401:18;:27::i;:::-;53313:123:::0;:::o;2627:205::-;2108:12;;;;2094:10;:26;2086:51;;;;;;;;;;;;:::i;:::-;2744:12:::1;::::0;;2737:5;2716:41:::1;::::0;2744:12:::1;::::0;;::::1;::::0;2737:5;;::::1;::::0;2716:41:::1;::::0;2744:12:::1;::::0;2716:41:::1;2776:12;::::0;;;2768:20;;;;;::::1;2776:12;::::0;::::1;2768:20;::::0;;;2799:25:::1;::::0;;2627:205::o;1408:161::-;914:5;;;;900:10;:19;892:44;;;;;;;;;;;;:::i;:::-;1514:5:::1;::::0;1493:39:::1;::::0;1529:1:::1;::::0;1493:39:::1;1514:5;::::0;1493:39:::1;::::0;1529:1;;1493:39:::1;1543:5;:18:::0;;;::::1;::::0;;1408:161::o;52544:140::-;52612:16;52653:23;52038:24;52653:14;:23::i;:::-;52646:30;;52544:140;:::o;64029:543::-;64134:11;64171:27;64180:10;64192:5;64171:8;:27::i;:::-;64163:52;;;;;;;;;;;;:::i;:::-;64232:19;;;64228:293;;-1:-1:-1;64277:21:0;64313:38;64277:21;64341:9;64313:19;;;;:38;:19;:38::i;:::-;;64228:293;;;64402:37;;;;;:22;;;;;;:37;;64433:4;;64402:37;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;64393:46;-1:-1:-1;64454:39:0;:27;;;64482:2;64393:46;64454:27;:39::i;:::-;64538:26;64546:2;64550:5;64557:6;64538:26;;;;;;;;:::i;:::-;;;;;;;;64029:543;;;;:::o;468:20::-;;;;;;:::o;65074:200::-;65236:5;;65198:4;;65236:5;;65222:10;:19;;:44;;;65245:21;65255:10;65245:9;:21::i;:::-;65215:51;;65074:200;;;;;:::o;53524:176::-;914:5;;;;900:10;:19;892:44;;;;;;;;;;;;:::i;:::-;53615:38:::1;52038:24;53645:7;53615:20;:38::i;:::-;53669:23;::::0;::::1;::::0;::::1;::::0;::::1;::::0;;;::::1;53524:176:::0;:::o;65282:444::-;49338:11;;:16;49330:39;;;;;;;;;;;;:::i;:::-;49440:1;49426:11;:15;;;52353:5;::::1;;52339:10;:19;::::0;:44:::1;;;52362:21;52372:10;52362:9;:21::i;:::-;52331:77;;;;;;;;;;;;:::i;:::-;65534:85:::2;::::0;;;;:42:::2;::::0;::::2;::::0;::::2;::::0;65584:9:::2;::::0;65534:85:::2;::::0;65595:5;;65602;;65609:9;;65534:85:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;65660:1;65636:21;:25;65632:87;;;65678:29;65684:10;65704:1;65678:5;:29::i;:::-;;65632:87;-1:-1:-1::0;;49539:1:0;49525:15;;-1:-1:-1;;65282:444:0:o;1927:27::-;;;;;;:::o;52775:134::-;52846:4;52875:26;52038:24;52875:17;:26::i;2300:247::-;914:5;;;;900:10;:19;892:44;;;;;;;;;;;;:::i;:::-;2442:22:::1;::::0;::::1;::::0;;::::1;::::0;:43:::1;;-1:-1:-1::0;2480:5:0::1;::::0;::::1;2468:17:::0;;::::1;2480:5:::0;::::1;2468:17;;2442:43;2434:71;;;;;;;;;;;;:::i;:::-;2516:12;:23:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;2300:247::o;53076:147::-;53157:4;53186:29;52038:24;53210:4;53186:14;:29::i;53708:163::-;53787:39;52038:24;53812:7;53821:4;53787:15;:39::i;:::-;53842:21;;;;;;;;;;;53708:163;:::o;51573:264::-;51694:15;51712:9;;;:4;:9;;;;;51753:20;;51740:9;;;;51660:16;;51712:9;51740:33;51732:60;;;;;;;;;;;;:::i;:::-;51810:9;;;;:4;:9;;;;;;;;;51803:26;;;;;;;;;;;;;;;;;51810:9;;51803:26;;51810:9;51803:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51573:264;;;:::o;55686:269::-;55832:12;55872:28;:10;;;55883:6;55891:8;55872:10;:28::i;:::-;55862:38;;55919:7;55911:36;;;;;;;;;;;;:::i;:::-;55686:269;;;;;:::o;58739:278::-;58884:125;58932:5;58952:2;58969:5;58989:9;58884:33;:125::i;:::-;58739:278;;;:::o;50480:600::-;50600:15;50618:9;;;:4;:9;;;;;;;;50649:19;;;;;:13;;;:19;;;;;;;50687:8;50679:31;;;;;;;;;;;;:::i;:::-;50730:19;;;;;;;:13;;;:19;;;;;50723:26;50760:9;;;:14;;;;;;50791:20;;:24;50787:286;;50832:16;50851:3;:13;;50865:3;:9;;;50851:24;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;50894:16:0;;;;50890:138;;50956:8;50931:3;:13;;50951:1;50945:3;:7;50931:22;;;;;;;;;;;;;;;;;;;;:33;;;;;;;;;;;50983:23;;;;;-1:-1:-1;50983:13:0;;:23;;;;;;:29;;;50890:138;51042:19;;:3;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;50787:286:0;50480:600;;;;:::o;51391:174::-;51481:4;51521:9;;;:4;:9;;;;;51548;;;;51391:174::o;51186:197::-;51316:4;51345:9;;;:4;:9;;;;;;;;:25;;;;;:19;;:25;;;;;;:30;;51186:197;;;;:::o;49921:551::-;50055:15;50073:9;;;:4;:9;;;;;;;;50101:19;;;;;:13;;;:19;;;;;;;:24;50093:51;;;;;;;;;;;;:::i;:::-;50161:12;50157:239;;;50222:9;;;;50198:20;;:33;50190:71;;;;;;;;;;;;:::i;:::-;50276:24;;;;;;;-1:-1:-1;50276:24:0;;;;;;;;;;;;;;;;;50157:239;;;50341:20;;:25;50333:51;;;;;;;;;;;;:::i;:::-;50408:9;;;:14;;50421:1;50408:14;;;;;;;50433:19;;;;50408:9;50433:19;;;:13;;;;:19;;;;;:31;;;;-1:-1:-1;;49921:551:0:o;55136:395::-;55273:12;55307:11;55303:55;;-1:-1:-1;55342:4:0;55335:11;;55303:55;55368:25;55396:14;:2;:12;;;:14::i;:::-;55368:42;;55475:9;:14;;55497:6;55510:8;55475:48;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;55461:62:0;;55136:395;-1:-1:-1;;;;;;55136:395:0:o;59324:310::-;59530:52;59555:5;59562:2;59566:5;59573:8;59530:24;:52::i;:::-;59508:118;;;;;;;;;;;;:::i;54821:164::-;54972:4;54821:164::o;59642:800::-;59819:4;60199:21;60267:10;60260:18;;60293:2;60310:5;60223:103;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60199:127;;60338:12;60356:5;:10;;60372:8;60382;60356:35;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60337:54;;;60409:25;60426:7;60409:16;:25::i;:::-;60402:32;59642:800;-1:-1:-1;;;;;;;59642:800:0:o;62430:1127::-;62540:4;62863:7;62859:666;;;62922:16;63077:61;;;;63255:2;63250:115;;;;63479:1;63468:12;;62915:584;;63077:61;63118:1;63107:12;;63077:61;;63250:115;63302:2;63299:1;63296;63281:24;63344:1;63338:8;63327:19;;62915:584;;62896:618;-1:-1:-1;63542:7:0;62430:1127::o;5:130:-1:-;72:20;;15831:42;15820:54;;16396:35;;16386:2;;16445:1;;16435:12;418:241;;522:2;510:9;501:7;497:23;493:32;490:2;;;-1:-1;;528:12;490:2;590:53;635:7;611:22;590:53;:::i;666:366::-;;;787:2;775:9;766:7;762:23;758:32;755:2;;;-1:-1;;793:12;755:2;855:53;900:7;876:22;855:53;:::i;:::-;845:63;;963:53;1008:7;945:2;988:9;984:22;963:53;:::i;:::-;953:63;;749:283;;;;;:::o;1039:615::-;;;;;1193:3;1181:9;1172:7;1168:23;1164:33;1161:2;;;-1:-1;;1200:12;1161:2;1262:53;1307:7;1283:22;1262:53;:::i;:::-;1252:63;;1370:53;1415:7;1352:2;1395:9;1391:22;1370:53;:::i;:::-;1360:63;;1478:53;1523:7;1460:2;1503:9;1499:22;1478:53;:::i;:::-;1468:63;;1568:2;1610:9;1606:22;349:20;16037:10;16670:5;16026:22;16646:5;16643:34;16633:2;;-1:-1;;16681:12;16633:2;1155:499;;;;-1:-1;1155:499;;-1:-1;;1155:499::o;1661:263::-;;1776:2;1764:9;1755:7;1751:23;1747:32;1744:2;;;-1:-1;;1782:12;1744:2;-1:-1;220:13;;1738:186;-1:-1;1738:186::o;7327:271::-;;3343:5;14772:12;-1:-1;16133:101;16147:6;16144:1;16141:13;16133:101;;;3487:4;16214:11;;;;;16208:18;16195:11;;;16188:39;16162:10;16133:101;;;16249:6;16246:1;16243:13;16240:2;;;-1:-1;16305:6;16300:3;16296:16;16289:27;16240:2;-1:-1;3518:16;;;;;7461:137;-1:-1;;7461:137::o;7991:222::-;15831:42;15820:54;;;;2174:37;;8118:2;8103:18;;8089:124::o;8220:444::-;15831:42;15820:54;;;2174:37;;15820:54;;;;8567:2;8552:18;;2174:37;8650:2;8635:18;;7161:37;;;;8403:2;8388:18;;8374:290::o;8671:440::-;15831:42;15820:54;;;2174:37;;15820:54;;;;9016:2;9001:18;;2174:37;16037:10;16026:22;;;9097:2;9082:18;;7279:36;8852:2;8837:18;;8823:288::o;9118:333::-;15831:42;15820:54;;;;2174:37;;9437:2;9422:18;;7161:37;9273:2;9258:18;;9244:207::o;9458:370::-;9635:2;9649:47;;;14772:12;;9620:18;;;15175:19;;;9458:370;;9635:2;14626:14;;;;15215;;;;9458:370;2782:260;2807:6;2804:1;2801:13;2782:260;;;2868:13;;15831:42;15820:54;2174:37;;15030:14;;;;2085;;;;2829:1;2822:9;2782:260;;9835:210;15732:13;;15725:21;3137:34;;9956:2;9941:18;;9927:118::o;10052:416::-;10252:2;10266:47;;;3771:2;10237:18;;;15175:19;3807:17;15215:14;;;3787:38;3844:12;;;10223:245::o;10475:416::-;10675:2;10689:47;;;4095:2;10660:18;;;15175:19;4131:12;15215:14;;;4111:33;4163:12;;;10646:245::o;10898:416::-;11098:2;11112:47;;;4414:2;11083:18;;;15175:19;4450:14;15215;;;4430:35;4484:12;;;11069:245::o;11321:416::-;11521:2;11535:47;;;4735:2;11506:18;;;15175:19;4771:22;15215:14;;;4751:43;4813:12;;;11492:245::o;11744:416::-;11944:2;11958:47;;;5064:2;11929:18;;;15175:19;5100:18;15215:14;;;5080:39;5138:12;;;11915:245::o;12167:416::-;12367:2;12381:47;;;5389:2;12352:18;;;15175:19;5425:16;15215:14;;;5405:37;5461:12;;;12338:245::o;12590:416::-;12790:2;12804:47;;;5712:2;12775:18;;;15175:19;5748:15;15215:14;;;5728:36;5783:12;;;12761:245::o;13013:416::-;13213:2;13227:47;;;6034:2;13198:18;;;15175:19;6070:12;15215:14;;;6050:33;6102:12;;;13184:245::o;13436:416::-;13636:2;13650:47;;;6658:2;13621:18;;;15175:19;6694:27;15215:14;;;6674:48;6741:12;;;13607:245::o;13859:416::-;14059:2;14073:47;;;6992:2;14044:18;;;15175:19;7028:16;15215:14;;;7008:37;7064:12;;;14030:245::o;14282:222::-;7161:37;;;14409:2;14394:18;;14380:124::o
Swarm Source
ipfs://cc3137f5d8e2a73a4d717fb82401ebd582d4040ff47b9b0e9c72dad7eaf00970
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ 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.