Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
EscrowDelegateCheckpoints
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 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";
import {Constants} from "../../../Constants.sol";
/**
* @title EscrowDelegateCheckpoints
* @dev This library is used to manage checkpoints of escrow locks and delegatees.
*/
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;
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;
}
/// @notice Emitted when a global checkpoint is created
/// @param timestamp The timestamp of the checkpoint
/// @param slope The slope of the checkpoint
/// @param bias The bias of the checkpoint
/// @param permanent The permanent value of the checkpoint
event CheckpointGlobal(uint48 timestamp, int128 slope, int128 bias, int128 permanent);
/// @notice Emitted when a delegate checkpoint is created
/// @param delegatee The address of the delegatee
/// @param timestamp The timestamp of the checkpoint
/// @param slope The slope of the checkpoint
/// @param bias The bias of the checkpoint
/// @param permanent The permanent value of the checkpoint
event CheckpointDelegate(address delegatee, uint48 timestamp, int128 slope, int128 bias, int128 permanent);
/// @notice Emitted when an escrow checkpoint is created
/// @param escrowId The ID of the escrow
/// @param timestamp The timestamp of the checkpoint
/// @param slope The slope of the checkpoint
/// @param bias The bias of the checkpoint
/// @param permanent The permanent value of the checkpoint
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 / Constants.EPOCH) * Constants.EPOCH);
}
/**
* @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
* @param store_ The EscrowDelegateStore struct containing all the storage mappings
*/
function globalCheckpoint(EscrowDelegateStore storage store_) external {
globalCheckpoint(store_, 0, Checkpoints.blankPoint(), Checkpoints.blankPoint());
}
/**
* @dev Function to update global checkpoint with new points
* @param store_ The EscrowDelegateStore struct containing all the storage mappings
* @param escrowId The ID of the escrow lock
* @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 > testTime
uint256 maxTime = testTime + MAX_TIME.toUint256();
while (testTime < block.timestamp) {
testTime += Constants.EPOCH;
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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 > testTime
uint256 maxTime = testTime + MAX_TIME.toUint256();
while (testTime < timestamp) {
testTime += Constants.EPOCH;
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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 != 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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 > testTime
uint256 maxTime = testTime + MAX_TIME.toUint256();
// Iterate over time until current block timestamp or maxtime
while (testTime < block.timestamp) {
testTime += Constants.EPOCH;
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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @param timestamp Time to calculate the total voting power at
* @return The adjusted checkpoint at the provided timestamp
*/
function _getAdjustedCheckpoint(
EscrowDelegateStore storage store_,
uint48 timestamp
) internal view returns (Checkpoints.Point memory) {
(bool exists, uint48 lastCheckpointTs, Checkpoints.Point memory lastGlobal) = store_
._globalCheckpoints
.upperLookupRecent(timestamp);
if (!exists) return lastGlobal;
uint48 testTime = toGlobalClock(lastCheckpointTs); /// @dev lastCheckpointTs > testTime
uint256 maxTime = testTime + MAX_TIME.toUint256();
// Iterate over time until the specified timestamp or maxtime is reached
while (testTime < timestamp) {
testTime += Constants.EPOCH;
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(timestamp - 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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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 store_ The EscrowDelegateStore struct containing all the storage mappings
* @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);
}
/**
* @notice Get the first escrow point for `escrowId`
* @param store_ The EscrowDelegateStore struct containing all the storage mappings
* @param escrowId The ID of the escrow lock
* @return The first point and the timestamp of the first checkpoint
*/
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
pragma solidity 0.8.13;
library Constants {
uint48 constant EPOCH = 1 weeks;
}// 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": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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":"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
61258961003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100f45760003560e01c80639511aa5311610096578063e680a31011610070578063e680a3101461028a578063f400f3c41461029d578063f8183ecf146102b0578063f83bb313146102c357600080fd5b80639511aa53146101c65780639bdd2e4d146101f1578063d7ac26da1461023157600080fd5b8063683e955b116100d2578063683e955b1461015f5780636977e3a91461017f57806382d4bd171461019f57806391ddadf4146101be57600080fd5b806326949984146100f957806334e78a9e1461011c5780634cd260561461013d575b600080fd5b6101046303c2670081565b604051600f9190910b81526020015b60405180910390f35b61012f61012a36600461200f565b6102d6565b604051908152602001610113565b81801561014957600080fd5b5061015d61015836600461204d565b61030e565b005b81801561016b57600080fd5b5061015d61017a366004612122565b6105f9565b81801561018b57600080fd5b5061015d61019a36600461216b565b6108f3565b6101a761090c565b60405165ffffffffffff9091168152602001610113565b6101a761092b565b6101d96101d4366004612184565b610935565b6040516001600160a01b039091168152602001610113565b8180156101fd57600080fd5b5061021161020c3660046121d0565b610959565b604080516001600160a01b03938416815292909116602083015201610113565b81801561023d57600080fd5b5061025161024c36600461220d565b610a5c565b604080518351600f90810b8252602080860151820b908301529382015190930b9083015265ffffffffffff166060820152608001610113565b610251610298366004612230565b610c81565b61012f6102ab366004612230565b610d3c565b61012f6102be36600461225c565b610da2565b6101d96102d136600461228f565b610dd2565b6000806102e38484610de2565b9050610304816040015182600001516102fc91906122c7565b600f0b610fbc565b9150505b92915050565b600080600061031b610fe8565b90506000610327610fe8565b90506103328561101d565b65ffffffffffff16945088156105e157841561034f576000610351565b865b600f0b60408201528515610366576000610368565b875b600f0b604083015242861180156103825750600088600f0b135b156103c4576103956303c267008961232c565b600f0b60208301526103af6103aa428861236a565b611037565b82602001516103be9190612381565b600f0b82525b42851180156103d65750600087600f0b135b15610413576103e96303c267008861232c565b600f0b60208201526103fe6103aa428761236a565b816020015161040d9190612381565b600f0b81525b600086815260018b016020526040902054600f0b935084156104555785850361043e57839250610455565b600085815260018b016020526040902054600f0b92505b428611156104b157602082015161046c90856122c7565b93508486036104875760208101516104849085612416565b93505b600086815260018b016020526040902080546001600160801b0319166001600160801b0386161790555b428511156104fc57858511156104fc5760208101516104d09084612416565b600086815260018c016020526040902080546001600160801b0319166001600160801b03831617905592505b600089815260028b01602052604090206105169082611065565b50507f8b0a9686e26f875f7c3be0382e7593609c4d02c5161afd329687ca49cc339b608961054261092b565b60208401518451604080870151905161058a95949392919094855265ffffffffffff939093166020850152600f91820b6040850152810b60608401520b608082015260a00190565b60405180910390a1600089815260048b016020526040812081906105ad906110b8565b92509250508165ffffffffffff166000146105de576105d08c82868b6000611140565b6105de8c82858a6001611140565b50505b6105ed8a8a84846105f9565b50505050505050505050565b600080610605866113e1565b925092505060008265ffffffffffff166000036106225742610624565b825b905060006106398265ffffffffffff1661101d565b9050600061064a6303c26700610fbc565b61065c9065ffffffffffff8416612466565b90505b428265ffffffffffff16101561077e5761067c62093a808361247e565b91506000428365ffffffffffff1611156106a05761069942611499565b92506106bf565b5065ffffffffffff8216600090815260018a016020526040902054600f0b5b80600f0b600014610762576106e46106d785856124a8565b65ffffffffffff16611037565b85602001516106f39190612381565b85518690610702908390612416565b600f0b90525060208501805182919061071c9083906122c7565b600f90810b90915286516000910b1215905061073757600085525b60008560200151600f0b121561074f57600060208601525b919250829161075f8a84876114c2565b50505b818365ffffffffffff161115610778575061077e565b5061065f565b505085156108395761079b6103aa65ffffffffffff83164261236a565b82602001516107aa9190612381565b82516107b69190612416565b600f0b8252602080860151908501516107cf9190612416565b826020018181516107e091906122c7565b600f0b905250845184516107f49190612416565b825183906108039083906122c7565b600f0b9052506040808601519085015161081d9190612416565b8260400181815161082e91906122c7565b600f0b905250610875565b4261084f6103aa65ffffffffffff84168361236a565b836020015161085e9190612381565b8351849061086d908390612416565b600f0b905250505b61087f8783611065565b50507fdc8ed15e968adee1196e5ff0d83b745b050ee7aa99544d40a74145a036e35e386108aa61092b565b6020848101518551604080880151815165ffffffffffff9096168652600f93840b9486019490945290820b908401520b606082015260800160405180910390a150505050505050565b610909816000610901610fe8565b61017a610fe8565b50565b600061092661091961150e565b65ffffffffffff1661101d565b905090565b600061092661150e565b6000828152600484016020526040812061094f9083611519565b90505b9392505050565b600083815260048501602052604081208190610974906115c1565b9150836001600160a01b0316826001600160a01b031603610996575082610a53565b6000858152600287016020526040812081906109b1906113e1565b92509250506109cd8265ffffffffffff16426103aa919061236a565b81602001516109dc9190612381565b815182906109eb908390612416565b600f90810b90915282516000910b12159050610a0657600081525b6001600160a01b03841615610a2357610a23888583886000611140565b610a31888783886001611140565b60008781526004890160205260409020610a4b90876115fa565b508693505050505b94509492505050565b60408051606081018252600080825260208201819052918101919091526001600160a01b03821660009081526003840160205260408120819081908190610aa2906113e1565b9250925092508094508193508215610c28576000610ac78565ffffffffffff1661101d565b90506000610ad86303c26700610fbc565b610aea9065ffffffffffff8416612466565b90505b428265ffffffffffff161015610c2557610b0a62093a808361247e565b91506000428365ffffffffffff161115610b2657429250610b59565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b600014610c0957610b716106d788856124a8565b8860200151610b809190612381565b88518990610b8f908390612416565b600f0b905250602088018051829190610ba99083906122c7565b600f90810b90915289516000910b12159050610bc457600088525b60008860200151600f0b1215610bdc57600060208901525b6001600160a01b038916600090815260038b01602052604090209296508692610c0690848a6114c2565b50505b818365ffffffffffff161115610c1f5750610c25565b50610aed565b50505b7fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b3986610c5261092b565b602088015188516040808b01519051610c6f9594939291906124cf565b60405180910390a15050509250929050565b604080516060810182526000808252602082018190529181018290529080610ca884611499565b600086815260028801602052604081209192509081908190610cca9085611610565b92509250925082610ce15794509250610d34915050565b6000610cf06106d784876124a8565b8260200151610cff9190612381565b905080600f0b8260000151600f0b12610d24578151610d1f908290612416565b610d27565b60005b600f0b8252509450925050505b935093915050565b600080610d4883611499565b90506000610d5f86868465ffffffffffff16610c81565b5090508060400151600f0b600014610d8a57610d818160400151600f0b610fbc565b92505050610952565b8051610d9890600f0b610fbc565b9695505050505050565b600080610db0858585611726565b9050610dc9816040015182600001516102fc91906122c7565b95945050505050565b600061095283836101d442611499565b60408051606081018252600080825260208201819052918101829052908080610e0b8686611610565b92509250925082610e20579250610308915050565b6000610e338365ffffffffffff1661101d565b90506000610e446303c26700610fbc565b610e569065ffffffffffff8416612466565b90505b8665ffffffffffff168265ffffffffffff161015610f6457610e7e62093a808361247e565b915060008765ffffffffffff168365ffffffffffff161115610ea257879250610ec1565b5065ffffffffffff82166000908152600189016020526040902054600f0b5b80600f0b600014610f4857610ed96106d786856124a8565b8460200151610ee89190612381565b84518590610ef7908390612416565b600f0b905250602084018051829190610f119083906122c7565b600f90810b90915285516000910b12159050610f2c57600084525b60008460200151600f0b1215610f4457600060208501525b8294505b818365ffffffffffff161115610f5e5750610f64565b50610e59565b6000610f736106d7868a6124a8565b8460200151610f829190612381565b905080600f0b8460000151600f0b12610fa7578351610fa2908290612416565b610faa565b60005b600f0b84525091979650505050505050565b60008082600f0b1215610fe15760405162406f5d60e21b815260040160405180910390fd5b50600f0b90565b604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b600062093a8061102d818461250a565b610308919061251e565b600060016001607f1b03821115611061576040516393dafdf160e01b815260040160405180910390fd5b5090565b60408051606080820183526000808352602080840182905283850182905284519283018552818352820181905292810192909252906110ad6110a561092b565b8590856114c2565b915091509250929050565b8054600090819081908082036110d957600080600093509350935050611139565b60006110f8866110ea60018561236a565b600091825260209091200190565b60408051808201909152905465ffffffffffff8116808352600160301b9091046001600160a01b031660209092018290526001965094509250611139915050565b9193909250565b60008061114d8787610a5c565b909250905060006111696103aa65ffffffffffff84164261236a565b83602001516111789190612381565b83516111849190612416565b9050836112975742851115611230576020808701516001600160a01b038916600090815260058b01835260408082208983529093529182208054919290916111d0908490600f0b6122c7565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508260200151600f0b8660200151600f0b12611213576000611227565b856020015183602001516112279190612416565b600f0b60208401525b80600f0b8660000151600f0b12611248576000611254565b85516112549082612416565b600f90810b84526040808501519088015190820b910b1261127657600061128a565b8560400151836040015161128a9190612416565b600f0b604084015261134e565b42851115611320576020808701516001600160a01b038916600090815260058b01835260408082208983529093529182208054919290916112dc908490600f0b612416565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508560200151836020015161131791906122c7565b600f0b60208401525b855161132c90826122c7565b600f0b83526040808701519084015161134591906122c7565b600f0b60408401525b8260200151600f0b60000361136257600083525b6001600160a01b038716600090815260038901602052604090206113869084611065565b50507fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b39876113b261092b565b6020860151865160408089015190516113cf9594939291906124cf565b60405180910390a15050505050505050565b6040805160608101825260008082526020820181905291810182905281908354600081900361142157600080611415610fe8565b93509350935050611139565b60006114378661143260018561236a565b611931565b604080518082018252825465ffffffffffff1681528151606081018352600180850154600f81810b8452600160801b909104810b602084810191909152600290960154900b938201939093529281018390525190965094509250611139915050565b600065ffffffffffff821115611061576040516393dafdf160e01b815260040160405180910390fd5b604080516060808201835260008083526020808401829052838501829052845192830185528183528201819052928101929092529061150285858561195b565b91509150935093915050565b600061092642611499565b81546000908181600581111561157857600061153484611bd9565b61153e908561236a565b60008881526020902090915081015465ffffffffffff908116908716101561156857809150611576565b611573816001612466565b92505b505b600061158687878585611cc1565b905080156115b35761159d876110ea60018461236a565b54600160301b90046001600160a01b03166115b6565b60005b979650505050505050565b805460009080156115f1576115db836110ea60018461236a565b54600160301b90046001600160a01b0316610952565b60009392505050565b6000806110ad61160861092b565b859085611d23565b6040805160608101825260008082526020820181905291810182905281908454600081600581111561168957600061164784611bd9565b611651908561236a565b905061165d8982611931565b5465ffffffffffff908116908916101561167957809150611687565b611684816001612466565b92505b505b600061169789898585611d31565b80151597509050866116b0576116ab610fe8565b6116f2565b6116bf8961143260018461236a565b604080516060810182526001830154600f81810b8352600160801b909104810b602083015260029093015490920b908201525b945086611700576000611719565b61170f8961143260018461236a565b5465ffffffffffff165b9550505050509250925092565b60408051606081018252600080825260208201819052918101919091526001600160a01b038316600090815260038501602052604081208190819061176b9086611610565b92509250925082611780579250610952915050565b60006117938365ffffffffffff1661101d565b905060006117a46303c26700610fbc565b6117b69065ffffffffffff8416612466565b90505b8665ffffffffffff168265ffffffffffff1610156118d8576117de62093a808361247e565b915060008765ffffffffffff168365ffffffffffff16111561180257879250611835565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b6000146118bc5761184d6106d786856124a8565b846020015161185c9190612381565b8451859061186b908390612416565b600f0b9052506020840180518291906118859083906122c7565b600f90810b90915285516000910b121590506118a057600084525b60008460200151600f0b12156118b857600060208501525b8294505b818365ffffffffffff1611156118d257506118d8565b506117b9565b60006118e76106d7868a6124a8565b84602001516118f69190612381565b905080600f0b8460000151600f0b1261191b578351611916908290612416565b61191e565b60005b600f0b8452509198975050505050505050565b60008282815481106119455761194561253d565b9060005260206000209060030201905092915050565b6040805160608101825260008082526020820181905291810191909152604080516060810182526000808252602082018190529181019190915284548015611b365760006119ae8761143260018561236a565b604080518082018252825465ffffffffffff908116825282516060810184526001850154600f81810b8352600160801b909104810b602083810191909152600290960154900b9381019390935292810191909152805190925087821691161115611a2b57604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff808816911603611a955784611a4e8861143260018661236a565b815160208301516001600160801b03918216600160801b91831691909102176001830155604090920151600290910180546001600160801b03191691909216179055611b26565b60408051808201825265ffffffffffff888116825260208083018981528b5460018082018e5560008e815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546001600160801b031916929091169190911790555b602001519250839150610d349050565b60408051808201825265ffffffffffff878116825260208083018881528a5460018082018d5560008d815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546001600160801b03191692909116919091179055611bce610fe8565b849250925050610d34565b600081600003611beb57506000919050565b60006001611bf884611d88565b901c6001901b90506001818481611c1157611c11612316565b048201901c90506001818481611c2957611c29612316565b048201901c90506001818481611c4157611c41612316565b048201901c90506001818481611c5957611c59612316565b048201901c90506001818481611c7157611c71612316565b048201901c90506001818481611c8957611c89612316565b048201901c90506001818481611ca157611ca1612316565b048201901c905061095281828581611cbb57611cbb612316565b04611e1c565b60005b81831015611d1b576000611cd88484611e32565b60008781526020902090915065ffffffffffff86169082015465ffffffffffff161115611d0757809250611d15565b611d12816001612466565b93505b50611cc4565b509392505050565b600080611502858585611e4d565b60005b81831015611d1b576000611d488484611e32565b90508465ffffffffffff16611d5d8783611931565b5465ffffffffffff161115611d7457809250611d82565b611d7f816001612466565b93505b50611d34565b600080608083901c15611d9d57608092831c92015b604083901c15611daf57604092831c92015b602083901c15611dc157602092831c92015b601083901c15611dd357601092831c92015b600883901c15611de557600892831c92015b600483901c15611df757600492831c92015b600283901c15611e0957600292831c92015b600183901c156103085760010192915050565b6000818310611e2b5781610952565b5090919050565b6000611e41600284841861250a565b61095290848416612466565b825460009081908015611f85576000611e6b876110ea60018561236a565b60408051808201909152905465ffffffffffff808216808452600160301b9092046001600160a01b031660208401529192509087161015611ebf57604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff808816911603611f135784611ee2886110ea60018661236a565b80546001600160a01b0392909216600160301b026601000000000000600160d01b0319909216919091179055611b26565b6040805180820190915265ffffffffffff80881682526001600160a01b0380881660208085019182528b54600181018d5560008d8152919091209451940180549151909216600160301b026001600160d01b03199091169390921692909217179055602001519250839150610d349050565b50506040805180820190915265ffffffffffff80851682526001600160a01b0380851660208085019182528854600181018a5560008a81529182209551950180549251909316600160301b026001600160d01b0319909216949093169390931792909217909155905081610d34565b803565ffffffffffff8116811461200a57600080fd5b919050565b6000806040838503121561202257600080fd5b8235915061203260208401611ff4565b90509250929050565b8035600f81900b811461200a57600080fd5b60008060008060008060c0878903121561206657600080fd5b863595506020870135945061207d6040880161203b565b935061208b6060880161203b565b92506080870135915060a087013590509295509295509295565b6000606082840312156120b757600080fd5b6040516060810181811067ffffffffffffffff821117156120e857634e487b7160e01b600052604160045260246000fd5b6040529050806120f78361203b565b81526121056020840161203b565b60208201526121166040840161203b565b60408201525092915050565b600080600080610100858703121561213957600080fd5b843593506020850135925061215186604087016120a5565b91506121608660a087016120a5565b905092959194509250565b60006020828403121561217d57600080fd5b5035919050565b60008060006060848603121561219957600080fd5b83359250602084013591506121b060408501611ff4565b90509250925092565b80356001600160a01b038116811461200a57600080fd5b600080600080608085870312156121e657600080fd5b84359350602085013592506121fd604086016121b9565b9396929550929360600135925050565b6000806040838503121561222057600080fd5b82359150612032602084016121b9565b60008060006060848603121561224557600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561227157600080fd5b83359250612281602085016121b9565b91506121b060408501611ff4565b600080604083850312156122a257600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b600081600f0b83600f0b600082128260016001607f1b03038213811516156122f1576122f16122b1565b8260016001607f1b031903821281161561230d5761230d6122b1565b50019392505050565b634e487b7160e01b600052601260045260246000fd5b600081600f0b83600f0b8061234357612343612316565b60016001607f1b0319821460001982141615612361576123616122b1565b90059392505050565b60008282101561237c5761237c6122b1565b500390565b600081600f0b83600f0b60016001607f1b036000821360008413838304851182821616156123b1576123b16122b1565b60016001607f1b031960008512828116878305871216156123d4576123d46122b1565b600087129250858205871284841616156123f0576123f06122b1565b85850587128184161615612406576124066122b1565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b031901831281151615612441576124416122b1565b8160016001607f1b0301831381161561245c5761245c6122b1565b5090039392505050565b60008219821115612479576124796122b1565b500190565b600065ffffffffffff80831681851680830382111561249f5761249f6122b1565b01949350505050565b600065ffffffffffff838116908316818110156124c7576124c76122b1565b039392505050565b6001600160a01b0395909516855265ffffffffffff939093166020850152600f91820b6040850152810b60608401520b608082015260a00190565b60008261251957612519612316565b500490565b6000816000190483118215151615612538576125386122b1565b500290565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220a77fad9c0993e22947fdc797415b9fdbfa4c1a39c63b8e775729dc965aa2021964736f6c634300080d0033
Deployed Bytecode
0x73fd3d17d25c05456caa4a9d6e9feaf71aa604710230146080604052600436106100f45760003560e01c80639511aa5311610096578063e680a31011610070578063e680a3101461028a578063f400f3c41461029d578063f8183ecf146102b0578063f83bb313146102c357600080fd5b80639511aa53146101c65780639bdd2e4d146101f1578063d7ac26da1461023157600080fd5b8063683e955b116100d2578063683e955b1461015f5780636977e3a91461017f57806382d4bd171461019f57806391ddadf4146101be57600080fd5b806326949984146100f957806334e78a9e1461011c5780634cd260561461013d575b600080fd5b6101046303c2670081565b604051600f9190910b81526020015b60405180910390f35b61012f61012a36600461200f565b6102d6565b604051908152602001610113565b81801561014957600080fd5b5061015d61015836600461204d565b61030e565b005b81801561016b57600080fd5b5061015d61017a366004612122565b6105f9565b81801561018b57600080fd5b5061015d61019a36600461216b565b6108f3565b6101a761090c565b60405165ffffffffffff9091168152602001610113565b6101a761092b565b6101d96101d4366004612184565b610935565b6040516001600160a01b039091168152602001610113565b8180156101fd57600080fd5b5061021161020c3660046121d0565b610959565b604080516001600160a01b03938416815292909116602083015201610113565b81801561023d57600080fd5b5061025161024c36600461220d565b610a5c565b604080518351600f90810b8252602080860151820b908301529382015190930b9083015265ffffffffffff166060820152608001610113565b610251610298366004612230565b610c81565b61012f6102ab366004612230565b610d3c565b61012f6102be36600461225c565b610da2565b6101d96102d136600461228f565b610dd2565b6000806102e38484610de2565b9050610304816040015182600001516102fc91906122c7565b600f0b610fbc565b9150505b92915050565b600080600061031b610fe8565b90506000610327610fe8565b90506103328561101d565b65ffffffffffff16945088156105e157841561034f576000610351565b865b600f0b60408201528515610366576000610368565b875b600f0b604083015242861180156103825750600088600f0b135b156103c4576103956303c267008961232c565b600f0b60208301526103af6103aa428861236a565b611037565b82602001516103be9190612381565b600f0b82525b42851180156103d65750600087600f0b135b15610413576103e96303c267008861232c565b600f0b60208201526103fe6103aa428761236a565b816020015161040d9190612381565b600f0b81525b600086815260018b016020526040902054600f0b935084156104555785850361043e57839250610455565b600085815260018b016020526040902054600f0b92505b428611156104b157602082015161046c90856122c7565b93508486036104875760208101516104849085612416565b93505b600086815260018b016020526040902080546001600160801b0319166001600160801b0386161790555b428511156104fc57858511156104fc5760208101516104d09084612416565b600086815260018c016020526040902080546001600160801b0319166001600160801b03831617905592505b600089815260028b01602052604090206105169082611065565b50507f8b0a9686e26f875f7c3be0382e7593609c4d02c5161afd329687ca49cc339b608961054261092b565b60208401518451604080870151905161058a95949392919094855265ffffffffffff939093166020850152600f91820b6040850152810b60608401520b608082015260a00190565b60405180910390a1600089815260048b016020526040812081906105ad906110b8565b92509250508165ffffffffffff166000146105de576105d08c82868b6000611140565b6105de8c82858a6001611140565b50505b6105ed8a8a84846105f9565b50505050505050505050565b600080610605866113e1565b925092505060008265ffffffffffff166000036106225742610624565b825b905060006106398265ffffffffffff1661101d565b9050600061064a6303c26700610fbc565b61065c9065ffffffffffff8416612466565b90505b428265ffffffffffff16101561077e5761067c62093a808361247e565b91506000428365ffffffffffff1611156106a05761069942611499565b92506106bf565b5065ffffffffffff8216600090815260018a016020526040902054600f0b5b80600f0b600014610762576106e46106d785856124a8565b65ffffffffffff16611037565b85602001516106f39190612381565b85518690610702908390612416565b600f0b90525060208501805182919061071c9083906122c7565b600f90810b90915286516000910b1215905061073757600085525b60008560200151600f0b121561074f57600060208601525b919250829161075f8a84876114c2565b50505b818365ffffffffffff161115610778575061077e565b5061065f565b505085156108395761079b6103aa65ffffffffffff83164261236a565b82602001516107aa9190612381565b82516107b69190612416565b600f0b8252602080860151908501516107cf9190612416565b826020018181516107e091906122c7565b600f0b905250845184516107f49190612416565b825183906108039083906122c7565b600f0b9052506040808601519085015161081d9190612416565b8260400181815161082e91906122c7565b600f0b905250610875565b4261084f6103aa65ffffffffffff84168361236a565b836020015161085e9190612381565b8351849061086d908390612416565b600f0b905250505b61087f8783611065565b50507fdc8ed15e968adee1196e5ff0d83b745b050ee7aa99544d40a74145a036e35e386108aa61092b565b6020848101518551604080880151815165ffffffffffff9096168652600f93840b9486019490945290820b908401520b606082015260800160405180910390a150505050505050565b610909816000610901610fe8565b61017a610fe8565b50565b600061092661091961150e565b65ffffffffffff1661101d565b905090565b600061092661150e565b6000828152600484016020526040812061094f9083611519565b90505b9392505050565b600083815260048501602052604081208190610974906115c1565b9150836001600160a01b0316826001600160a01b031603610996575082610a53565b6000858152600287016020526040812081906109b1906113e1565b92509250506109cd8265ffffffffffff16426103aa919061236a565b81602001516109dc9190612381565b815182906109eb908390612416565b600f90810b90915282516000910b12159050610a0657600081525b6001600160a01b03841615610a2357610a23888583886000611140565b610a31888783886001611140565b60008781526004890160205260409020610a4b90876115fa565b508693505050505b94509492505050565b60408051606081018252600080825260208201819052918101919091526001600160a01b03821660009081526003840160205260408120819081908190610aa2906113e1565b9250925092508094508193508215610c28576000610ac78565ffffffffffff1661101d565b90506000610ad86303c26700610fbc565b610aea9065ffffffffffff8416612466565b90505b428265ffffffffffff161015610c2557610b0a62093a808361247e565b91506000428365ffffffffffff161115610b2657429250610b59565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b600014610c0957610b716106d788856124a8565b8860200151610b809190612381565b88518990610b8f908390612416565b600f0b905250602088018051829190610ba99083906122c7565b600f90810b90915289516000910b12159050610bc457600088525b60008860200151600f0b1215610bdc57600060208901525b6001600160a01b038916600090815260038b01602052604090209296508692610c0690848a6114c2565b50505b818365ffffffffffff161115610c1f5750610c25565b50610aed565b50505b7fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b3986610c5261092b565b602088015188516040808b01519051610c6f9594939291906124cf565b60405180910390a15050509250929050565b604080516060810182526000808252602082018190529181018290529080610ca884611499565b600086815260028801602052604081209192509081908190610cca9085611610565b92509250925082610ce15794509250610d34915050565b6000610cf06106d784876124a8565b8260200151610cff9190612381565b905080600f0b8260000151600f0b12610d24578151610d1f908290612416565b610d27565b60005b600f0b8252509450925050505b935093915050565b600080610d4883611499565b90506000610d5f86868465ffffffffffff16610c81565b5090508060400151600f0b600014610d8a57610d818160400151600f0b610fbc565b92505050610952565b8051610d9890600f0b610fbc565b9695505050505050565b600080610db0858585611726565b9050610dc9816040015182600001516102fc91906122c7565b95945050505050565b600061095283836101d442611499565b60408051606081018252600080825260208201819052918101829052908080610e0b8686611610565b92509250925082610e20579250610308915050565b6000610e338365ffffffffffff1661101d565b90506000610e446303c26700610fbc565b610e569065ffffffffffff8416612466565b90505b8665ffffffffffff168265ffffffffffff161015610f6457610e7e62093a808361247e565b915060008765ffffffffffff168365ffffffffffff161115610ea257879250610ec1565b5065ffffffffffff82166000908152600189016020526040902054600f0b5b80600f0b600014610f4857610ed96106d786856124a8565b8460200151610ee89190612381565b84518590610ef7908390612416565b600f0b905250602084018051829190610f119083906122c7565b600f90810b90915285516000910b12159050610f2c57600084525b60008460200151600f0b1215610f4457600060208501525b8294505b818365ffffffffffff161115610f5e5750610f64565b50610e59565b6000610f736106d7868a6124a8565b8460200151610f829190612381565b905080600f0b8460000151600f0b12610fa7578351610fa2908290612416565b610faa565b60005b600f0b84525091979650505050505050565b60008082600f0b1215610fe15760405162406f5d60e21b815260040160405180910390fd5b50600f0b90565b604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b600062093a8061102d818461250a565b610308919061251e565b600060016001607f1b03821115611061576040516393dafdf160e01b815260040160405180910390fd5b5090565b60408051606080820183526000808352602080840182905283850182905284519283018552818352820181905292810192909252906110ad6110a561092b565b8590856114c2565b915091509250929050565b8054600090819081908082036110d957600080600093509350935050611139565b60006110f8866110ea60018561236a565b600091825260209091200190565b60408051808201909152905465ffffffffffff8116808352600160301b9091046001600160a01b031660209092018290526001965094509250611139915050565b9193909250565b60008061114d8787610a5c565b909250905060006111696103aa65ffffffffffff84164261236a565b83602001516111789190612381565b83516111849190612416565b9050836112975742851115611230576020808701516001600160a01b038916600090815260058b01835260408082208983529093529182208054919290916111d0908490600f0b6122c7565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508260200151600f0b8660200151600f0b12611213576000611227565b856020015183602001516112279190612416565b600f0b60208401525b80600f0b8660000151600f0b12611248576000611254565b85516112549082612416565b600f90810b84526040808501519088015190820b910b1261127657600061128a565b8560400151836040015161128a9190612416565b600f0b604084015261134e565b42851115611320576020808701516001600160a01b038916600090815260058b01835260408082208983529093529182208054919290916112dc908490600f0b612416565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508560200151836020015161131791906122c7565b600f0b60208401525b855161132c90826122c7565b600f0b83526040808701519084015161134591906122c7565b600f0b60408401525b8260200151600f0b60000361136257600083525b6001600160a01b038716600090815260038901602052604090206113869084611065565b50507fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b39876113b261092b565b6020860151865160408089015190516113cf9594939291906124cf565b60405180910390a15050505050505050565b6040805160608101825260008082526020820181905291810182905281908354600081900361142157600080611415610fe8565b93509350935050611139565b60006114378661143260018561236a565b611931565b604080518082018252825465ffffffffffff1681528151606081018352600180850154600f81810b8452600160801b909104810b602084810191909152600290960154900b938201939093529281018390525190965094509250611139915050565b600065ffffffffffff821115611061576040516393dafdf160e01b815260040160405180910390fd5b604080516060808201835260008083526020808401829052838501829052845192830185528183528201819052928101929092529061150285858561195b565b91509150935093915050565b600061092642611499565b81546000908181600581111561157857600061153484611bd9565b61153e908561236a565b60008881526020902090915081015465ffffffffffff908116908716101561156857809150611576565b611573816001612466565b92505b505b600061158687878585611cc1565b905080156115b35761159d876110ea60018461236a565b54600160301b90046001600160a01b03166115b6565b60005b979650505050505050565b805460009080156115f1576115db836110ea60018461236a565b54600160301b90046001600160a01b0316610952565b60009392505050565b6000806110ad61160861092b565b859085611d23565b6040805160608101825260008082526020820181905291810182905281908454600081600581111561168957600061164784611bd9565b611651908561236a565b905061165d8982611931565b5465ffffffffffff908116908916101561167957809150611687565b611684816001612466565b92505b505b600061169789898585611d31565b80151597509050866116b0576116ab610fe8565b6116f2565b6116bf8961143260018461236a565b604080516060810182526001830154600f81810b8352600160801b909104810b602083015260029093015490920b908201525b945086611700576000611719565b61170f8961143260018461236a565b5465ffffffffffff165b9550505050509250925092565b60408051606081018252600080825260208201819052918101919091526001600160a01b038316600090815260038501602052604081208190819061176b9086611610565b92509250925082611780579250610952915050565b60006117938365ffffffffffff1661101d565b905060006117a46303c26700610fbc565b6117b69065ffffffffffff8416612466565b90505b8665ffffffffffff168265ffffffffffff1610156118d8576117de62093a808361247e565b915060008765ffffffffffff168365ffffffffffff16111561180257879250611835565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b6000146118bc5761184d6106d786856124a8565b846020015161185c9190612381565b8451859061186b908390612416565b600f0b9052506020840180518291906118859083906122c7565b600f90810b90915285516000910b121590506118a057600084525b60008460200151600f0b12156118b857600060208501525b8294505b818365ffffffffffff1611156118d257506118d8565b506117b9565b60006118e76106d7868a6124a8565b84602001516118f69190612381565b905080600f0b8460000151600f0b1261191b578351611916908290612416565b61191e565b60005b600f0b8452509198975050505050505050565b60008282815481106119455761194561253d565b9060005260206000209060030201905092915050565b6040805160608101825260008082526020820181905291810191909152604080516060810182526000808252602082018190529181019190915284548015611b365760006119ae8761143260018561236a565b604080518082018252825465ffffffffffff908116825282516060810184526001850154600f81810b8352600160801b909104810b602083810191909152600290960154900b9381019390935292810191909152805190925087821691161115611a2b57604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff808816911603611a955784611a4e8861143260018661236a565b815160208301516001600160801b03918216600160801b91831691909102176001830155604090920151600290910180546001600160801b03191691909216179055611b26565b60408051808201825265ffffffffffff888116825260208083018981528b5460018082018e5560008e815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546001600160801b031916929091169190911790555b602001519250839150610d349050565b60408051808201825265ffffffffffff878116825260208083018881528a5460018082018d5560008d815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546001600160801b03191692909116919091179055611bce610fe8565b849250925050610d34565b600081600003611beb57506000919050565b60006001611bf884611d88565b901c6001901b90506001818481611c1157611c11612316565b048201901c90506001818481611c2957611c29612316565b048201901c90506001818481611c4157611c41612316565b048201901c90506001818481611c5957611c59612316565b048201901c90506001818481611c7157611c71612316565b048201901c90506001818481611c8957611c89612316565b048201901c90506001818481611ca157611ca1612316565b048201901c905061095281828581611cbb57611cbb612316565b04611e1c565b60005b81831015611d1b576000611cd88484611e32565b60008781526020902090915065ffffffffffff86169082015465ffffffffffff161115611d0757809250611d15565b611d12816001612466565b93505b50611cc4565b509392505050565b600080611502858585611e4d565b60005b81831015611d1b576000611d488484611e32565b90508465ffffffffffff16611d5d8783611931565b5465ffffffffffff161115611d7457809250611d82565b611d7f816001612466565b93505b50611d34565b600080608083901c15611d9d57608092831c92015b604083901c15611daf57604092831c92015b602083901c15611dc157602092831c92015b601083901c15611dd357601092831c92015b600883901c15611de557600892831c92015b600483901c15611df757600492831c92015b600283901c15611e0957600292831c92015b600183901c156103085760010192915050565b6000818310611e2b5781610952565b5090919050565b6000611e41600284841861250a565b61095290848416612466565b825460009081908015611f85576000611e6b876110ea60018561236a565b60408051808201909152905465ffffffffffff808216808452600160301b9092046001600160a01b031660208401529192509087161015611ebf57604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff808816911603611f135784611ee2886110ea60018661236a565b80546001600160a01b0392909216600160301b026601000000000000600160d01b0319909216919091179055611b26565b6040805180820190915265ffffffffffff80881682526001600160a01b0380881660208085019182528b54600181018d5560008d8152919091209451940180549151909216600160301b026001600160d01b03199091169390921692909217179055602001519250839150610d349050565b50506040805180820190915265ffffffffffff80851682526001600160a01b0380851660208085019182528854600181018a5560008a81529182209551950180549251909316600160301b026001600160d01b0319909216949093169390931792909217909155905081610d34565b803565ffffffffffff8116811461200a57600080fd5b919050565b6000806040838503121561202257600080fd5b8235915061203260208401611ff4565b90509250929050565b8035600f81900b811461200a57600080fd5b60008060008060008060c0878903121561206657600080fd5b863595506020870135945061207d6040880161203b565b935061208b6060880161203b565b92506080870135915060a087013590509295509295509295565b6000606082840312156120b757600080fd5b6040516060810181811067ffffffffffffffff821117156120e857634e487b7160e01b600052604160045260246000fd5b6040529050806120f78361203b565b81526121056020840161203b565b60208201526121166040840161203b565b60408201525092915050565b600080600080610100858703121561213957600080fd5b843593506020850135925061215186604087016120a5565b91506121608660a087016120a5565b905092959194509250565b60006020828403121561217d57600080fd5b5035919050565b60008060006060848603121561219957600080fd5b83359250602084013591506121b060408501611ff4565b90509250925092565b80356001600160a01b038116811461200a57600080fd5b600080600080608085870312156121e657600080fd5b84359350602085013592506121fd604086016121b9565b9396929550929360600135925050565b6000806040838503121561222057600080fd5b82359150612032602084016121b9565b60008060006060848603121561224557600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561227157600080fd5b83359250612281602085016121b9565b91506121b060408501611ff4565b600080604083850312156122a257600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b600081600f0b83600f0b600082128260016001607f1b03038213811516156122f1576122f16122b1565b8260016001607f1b031903821281161561230d5761230d6122b1565b50019392505050565b634e487b7160e01b600052601260045260246000fd5b600081600f0b83600f0b8061234357612343612316565b60016001607f1b0319821460001982141615612361576123616122b1565b90059392505050565b60008282101561237c5761237c6122b1565b500390565b600081600f0b83600f0b60016001607f1b036000821360008413838304851182821616156123b1576123b16122b1565b60016001607f1b031960008512828116878305871216156123d4576123d46122b1565b600087129250858205871284841616156123f0576123f06122b1565b85850587128184161615612406576124066122b1565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b031901831281151615612441576124416122b1565b8160016001607f1b0301831381161561245c5761245c6122b1565b5090039392505050565b60008219821115612479576124796122b1565b500190565b600065ffffffffffff80831681851680830382111561249f5761249f6122b1565b01949350505050565b600065ffffffffffff838116908316818110156124c7576124c76122b1565b039392505050565b6001600160a01b0395909516855265ffffffffffff939093166020850152600f91820b6040850152810b60608401520b608082015260a00190565b60008261251957612519612316565b500490565b6000816000190483118215151615612538576125386122b1565b500290565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220a77fad9c0993e22947fdc797415b9fdbfa4c1a39c63b8e775729dc965aa2021964736f6c634300080d0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.