Overview
ETH Balance
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
12871213 | 140 days ago | 0 ETH | ||||
12871184 | 140 days ago | 0 ETH | ||||
12871184 | 140 days ago | 0 ETH | ||||
12871184 | 140 days ago | 0 ETH | ||||
12870966 | 140 days ago | 0 ETH | ||||
12870909 | 140 days ago | 0 ETH | ||||
12870907 | 140 days ago | 0 ETH | ||||
12870292 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH | ||||
12869945 | 140 days ago | 0 ETH |
Loading...
Loading
Contract Name:
EscrowDelegateCheckpoints
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import {SafeCastLibrary} from "../libraries/SafeCastLibrary.sol"; import {Checkpoints} from "../libraries/Checkpoints.sol"; import {Time} from "../libraries/Time.sol"; /** * @title CheckPointSystem * @dev This contract is used to manage checkpoints in the system. */ library EscrowDelegateCheckpoints { using Checkpoints for Checkpoints.Trace; using Checkpoints for Checkpoints.TraceAddress; using SafeCastLibrary for int128; using SafeCastLibrary for uint256; /// @notice Maximum time for a checkpoint int128 public constant MAX_TIME = 2 * 365 * 86400; /// @notice Unit of time for the clock uint48 public constant CLOCK_UNIT = 7 days; struct EscrowDelegateStore { /// @notice Global checkpoints Checkpoints.Trace _globalCheckpoints; /// @notice Mapping of global slope changes /// @dev Intended to be exposed with a getter mapping(uint256 => int128) globalSlopeChanges; /// @notice escrow lock checkpoints mapping(uint256 => Checkpoints.Trace) _escrowCheckpoints; /// @notice Delegate checkpoints mapping(address => Checkpoints.Trace) _delegateCheckpoints; /// @notice escrow lock to delegatee mapping mapping(uint256 => Checkpoints.TraceAddress) _escrowDelegateeAddress; /// @notice Delegatee slope changes /// @dev Intended to be exposed with a getter mapping(address => mapping(uint256 => int128)) delegateeSlopeChanges; } event CheckpointGlobal(uint48 timestamp, int128 slope, int128 bias, int128 permanent); event CheckpointDelegate(address delegatee, uint48 timestamp, int128 slope, int128 bias, int128 permanent); event CheckpointEscrow(uint256 escrowId, uint48 timestamp, int128 slope, int128 bias, int128 permanent); /** * @notice Clock used for flagging checkpoints. * @return Current timestamp */ function clock() public view returns (uint48) { return Time.timestamp(); } /** * @notice Clock used for flagging global checkpoints. * @return Current timestamp rounded to the nearest clock unit */ function globalClock() public view returns (uint48) { return toGlobalClock(Time.timestamp()); } /** * @notice Converts a timestamp to a global clock value. * @param timestamp The timestamp to convert * @return The converted global clock value */ function toGlobalClock(uint256 timestamp) internal pure returns (uint48) { return uint48((timestamp / CLOCK_UNIT) * CLOCK_UNIT); } /** * @dev Record global and per-escrow data to checkpoints. Used by VotingEscrow system. * @param store_ The EscrowDelegateStore struct containing all the storage mappings. * @param escrowId NFT escrow lock ID. No escrow checkpoint if 0 * @param uOldAmount Locked amount from last checkpoint * @param uNewAmount Locked amount from current checkpoint * @param uOldEndTime Last checkpoint time * @param uNewEndTime Current checkpoint time */ function checkpoint( EscrowDelegateStore storage store_, uint256 escrowId, int128 uOldAmount, int128 uNewAmount, uint256 uOldEndTime, uint256 uNewEndTime ) external { int128 oldDslope = 0; int128 newDslope = 0; Checkpoints.Point memory uOldPoint = Checkpoints.blankPoint(); Checkpoints.Point memory uNewPoint = Checkpoints.blankPoint(); /// @notice if this is not rounded to CLOCK_UNIT /// the system will not be able to go too long without checkpoints uNewEndTime = toGlobalClock(uNewEndTime); if (escrowId != 0) { // Calculate slopes and biases // Kept at zero when they have to uNewPoint.permanent = uNewEndTime == 0 ? uNewAmount : int128(0); uOldPoint.permanent = uOldEndTime == 0 ? uOldAmount : int128(0); if (uOldEndTime > block.timestamp && uOldAmount > 0) { /// @dev Calculate the slope based on the older checkpoint amount uOldPoint.slope = (uOldAmount) / MAX_TIME; uOldPoint.bias = (uOldPoint.slope * (uOldEndTime - block.timestamp).toInt128()); } if (uNewEndTime > block.timestamp && uNewAmount > 0) { uNewPoint.slope = (uNewAmount) / MAX_TIME; uNewPoint.bias = (uNewPoint.slope * (uNewEndTime - block.timestamp).toInt128()); } oldDslope = store_.globalSlopeChanges[uOldEndTime]; if (uNewEndTime != 0) { if (uNewEndTime == uOldEndTime) { newDslope = oldDslope; } else { newDslope = store_.globalSlopeChanges[uNewEndTime]; } } // Schedule the slope changes (slope is going down) // We subtract new escrow slope from [_newLocked.endTime] // and add old_escrow_slope to [_oldLocked.end] if (uOldEndTime > block.timestamp) { // oldDslope was <something> - uOld.slope, so we cancel that oldDslope += uOldPoint.slope; if (uOldEndTime == uNewEndTime) { oldDslope -= uNewPoint.slope; // It was a new deposit, not extension } store_.globalSlopeChanges[uOldEndTime] = oldDslope; } if (uNewEndTime > block.timestamp) { // update slope if new lock is greater than old lock and is not permanent or if old lock is permanent if ((uNewEndTime > uOldEndTime)) { newDslope -= uNewPoint.slope; // old slope disappeared at this point store_.globalSlopeChanges[uNewEndTime] = newDslope; } // else: we recorded it already in oldDslope } /// @dev Add the new point to the escrowId Checkpoints.Trace _pushPointAtClock(store_._escrowCheckpoints[escrowId], uNewPoint); emit CheckpointEscrow(escrowId, clock(), uNewPoint.slope, uNewPoint.bias, uNewPoint.permanent); (, uint48 delegateTs, address delegateeAddress) = store_ ._escrowDelegateeAddress[escrowId] .latestCheckpoint(); if (delegateTs != 0) { /// @notice this can likely be handled more efficiently _checkpointDelegatee(store_, delegateeAddress, uOldPoint, uOldEndTime, false); _checkpointDelegatee(store_, delegateeAddress, uNewPoint, uNewEndTime, true); } } /// @dev If escrowId is 0, this will still create a global checkpoint globalCheckpoint(store_, escrowId, uOldPoint, uNewPoint); } /** * @dev Function to update global checkpoint */ function globalCheckpoint(EscrowDelegateStore storage store_) external { globalCheckpoint(store_, 0, Checkpoints.blankPoint(), Checkpoints.blankPoint()); } /** * @dev Function to update global checkpoint with new points * @param escrowId The ID of the escrow lock * - If * @param uOldPoint The old point to be updated * @param uNewPoint The new point to be updated */ function globalCheckpoint( EscrowDelegateStore storage store_, uint256 escrowId, Checkpoints.Point memory uOldPoint, Checkpoints.Point memory uNewPoint ) public { (, uint48 lastPoint, Checkpoints.Point memory lastGlobal) = store_._globalCheckpoints.latestCheckpoint(); uint48 lastCheckpoint = lastPoint != 0 ? lastPoint : uint48(block.timestamp); { // Go over weeks to fill history and calculate what the current point is uint48 testTime = toGlobalClock(lastCheckpoint); /// @dev lastCheckpoint > tesTime uint256 maxTime = testTime + MAX_TIME.toUint256(); while (testTime < block.timestamp) { testTime += CLOCK_UNIT; int128 dSlope = 0; if (testTime > block.timestamp) { testTime = block.timestamp.toUint48(); } else { dSlope = store_.globalSlopeChanges[testTime]; } if (dSlope != 0) { lastGlobal.bias -= lastGlobal.slope * uint256(testTime - lastCheckpoint).toInt128(); lastGlobal.slope += dSlope; if (lastGlobal.bias < 0) { lastGlobal.bias = 0; } if (lastGlobal.slope < 0) { lastGlobal.slope = 0; } lastCheckpoint = testTime; store_._globalCheckpoints.push(lastCheckpoint, lastGlobal); } if (testTime > maxTime) break; } } if (escrowId != 0) { lastGlobal.bias = lastGlobal.bias - ((lastGlobal.slope * (block.timestamp - lastCheckpoint).toInt128())); lastGlobal.slope += uNewPoint.slope - uOldPoint.slope; lastGlobal.bias += uNewPoint.bias - uOldPoint.bias; lastGlobal.permanent += uNewPoint.permanent - uOldPoint.permanent; } else { // Initial value of testTime is always larger than the ts of the last point uint256 testTime = block.timestamp; lastGlobal.bias -= (lastGlobal.slope * (testTime - lastCheckpoint).toInt128()); } _pushPointAtClock(store_._globalCheckpoints, lastGlobal); emit CheckpointGlobal(clock(), lastGlobal.slope, lastGlobal.bias, lastGlobal.permanent); } /** * @dev Function to calculate total voting power at some point in the past * @param _delegateeAddress The address of the delegatee * @param timestamp Time to calculate the total voting power at * @return Total voting power at that time */ function getAdjustedVotes( EscrowDelegateStore storage store_, address _delegateeAddress, uint48 timestamp ) external view returns (uint256) { Checkpoints.Point memory lastPoint = _getAdjustedVotesCheckpoint(store_, _delegateeAddress, timestamp); return (lastPoint.bias + lastPoint.permanent).toUint256(); } /** * @dev Function to get delegated votes checkpoint at some point in the past * @param _delegateeAddress The address of the delegatee * @param timestamp Time to calculate the total voting power at * @return Total voting power at that time */ function _getAdjustedVotesCheckpoint( EscrowDelegateStore storage store_, address _delegateeAddress, uint48 timestamp ) internal view returns (Checkpoints.Point memory) { (bool exists, uint48 lastCheckpointTs, Checkpoints.Point memory lastPoint) = store_ ._delegateCheckpoints[_delegateeAddress] .upperLookupRecent(timestamp); if (!exists) return lastPoint; uint48 testTime = toGlobalClock(lastCheckpointTs); /// @dev lastCheckpointTs > tesTime uint256 maxTime = testTime + MAX_TIME.toUint256(); while (testTime < timestamp) { testTime += CLOCK_UNIT; int128 dSlope = 0; if (testTime > timestamp) { testTime = timestamp; } else { dSlope = store_.delegateeSlopeChanges[_delegateeAddress][testTime]; } if (dSlope != 0) { lastPoint.bias -= lastPoint.slope * uint256(testTime - lastCheckpointTs).toInt128(); lastPoint.slope += dSlope; if (lastPoint.bias < 0) { lastPoint.bias = 0; } if (lastPoint.slope < 0) { lastPoint.slope = 0; } lastCheckpointTs = uint48(testTime); } if (testTime > maxTime) break; } int128 change = lastPoint.slope * uint256(timestamp - lastCheckpointTs).toInt128(); lastPoint.bias = lastPoint.bias < change ? int128(0) : lastPoint.bias - change; return lastPoint; } /** * @notice Public function to get the delegatee of an escrow lock * @param escrowId The ID of the escrow * @return The address of the delegate */ function getEscrowDelegatee(EscrowDelegateStore storage store_, uint256 escrowId) external view returns (address) { return getEscrowDelegateeAtTime(store_, escrowId, block.timestamp.toUint48()); } /** * @notice Public function to get the delegatee of an escrow lock * @param escrowId The ID of the escrow lock * @param timestamp The timestamp to get the delegate at * @return The address of the delegate */ function getEscrowDelegateeAtTime( EscrowDelegateStore storage store_, uint256 escrowId, uint48 timestamp ) public view returns (address) { return store_._escrowDelegateeAddress[escrowId].upperLookupRecent(timestamp); } /** * @dev Function to record escrow delegation checkpoints. Used by voting system. * @param escrowId The ID of the escrow lock * @param delegatee The address of the delegatee * @param endTime The end time of the delegation */ function delegate( EscrowDelegateStore storage store_, uint256 escrowId, address delegatee, uint256 endTime ) external returns (address oldDelegatee, address newDelegatee) { oldDelegatee = store_._escrowDelegateeAddress[escrowId].latest(); if (oldDelegatee == delegatee) return (oldDelegatee, delegatee); (, uint48 ts, Checkpoints.Point memory lastPoint) = store_._escrowCheckpoints[escrowId].latestCheckpoint(); lastPoint.bias -= ((lastPoint.slope * (block.timestamp - ts).toInt128())); if (lastPoint.bias < 0) { lastPoint.bias = 0; } if (oldDelegatee != delegatee && oldDelegatee != address(0)) { _checkpointDelegatee(store_, oldDelegatee, lastPoint, endTime, false); } // Delegate to new delegator _checkpointDelegatee(store_, delegatee, lastPoint, endTime, true); _pushAddressAtClock(store_._escrowDelegateeAddress[escrowId], delegatee); return (oldDelegatee, delegatee); } /** * @dev Function to update delegatee's `delegatedBalance` by `balance`. * Only updates if delegating to a new delegatee. * @param delegateeAddress The address of the delegatee * @param escrowPoint The point of the escrow * @param endTime The end time of the delegation * @param increase Whether to increase or decrease the balance */ function _checkpointDelegatee( EscrowDelegateStore storage store_, address delegateeAddress, Checkpoints.Point memory escrowPoint, uint256 endTime, bool increase ) internal { (Checkpoints.Point memory lastPoint, uint48 lastCheckpoint) = baseCheckpointDelegatee(store_, delegateeAddress); int128 baseBias = lastPoint.bias - (lastPoint.slope * (block.timestamp - lastCheckpoint).toInt128()); if (!increase) { if (endTime > block.timestamp) { store_.delegateeSlopeChanges[delegateeAddress][endTime] += escrowPoint.slope; lastPoint.slope = escrowPoint.slope < lastPoint.slope ? lastPoint.slope - escrowPoint.slope : int128(0); } lastPoint.bias = escrowPoint.bias < baseBias ? baseBias - escrowPoint.bias : int128(0); lastPoint.permanent = escrowPoint.permanent < lastPoint.permanent ? lastPoint.permanent - escrowPoint.permanent : int128(0); } else { if (endTime > block.timestamp) { store_.delegateeSlopeChanges[delegateeAddress][endTime] -= escrowPoint.slope; lastPoint.slope = lastPoint.slope + escrowPoint.slope; } lastPoint.bias = baseBias + escrowPoint.bias; lastPoint.permanent = lastPoint.permanent + escrowPoint.permanent; } /// @dev bias can be rounded up by lack of precision. If slope is 0 we are out if (lastPoint.slope == 0) { lastPoint.bias = 0; } _pushPointAtClock(store_._delegateCheckpoints[delegateeAddress], lastPoint); emit CheckpointDelegate(delegateeAddress, clock(), lastPoint.slope, lastPoint.bias, lastPoint.permanent); } /** * @dev Function to update delegatee's checkpoint * @param delegateeAddress The address of the delegatee * @return lastPoint The last point of the delegatee * @return lastCheckpoint The last checkpoint time of the delegatee */ function baseCheckpointDelegatee( EscrowDelegateStore storage store_, address delegateeAddress ) public returns (Checkpoints.Point memory lastPoint, uint48 lastCheckpoint) { (bool exists, uint48 ts, Checkpoints.Point memory point) = store_ ._delegateCheckpoints[delegateeAddress] .latestCheckpoint(); lastPoint = point; lastCheckpoint = ts; if (exists) { // Go over days to fill history and calculate what the current point is uint48 testTime = toGlobalClock(lastCheckpoint); /// @dev lastCheckpoint > tesTime uint256 maxTime = testTime + MAX_TIME.toUint256(); // Iterate over time until current block timestamp or maxtime while (testTime < block.timestamp) { testTime += CLOCK_UNIT; int128 dSlope = 0; if (testTime > block.timestamp) { testTime = uint48(block.timestamp); } else { dSlope = store_.delegateeSlopeChanges[delegateeAddress][testTime]; } if (dSlope != 0) { lastPoint.bias -= lastPoint.slope * uint256(testTime - lastCheckpoint).toInt128(); lastPoint.slope += dSlope; if (lastPoint.bias < 0) { lastPoint.bias = 0; } if (lastPoint.slope < 0) { lastPoint.slope = 0; } lastCheckpoint = uint48(testTime); store_._delegateCheckpoints[delegateeAddress].push(lastCheckpoint, lastPoint); } if (testTime > maxTime) break; } } emit CheckpointDelegate(delegateeAddress, clock(), lastPoint.slope, lastPoint.bias, lastPoint.permanent); } /** * @dev Function to calculate total voting power at some point in the past * @param timestamp Time to calculate the total voting power at * @return Total voting power at that time */ function getAdjustedGlobalVotes( EscrowDelegateStore storage store_, uint48 timestamp ) external view returns (uint256) { Checkpoints.Point memory lastPoint = _getAdjustedCheckpoint(store_, timestamp); return (lastPoint.bias + lastPoint.permanent).toUint256(); } /** * @dev Function to get latest checkpoint of some point in the past * @param timestamp Time to calculate the total voting power at * @return Total voting power at that time */ function _getAdjustedCheckpoint( EscrowDelegateStore storage store_, uint48 timestamp ) internal view returns (Checkpoints.Point memory) { uint48 clockTime = timestamp; (bool exists, uint48 lastCheckpointTs, Checkpoints.Point memory lastGlobal) = store_ ._globalCheckpoints .upperLookupRecent(clockTime); if (!exists) return lastGlobal; uint48 testTime = toGlobalClock(lastCheckpointTs); /// @dev lastCheckpointTs > tesTime uint256 maxTime = testTime + MAX_TIME.toUint256(); // Iterate over time until the specified timestamp or maxtime is reached while (testTime < timestamp) { testTime += CLOCK_UNIT; int128 dSlope = 0; if (testTime > timestamp) { testTime = timestamp; } else { dSlope = store_.globalSlopeChanges[testTime]; } if (dSlope != 0) { lastGlobal.bias -= lastGlobal.slope * uint256(testTime - lastCheckpointTs).toInt128(); lastGlobal.slope += dSlope; if (lastGlobal.bias < 0) { lastGlobal.bias = 0; } if (lastGlobal.slope < 0) { lastGlobal.slope = 0; } lastCheckpointTs = uint48(testTime); } if (testTime > maxTime) break; } int128 change = lastGlobal.slope * uint256(clockTime - lastCheckpointTs).toInt128(); lastGlobal.bias = lastGlobal.bias < change ? int128(0) : lastGlobal.bias - change; return lastGlobal; } /** * @notice Get the current bias for `escrowId` at `timestamp` * @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility * @dev Fetches last escrow point prior to a certain timestamp, then walks forward to timestamp. * @param escrowId NFT for lock * @param timestamp Epoch time to return bias power at * @return NFT bias */ function getAdjustedEscrowBias( EscrowDelegateStore storage store_, uint256 escrowId, uint256 timestamp ) external view returns (uint256) { uint48 clockTime = timestamp.toUint48(); (Checkpoints.Point memory lastPoint,) = getAdjustedEscrow(store_, escrowId, clockTime); if (lastPoint.permanent != 0) return lastPoint.permanent.toUint256(); return lastPoint.bias.toUint256(); } /** * @notice Get the current bias for `escrowId` at `timestamp` * @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility * @dev Fetches last escrow point prior to a certain timestamp, then walks forward to timestamp. * @param escrowId NFT for lock * @param timestamp Epoch time to return bias power at * @return NFT bias */ function getAdjustedEscrow( EscrowDelegateStore storage store_, uint256 escrowId, uint256 timestamp ) public view returns (Checkpoints.Point memory, uint48) { uint48 clockTime = timestamp.toUint48(); (bool exists, uint48 ts, Checkpoints.Point memory lastPoint) = store_ ._escrowCheckpoints[escrowId] .upperLookupRecent(clockTime); if (!exists) return (lastPoint, ts); int128 change = ((lastPoint.slope * uint256(clockTime - ts).toInt128())); lastPoint.bias = lastPoint.bias < change ? int128(0) : lastPoint.bias - change; return (lastPoint, ts); } function getFirstEscrowPoint( EscrowDelegateStore storage store_, uint256 escrowId ) internal view returns (Checkpoints.Point memory, uint48) { (, uint48 ts, Checkpoints.Point memory point) = store_._escrowCheckpoints[escrowId].firstCheckpoint(); return (point, ts); } /// ----------------------------------------------------------------------- /// Private functions /// ----------------------------------------------------------------------- /** * @dev Function to push an address to the checkpoint * @param store The storage to push the address to * @param value The address to be pushed * @return The old and new address */ function _pushAddressAtClock( Checkpoints.TraceAddress storage store, address value ) private returns (address, address) { return store.push(clock(), value); } /** * @dev Function to push a struct to the checkpoint * @param store The storage to push the struct to * @param value The struct to be pushed * @return The old and new struct */ function _pushPointAtClock( Checkpoints.Trace storage store, Checkpoints.Point memory value ) private returns (Checkpoints.Point memory, Checkpoints.Point memory) { return store.push(clock(), value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // This file was derived from OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol) pragma solidity 0.8.13; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; /** * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in * time, and later looking up past values by block number. See {Votes} as an example. * * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new * checkpoint for the current transaction block using the {push} function. */ library Checkpoints { struct Trace { Checkpoint[] _checkpoints; } /** * @dev Struct to keep track of the voting power over time. */ struct Point { /// @dev The voting power at a specific time /// - MUST never be negative. int128 bias; /// @dev The rate at which the voting power decreases over time. int128 slope; /// @dev The value of tokens which do not decrease over time, representing permanent voting power /// - MUST never be negative. int128 permanent; } struct Checkpoint { uint48 _key; Point _value; } /** * @dev A value was attempted to be inserted on a past checkpoint. */ error CheckpointUnorderedInsertions(); /** * @dev Pushes a (`key`, `value`) pair into a Trace so that it is stored as the checkpoint. * * Returns previous value and new value. * * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the * library. */ function push(Trace storage self, uint48 key, Point memory value) internal returns (Point memory, Point memory) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if * there is none. */ function lowerLookup(Trace storage self, uint48 key) internal view returns (Point memory) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? blankPoint() : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. */ function upperLookup( Trace storage self, uint48 key ) internal view returns (bool exists, uint48 _key, Point memory _value) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); exists = pos != 0; _value = exists ? _unsafeAccess(self._checkpoints, pos - 1)._value : blankPoint(); _key = exists ? _unsafeAccess(self._checkpoints, pos - 1)._key : 0; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high * keys). */ function upperLookupRecent( Trace storage self, uint48 key ) internal view returns (bool exists, uint48 _key, Point memory _value) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); exists = pos != 0; _value = exists ? _unsafeAccess(self._checkpoints, pos - 1)._value : blankPoint(); _key = exists ? _unsafeAccess(self._checkpoints, pos - 1)._key : 0; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(Trace storage self) internal view returns (Point memory) { uint256 pos = self._checkpoints.length; return pos == 0 ? blankPoint() : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint( Trace storage self ) internal view returns (bool exists, uint48 _key, Point memory _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, blankPoint()); } else { Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function firstCheckpoint( Trace storage self ) internal view returns (bool exists, uint48 _key, Point memory _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, blankPoint()); } else { Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, 0); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(Trace storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Returns checkpoint at given position. */ function at(Trace storage self, uint48 pos) internal view returns (Checkpoint memory) { return self._checkpoints[pos]; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert( Checkpoint[] storage self, uint48 key, Point memory value ) private returns (Point memory, Point memory) { uint256 pos = self.length; if (pos > 0) { // Copying to memory is important here. Checkpoint memory last = _unsafeAccess(self, pos - 1); // Checkpoint keys must be non-decreasing. if (last._key > key) { revert CheckpointUnorderedInsertions(); } // Update or push new checkpoint if (last._key == key) { _unsafeAccess(self, pos - 1)._value = value; } else { self.push(Checkpoint({_key: key, _value: value})); } return (last._value, value); } else { self.push(Checkpoint({_key: key, _value: value})); return (blankPoint(), value); } } /** * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( Checkpoint[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and * exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( Checkpoint[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private view returns (Checkpoint storage result) { return self[pos]; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _realUnsafeAccess( Checkpoint[] storage self, uint256 pos ) private pure returns (Checkpoint storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } function blankPoint() internal pure returns (Point memory) { return Point({bias: 0, slope: 0, permanent: 0}); } struct TraceAddress { CheckpointAddress[] _checkpoints; } struct CheckpointAddress { uint48 _key; address _value; } /** * @dev Pushes a (`key`, `value`) pair into a TraceAddress so that it is stored as the checkpoint. * * Returns previous value and new value. * * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the * library. */ function push(TraceAddress storage self, uint48 key, address value) internal returns (address, address) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if * there is none. */ function lowerLookup(TraceAddress storage self, uint48 key) internal view returns (address) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? address(0) : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. */ function upperLookup(TraceAddress storage self, uint48 key) internal view returns (address) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); return pos == 0 ? address(0) : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high * keys). */ function upperLookupRecent(TraceAddress storage self, uint48 key) internal view returns (address) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); return pos == 0 ? address(0) : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(TraceAddress storage self) internal view returns (address) { uint256 pos = self._checkpoints.length; return pos == 0 ? address(0) : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint( TraceAddress storage self ) internal view returns (bool exists, uint48 _key, address _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, address(0)); } else { CheckpointAddress memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(TraceAddress storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Returns checkpoint at given position. */ function at(TraceAddress storage self, uint48 pos) internal view returns (CheckpointAddress memory) { return self._checkpoints[pos]; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert(CheckpointAddress[] storage self, uint48 key, address value) private returns (address, address) { uint256 pos = self.length; if (pos > 0) { // Copying to memory is important here. CheckpointAddress memory last = _unsafeAccess(self, pos - 1); // Checkpoint keys must be non-decreasing. if (last._key > key) { revert CheckpointUnorderedInsertions(); } // Update or push new checkpoint if (last._key == key) { _unsafeAccess(self, pos - 1)._value = value; } else { self.push(CheckpointAddress({_key: key, _value: value})); } return (last._value, value); } else { self.push(CheckpointAddress({_key: key, _value: value})); return (address(0), value); } } /** * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( CheckpointAddress[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or * `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and * exclusive `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( CheckpointAddress[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess( CheckpointAddress[] storage self, uint256 pos ) private pure returns (CheckpointAddress storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; /// @title SafeCast Library /// @author velodrome.finance /// @notice Safely convert unsigned and signed integers without overflow / underflow library SafeCastLibrary { error SafeCastOverflow(); error SafeCastUnderflow(); /// @dev Safely convert uint256 to int128 function toInt128(uint256 value) internal pure returns (int128) { if (value > uint128(type(int128).max)) revert SafeCastOverflow(); return int128(uint128(value)); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) revert SafeCastOverflow(); return uint48(value); } /// @dev Safely convert int128 to uint256 function toUint256(int128 value) internal pure returns (uint256) { if (value < 0) revert SafeCastUnderflow(); return uint256(int256(value)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; import {SafeCastLibrary} from "./SafeCastLibrary.sol"; /** * @notice Adapted from OpenZeppelin's Time library: v5.0.0 for solc 0.8.13 * @dev This library provides helpers for manipulating time-related objects. * * It uses the following types: * - `uint48` for timepoints * - `uint32` for durations * * While the library doesn't provide specific types for timepoints and duration, it does provide: * - a `Delay` type to represent duration that can be programmed to change value automatically at a given point * - additional helper functions */ library Time { using Time for *; /** * @dev Get the block timestamp as a Timepoint. */ function timestamp() internal view returns (uint48) { return SafeCastLibrary.toUint48(block.timestamp); } /** * @dev Get the block number as a Timepoint. */ function blockNumber() internal view returns (uint48) { return SafeCastLibrary.toUint48(block.number); } }
{ "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"CheckpointUnorderedInsertions","type":"error"},{"inputs":[],"name":"SafeCastOverflow","type":"error"},{"inputs":[],"name":"SafeCastUnderflow","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"uint48","name":"timestamp","type":"uint48"},{"indexed":false,"internalType":"int128","name":"slope","type":"int128"},{"indexed":false,"internalType":"int128","name":"bias","type":"int128"},{"indexed":false,"internalType":"int128","name":"permanent","type":"int128"}],"name":"CheckpointDelegate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"escrowId","type":"uint256"},{"indexed":false,"internalType":"uint48","name":"timestamp","type":"uint48"},{"indexed":false,"internalType":"int128","name":"slope","type":"int128"},{"indexed":false,"internalType":"int128","name":"bias","type":"int128"},{"indexed":false,"internalType":"int128","name":"permanent","type":"int128"}],"name":"CheckpointEscrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint48","name":"timestamp","type":"uint48"},{"indexed":false,"internalType":"int128","name":"slope","type":"int128"},{"indexed":false,"internalType":"int128","name":"bias","type":"int128"},{"indexed":false,"internalType":"int128","name":"permanent","type":"int128"}],"name":"CheckpointGlobal","type":"event"},{"inputs":[],"name":"CLOCK_UNIT","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TIME","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clock","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalClock","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
61279461003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100ff5760003560e01c806391ddadf4116100a1578063e680a31011610070578063e680a3101461029f578063f400f3c4146102b2578063f8183ecf146102c5578063f83bb313146102d857600080fd5b806391ddadf4146101d35780639511aa53146101db5780639bdd2e4d14610206578063d7ac26da1461024657600080fd5b806354703153116100dd578063547031531461016a578063683e955b1461018b5780636977e3a9146101ab57806382d4bd17146101cb57600080fd5b8063269499841461010457806334e78a9e146101275780634cd2605614610148575b600080fd5b61010f6303c2670081565b604051600f9190910b81526020015b60405180910390f35b61013a610135366004612216565b6102eb565b60405190815260200161011e565b81801561015457600080fd5b50610168610163366004612254565b610323565b005b61017462093a8081565b60405165ffffffffffff909116815260200161011e565b81801561019757600080fd5b506101686101a6366004612329565b610680565b8180156101b757600080fd5b506101686101c6366004612372565b61097a565b6101746109f2565b610174610a11565b6101ee6101e936600461238b565b610a1b565b6040516001600160a01b03909116815260200161011e565b81801561021257600080fd5b506102266102213660046123d7565b610a3f565b604080516001600160a01b0393841681529290911660208301520161011e565b81801561025257600080fd5b50610266610261366004612414565b610b62565b604080518351600f90810b8252602080860151820b908301529382015190930b9083015265ffffffffffff16606082015260800161011e565b6102666102ad366004612437565b610db5565b61013a6102c0366004612437565b610e70565b61013a6102d3366004612463565b610ed6565b6101ee6102e6366004612496565b610f06565b6000806102f88484610f16565b90506103198160400151826000015161031191906124ce565b600f0b6110f5565b9150505b92915050565b6000806000610360604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b9050600061039c604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b90506103a78561113b565b65ffffffffffff16945088156106685784156103c45760006103c6565b865b600f0b604082015285156103db5760006103dd565b875b600f0b604083015242861180156103f75750600088600f0b135b156104395761040a6303c2670089612545565b600f0b602083015261042461041f428861258c565b611155565b826020015161043391906125a3565b600f0b82525b428511801561044b5750600087600f0b135b156104885761045e6303c2670088612545565b600f0b602082015261047361041f428761258c565b816020015161048291906125a3565b600f0b81525b600086815260018b016020526040902054600f0b935084156104ca578585036104b3578392506104ca565b600085815260018b016020526040902054600f0b92505b4286111561052f5760208201516104e190856124ce565b93508486036104fc5760208101516104f9908561264a565b93505b600086815260018b016020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b0386161790555b42851115610583578585111561058357602081015161054e908461264a565b600086815260018c016020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b03831617905592505b600089815260028b016020526040902061059d908261118c565b50507f8b0a9686e26f875f7c3be0382e7593609c4d02c5161afd329687ca49cc339b60896105c9610a11565b60208401518451604080870151905161061195949392919094855265ffffffffffff939093166020850152600f91820b6040850152810b60608401520b608082015260a00190565b60405180910390a1600089815260048b01602052604081208190610634906111df565b92509250508165ffffffffffff16600014610665576106578c82868b600061126a565b6106658c82858a600161126a565b50505b6106748a8a8484610680565b50505050505050505050565b60008061068c86611539565b925092505060008265ffffffffffff166000036106a957426106ab565b825b905060006106c08265ffffffffffff1661113b565b905060006106d16303c267006110f5565b6106e39065ffffffffffff84166126ac565b90505b428265ffffffffffff1610156108055761070362093a80836126c4565b91506000428365ffffffffffff1611156107275761072042611621565b9250610746565b5065ffffffffffff8216600090815260018a016020526040902054600f0b5b80600f0b6000146107e95761076b61075e85856126ee565b65ffffffffffff16611155565b856020015161077a91906125a3565b8551869061078990839061264a565b600f0b9052506020850180518291906107a39083906124ce565b600f90810b90915286516000910b121590506107be57600085525b60008560200151600f0b12156107d657600060208601525b91925082916107e68a848761164a565b50505b818365ffffffffffff1611156107ff5750610805565b506106e6565b505085156108c05761082261041f65ffffffffffff83164261258c565b826020015161083191906125a3565b825161083d919061264a565b600f0b825260208086015190850151610856919061264a565b8260200181815161086791906124ce565b600f0b9052508451845161087b919061264a565b8251839061088a9083906124ce565b600f0b905250604080860151908501516108a4919061264a565b826040018181516108b591906124ce565b600f0b9052506108fc565b426108d661041f65ffffffffffff84168361258c565b83602001516108e591906125a3565b835184906108f490839061264a565b600f0b905250505b610906878361118c565b50507fdc8ed15e968adee1196e5ff0d83b745b050ee7aa99544d40a74145a036e35e38610931610a11565b6020848101518551604080880151815165ffffffffffff9096168652600f93840b9486019490945290820b908401520b606082015260800160405180910390a150505050505050565b6109ef8160006109b8604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b6040805160608082018352600080835260208084018290529284018190528351918201845280825291810182905291820152610680565b50565b6000610a0c6109ff611696565b65ffffffffffff1661113b565b905090565b6000610a0c611696565b60008281526004840160205260408120610a3590836116a1565b90505b9392505050565b600083815260048501602052604081208190610a5a9061174c565b9150836001600160a01b0316826001600160a01b031603610a7c575082610b59565b600085815260028701602052604081208190610a9790611539565b9250925050610ab38265ffffffffffff164261041f919061258c565b8160200151610ac291906125a3565b81518290610ad190839061264a565b600f90810b90915282516000910b12159050610aec57600081525b856001600160a01b0316846001600160a01b031614158015610b1657506001600160a01b03841615155b15610b2957610b2988858388600061126a565b610b3788878388600161126a565b60008781526004890160205260409020610b519087611788565b508693505050505b94509492505050565b60408051606081018252600080825260208201819052918101919091526001600160a01b03821660009081526003840160205260408120819081908190610ba890611539565b9250925092508094508193508215610d2e576000610bcd8565ffffffffffff1661113b565b90506000610bde6303c267006110f5565b610bf09065ffffffffffff84166126ac565b90505b428265ffffffffffff161015610d2b57610c1062093a80836126c4565b91506000428365ffffffffffff161115610c2c57429250610c5f565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b600014610d0f57610c7761075e88856126ee565b8860200151610c8691906125a3565b88518990610c9590839061264a565b600f0b905250602088018051829190610caf9083906124ce565b600f90810b90915289516000910b12159050610cca57600088525b60008860200151600f0b1215610ce257600060208901525b6001600160a01b038916600090815260038b01602052604090209296508692610d0c90848a61164a565b50505b818365ffffffffffff161115610d255750610d2b565b50610bf3565b50505b7fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b3986610d58610a11565b60208881015189516040808c015181516001600160a01b03909716875265ffffffffffff90951693860193909352600f91820b9285019290925290810b60608401520b608082015260a00160405180910390a15050509250929050565b604080516060810182526000808252602082018190529181018290529080610ddc84611621565b600086815260028801602052604081209192509081908190610dfe908561179e565b92509250925082610e155794509250610e68915050565b6000610e2461075e84876126ee565b8260200151610e3391906125a3565b905080600f0b8260000151600f0b12610e58578151610e5390829061264a565b610e5b565b60005b600f0b8252509450925050505b935093915050565b600080610e7c83611621565b90506000610e9386868465ffffffffffff16610db5565b5090508060400151600f0b600014610ebe57610eb58160400151600f0b6110f5565b92505050610a38565b8051610ecc90600f0b6110f5565b9695505050505050565b600080610ee48585856118de565b9050610efd8160400151826000015161031191906124ce565b95945050505050565b6000610a3883836101e942611621565b60408051606081018252600080825260208201819052918101919091528160008080610f42878561179e565b92509250925082610f5857935061031d92505050565b6000610f6b8365ffffffffffff1661113b565b90506000610f7c6303c267006110f5565b610f8e9065ffffffffffff84166126ac565b90505b8765ffffffffffff168265ffffffffffff16101561109c57610fb662093a80836126c4565b915060008865ffffffffffff168365ffffffffffff161115610fda57889250610ff9565b5065ffffffffffff8216600090815260018a016020526040902054600f0b5b80600f0b6000146110805761101161075e86856126ee565b846020015161102091906125a3565b8451859061102f90839061264a565b600f0b9052506020840180518291906110499083906124ce565b600f90810b90915285516000910b1215905061106457600084525b60008460200151600f0b121561107c57600060208501525b8294505b818365ffffffffffff161115611096575061109c565b50610f91565b60006110ab61075e86896126ee565b84602001516110ba91906125a3565b905080600f0b8460000151600f0b126110df5783516110da90829061264a565b6110e2565b60005b600f0b8452509198975050505050505050565b60008082600f0b1215611134576040517f0101bd7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600f0b90565b600062093a8061114b8184612715565b61031d9190612729565b60006f7fffffffffffffffffffffffffffffff821115611188576040516393dafdf160e01b815260040160405180910390fd5b5090565b60408051606080820183526000808352602080840182905283850182905284519283018552818352820181905292810192909252906111d46111cc610a11565b85908561164a565b915091509250929050565b80546000908190819080820361120057600080600093509350935050611263565b600061121f8661121160018561258c565b600091825260209091200190565b60408051808201909152905465ffffffffffff811680835266010000000000009091046001600160a01b031660209092018290526001965094509250611263915050565b9193909250565b6000806112778787610b62565b9092509050600061129361041f65ffffffffffff84164261258c565b83602001516112a291906125a3565b83516112ae919061264a565b9050836113c1574285111561135a576020808701516001600160a01b038916600090815260058b01835260408082208983529093529182208054919290916112fa908490600f0b6124ce565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508260200151600f0b8660200151600f0b1261133d576000611351565b85602001518360200151611351919061264a565b600f0b60208401525b80600f0b8660000151600f0b1261137257600061137e565b855161137e908261264a565b600f90810b84526040808501519088015190820b910b126113a05760006113b4565b856040015183604001516113b4919061264a565b600f0b6040840152611478565b4285111561144a576020808701516001600160a01b038916600090815260058b0183526040808220898352909352918220805491929091611406908490600f0b61264a565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508560200151836020015161144191906124ce565b600f0b60208401525b855161145690826124ce565b600f0b83526040808701519084015161146f91906124ce565b600f0b60408401525b8260200151600f0b60000361148c57600083525b6001600160a01b038716600090815260038901602052604090206114b0908461118c565b50507fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b39876114dc610a11565b60208681015187516040808a015181516001600160a01b03909716875265ffffffffffff90951693860193909352600f91820b9285019290925290810b60608401520b608082015260a00160405180910390a15050505050505050565b604080516060810182526000808252602082018190529181018290528190835460008190036115a95760008061159d604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b93509350935050611263565b60006115bf866115ba60018561258c565b611a9f565b604080518082018252825465ffffffffffff1681528151606081018352600180850154600f81810b8452600160801b909104810b602084810191909152600290960154900b938201939093529281018390525190965094509250611263915050565b600065ffffffffffff821115611188576040516393dafdf160e01b815260040160405180910390fd5b604080516060808201835260008083526020808401829052838501829052845192830185528183528201819052928101929092529061168a858585611ac9565b91509150935093915050565b6000610a0c42611621565b8154600090818160058111156117005760006116bc84611d92565b6116c6908561258c565b60008881526020902090915081015465ffffffffffff90811690871610156116f0578091506116fe565b6116fb8160016126ac565b92505b505b600061170e87878585611e7a565b9050801561173e576117258761121160018461258c565b54660100000000000090046001600160a01b0316611741565b60005b979650505050505050565b8054600090801561177f576117668361121160018461258c565b54660100000000000090046001600160a01b0316610a38565b60009392505050565b6000806111d4611796610a11565b859085611edc565b604080516060810182526000808252602082018190529181018290528190845460008160058111156118175760006117d584611d92565b6117df908561258c565b90506117eb8982611a9f565b5465ffffffffffff908116908916101561180757809150611815565b6118128160016126ac565b92505b505b600061182589898585611eea565b80151597509050866118685760408051606080820183526000808352602080840182905292840181905283519182018452808252918101829052918201526118aa565b611877896115ba60018461258c565b604080516060810182526001830154600f81810b8352600160801b909104810b602083015260029093015490920b908201525b9450866118b85760006118d1565b6118c7896115ba60018461258c565b5465ffffffffffff165b9550505050509250925092565b60408051606081018252600080825260208201819052918101919091526001600160a01b0383166000908152600385016020526040812081908190611923908661179e565b92509250925082611938579250610a38915050565b600061194b8365ffffffffffff1661113b565b9050600061195c6303c267006110f5565b61196e9065ffffffffffff84166126ac565b90505b8665ffffffffffff168265ffffffffffff161015611a905761199662093a80836126c4565b915060008765ffffffffffff168365ffffffffffff1611156119ba578792506119ed565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b600014611a7457611a0561075e86856126ee565b8460200151611a1491906125a3565b84518590611a2390839061264a565b600f0b905250602084018051829190611a3d9083906124ce565b600f90810b90915285516000910b12159050611a5857600084525b60008460200151600f0b1215611a7057600060208501525b8294505b818365ffffffffffff161115611a8a5750611a90565b50611971565b60006110ab61075e868a6126ee565b6000828281548110611ab357611ab3612748565b9060005260206000209060030201905092915050565b6040805160608101825260008082526020820181905291810191909152604080516060810182526000808252602082018190529181019190915284548015611cb6576000611b1c876115ba60018561258c565b604080518082018252825465ffffffffffff908116825282516060810184526001850154600f81810b8352600160801b909104810b602083810191909152600290960154900b9381019390935292810191909152805190925087821691161115611b9957604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff808816911603611c0c5784611bbc886115ba60018661258c565b815160208301516001600160801b03918216600160801b91831691909102176001830155604090920151600290910180546fffffffffffffffffffffffffffffffff191691909216179055611ca6565b60408051808201825265ffffffffffff888116825260208083018981528b5460018082018e5560008e815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546fffffffffffffffffffffffffffffffff1916929091169190911790555b602001519250839150610e689050565b60408051808201825265ffffffffffff878116825260208083018881528a5460018082018d5560008d815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546fffffffffffffffffffffffffffffffff191692909116919091179055611d87604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b849250925050610e68565b600081600003611da457506000919050565b60006001611db184611f41565b901c6001901b90506001818481611dca57611dca61252f565b048201901c90506001818481611de257611de261252f565b048201901c90506001818481611dfa57611dfa61252f565b048201901c90506001818481611e1257611e1261252f565b048201901c90506001818481611e2a57611e2a61252f565b048201901c90506001818481611e4257611e4261252f565b048201901c90506001818481611e5a57611e5a61252f565b048201901c9050610a3881828581611e7457611e7461252f565b04611fd5565b60005b81831015611ed4576000611e918484611feb565b60008781526020902090915065ffffffffffff86169082015465ffffffffffff161115611ec057809250611ece565b611ecb8160016126ac565b93505b50611e7d565b509392505050565b60008061168a858585612006565b60005b81831015611ed4576000611f018484611feb565b90508465ffffffffffff16611f168783611a9f565b5465ffffffffffff161115611f2d57809250611f3b565b611f388160016126ac565b93505b50611eed565b600080608083901c15611f5657608092831c92015b604083901c15611f6857604092831c92015b602083901c15611f7a57602092831c92015b601083901c15611f8c57601092831c92015b600883901c15611f9e57600892831c92015b600483901c15611fb057600492831c92015b600283901c15611fc257600292831c92015b600183901c1561031d5760010192915050565b6000818310611fe45781610a38565b5090919050565b6000611ffa6002848418612715565b610a38908484166126ac565b8254600090819080156121715760006120248761121160018561258c565b60408051808201909152905465ffffffffffff80821680845266010000000000009092046001600160a01b03166020840152919250908716101561207b57604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff8088169116036120e4578461209e8861121160018661258c565b80546001600160a01b03929092166601000000000000027fffffffffffff0000000000000000000000000000000000000000ffffffffffff909216919091179055611ca6565b6040805180820190915265ffffffffffff80881682526001600160a01b0380881660208085019182528b54600181018d5560008d81529190912094519401805491519092166601000000000000027fffffffffffff00000000000000000000000000000000000000000000000000009091169390921692909217179055602001519250839150610e689050565b50506040805180820190915265ffffffffffff80851682526001600160a01b0380851660208085019182528854600181018a5560008a815291822095519501805492519093166601000000000000027fffffffffffff0000000000000000000000000000000000000000000000000000909216949093169390931792909217909155905081610e68565b803565ffffffffffff8116811461221157600080fd5b919050565b6000806040838503121561222957600080fd5b82359150612239602084016121fb565b90509250929050565b8035600f81900b811461221157600080fd5b60008060008060008060c0878903121561226d57600080fd5b863595506020870135945061228460408801612242565b935061229260608801612242565b92506080870135915060a087013590509295509295509295565b6000606082840312156122be57600080fd5b6040516060810181811067ffffffffffffffff821117156122ef57634e487b7160e01b600052604160045260246000fd5b6040529050806122fe83612242565b815261230c60208401612242565b602082015261231d60408401612242565b60408201525092915050565b600080600080610100858703121561234057600080fd5b843593506020850135925061235886604087016122ac565b91506123678660a087016122ac565b905092959194509250565b60006020828403121561238457600080fd5b5035919050565b6000806000606084860312156123a057600080fd5b83359250602084013591506123b7604085016121fb565b90509250925092565b80356001600160a01b038116811461221157600080fd5b600080600080608085870312156123ed57600080fd5b8435935060208501359250612404604086016123c0565b9396929550929360600135925050565b6000806040838503121561242757600080fd5b82359150612239602084016123c0565b60008060006060848603121561244c57600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561247857600080fd5b83359250612488602085016123c0565b91506123b7604085016121fb565b600080604083850312156124a957600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b600081600f0b83600f0b60008212826f7fffffffffffffffffffffffffffffff03821381151615612501576125016124b8565b826f7fffffffffffffffffffffffffffffff19038212811615612526576125266124b8565b50019392505050565b634e487b7160e01b600052601260045260246000fd5b600081600f0b83600f0b8061255c5761255c61252f565b6f7fffffffffffffffffffffffffffffff19821460001982141615612583576125836124b8565b90059392505050565b60008282101561259e5761259e6124b8565b500390565b600081600f0b83600f0b6f7fffffffffffffffffffffffffffffff6000821360008413838304851182821616156125dc576125dc6124b8565b6f7fffffffffffffffffffffffffffffff196000851286820586128184161615612608576126086124b8565b60008712925085820587128484161615612624576126246124b8565b8585058712818416161561263a5761263a6124b8565b5050509290910295945050505050565b600081600f0b83600f0b60008112816f7fffffffffffffffffffffffffffffff190183128115161561267e5761267e6124b8565b816f7fffffffffffffffffffffffffffffff0183138116156126a2576126a26124b8565b5090039392505050565b600082198211156126bf576126bf6124b8565b500190565b600065ffffffffffff8083168185168083038211156126e5576126e56124b8565b01949350505050565b600065ffffffffffff8381169083168181101561270d5761270d6124b8565b039392505050565b6000826127245761272461252f565b500490565b6000816000190483118215151615612743576127436124b8565b500290565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220748bcf20bdfca2e5f378cebfccd87187ad8ad45e09b55f275f355693caa63a9764736f6c634300080d0033
Deployed Bytecode
0x73a615388bd2f920ee2fec7606f26908b454f0c24930146080604052600436106100ff5760003560e01c806391ddadf4116100a1578063e680a31011610070578063e680a3101461029f578063f400f3c4146102b2578063f8183ecf146102c5578063f83bb313146102d857600080fd5b806391ddadf4146101d35780639511aa53146101db5780639bdd2e4d14610206578063d7ac26da1461024657600080fd5b806354703153116100dd578063547031531461016a578063683e955b1461018b5780636977e3a9146101ab57806382d4bd17146101cb57600080fd5b8063269499841461010457806334e78a9e146101275780634cd2605614610148575b600080fd5b61010f6303c2670081565b604051600f9190910b81526020015b60405180910390f35b61013a610135366004612216565b6102eb565b60405190815260200161011e565b81801561015457600080fd5b50610168610163366004612254565b610323565b005b61017462093a8081565b60405165ffffffffffff909116815260200161011e565b81801561019757600080fd5b506101686101a6366004612329565b610680565b8180156101b757600080fd5b506101686101c6366004612372565b61097a565b6101746109f2565b610174610a11565b6101ee6101e936600461238b565b610a1b565b6040516001600160a01b03909116815260200161011e565b81801561021257600080fd5b506102266102213660046123d7565b610a3f565b604080516001600160a01b0393841681529290911660208301520161011e565b81801561025257600080fd5b50610266610261366004612414565b610b62565b604080518351600f90810b8252602080860151820b908301529382015190930b9083015265ffffffffffff16606082015260800161011e565b6102666102ad366004612437565b610db5565b61013a6102c0366004612437565b610e70565b61013a6102d3366004612463565b610ed6565b6101ee6102e6366004612496565b610f06565b6000806102f88484610f16565b90506103198160400151826000015161031191906124ce565b600f0b6110f5565b9150505b92915050565b6000806000610360604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b9050600061039c604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b90506103a78561113b565b65ffffffffffff16945088156106685784156103c45760006103c6565b865b600f0b604082015285156103db5760006103dd565b875b600f0b604083015242861180156103f75750600088600f0b135b156104395761040a6303c2670089612545565b600f0b602083015261042461041f428861258c565b611155565b826020015161043391906125a3565b600f0b82525b428511801561044b5750600087600f0b135b156104885761045e6303c2670088612545565b600f0b602082015261047361041f428761258c565b816020015161048291906125a3565b600f0b81525b600086815260018b016020526040902054600f0b935084156104ca578585036104b3578392506104ca565b600085815260018b016020526040902054600f0b92505b4286111561052f5760208201516104e190856124ce565b93508486036104fc5760208101516104f9908561264a565b93505b600086815260018b016020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b0386161790555b42851115610583578585111561058357602081015161054e908461264a565b600086815260018c016020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b03831617905592505b600089815260028b016020526040902061059d908261118c565b50507f8b0a9686e26f875f7c3be0382e7593609c4d02c5161afd329687ca49cc339b60896105c9610a11565b60208401518451604080870151905161061195949392919094855265ffffffffffff939093166020850152600f91820b6040850152810b60608401520b608082015260a00190565b60405180910390a1600089815260048b01602052604081208190610634906111df565b92509250508165ffffffffffff16600014610665576106578c82868b600061126a565b6106658c82858a600161126a565b50505b6106748a8a8484610680565b50505050505050505050565b60008061068c86611539565b925092505060008265ffffffffffff166000036106a957426106ab565b825b905060006106c08265ffffffffffff1661113b565b905060006106d16303c267006110f5565b6106e39065ffffffffffff84166126ac565b90505b428265ffffffffffff1610156108055761070362093a80836126c4565b91506000428365ffffffffffff1611156107275761072042611621565b9250610746565b5065ffffffffffff8216600090815260018a016020526040902054600f0b5b80600f0b6000146107e95761076b61075e85856126ee565b65ffffffffffff16611155565b856020015161077a91906125a3565b8551869061078990839061264a565b600f0b9052506020850180518291906107a39083906124ce565b600f90810b90915286516000910b121590506107be57600085525b60008560200151600f0b12156107d657600060208601525b91925082916107e68a848761164a565b50505b818365ffffffffffff1611156107ff5750610805565b506106e6565b505085156108c05761082261041f65ffffffffffff83164261258c565b826020015161083191906125a3565b825161083d919061264a565b600f0b825260208086015190850151610856919061264a565b8260200181815161086791906124ce565b600f0b9052508451845161087b919061264a565b8251839061088a9083906124ce565b600f0b905250604080860151908501516108a4919061264a565b826040018181516108b591906124ce565b600f0b9052506108fc565b426108d661041f65ffffffffffff84168361258c565b83602001516108e591906125a3565b835184906108f490839061264a565b600f0b905250505b610906878361118c565b50507fdc8ed15e968adee1196e5ff0d83b745b050ee7aa99544d40a74145a036e35e38610931610a11565b6020848101518551604080880151815165ffffffffffff9096168652600f93840b9486019490945290820b908401520b606082015260800160405180910390a150505050505050565b6109ef8160006109b8604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b6040805160608082018352600080835260208084018290529284018190528351918201845280825291810182905291820152610680565b50565b6000610a0c6109ff611696565b65ffffffffffff1661113b565b905090565b6000610a0c611696565b60008281526004840160205260408120610a3590836116a1565b90505b9392505050565b600083815260048501602052604081208190610a5a9061174c565b9150836001600160a01b0316826001600160a01b031603610a7c575082610b59565b600085815260028701602052604081208190610a9790611539565b9250925050610ab38265ffffffffffff164261041f919061258c565b8160200151610ac291906125a3565b81518290610ad190839061264a565b600f90810b90915282516000910b12159050610aec57600081525b856001600160a01b0316846001600160a01b031614158015610b1657506001600160a01b03841615155b15610b2957610b2988858388600061126a565b610b3788878388600161126a565b60008781526004890160205260409020610b519087611788565b508693505050505b94509492505050565b60408051606081018252600080825260208201819052918101919091526001600160a01b03821660009081526003840160205260408120819081908190610ba890611539565b9250925092508094508193508215610d2e576000610bcd8565ffffffffffff1661113b565b90506000610bde6303c267006110f5565b610bf09065ffffffffffff84166126ac565b90505b428265ffffffffffff161015610d2b57610c1062093a80836126c4565b91506000428365ffffffffffff161115610c2c57429250610c5f565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b600014610d0f57610c7761075e88856126ee565b8860200151610c8691906125a3565b88518990610c9590839061264a565b600f0b905250602088018051829190610caf9083906124ce565b600f90810b90915289516000910b12159050610cca57600088525b60008860200151600f0b1215610ce257600060208901525b6001600160a01b038916600090815260038b01602052604090209296508692610d0c90848a61164a565b50505b818365ffffffffffff161115610d255750610d2b565b50610bf3565b50505b7fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b3986610d58610a11565b60208881015189516040808c015181516001600160a01b03909716875265ffffffffffff90951693860193909352600f91820b9285019290925290810b60608401520b608082015260a00160405180910390a15050509250929050565b604080516060810182526000808252602082018190529181018290529080610ddc84611621565b600086815260028801602052604081209192509081908190610dfe908561179e565b92509250925082610e155794509250610e68915050565b6000610e2461075e84876126ee565b8260200151610e3391906125a3565b905080600f0b8260000151600f0b12610e58578151610e5390829061264a565b610e5b565b60005b600f0b8252509450925050505b935093915050565b600080610e7c83611621565b90506000610e9386868465ffffffffffff16610db5565b5090508060400151600f0b600014610ebe57610eb58160400151600f0b6110f5565b92505050610a38565b8051610ecc90600f0b6110f5565b9695505050505050565b600080610ee48585856118de565b9050610efd8160400151826000015161031191906124ce565b95945050505050565b6000610a3883836101e942611621565b60408051606081018252600080825260208201819052918101919091528160008080610f42878561179e565b92509250925082610f5857935061031d92505050565b6000610f6b8365ffffffffffff1661113b565b90506000610f7c6303c267006110f5565b610f8e9065ffffffffffff84166126ac565b90505b8765ffffffffffff168265ffffffffffff16101561109c57610fb662093a80836126c4565b915060008865ffffffffffff168365ffffffffffff161115610fda57889250610ff9565b5065ffffffffffff8216600090815260018a016020526040902054600f0b5b80600f0b6000146110805761101161075e86856126ee565b846020015161102091906125a3565b8451859061102f90839061264a565b600f0b9052506020840180518291906110499083906124ce565b600f90810b90915285516000910b1215905061106457600084525b60008460200151600f0b121561107c57600060208501525b8294505b818365ffffffffffff161115611096575061109c565b50610f91565b60006110ab61075e86896126ee565b84602001516110ba91906125a3565b905080600f0b8460000151600f0b126110df5783516110da90829061264a565b6110e2565b60005b600f0b8452509198975050505050505050565b60008082600f0b1215611134576040517f0101bd7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600f0b90565b600062093a8061114b8184612715565b61031d9190612729565b60006f7fffffffffffffffffffffffffffffff821115611188576040516393dafdf160e01b815260040160405180910390fd5b5090565b60408051606080820183526000808352602080840182905283850182905284519283018552818352820181905292810192909252906111d46111cc610a11565b85908561164a565b915091509250929050565b80546000908190819080820361120057600080600093509350935050611263565b600061121f8661121160018561258c565b600091825260209091200190565b60408051808201909152905465ffffffffffff811680835266010000000000009091046001600160a01b031660209092018290526001965094509250611263915050565b9193909250565b6000806112778787610b62565b9092509050600061129361041f65ffffffffffff84164261258c565b83602001516112a291906125a3565b83516112ae919061264a565b9050836113c1574285111561135a576020808701516001600160a01b038916600090815260058b01835260408082208983529093529182208054919290916112fa908490600f0b6124ce565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508260200151600f0b8660200151600f0b1261133d576000611351565b85602001518360200151611351919061264a565b600f0b60208401525b80600f0b8660000151600f0b1261137257600061137e565b855161137e908261264a565b600f90810b84526040808501519088015190820b910b126113a05760006113b4565b856040015183604001516113b4919061264a565b600f0b6040840152611478565b4285111561144a576020808701516001600160a01b038916600090815260058b0183526040808220898352909352918220805491929091611406908490600f0b61264a565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508560200151836020015161144191906124ce565b600f0b60208401525b855161145690826124ce565b600f0b83526040808701519084015161146f91906124ce565b600f0b60408401525b8260200151600f0b60000361148c57600083525b6001600160a01b038716600090815260038901602052604090206114b0908461118c565b50507fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b39876114dc610a11565b60208681015187516040808a015181516001600160a01b03909716875265ffffffffffff90951693860193909352600f91820b9285019290925290810b60608401520b608082015260a00160405180910390a15050505050505050565b604080516060810182526000808252602082018190529181018290528190835460008190036115a95760008061159d604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b93509350935050611263565b60006115bf866115ba60018561258c565b611a9f565b604080518082018252825465ffffffffffff1681528151606081018352600180850154600f81810b8452600160801b909104810b602084810191909152600290960154900b938201939093529281018390525190965094509250611263915050565b600065ffffffffffff821115611188576040516393dafdf160e01b815260040160405180910390fd5b604080516060808201835260008083526020808401829052838501829052845192830185528183528201819052928101929092529061168a858585611ac9565b91509150935093915050565b6000610a0c42611621565b8154600090818160058111156117005760006116bc84611d92565b6116c6908561258c565b60008881526020902090915081015465ffffffffffff90811690871610156116f0578091506116fe565b6116fb8160016126ac565b92505b505b600061170e87878585611e7a565b9050801561173e576117258761121160018461258c565b54660100000000000090046001600160a01b0316611741565b60005b979650505050505050565b8054600090801561177f576117668361121160018461258c565b54660100000000000090046001600160a01b0316610a38565b60009392505050565b6000806111d4611796610a11565b859085611edc565b604080516060810182526000808252602082018190529181018290528190845460008160058111156118175760006117d584611d92565b6117df908561258c565b90506117eb8982611a9f565b5465ffffffffffff908116908916101561180757809150611815565b6118128160016126ac565b92505b505b600061182589898585611eea565b80151597509050866118685760408051606080820183526000808352602080840182905292840181905283519182018452808252918101829052918201526118aa565b611877896115ba60018461258c565b604080516060810182526001830154600f81810b8352600160801b909104810b602083015260029093015490920b908201525b9450866118b85760006118d1565b6118c7896115ba60018461258c565b5465ffffffffffff165b9550505050509250925092565b60408051606081018252600080825260208201819052918101919091526001600160a01b0383166000908152600385016020526040812081908190611923908661179e565b92509250925082611938579250610a38915050565b600061194b8365ffffffffffff1661113b565b9050600061195c6303c267006110f5565b61196e9065ffffffffffff84166126ac565b90505b8665ffffffffffff168265ffffffffffff161015611a905761199662093a80836126c4565b915060008765ffffffffffff168365ffffffffffff1611156119ba578792506119ed565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b600014611a7457611a0561075e86856126ee565b8460200151611a1491906125a3565b84518590611a2390839061264a565b600f0b905250602084018051829190611a3d9083906124ce565b600f90810b90915285516000910b12159050611a5857600084525b60008460200151600f0b1215611a7057600060208501525b8294505b818365ffffffffffff161115611a8a5750611a90565b50611971565b60006110ab61075e868a6126ee565b6000828281548110611ab357611ab3612748565b9060005260206000209060030201905092915050565b6040805160608101825260008082526020820181905291810191909152604080516060810182526000808252602082018190529181019190915284548015611cb6576000611b1c876115ba60018561258c565b604080518082018252825465ffffffffffff908116825282516060810184526001850154600f81810b8352600160801b909104810b602083810191909152600290960154900b9381019390935292810191909152805190925087821691161115611b9957604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff808816911603611c0c5784611bbc886115ba60018661258c565b815160208301516001600160801b03918216600160801b91831691909102176001830155604090920151600290910180546fffffffffffffffffffffffffffffffff191691909216179055611ca6565b60408051808201825265ffffffffffff888116825260208083018981528b5460018082018e5560008e815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546fffffffffffffffffffffffffffffffff1916929091169190911790555b602001519250839150610e689050565b60408051808201825265ffffffffffff878116825260208083018881528a5460018082018d5560008d815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546fffffffffffffffffffffffffffffffff191692909116919091179055611d87604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b849250925050610e68565b600081600003611da457506000919050565b60006001611db184611f41565b901c6001901b90506001818481611dca57611dca61252f565b048201901c90506001818481611de257611de261252f565b048201901c90506001818481611dfa57611dfa61252f565b048201901c90506001818481611e1257611e1261252f565b048201901c90506001818481611e2a57611e2a61252f565b048201901c90506001818481611e4257611e4261252f565b048201901c90506001818481611e5a57611e5a61252f565b048201901c9050610a3881828581611e7457611e7461252f565b04611fd5565b60005b81831015611ed4576000611e918484611feb565b60008781526020902090915065ffffffffffff86169082015465ffffffffffff161115611ec057809250611ece565b611ecb8160016126ac565b93505b50611e7d565b509392505050565b60008061168a858585612006565b60005b81831015611ed4576000611f018484611feb565b90508465ffffffffffff16611f168783611a9f565b5465ffffffffffff161115611f2d57809250611f3b565b611f388160016126ac565b93505b50611eed565b600080608083901c15611f5657608092831c92015b604083901c15611f6857604092831c92015b602083901c15611f7a57602092831c92015b601083901c15611f8c57601092831c92015b600883901c15611f9e57600892831c92015b600483901c15611fb057600492831c92015b600283901c15611fc257600292831c92015b600183901c1561031d5760010192915050565b6000818310611fe45781610a38565b5090919050565b6000611ffa6002848418612715565b610a38908484166126ac565b8254600090819080156121715760006120248761121160018561258c565b60408051808201909152905465ffffffffffff80821680845266010000000000009092046001600160a01b03166020840152919250908716101561207b57604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff8088169116036120e4578461209e8861121160018661258c565b80546001600160a01b03929092166601000000000000027fffffffffffff0000000000000000000000000000000000000000ffffffffffff909216919091179055611ca6565b6040805180820190915265ffffffffffff80881682526001600160a01b0380881660208085019182528b54600181018d5560008d81529190912094519401805491519092166601000000000000027fffffffffffff00000000000000000000000000000000000000000000000000009091169390921692909217179055602001519250839150610e689050565b50506040805180820190915265ffffffffffff80851682526001600160a01b0380851660208085019182528854600181018a5560008a815291822095519501805492519093166601000000000000027fffffffffffff0000000000000000000000000000000000000000000000000000909216949093169390931792909217909155905081610e68565b803565ffffffffffff8116811461221157600080fd5b919050565b6000806040838503121561222957600080fd5b82359150612239602084016121fb565b90509250929050565b8035600f81900b811461221157600080fd5b60008060008060008060c0878903121561226d57600080fd5b863595506020870135945061228460408801612242565b935061229260608801612242565b92506080870135915060a087013590509295509295509295565b6000606082840312156122be57600080fd5b6040516060810181811067ffffffffffffffff821117156122ef57634e487b7160e01b600052604160045260246000fd5b6040529050806122fe83612242565b815261230c60208401612242565b602082015261231d60408401612242565b60408201525092915050565b600080600080610100858703121561234057600080fd5b843593506020850135925061235886604087016122ac565b91506123678660a087016122ac565b905092959194509250565b60006020828403121561238457600080fd5b5035919050565b6000806000606084860312156123a057600080fd5b83359250602084013591506123b7604085016121fb565b90509250925092565b80356001600160a01b038116811461221157600080fd5b600080600080608085870312156123ed57600080fd5b8435935060208501359250612404604086016123c0565b9396929550929360600135925050565b6000806040838503121561242757600080fd5b82359150612239602084016123c0565b60008060006060848603121561244c57600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561247857600080fd5b83359250612488602085016123c0565b91506123b7604085016121fb565b600080604083850312156124a957600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b600081600f0b83600f0b60008212826f7fffffffffffffffffffffffffffffff03821381151615612501576125016124b8565b826f7fffffffffffffffffffffffffffffff19038212811615612526576125266124b8565b50019392505050565b634e487b7160e01b600052601260045260246000fd5b600081600f0b83600f0b8061255c5761255c61252f565b6f7fffffffffffffffffffffffffffffff19821460001982141615612583576125836124b8565b90059392505050565b60008282101561259e5761259e6124b8565b500390565b600081600f0b83600f0b6f7fffffffffffffffffffffffffffffff6000821360008413838304851182821616156125dc576125dc6124b8565b6f7fffffffffffffffffffffffffffffff196000851286820586128184161615612608576126086124b8565b60008712925085820587128484161615612624576126246124b8565b8585058712818416161561263a5761263a6124b8565b5050509290910295945050505050565b600081600f0b83600f0b60008112816f7fffffffffffffffffffffffffffffff190183128115161561267e5761267e6124b8565b816f7fffffffffffffffffffffffffffffff0183138116156126a2576126a26124b8565b5090039392505050565b600082198211156126bf576126bf6124b8565b500190565b600065ffffffffffff8083168185168083038211156126e5576126e56124b8565b01949350505050565b600065ffffffffffff8381169083168181101561270d5761270d6124b8565b039392505050565b6000826127245761272461252f565b500490565b6000816000190483118215151615612743576127436124b8565b500290565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220748bcf20bdfca2e5f378cebfccd87187ad8ad45e09b55f275f355693caa63a9764736f6c634300080d0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.