Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
LockingVault
Compiler Version
v0.8.3+commit.8d00100c
Optimization Enabled:
Yes with 7500 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.3; import "../libraries/History.sol"; import "../libraries/Storage.sol"; import "../interfaces/IERC20.sol"; import "../interfaces/IVotingVault.sol"; import "../interfaces/ILockingVault.sol"; abstract contract AbstractLockingVault is IVotingVault, ILockingVault { // Bring our libraries into scope using History for *; using Storage for *; // Immutables are in bytecode so don't need special storage treatment IERC20 public immutable override token; // A constant which is how far back stale blocks are uint256 public immutable staleBlockLag; // Event to track delegation data event VoteChange(address indexed from, address indexed to, int256 amount); /// @notice Constructs the contract by setting immutables /// @param _token The external erc20 token contract /// @param _staleBlockLag The number of blocks before the delegation history is forgotten constructor(IERC20 _token, uint256 _staleBlockLag) { token = _token; staleBlockLag = _staleBlockLag; } // This contract is a proxy so we use the custom state management system from // storage and return the following as methods to isolate that call. // deposits mapping(address => (address, uint96)) /// @notice A single function endpoint for loading storage for deposits /// @return returns a storage mapping which can be used to look up deposit data function _deposits() internal pure returns (mapping(address => Storage.AddressUint) storage) { // This call returns a storage mapping with a unique non overwrite-able storage location // which can be persisted through upgrades, even if they change storage layout return (Storage.mappingAddressToPackedAddressUint("deposits")); } /// Getter for the deposits mapping /// @param who The user to query the balance of /// @return (address delegated to, amount of deposit) function deposits(address who) external view returns (address, uint96) { Storage.AddressUint storage userData = _deposits()[who]; return (userData.who, userData.amount); } /// @notice Returns the historical voting power tracker /// @return A struct which can push to and find items in block indexed storage function _votingPower() internal pure returns (History.HistoricalBalances memory) { // This call returns a storage mapping with a unique non overwrite-able storage location // which can be persisted through upgrades, even if they change storage layout return (History.load("votingPower")); } /// @notice Attempts to load the voting power of a user /// @param user The address we want to load the voting power of /// @param blockNumber the block number we want the user's voting power at /// @return the number of votes function queryVotePower( address user, uint256 blockNumber, bytes calldata ) external override returns (uint256) { // Get our reference to historical data History.HistoricalBalances memory votingPower = _votingPower(); // Find the historical data and clear everything more than 'staleBlockLag' into the past return votingPower.findAndClear( user, blockNumber, block.number - staleBlockLag ); } /// @notice Loads the voting power of a user without changing state /// @param user The address we want to load the voting power of /// @param blockNumber the block number we want the user's voting power at /// @return the number of votes function queryVotePowerView(address user, uint256 blockNumber) external view returns (uint256) { // Get our reference to historical data History.HistoricalBalances memory votingPower = _votingPower(); // Find the historical datum return votingPower.find(user, blockNumber); } /// @notice Deposits and delegates voting power to an address provided with the call /// @param fundedAccount The address to credit this deposit to /// @param amount The amount of token which is deposited /// @param firstDelegation First delegation address /// @dev Note - There's a minor griefing attack on this which sets someones delegation /// address by depositing before them, requiring them to call delegate to reset it. /// Given the gas price required and 0 financial benefit we consider it unlikely. /// Warning - Users should not set delegation to the zero address as this will allow /// someone to change their delegation by depositing a small amount to their /// account. function deposit( address fundedAccount, uint256 amount, address firstDelegation ) external override { // No delegating to zero require(firstDelegation != address(0), "Zero addr delegation"); // Move the tokens into this contract token.transferFrom(msg.sender, address(this), amount); // Load our deposits storage Storage.AddressUint storage userData = _deposits()[fundedAccount]; // Load who has the user's votes address delegate = userData.who; if (delegate == address(0)) { // If the user is un-delegated we delegate to their indicated address delegate = firstDelegation; // Set the delegation userData.who = delegate; // Now we increase the user's balance userData.amount += uint96(amount); } else { // In this case we make no change to the user's delegation // Now we increase the user's balance userData.amount += uint96(amount); } // Next we increase the delegation to their delegate // Get the storage pointer History.HistoricalBalances memory votingPower = _votingPower(); // Load the most recent voter power stamp uint256 delegateeVotes = votingPower.loadTop(delegate); // Emit an event to track votes emit VoteChange(fundedAccount, delegate, int256(amount)); // Add the newly deposited votes to the delegate votingPower.push(delegate, delegateeVotes + amount); } /// @notice Removes tokens from this contract and the voting power they represent /// @param amount The amount of token to withdraw function withdraw(uint256 amount) external virtual override { // Load our deposits storage Storage.AddressUint storage userData = _deposits()[msg.sender]; // Reduce the user's stored balance // If properly optimized this block should result in 1 sload 1 store userData.amount -= uint96(amount); address delegate = userData.who; // Reduce the delegate voting power // Get the storage pointer History.HistoricalBalances memory votingPower = _votingPower(); // Load the most recent voter power stamp uint256 delegateeVotes = votingPower.loadTop(delegate); // remove the votes from the delegate votingPower.push(delegate, delegateeVotes - amount); // Emit an event to track votes emit VoteChange(msg.sender, delegate, -1 * int256(amount)); // Transfers the result to the sender token.transfer(msg.sender, amount); } /// @notice Changes a user's voting power /// @param newDelegate The new address which gets voting power function changeDelegation(address newDelegate) external override { // Get the stored user data Storage.AddressUint storage userData = _deposits()[msg.sender]; // Get the user balance uint256 userBalance = uint256(userData.amount); address oldDelegate = userData.who; // Reset the user delegation userData.who = newDelegate; // Reduce the old voting power // Get the storage pointer History.HistoricalBalances memory votingPower = _votingPower(); // Load the old delegate's voting power uint256 oldDelegateVotes = votingPower.loadTop(oldDelegate); // Reduce the old voting power votingPower.push(oldDelegate, oldDelegateVotes - userBalance); // Emit an event to track votes emit VoteChange(msg.sender, oldDelegate, -1 * int256(userBalance)); // Get the new delegate's votes uint256 newDelegateVotes = votingPower.loadTop(newDelegate); // Store the increase in power votingPower.push(newDelegate, newDelegateVotes + userBalance); // Emit an event tracking this voting power change emit VoteChange(msg.sender, newDelegate, int256(userBalance)); } } contract LockingVault is AbstractLockingVault { /// @notice Constructs the contract by setting immutables /// @param _token The external erc20 token contract /// @param _staleBlockLag The number of blocks before the delegation history is forgotten constructor(IERC20 _token, uint256 _staleBlockLag) AbstractLockingVault(_token, _staleBlockLag) {} }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.3; interface IERC20 { function symbol() external view returns (string memory); function balanceOf(address account) external view returns (uint256); // Note this is non standard but nearly all ERC20 have exposed decimal functions function decimals() external view returns (uint8); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.3; import "./IERC20.sol"; interface ILockingVault { /// @notice Deposits and delegates voting power to an address provided with the call /// @param fundedAccount The address to credit this deposit to /// @param amount The amount of token which is deposited /// @param firstDelegation First delegation address function deposit( address fundedAccount, uint256 amount, address firstDelegation ) external; /// @notice Removes tokens from this contract and the voting power they represent /// @param amount The amount of token to withdraw function withdraw(uint256 amount) external; /// @notice The token for this locking vault function token() external returns (IERC20); /// @notice Changes a user's voting power /// @param newDelegate The new address which gets voting power function changeDelegation(address newDelegate) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.3; interface IVotingVault { /// @notice Attempts to load the voting power of a user /// @param user The address we want to load the voting power of /// @param blockNumber the block number we want the user's voting power at /// @param extraData Abi encoded optional extra data used by some vaults, such as merkle proofs /// @return the number of votes function queryVotePower( address user, uint256 blockNumber, bytes calldata extraData ) external returns (uint256); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.3; import "./Storage.sol"; // This library is an assembly optimized storage library which is designed // to track timestamp history in a struct which uses hash derived pointers. // WARNING - Developers using it should not access the underlying storage // directly since we break some assumptions of high level solidity. Please // note this library also increases the risk profile of memory manipulation // please be cautious in your usage of uninitialized memory structs and other // anti patterns. library History { // The storage layout of the historical array looks like this // [(128 bit min index)(128 bit length)] [0][0] ... [(64 bit block num)(192 bit data)] .... [(64 bit block num)(192 bit data)] // We give the option to the invoker of the search function the ability to clear // stale storage. To find data we binary search for the block number we need // This library expects the blocknumber indexed data to be pushed in ascending block number // order and if data is pushed with the same blocknumber it only retains the most recent. // This ensures each blocknumber is unique and contains the most recent data at the end // of whatever block it indexes [as long as that block is not the current one]. // A struct which wraps a memory pointer to a string and the pointer to storage // derived from that name string by the storage library // WARNING - For security purposes never directly construct this object always use load struct HistoricalBalances { string name; // Note - We use bytes32 to reduce how easy this is to manipulate in high level sol bytes32 cachedPointer; } /// @notice The method by which inheriting contracts init the HistoricalBalances struct /// @param name The name of the variable. Note - these are globals, any invocations of this /// with the same name work on the same storage. /// @return The memory pointer to the wrapper of the storage pointer function load(string memory name) internal pure returns (HistoricalBalances memory) { mapping(address => uint256[]) storage storageData = Storage.mappingAddressToUnit256ArrayPtr(name); bytes32 pointer; assembly { pointer := storageData.slot } return HistoricalBalances(name, pointer); } /// @notice An unsafe method of attaching the cached ptr in a historical balance memory objects /// @param pointer cached pointer to storage /// @return storageData A storage array mapping pointer /// @dev PLEASE DO NOT USE THIS METHOD WITHOUT SERIOUS REVIEW. IF AN EXTERNAL ACTOR CAN CALL THIS WITH // ARBITRARY DATA THEY MAY BE ABLE TO OVERWRITE ANY STORAGE IN THE CONTRACT. function _getMapping(bytes32 pointer) private pure returns (mapping(address => uint256[]) storage storageData) { assembly { storageData.slot := pointer } } /// @notice This function adds a block stamp indexed piece of data to a historical data array /// To prevent duplicate entries if the top of the array has the same blocknumber /// the value is updated instead /// @param wrapper The wrapper which hold the reference to the historical data storage pointer /// @param who The address which indexes the array we need to push to /// @param data The data to append, should be at most 192 bits and will revert if not function push( HistoricalBalances memory wrapper, address who, uint256 data ) internal { // Check preconditions // OoB = Out of Bounds, short for contract bytecode size reduction require(data <= type(uint192).max, "OoB"); // Get the storage this is referencing mapping(address => uint256[]) storage storageMapping = _getMapping(wrapper.cachedPointer); // Get the array we need to push to uint256[] storage storageData = storageMapping[who]; // We load the block number and then shift it to be in the top 64 bits uint256 blockNumber = block.number << 192; // We combine it with the data, because of our require this will have a clean // top 64 bits uint256 packedData = blockNumber | data; // Load the array length (uint256 minIndex, uint256 length) = _loadBounds(storageData); // On the first push we don't try to load uint256 loadedBlockNumber = 0; if (length != 0) { (loadedBlockNumber, ) = _loadAndUnpack(storageData, length - 1); } // The index we push to, note - we use this pattern to not branch the assembly uint256 index = length; // If the caller is changing data in the same block we change the entry for this block // instead of adding a new one. This ensures each block numb is unique in the array. if (loadedBlockNumber == block.number) { index = length - 1; } // We use assembly to write our data to the index assembly { // Stores packed data in the equivalent of storageData[length] sstore( add( // The start of the data slots add(storageData.slot, 1), // index where we store index ), packedData ) } // Reset the boundaries if they changed if (loadedBlockNumber != block.number) { _setBounds(storageData, minIndex, length + 1); } } /// @notice Loads the most recent timestamp of delegation power /// @param wrapper The memory struct which we want to search for historical data /// @param who The user who's balance we want to load /// @return the top slot of the array function loadTop(HistoricalBalances memory wrapper, address who) internal view returns (uint256) { // Load the storage pointer uint256[] storage userData = _getMapping(wrapper.cachedPointer)[who]; // Load the length (, uint256 length) = _loadBounds(userData); // If it's zero no data has ever been pushed so we return zero if (length == 0) { return 0; } // Load the current top (, uint256 storedData) = _loadAndUnpack(userData, length - 1); // and return it return (storedData); } /// @notice Finds the data stored with the highest block number which is less than or equal to a provided /// blocknumber. /// @param wrapper The memory struct which we want to search for historical data /// @param who The address which indexes the array to be searched /// @param blocknumber The blocknumber we want to load the historical data of /// @return The loaded unpacked data at this point in time. function find( HistoricalBalances memory wrapper, address who, uint256 blocknumber ) internal view returns (uint256) { // Get the storage this is referencing mapping(address => uint256[]) storage storageMapping = _getMapping(wrapper.cachedPointer); // Get the array we need to push to uint256[] storage storageData = storageMapping[who]; // Pre load the bounds (uint256 minIndex, uint256 length) = _loadBounds(storageData); // Search for the blocknumber (, uint256 loadedData) = _find(storageData, blocknumber, 0, minIndex, length); // In this function we don't have to change the stored length data return (loadedData); } /// @notice Finds the data stored with the highest blocknumber which is less than or equal to a provided block number /// Opportunistically clears any data older than staleBlock which is possible to clear. /// @param wrapper The memory struct which points to the storage we want to search /// @param who The address which indexes the historical data we want to search /// @param blocknumber The blocknumber we want to load the historical state of /// @param staleBlock A block number which we can [but are not obligated to] delete history older than /// @return The found data function findAndClear( HistoricalBalances memory wrapper, address who, uint256 blocknumber, uint256 staleBlock ) internal returns (uint256) { // Get the storage this is referencing mapping(address => uint256[]) storage storageMapping = _getMapping(wrapper.cachedPointer); // Get the array we need to push to uint256[] storage storageData = storageMapping[who]; // Pre load the bounds (uint256 minIndex, uint256 length) = _loadBounds(storageData); // Search for the blocknumber (uint256 staleIndex, uint256 loadedData) = _find(storageData, blocknumber, staleBlock, minIndex, length); // We clear any data in the stale region // Note - Since find returns 0 if no stale data is found and we use > instead of >= // this won't trigger if no stale data is found. Plus it won't trigger on minIndex == staleIndex // == maxIndex and clear the whole array. if (staleIndex > minIndex) { // Delete the outdated stored info _clear(minIndex, staleIndex, storageData); // Reset the array info with stale index as the new minIndex _setBounds(storageData, staleIndex, length); } return (loadedData); } /// @notice Searches for the data stored at the largest blocknumber index less than a provided parameter. /// Allows specification of a expiration stamp and returns the greatest examined index which is /// found to be older than that stamp. /// @param data The stored data /// @param blocknumber the blocknumber we want to load the historical data for. /// @param staleBlock The oldest block that we care about the data stored for, all previous data can be deleted /// @param startingMinIndex The smallest filled index in the array /// @param length the length of the array /// @return Returns the largest stale data index seen or 0 for no seen stale data and the stored data function _find( uint256[] storage data, uint256 blocknumber, uint256 staleBlock, uint256 startingMinIndex, uint256 length ) private view returns (uint256, uint256) { // We explicitly revert on the reading of memory which is uninitialized require(length != 0, "uninitialized"); // Do some correctness checks require(staleBlock <= blocknumber); require(startingMinIndex < length); // Load the bounds of our binary search uint256 maxIndex = length - 1; uint256 minIndex = startingMinIndex; uint256 staleIndex = 0; // We run a binary search on the block number fields in the array between // the minIndex and maxIndex. If we find indexes with blocknumber < staleBlock // we set staleIndex to them and return that data for an optional clearing step // in the calling function. while (minIndex != maxIndex) { // We use the ceil instead of the floor because this guarantees that // we pick the highest blocknumber less than or equal the requested one uint256 mid = (minIndex + maxIndex + 1) / 2; // Load and unpack the data in the midpoint index (uint256 pastBlock, uint256 loadedData) = _loadAndUnpack(data, mid); // If we've found the exact block we are looking for if (pastBlock == blocknumber) { // Then we just return the data return (staleIndex, loadedData); // Otherwise if the loaded block is smaller than the block number } else if (pastBlock < blocknumber) { // Then we first check if this is possibly a stale block if (pastBlock < staleBlock) { // If it is we mark it for clearing staleIndex = mid; } // We then repeat the search logic on the indices greater than the midpoint minIndex = mid; // In this case the pastBlock > blocknumber } else { // We then repeat the search on the indices below the midpoint maxIndex = mid - 1; } } // We load at the final index of the search (uint256 _pastBlock, uint256 _loadedData) = _loadAndUnpack(data, minIndex); // This will only be hit if a user has misconfigured the stale index and then // tried to load father into the past than has been preserved require(_pastBlock <= blocknumber, "Search Failure"); return (staleIndex, _loadedData); } /// @notice Clears storage between two bounds in array /// @param oldMin The first index to set to zero /// @param newMin The new minimum filled index, ie clears to index < newMin /// @param data The storage array pointer function _clear( uint256 oldMin, uint256 newMin, uint256[] storage data ) private { // Correctness checks on this call require(oldMin <= newMin); // This function is private and trusted and should be only called by functions which ensure // that oldMin < newMin < length assembly { // The layout of arrays in solidity is [length][data]....[data] so this pointer is the // slot to write to data let dataLocation := add(data.slot, 1) // Loop through each index which is below new min and clear the storage // Note - Uses strict min so if given an input like oldMin = 5 newMin = 5 will be a no op for { let i := oldMin } lt(i, newMin) { i := add(i, 1) } { // store at the starting data pointer + i 256 bits of zero sstore(add(dataLocation, i), 0) } } } /// @notice Loads and unpacks the block number index and stored data from a data array /// @param data the storage array /// @param i the index to load and unpack /// @return (block number, stored data) function _loadAndUnpack(uint256[] storage data, uint256 i) private view returns (uint256, uint256) { // This function is trusted and should only be called after checking data lengths // we use assembly for the sload to avoid reloading length. uint256 loaded; assembly { loaded := sload(add(add(data.slot, 1), i)) } // Unpack the packed 64 bit block number and 192 bit data field return ( loaded >> 192, loaded & 0x0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff ); } /// @notice This function sets our non standard bounds data field where a normal array /// would have length /// @param data the pointer to the storage array /// @param minIndex The minimum non stale index /// @param length The length of the storage array function _setBounds( uint256[] storage data, uint256 minIndex, uint256 length ) private { // Correctness check require(minIndex < length); assembly { // Ensure data cleanliness let clearedLength := and( length, 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff ) // We move the min index into the top 128 bits by shifting it left by 128 bits let minInd := shl(128, minIndex) // We pack the data using binary or let packed := or(minInd, clearedLength) // We store in the packed data in the length field of this storage array sstore(data.slot, packed) } } /// @notice This function loads and unpacks our packed min index and length for our custom storage array /// @param data The pointer to the storage location /// @return minInd the first filled index in the array /// @return length the length of the array function _loadBounds(uint256[] storage data) private view returns (uint256 minInd, uint256 length) { // Use assembly to manually load the length storage field uint256 packedData; assembly { packedData := sload(data.slot) } // We use a shift right to clear out the low order bits of the data field minInd = packedData >> 128; // We use a binary and to extract only the bottom 128 bits length = packedData & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.3; // This library allows for secure storage pointers across proxy implementations // It will return storage pointers based on a hashed name and type string. library Storage { // This library follows a pattern which if solidity had higher level // type or macro support would condense quite a bit. // Each basic type which does not support storage locations is encoded as // a struct of the same name capitalized and has functions 'load' and 'set' // which load the data and set the data respectively. // All types will have a function of the form 'typename'Ptr('name') -> storage ptr // which will return a storage version of the type with slot which is the hash of // the variable name and type string. This pointer allows easy state management between // upgrades and overrides the default solidity storage slot system. /// @dev The address type container struct Address { address data; } /// @notice A function which turns a variable name for a storage address into a storage /// pointer for its container. /// @param name the variable name /// @return data the storage pointer function addressPtr(string memory name) internal pure returns (Address storage data) { bytes32 typehash = keccak256("address"); bytes32 offset = keccak256(abi.encodePacked(typehash, name)); assembly { data.slot := offset } } /// @notice A function to load an address from the container struct /// @param input the storage pointer for the container /// @return the loaded address function load(Address storage input) internal view returns (address) { return input.data; } /// @notice A function to set the internal field of an address container /// @param input the storage pointer to the container /// @param to the address to set the container to function set(Address storage input, address to) internal { input.data = to; } /// @dev The uint256 type container struct Uint256 { uint256 data; } /// @notice A function which turns a variable name for a storage uint256 into a storage /// pointer for its container. /// @param name the variable name /// @return data the storage pointer function uint256Ptr(string memory name) internal pure returns (Uint256 storage data) { bytes32 typehash = keccak256("uint256"); bytes32 offset = keccak256(abi.encodePacked(typehash, name)); assembly { data.slot := offset } } /// @notice A function to load an uint256 from the container struct /// @param input the storage pointer for the container /// @return the loaded uint256 function load(Uint256 storage input) internal view returns (uint256) { return input.data; } /// @notice A function to set the internal field of a unit256 container /// @param input the storage pointer to the container /// @param to the address to set the container to function set(Uint256 storage input, uint256 to) internal { input.data = to; } /// @notice Returns the storage pointer for a named mapping of address to uint256 /// @param name the variable name for the pointer /// @return data the mapping pointer function mappingAddressToUnit256Ptr(string memory name) internal pure returns (mapping(address => uint256) storage data) { bytes32 typehash = keccak256("mapping(address => uint256)"); bytes32 offset = keccak256(abi.encodePacked(typehash, name)); assembly { data.slot := offset } } /// @notice Returns the storage pointer for a named mapping of address to uint256[] /// @param name the variable name for the pointer /// @return data the mapping pointer function mappingAddressToUnit256ArrayPtr(string memory name) internal pure returns (mapping(address => uint256[]) storage data) { bytes32 typehash = keccak256("mapping(address => uint256[])"); bytes32 offset = keccak256(abi.encodePacked(typehash, name)); assembly { data.slot := offset } } /// @notice Allows external users to calculate the slot given by this lib /// @param typeString the string which encodes the type /// @param name the variable name /// @return the slot assigned by this lib function getPtr(string memory typeString, string memory name) external pure returns (uint256) { bytes32 typehash = keccak256(abi.encodePacked(typeString)); bytes32 offset = keccak256(abi.encodePacked(typehash, name)); return (uint256)(offset); } // A struct which represents 1 packed storage location with a compressed // address and uint96 pair struct AddressUint { address who; uint96 amount; } /// @notice Returns the storage pointer for a named mapping of address to uint256[] /// @param name the variable name for the pointer /// @return data the mapping pointer function mappingAddressToPackedAddressUint(string memory name) internal pure returns (mapping(address => AddressUint) storage data) { bytes32 typehash = keccak256("mapping(address => AddressUint)"); bytes32 offset = keccak256(abi.encodePacked(typehash, name)); assembly { data.slot := offset } } }
{ "optimizer": { "enabled": true, "runs": 7500 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint256","name":"_staleBlockLag","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"}],"name":"VoteChange","type":"event"},{"inputs":[{"internalType":"address","name":"newDelegate","type":"address"}],"name":"changeDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fundedAccount","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"firstDelegation","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"deposits","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"queryVotePower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"queryVotePowerView","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"staleBlockLag","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c060405234801561001057600080fd5b5060405161144d38038061144d83398101604081905261002f9161004a565b60609190911b6001600160601b03191660805260a052610082565b6000806040838503121561005c578182fd5b82516001600160a01b0381168114610072578283fd5b6020939093015192949293505050565b60805160601c60a05161138f6100be6000396000818160ba015261059d01526000818161012d015281816103300152610692015261138f6000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063e91f32351161005b578063e91f323514610102578063f45346dc14610115578063fc0c546a14610128578063fc7e286d1461017457610088565b80632e1a7d4d1461008d5780639f973fd5146100a2578063c2c94b88146100b5578063e7d20283146100ef575b600080fd5b6100a061009b366004611150565b6101c0565b005b6100a06100b0366004611029565b6103c9565b6100dc7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b6100dc6100fd36600461104a565b610564565b6100dc6101103660046110ae565b610586565b6100a0610123366004611073565b6105d5565b61014f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e6565b610187610182366004611029565b61090f565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff9091166020830152016100e6565b60006101ca610976565b336000908152602091909152604090208054909150829082906014906102179084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff166112fd565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550805473ffffffffffffffffffffffffffffffffffffffff1660006102616109bb565b9050600061026f8284610a0e565b90506102878361027f87846112e6565b849190610aaf565b73ffffffffffffffffffffffffffffffffffffffff8316337f33161cf2da28d747be9df136b6f3729390298494947268743193c53d73d3c2e06102ea887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61122e565b60405190815260200160405180910390a36040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb90604401602060405180830381600087803b15801561038957600080fd5b505af115801561039d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103c19190611130565b505050505050565b60006103d3610976565b33600090815260209190915260408120805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff000000000000000000000000000000000000000083161783559193506bffffffffffffffffffffffff74010000000000000000000000000000000000000000820416929116906104586109bb565b905060006104668284610a0e565b90506104768361027f86846112e6565b73ffffffffffffffffffffffffffffffffffffffff8316337f33161cf2da28d747be9df136b6f3729390298494947268743193c53d73d3c2e06104d9877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61122e565b60405190815260200160405180910390a360006104f68388610a0e565b905061050e8761050687846111ad565b859190610aaf565b60405185815273ffffffffffffffffffffffffffffffffffffffff88169033907f33161cf2da28d747be9df136b6f3729390298494947268743193c53d73d3c2e09060200160405180910390a350505050505050565b60008061056f6109bb565b905061057c818585610bee565b9150505b92915050565b6000806105916109bb565b90506105cb86866105c27f0000000000000000000000000000000000000000000000000000000000000000436112e6565b84929190610c5d565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116610657576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5a65726f20616464722064656c65676174696f6e00000000000000000000000060448201526064015b60405180910390fd5b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401602060405180830381600087803b1580156106eb57600080fd5b505af11580156106ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107239190611130565b50600061072e610976565b73ffffffffffffffffffffffffffffffffffffffff808616600090815260209290925260409091208054909250168061080e575080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316178082558290849083906014906107db9084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff166111c5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610877565b8154849083906014906108489084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff166111c5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b60006108816109bb565b9050600061088f8284610a0e565b90508273ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f33161cf2da28d747be9df136b6f3729390298494947268743193c53d73d3c2e0886040516108f091815260200190565b60405180910390a36109068361027f88846111ad565b50505050505050565b600080600061091c610976565b73ffffffffffffffffffffffffffffffffffffffff9485166000908152602091909152604090205493841694740100000000000000000000000000000000000000009094046bffffffffffffffffffffffff169392505050565b60006109b66040518060400160405280600881526020017f6465706f73697473000000000000000000000000000000000000000000000000815250610ce1565b905090565b6040805180820190915260608152600060208201526109b66040518060400160405280600b81526020017f766f74696e67506f776572000000000000000000000000000000000000000000815250610d5a565b600080610a1c846020015190565b73ffffffffffffffffffffffffffffffffffffffff841660009081526020919091526040902080549091506fffffffffffffffffffffffffffffffff1680610a6957600092505050610580565b6000610aa483610a7a6001856112e6565b016001015460c081901c9177ffffffffffffffffffffffffffffffffffffffffffffffff90911690565b979650505050505050565b77ffffffffffffffffffffffffffffffffffffffffffffffff811115610b31576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f4f6f420000000000000000000000000000000000000000000000000000000000604482015260640161064e565b6000610b3e846020015190565b73ffffffffffffffffffffffffffffffffffffffff841660009081526020829052604081208054929350914360c01b9185831791608081901c916fffffffffffffffffffffffffffffffff909116908115610ba657610ba286610a7a6001856112e6565b5090505b8143821415610bbd57610bba6001846112e6565b90505b8481600189010155438214610be157610be18785610bdc8660016111ad565b610d98565b5050505050505050505050565b600080610bfc856020015190565b73ffffffffffffffffffffffffffffffffffffffff85166000908152602082905260408120805492935091608081901c916fffffffffffffffffffffffffffffffff90911690610c4f8488838686610dc1565b9a9950505050505050505050565b600080610c6b866020015190565b73ffffffffffffffffffffffffffffffffffffffff86166000908152602082905260408120805492935091608081901c916fffffffffffffffffffffffffffffffff9091169080610cbf858a8a8787610dc1565b9150915083821115610c4f57610cd6848387610f9a565b610c4f858385610d98565b6000807f03a912cdb153207069d92d44a2357e3f0ce00f7ee84da3510f1c6851b4cac4ee905060008184604051602001610d1c929190611168565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120949350505050565b6040805180820190915260608152600060208201526000610d7a83610fca565b6040805180820190915284815260208101919091529150505b919050565b808210610da457600080fd5b6fffffffffffffffffffffffffffffffff1660809190911b179055565b60008082610e2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f756e696e697469616c697a656400000000000000000000000000000000000000604482015260640161064e565b85851115610e3857600080fd5b828410610e4457600080fd5b6000610e516001856112e6565b90508460005b828214610ef55760006002610e6c85856111ad565b610e779060016111ad565b610e8191906111f5565b6001818d01015490915060c081901c9077ffffffffffffffffffffffffffffffffffffffffffffffff168b821415610ec357929650919450610f909350505050565b8b821015610edf578a821015610ed7578293505b829450610eed565b610eea6001846112e6565b95505b505050610e57565b60018a8301015460c081901c9077ffffffffffffffffffffffffffffffffffffffffffffffff168a821115610f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f536561726368204661696c757265000000000000000000000000000000000000604482015260640161064e565b9195509093505050505b9550959350505050565b81831115610fa757600080fd5b60018101835b83811015610fc357600082820155600101610fad565b5050505050565b6000807f7b1a68ec3e3284b167e69db1c622dcfa612281976b71d7e2d239dbe16a75891a905060008184604051602001610d1c929190611168565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d9357600080fd5b60006020828403121561103a578081fd5b61104382611005565b9392505050565b6000806040838503121561105c578081fd5b61106583611005565b946020939093013593505050565b600080600060608486031215611087578081fd5b61109084611005565b9250602084013591506110a560408501611005565b90509250925092565b600080600080606085870312156110c3578081fd5b6110cc85611005565b935060208501359250604085013567ffffffffffffffff808211156110ef578283fd5b818701915087601f830112611102578283fd5b813581811115611110578384fd5b886020828501011115611121578384fd5b95989497505060200194505050565b600060208284031215611141578081fd5b81518015158114611043578182fd5b600060208284031215611161578081fd5b5035919050565b60008382528251815b8181101561118d57602081860181015185830182015201611171565b8181111561119e5782602083860101525b50919091016020019392505050565b600082198211156111c0576111c061132a565b500190565b60006bffffffffffffffffffffffff8083168185168083038211156111ec576111ec61132a565b01949350505050565b600082611229577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8184138284138583048511828216161561126d5761126d61132a565b7f8000000000000000000000000000000000000000000000000000000000000000848712868205881281841616156112a7576112a761132a565b8587129250878205871284841616156112c2576112c261132a565b878505871281841616156112d8576112d861132a565b505050929093029392505050565b6000828210156112f8576112f861132a565b500390565b60006bffffffffffffffffffffffff838116908316818110156113225761132261132a565b039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea264697066735822122031efbbc9dfc48d14a1cb376d2e16e00eb9e63ab249a99197bf8b7b3c6133c51064736f6c634300080300330000000000000000000000005c6d51ecba4d8e4f20373e3ce96a62342b125d6d0000000000000000000000000000000000000000000000000000000000030d40
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063e91f32351161005b578063e91f323514610102578063f45346dc14610115578063fc0c546a14610128578063fc7e286d1461017457610088565b80632e1a7d4d1461008d5780639f973fd5146100a2578063c2c94b88146100b5578063e7d20283146100ef575b600080fd5b6100a061009b366004611150565b6101c0565b005b6100a06100b0366004611029565b6103c9565b6100dc7f0000000000000000000000000000000000000000000000000000000000030d4081565b6040519081526020015b60405180910390f35b6100dc6100fd36600461104a565b610564565b6100dc6101103660046110ae565b610586565b6100a0610123366004611073565b6105d5565b61014f7f0000000000000000000000005c6d51ecba4d8e4f20373e3ce96a62342b125d6d81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e6565b610187610182366004611029565b61090f565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff9091166020830152016100e6565b60006101ca610976565b336000908152602091909152604090208054909150829082906014906102179084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff166112fd565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550805473ffffffffffffffffffffffffffffffffffffffff1660006102616109bb565b9050600061026f8284610a0e565b90506102878361027f87846112e6565b849190610aaf565b73ffffffffffffffffffffffffffffffffffffffff8316337f33161cf2da28d747be9df136b6f3729390298494947268743193c53d73d3c2e06102ea887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61122e565b60405190815260200160405180910390a36040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f0000000000000000000000005c6d51ecba4d8e4f20373e3ce96a62342b125d6d73ffffffffffffffffffffffffffffffffffffffff169063a9059cbb90604401602060405180830381600087803b15801561038957600080fd5b505af115801561039d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103c19190611130565b505050505050565b60006103d3610976565b33600090815260209190915260408120805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff000000000000000000000000000000000000000083161783559193506bffffffffffffffffffffffff74010000000000000000000000000000000000000000820416929116906104586109bb565b905060006104668284610a0e565b90506104768361027f86846112e6565b73ffffffffffffffffffffffffffffffffffffffff8316337f33161cf2da28d747be9df136b6f3729390298494947268743193c53d73d3c2e06104d9877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61122e565b60405190815260200160405180910390a360006104f68388610a0e565b905061050e8761050687846111ad565b859190610aaf565b60405185815273ffffffffffffffffffffffffffffffffffffffff88169033907f33161cf2da28d747be9df136b6f3729390298494947268743193c53d73d3c2e09060200160405180910390a350505050505050565b60008061056f6109bb565b905061057c818585610bee565b9150505b92915050565b6000806105916109bb565b90506105cb86866105c27f0000000000000000000000000000000000000000000000000000000000030d40436112e6565b84929190610c5d565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116610657576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5a65726f20616464722064656c65676174696f6e00000000000000000000000060448201526064015b60405180910390fd5b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390527f0000000000000000000000005c6d51ecba4d8e4f20373e3ce96a62342b125d6d73ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401602060405180830381600087803b1580156106eb57600080fd5b505af11580156106ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107239190611130565b50600061072e610976565b73ffffffffffffffffffffffffffffffffffffffff808616600090815260209290925260409091208054909250168061080e575080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316178082558290849083906014906107db9084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff166111c5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610877565b8154849083906014906108489084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff166111c5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b60006108816109bb565b9050600061088f8284610a0e565b90508273ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f33161cf2da28d747be9df136b6f3729390298494947268743193c53d73d3c2e0886040516108f091815260200190565b60405180910390a36109068361027f88846111ad565b50505050505050565b600080600061091c610976565b73ffffffffffffffffffffffffffffffffffffffff9485166000908152602091909152604090205493841694740100000000000000000000000000000000000000009094046bffffffffffffffffffffffff169392505050565b60006109b66040518060400160405280600881526020017f6465706f73697473000000000000000000000000000000000000000000000000815250610ce1565b905090565b6040805180820190915260608152600060208201526109b66040518060400160405280600b81526020017f766f74696e67506f776572000000000000000000000000000000000000000000815250610d5a565b600080610a1c846020015190565b73ffffffffffffffffffffffffffffffffffffffff841660009081526020919091526040902080549091506fffffffffffffffffffffffffffffffff1680610a6957600092505050610580565b6000610aa483610a7a6001856112e6565b016001015460c081901c9177ffffffffffffffffffffffffffffffffffffffffffffffff90911690565b979650505050505050565b77ffffffffffffffffffffffffffffffffffffffffffffffff811115610b31576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f4f6f420000000000000000000000000000000000000000000000000000000000604482015260640161064e565b6000610b3e846020015190565b73ffffffffffffffffffffffffffffffffffffffff841660009081526020829052604081208054929350914360c01b9185831791608081901c916fffffffffffffffffffffffffffffffff909116908115610ba657610ba286610a7a6001856112e6565b5090505b8143821415610bbd57610bba6001846112e6565b90505b8481600189010155438214610be157610be18785610bdc8660016111ad565b610d98565b5050505050505050505050565b600080610bfc856020015190565b73ffffffffffffffffffffffffffffffffffffffff85166000908152602082905260408120805492935091608081901c916fffffffffffffffffffffffffffffffff90911690610c4f8488838686610dc1565b9a9950505050505050505050565b600080610c6b866020015190565b73ffffffffffffffffffffffffffffffffffffffff86166000908152602082905260408120805492935091608081901c916fffffffffffffffffffffffffffffffff9091169080610cbf858a8a8787610dc1565b9150915083821115610c4f57610cd6848387610f9a565b610c4f858385610d98565b6000807f03a912cdb153207069d92d44a2357e3f0ce00f7ee84da3510f1c6851b4cac4ee905060008184604051602001610d1c929190611168565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120949350505050565b6040805180820190915260608152600060208201526000610d7a83610fca565b6040805180820190915284815260208101919091529150505b919050565b808210610da457600080fd5b6fffffffffffffffffffffffffffffffff1660809190911b179055565b60008082610e2b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f756e696e697469616c697a656400000000000000000000000000000000000000604482015260640161064e565b85851115610e3857600080fd5b828410610e4457600080fd5b6000610e516001856112e6565b90508460005b828214610ef55760006002610e6c85856111ad565b610e779060016111ad565b610e8191906111f5565b6001818d01015490915060c081901c9077ffffffffffffffffffffffffffffffffffffffffffffffff168b821415610ec357929650919450610f909350505050565b8b821015610edf578a821015610ed7578293505b829450610eed565b610eea6001846112e6565b95505b505050610e57565b60018a8301015460c081901c9077ffffffffffffffffffffffffffffffffffffffffffffffff168a821115610f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f536561726368204661696c757265000000000000000000000000000000000000604482015260640161064e565b9195509093505050505b9550959350505050565b81831115610fa757600080fd5b60018101835b83811015610fc357600082820155600101610fad565b5050505050565b6000807f7b1a68ec3e3284b167e69db1c622dcfa612281976b71d7e2d239dbe16a75891a905060008184604051602001610d1c929190611168565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d9357600080fd5b60006020828403121561103a578081fd5b61104382611005565b9392505050565b6000806040838503121561105c578081fd5b61106583611005565b946020939093013593505050565b600080600060608486031215611087578081fd5b61109084611005565b9250602084013591506110a560408501611005565b90509250925092565b600080600080606085870312156110c3578081fd5b6110cc85611005565b935060208501359250604085013567ffffffffffffffff808211156110ef578283fd5b818701915087601f830112611102578283fd5b813581811115611110578384fd5b886020828501011115611121578384fd5b95989497505060200194505050565b600060208284031215611141578081fd5b81518015158114611043578182fd5b600060208284031215611161578081fd5b5035919050565b60008382528251815b8181101561118d57602081860181015185830182015201611171565b8181111561119e5782602083860101525b50919091016020019392505050565b600082198211156111c0576111c061132a565b500190565b60006bffffffffffffffffffffffff8083168185168083038211156111ec576111ec61132a565b01949350505050565b600082611229577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8184138284138583048511828216161561126d5761126d61132a565b7f8000000000000000000000000000000000000000000000000000000000000000848712868205881281841616156112a7576112a761132a565b8587129250878205871284841616156112c2576112c261132a565b878505871281841616156112d8576112d861132a565b505050929093029392505050565b6000828210156112f8576112f861132a565b500390565b60006bffffffffffffffffffffffff838116908316818110156113225761132261132a565b039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea264697066735822122031efbbc9dfc48d14a1cb376d2e16e00eb9e63ab249a99197bf8b7b3c6133c51064736f6c63430008030033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005c6d51ecba4d8e4f20373e3ce96a62342b125d6d0000000000000000000000000000000000000000000000000000000000030d40
-----Decoded View---------------
Arg [0] : _token (address): 0x5c6D51ecBA4D8E4F20373e3ce96a62342B125D6d
Arg [1] : _staleBlockLag (uint256): 200000
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000005c6d51ecba4d8e4f20373e3ce96a62342b125d6d
Arg [1] : 0000000000000000000000000000000000000000000000000000000000030d40
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.