Source Code
Overview
ETH Balance
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 3029470 | 677 days ago | 0 ETH | ||||
| 3029470 | 677 days ago | 0 ETH | ||||
| 3029470 | 677 days ago | 0 ETH | ||||
| 3029423 | 677 days ago | 0 ETH | ||||
| 3029393 | 677 days ago | 0 ETH | ||||
| 3029342 | 677 days ago | 0 ETH | ||||
| 3029342 | 677 days ago | 0 ETH | ||||
| 3029342 | 677 days ago | 0 ETH | ||||
| 3029342 | 677 days ago | 0 ETH | ||||
| 3029341 | 677 days ago | 0 ETH | ||||
| 3029335 | 677 days ago | 0 ETH | ||||
| 3029332 | 677 days ago | 0 ETH | ||||
| 3029332 | 677 days ago | 0 ETH | ||||
| 3029332 | 677 days ago | 0 ETH | ||||
| 3029332 | 677 days ago | 0 ETH | ||||
| 3029327 | 677 days ago | 0 ETH | ||||
| 3029327 | 677 days ago | 0 ETH | ||||
| 3029327 | 677 days ago | 0 ETH | ||||
| 3029327 | 677 days ago | 0 ETH | ||||
| 3029326 | 677 days ago | 0 ETH | ||||
| 3029326 | 677 days ago | 0 ETH | ||||
| 3029326 | 677 days ago | 0 ETH | ||||
| 3029326 | 677 days ago | 0 ETH | ||||
| 3029326 | 677 days ago | 0 ETH | ||||
| 3029326 | 677 days ago | 0 ETH |
Cross-Chain Transactions
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
0x7373aebf4fc47b6ee32a15520bdf720e58bb429bcf30146080604052600436106100ff5760003560e01c806391ddadf4116100a1578063e680a31011610070578063e680a3101461029f578063f400f3c4146102b2578063f8183ecf146102c5578063f83bb313146102d857600080fd5b806391ddadf4146101d35780639511aa53146101db5780639bdd2e4d14610206578063d7ac26da1461024657600080fd5b806354703153116100dd578063547031531461016a578063683e955b1461018b5780636977e3a9146101ab57806382d4bd17146101cb57600080fd5b8063269499841461010457806334e78a9e146101275780634cd2605614610148575b600080fd5b61010f6303c2670081565b604051600f9190910b81526020015b60405180910390f35b61013a610135366004612216565b6102eb565b60405190815260200161011e565b81801561015457600080fd5b50610168610163366004612254565b610323565b005b61017462093a8081565b60405165ffffffffffff909116815260200161011e565b81801561019757600080fd5b506101686101a6366004612329565b610680565b8180156101b757600080fd5b506101686101c6366004612372565b61097a565b6101746109f2565b610174610a11565b6101ee6101e936600461238b565b610a1b565b6040516001600160a01b03909116815260200161011e565b81801561021257600080fd5b506102266102213660046123d7565b610a3f565b604080516001600160a01b0393841681529290911660208301520161011e565b81801561025257600080fd5b50610266610261366004612414565b610b62565b604080518351600f90810b8252602080860151820b908301529382015190930b9083015265ffffffffffff16606082015260800161011e565b6102666102ad366004612437565b610db5565b61013a6102c0366004612437565b610e70565b61013a6102d3366004612463565b610ed6565b6101ee6102e6366004612496565b610f06565b6000806102f88484610f16565b90506103198160400151826000015161031191906124ce565b600f0b6110f5565b9150505b92915050565b6000806000610360604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b9050600061039c604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b90506103a78561113b565b65ffffffffffff16945088156106685784156103c45760006103c6565b865b600f0b604082015285156103db5760006103dd565b875b600f0b604083015242861180156103f75750600088600f0b135b156104395761040a6303c2670089612545565b600f0b602083015261042461041f428861258c565b611155565b826020015161043391906125a3565b600f0b82525b428511801561044b5750600087600f0b135b156104885761045e6303c2670088612545565b600f0b602082015261047361041f428761258c565b816020015161048291906125a3565b600f0b81525b600086815260018b016020526040902054600f0b935084156104ca578585036104b3578392506104ca565b600085815260018b016020526040902054600f0b92505b4286111561052f5760208201516104e190856124ce565b93508486036104fc5760208101516104f9908561264a565b93505b600086815260018b016020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b0386161790555b42851115610583578585111561058357602081015161054e908461264a565b600086815260018c016020526040902080546fffffffffffffffffffffffffffffffff19166001600160801b03831617905592505b600089815260028b016020526040902061059d908261118c565b50507f8b0a9686e26f875f7c3be0382e7593609c4d02c5161afd329687ca49cc339b60896105c9610a11565b60208401518451604080870151905161061195949392919094855265ffffffffffff939093166020850152600f91820b6040850152810b60608401520b608082015260a00190565b60405180910390a1600089815260048b01602052604081208190610634906111df565b92509250508165ffffffffffff16600014610665576106578c82868b600061126a565b6106658c82858a600161126a565b50505b6106748a8a8484610680565b50505050505050505050565b60008061068c86611539565b925092505060008265ffffffffffff166000036106a957426106ab565b825b905060006106c08265ffffffffffff1661113b565b905060006106d16303c267006110f5565b6106e39065ffffffffffff84166126ac565b90505b428265ffffffffffff1610156108055761070362093a80836126c4565b91506000428365ffffffffffff1611156107275761072042611621565b9250610746565b5065ffffffffffff8216600090815260018a016020526040902054600f0b5b80600f0b6000146107e95761076b61075e85856126ee565b65ffffffffffff16611155565b856020015161077a91906125a3565b8551869061078990839061264a565b600f0b9052506020850180518291906107a39083906124ce565b600f90810b90915286516000910b121590506107be57600085525b60008560200151600f0b12156107d657600060208601525b91925082916107e68a848761164a565b50505b818365ffffffffffff1611156107ff5750610805565b506106e6565b505085156108c05761082261041f65ffffffffffff83164261258c565b826020015161083191906125a3565b825161083d919061264a565b600f0b825260208086015190850151610856919061264a565b8260200181815161086791906124ce565b600f0b9052508451845161087b919061264a565b8251839061088a9083906124ce565b600f0b905250604080860151908501516108a4919061264a565b826040018181516108b591906124ce565b600f0b9052506108fc565b426108d661041f65ffffffffffff84168361258c565b83602001516108e591906125a3565b835184906108f490839061264a565b600f0b905250505b610906878361118c565b50507fdc8ed15e968adee1196e5ff0d83b745b050ee7aa99544d40a74145a036e35e38610931610a11565b6020848101518551604080880151815165ffffffffffff9096168652600f93840b9486019490945290820b908401520b606082015260800160405180910390a150505050505050565b6109ef8160006109b8604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b6040805160608082018352600080835260208084018290529284018190528351918201845280825291810182905291820152610680565b50565b6000610a0c6109ff611696565b65ffffffffffff1661113b565b905090565b6000610a0c611696565b60008281526004840160205260408120610a3590836116a1565b90505b9392505050565b600083815260048501602052604081208190610a5a9061174c565b9150836001600160a01b0316826001600160a01b031603610a7c575082610b59565b600085815260028701602052604081208190610a9790611539565b9250925050610ab38265ffffffffffff164261041f919061258c565b8160200151610ac291906125a3565b81518290610ad190839061264a565b600f90810b90915282516000910b12159050610aec57600081525b856001600160a01b0316846001600160a01b031614158015610b1657506001600160a01b03841615155b15610b2957610b2988858388600061126a565b610b3788878388600161126a565b60008781526004890160205260409020610b519087611788565b508693505050505b94509492505050565b60408051606081018252600080825260208201819052918101919091526001600160a01b03821660009081526003840160205260408120819081908190610ba890611539565b9250925092508094508193508215610d2e576000610bcd8565ffffffffffff1661113b565b90506000610bde6303c267006110f5565b610bf09065ffffffffffff84166126ac565b90505b428265ffffffffffff161015610d2b57610c1062093a80836126c4565b91506000428365ffffffffffff161115610c2c57429250610c5f565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b600014610d0f57610c7761075e88856126ee565b8860200151610c8691906125a3565b88518990610c9590839061264a565b600f0b905250602088018051829190610caf9083906124ce565b600f90810b90915289516000910b12159050610cca57600088525b60008860200151600f0b1215610ce257600060208901525b6001600160a01b038916600090815260038b01602052604090209296508692610d0c90848a61164a565b50505b818365ffffffffffff161115610d255750610d2b565b50610bf3565b50505b7fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b3986610d58610a11565b60208881015189516040808c015181516001600160a01b03909716875265ffffffffffff90951693860193909352600f91820b9285019290925290810b60608401520b608082015260a00160405180910390a15050509250929050565b604080516060810182526000808252602082018190529181018290529080610ddc84611621565b600086815260028801602052604081209192509081908190610dfe908561179e565b92509250925082610e155794509250610e68915050565b6000610e2461075e84876126ee565b8260200151610e3391906125a3565b905080600f0b8260000151600f0b12610e58578151610e5390829061264a565b610e5b565b60005b600f0b8252509450925050505b935093915050565b600080610e7c83611621565b90506000610e9386868465ffffffffffff16610db5565b5090508060400151600f0b600014610ebe57610eb58160400151600f0b6110f5565b92505050610a38565b8051610ecc90600f0b6110f5565b9695505050505050565b600080610ee48585856118de565b9050610efd8160400151826000015161031191906124ce565b95945050505050565b6000610a3883836101e942611621565b60408051606081018252600080825260208201819052918101919091528160008080610f42878561179e565b92509250925082610f5857935061031d92505050565b6000610f6b8365ffffffffffff1661113b565b90506000610f7c6303c267006110f5565b610f8e9065ffffffffffff84166126ac565b90505b8765ffffffffffff168265ffffffffffff16101561109c57610fb662093a80836126c4565b915060008865ffffffffffff168365ffffffffffff161115610fda57889250610ff9565b5065ffffffffffff8216600090815260018a016020526040902054600f0b5b80600f0b6000146110805761101161075e86856126ee565b846020015161102091906125a3565b8451859061102f90839061264a565b600f0b9052506020840180518291906110499083906124ce565b600f90810b90915285516000910b1215905061106457600084525b60008460200151600f0b121561107c57600060208501525b8294505b818365ffffffffffff161115611096575061109c565b50610f91565b60006110ab61075e86896126ee565b84602001516110ba91906125a3565b905080600f0b8460000151600f0b126110df5783516110da90829061264a565b6110e2565b60005b600f0b8452509198975050505050505050565b60008082600f0b1215611134576040517f0101bd7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600f0b90565b600062093a8061114b8184612715565b61031d9190612729565b60006f7fffffffffffffffffffffffffffffff821115611188576040516393dafdf160e01b815260040160405180910390fd5b5090565b60408051606080820183526000808352602080840182905283850182905284519283018552818352820181905292810192909252906111d46111cc610a11565b85908561164a565b915091509250929050565b80546000908190819080820361120057600080600093509350935050611263565b600061121f8661121160018561258c565b600091825260209091200190565b60408051808201909152905465ffffffffffff811680835266010000000000009091046001600160a01b031660209092018290526001965094509250611263915050565b9193909250565b6000806112778787610b62565b9092509050600061129361041f65ffffffffffff84164261258c565b83602001516112a291906125a3565b83516112ae919061264a565b9050836113c1574285111561135a576020808701516001600160a01b038916600090815260058b01835260408082208983529093529182208054919290916112fa908490600f0b6124ce565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508260200151600f0b8660200151600f0b1261133d576000611351565b85602001518360200151611351919061264a565b600f0b60208401525b80600f0b8660000151600f0b1261137257600061137e565b855161137e908261264a565b600f90810b84526040808501519088015190820b910b126113a05760006113b4565b856040015183604001516113b4919061264a565b600f0b6040840152611478565b4285111561144a576020808701516001600160a01b038916600090815260058b0183526040808220898352909352918220805491929091611406908490600f0b61264a565b92506101000a8154816001600160801b030219169083600f0b6001600160801b031602179055508560200151836020015161144191906124ce565b600f0b60208401525b855161145690826124ce565b600f0b83526040808701519084015161146f91906124ce565b600f0b60408401525b8260200151600f0b60000361148c57600083525b6001600160a01b038716600090815260038901602052604090206114b0908461118c565b50507fc5396bd0d5b21891ce90363f0f17e19e48b228d8a66186ae447c827403610b39876114dc610a11565b60208681015187516040808a015181516001600160a01b03909716875265ffffffffffff90951693860193909352600f91820b9285019290925290810b60608401520b608082015260a00160405180910390a15050505050505050565b604080516060810182526000808252602082018190529181018290528190835460008190036115a95760008061159d604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b93509350935050611263565b60006115bf866115ba60018561258c565b611a9f565b604080518082018252825465ffffffffffff1681528151606081018352600180850154600f81810b8452600160801b909104810b602084810191909152600290960154900b938201939093529281018390525190965094509250611263915050565b600065ffffffffffff821115611188576040516393dafdf160e01b815260040160405180910390fd5b604080516060808201835260008083526020808401829052838501829052845192830185528183528201819052928101929092529061168a858585611ac9565b91509150935093915050565b6000610a0c42611621565b8154600090818160058111156117005760006116bc84611d92565b6116c6908561258c565b60008881526020902090915081015465ffffffffffff90811690871610156116f0578091506116fe565b6116fb8160016126ac565b92505b505b600061170e87878585611e7a565b9050801561173e576117258761121160018461258c565b54660100000000000090046001600160a01b0316611741565b60005b979650505050505050565b8054600090801561177f576117668361121160018461258c565b54660100000000000090046001600160a01b0316610a38565b60009392505050565b6000806111d4611796610a11565b859085611edc565b604080516060810182526000808252602082018190529181018290528190845460008160058111156118175760006117d584611d92565b6117df908561258c565b90506117eb8982611a9f565b5465ffffffffffff908116908916101561180757809150611815565b6118128160016126ac565b92505b505b600061182589898585611eea565b80151597509050866118685760408051606080820183526000808352602080840182905292840181905283519182018452808252918101829052918201526118aa565b611877896115ba60018461258c565b604080516060810182526001830154600f81810b8352600160801b909104810b602083015260029093015490920b908201525b9450866118b85760006118d1565b6118c7896115ba60018461258c565b5465ffffffffffff165b9550505050509250925092565b60408051606081018252600080825260208201819052918101919091526001600160a01b0383166000908152600385016020526040812081908190611923908661179e565b92509250925082611938579250610a38915050565b600061194b8365ffffffffffff1661113b565b9050600061195c6303c267006110f5565b61196e9065ffffffffffff84166126ac565b90505b8665ffffffffffff168265ffffffffffff161015611a905761199662093a80836126c4565b915060008765ffffffffffff168365ffffffffffff1611156119ba578792506119ed565b506001600160a01b038816600090815260058a016020908152604080832065ffffffffffff86168452909152902054600f0b5b80600f0b600014611a7457611a0561075e86856126ee565b8460200151611a1491906125a3565b84518590611a2390839061264a565b600f0b905250602084018051829190611a3d9083906124ce565b600f90810b90915285516000910b12159050611a5857600084525b60008460200151600f0b1215611a7057600060208501525b8294505b818365ffffffffffff161115611a8a5750611a90565b50611971565b60006110ab61075e868a6126ee565b6000828281548110611ab357611ab3612748565b9060005260206000209060030201905092915050565b6040805160608101825260008082526020820181905291810191909152604080516060810182526000808252602082018190529181019190915284548015611cb6576000611b1c876115ba60018561258c565b604080518082018252825465ffffffffffff908116825282516060810184526001850154600f81810b8352600160801b909104810b602083810191909152600290960154900b9381019390935292810191909152805190925087821691161115611b9957604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff808816911603611c0c5784611bbc886115ba60018661258c565b815160208301516001600160801b03918216600160801b91831691909102176001830155604090920151600290910180546fffffffffffffffffffffffffffffffff191691909216179055611ca6565b60408051808201825265ffffffffffff888116825260208083018981528b5460018082018e5560008e815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546fffffffffffffffffffffffffffffffff1916929091169190911790555b602001519250839150610e689050565b60408051808201825265ffffffffffff878116825260208083018881528a5460018082018d5560008d815284902095516003909202909501805465ffffffffffff191691909416178355518051918101516001600160801b03928316600160801b9184169190910217938301939093559190920151600290920180546fffffffffffffffffffffffffffffffff191692909116919091179055611d87604080516060808201835260008083526020808401829052928401819052835191820184528082529181018290529182015290565b849250925050610e68565b600081600003611da457506000919050565b60006001611db184611f41565b901c6001901b90506001818481611dca57611dca61252f565b048201901c90506001818481611de257611de261252f565b048201901c90506001818481611dfa57611dfa61252f565b048201901c90506001818481611e1257611e1261252f565b048201901c90506001818481611e2a57611e2a61252f565b048201901c90506001818481611e4257611e4261252f565b048201901c90506001818481611e5a57611e5a61252f565b048201901c9050610a3881828581611e7457611e7461252f565b04611fd5565b60005b81831015611ed4576000611e918484611feb565b60008781526020902090915065ffffffffffff86169082015465ffffffffffff161115611ec057809250611ece565b611ecb8160016126ac565b93505b50611e7d565b509392505050565b60008061168a858585612006565b60005b81831015611ed4576000611f018484611feb565b90508465ffffffffffff16611f168783611a9f565b5465ffffffffffff161115611f2d57809250611f3b565b611f388160016126ac565b93505b50611eed565b600080608083901c15611f5657608092831c92015b604083901c15611f6857604092831c92015b602083901c15611f7a57602092831c92015b601083901c15611f8c57601092831c92015b600883901c15611f9e57600892831c92015b600483901c15611fb057600492831c92015b600283901c15611fc257600292831c92015b600183901c1561031d5760010192915050565b6000818310611fe45781610a38565b5090919050565b6000611ffa6002848418612715565b610a38908484166126ac565b8254600090819080156121715760006120248761121160018561258c565b60408051808201909152905465ffffffffffff80821680845266010000000000009092046001600160a01b03166020840152919250908716101561207b57604051638553be6160e01b815260040160405180910390fd5b805165ffffffffffff8088169116036120e4578461209e8861121160018661258c565b80546001600160a01b03929092166601000000000000027fffffffffffff0000000000000000000000000000000000000000ffffffffffff909216919091179055611ca6565b6040805180820190915265ffffffffffff80881682526001600160a01b0380881660208085019182528b54600181018d5560008d81529190912094519401805491519092166601000000000000027fffffffffffff00000000000000000000000000000000000000000000000000009091169390921692909217179055602001519250839150610e689050565b50506040805180820190915265ffffffffffff80851682526001600160a01b0380851660208085019182528854600181018a5560008a815291822095519501805492519093166601000000000000027fffffffffffff0000000000000000000000000000000000000000000000000000909216949093169390931792909217909155905081610e68565b803565ffffffffffff8116811461221157600080fd5b919050565b6000806040838503121561222957600080fd5b82359150612239602084016121fb565b90509250929050565b8035600f81900b811461221157600080fd5b60008060008060008060c0878903121561226d57600080fd5b863595506020870135945061228460408801612242565b935061229260608801612242565b92506080870135915060a087013590509295509295509295565b6000606082840312156122be57600080fd5b6040516060810181811067ffffffffffffffff821117156122ef57634e487b7160e01b600052604160045260246000fd5b6040529050806122fe83612242565b815261230c60208401612242565b602082015261231d60408401612242565b60408201525092915050565b600080600080610100858703121561234057600080fd5b843593506020850135925061235886604087016122ac565b91506123678660a087016122ac565b905092959194509250565b60006020828403121561238457600080fd5b5035919050565b6000806000606084860312156123a057600080fd5b83359250602084013591506123b7604085016121fb565b90509250925092565b80356001600160a01b038116811461221157600080fd5b600080600080608085870312156123ed57600080fd5b8435935060208501359250612404604086016123c0565b9396929550929360600135925050565b6000806040838503121561242757600080fd5b82359150612239602084016123c0565b60008060006060848603121561244c57600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561247857600080fd5b83359250612488602085016123c0565b91506123b7604085016121fb565b600080604083850312156124a957600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b600081600f0b83600f0b60008212826f7fffffffffffffffffffffffffffffff03821381151615612501576125016124b8565b826f7fffffffffffffffffffffffffffffff19038212811615612526576125266124b8565b50019392505050565b634e487b7160e01b600052601260045260246000fd5b600081600f0b83600f0b8061255c5761255c61252f565b6f7fffffffffffffffffffffffffffffff19821460001982141615612583576125836124b8565b90059392505050565b60008282101561259e5761259e6124b8565b500390565b600081600f0b83600f0b6f7fffffffffffffffffffffffffffffff6000821360008413838304851182821616156125dc576125dc6124b8565b6f7fffffffffffffffffffffffffffffff196000851286820586128184161615612608576126086124b8565b60008712925085820587128484161615612624576126246124b8565b8585058712818416161561263a5761263a6124b8565b5050509290910295945050505050565b600081600f0b83600f0b60008112816f7fffffffffffffffffffffffffffffff190183128115161561267e5761267e6124b8565b816f7fffffffffffffffffffffffffffffff0183138116156126a2576126a26124b8565b5090039392505050565b600082198211156126bf576126bf6124b8565b500190565b600065ffffffffffff8083168185168083038211156126e5576126e56124b8565b01949350505050565b600065ffffffffffff8381169083168181101561270d5761270d6124b8565b039392505050565b6000826127245761272461252f565b500490565b6000816000190483118215151615612743576127436124b8565b500290565b634e487b7160e01b600052603260045260246000fdfea2646970667358221220748bcf20bdfca2e5f378cebfccd87187ad8ad45e09b55f275f355693caa63a9764736f6c634300080d0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.