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:
RewardsDistributorV2
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: GPL-3.0-or-later
pragma solidity 0.8.13;
import "../libraries/Math.sol";
import "../interfaces/IERC20.sol";
import "../interfaces/IRewardsDistributor.sol";
import "../interfaces/IVersionable.sol";
import {IVotingEscrowV2} from "./VotingEscrow/IVotingEscrowV2.sol";
import {Checkpoints} from "./VotingEscrow/libraries/Checkpoints.sol";
import "../Constants.sol";
/**
@title RewardsDistributor for ve(3,3) emissions
@author RewardsDistributor V2 ApeGuru
@author RewardsDistributor V1 Curve Finance, andrecronje
@dev
- WARN If a user burns an expired VotingEscrowV2 NFT before claiming rewards, they will lose the unclaimed rewards.
*/
contract RewardsDistributorV2 is IRewardsDistributor, IVersionable {
event CheckpointToken(uint time, uint tokens);
event Claimed(uint tokenId, uint amount, uint claim_epoch, uint max_epoch);
string public constant override VERSION = "2.1.0";
uint immutable WEEK = Constants.EPOCH;
uint public start_time;
uint public time_cursor;
mapping(uint => uint) public time_cursor_of;
uint public last_token_time;
uint[1000000000000000] public tokens_per_week;
uint public token_last_balance;
address public owner;
address public immutable voting_escrow;
address public immutable token;
address public depositor;
constructor(address _voting_escrow) {
uint _t = (block.timestamp / WEEK) * WEEK;
start_time = _t;
last_token_time = _t;
time_cursor = _t;
address _token = address(IVotingEscrowV2(_voting_escrow).token());
token = _token;
voting_escrow = _voting_escrow;
depositor = msg.sender;
owner = msg.sender;
require(IERC20(_token).approve(_voting_escrow, type(uint).max));
}
function timestamp() public view returns (uint) {
return (block.timestamp / WEEK) * WEEK;
}
function _checkpoint_token() internal {
uint token_balance = IERC20(token).balanceOf(address(this));
uint to_distribute = token_balance - token_last_balance;
token_last_balance = token_balance;
uint t = last_token_time;
uint since_last = block.timestamp - t;
last_token_time = block.timestamp;
uint this_week = (t / WEEK) * WEEK;
uint next_week = 0;
for (uint i = 0; i < 20; i++) {
next_week = this_week + WEEK;
if (block.timestamp < next_week) {
if (since_last == 0 && block.timestamp == t) {
tokens_per_week[this_week] += to_distribute;
} else {
tokens_per_week[this_week] += (to_distribute * (block.timestamp - t)) / since_last;
}
break;
} else {
if (since_last == 0 && next_week == t) {
tokens_per_week[this_week] += to_distribute;
} else {
tokens_per_week[this_week] += (to_distribute * (next_week - t)) / since_last;
}
}
t = next_week;
this_week = next_week;
}
emit CheckpointToken(block.timestamp, to_distribute);
}
function checkpoint_token() external {
assert(msg.sender == depositor);
_checkpoint_token();
}
function _checkpoint_total_supply() internal {
IVotingEscrowV2(voting_escrow).checkpoint();
if (block.timestamp >= time_cursor) time_cursor = timestamp() + WEEK;
}
function checkpoint_total_supply() external {
_checkpoint_total_supply();
}
function _claim(uint _tokenId, address ve, uint _last_token_time) internal returns (uint) {
uint to_distribute = 0;
(, uint48 maxTs) = IVotingEscrowV2(ve).getPastEscrowPoint(_tokenId, block.timestamp);
uint _start_time = start_time;
if (maxTs == 0) return 0;
uint week_cursor = time_cursor_of[_tokenId];
if (week_cursor == 0) {
(, uint48 ts) = IVotingEscrowV2(ve).getFirstEscrowPoint(_tokenId);
week_cursor = ((ts + WEEK - 1) / WEEK) * WEEK;
}
if (week_cursor >= last_token_time) return 0;
if (week_cursor < _start_time) week_cursor = _start_time;
for (uint i = 0; i < 50; i++) {
if (week_cursor >= _last_token_time) break;
uint256 balance_of = IVotingEscrowV2(ve).balanceOfNFTAt(_tokenId, week_cursor);
if (balance_of == 0) continue;
if (balance_of != 0) {
/// @note potential brick if supply returns 0
to_distribute +=
(balance_of * tokens_per_week[week_cursor]) /
IVotingEscrowV2(ve).getPastTotalSupply(week_cursor);
}
week_cursor += WEEK;
}
time_cursor_of[_tokenId] = week_cursor;
emit Claimed(_tokenId, to_distribute, week_cursor, maxTs);
return to_distribute;
}
function _claimable(uint _tokenId, address ve, uint _last_token_time) internal view returns (uint) {
uint to_distribute = 0;
uint _start_time = start_time;
uint week_cursor = time_cursor_of[_tokenId];
if (week_cursor == 0) {
(, uint48 ts) = IVotingEscrowV2(ve).getFirstEscrowPoint(_tokenId);
if (ts == 0) return 0;
week_cursor = ((ts + WEEK - 1) / WEEK) * WEEK;
}
if (week_cursor >= last_token_time) return 0;
if (week_cursor < _start_time) week_cursor = _start_time;
for (uint i = 0; i < 50; i++) {
if (week_cursor >= _last_token_time) break;
uint256 balance_of = IVotingEscrowV2(ve).balanceOfNFTAt(_tokenId, week_cursor);
if (balance_of == 0) break;
if (balance_of != 0) {
/// @note potential brick if supply returns 0
to_distribute +=
(balance_of * tokens_per_week[week_cursor]) /
uint256(int256(IVotingEscrowV2(ve).getPastTotalSupply(week_cursor)));
}
week_cursor += WEEK;
}
return to_distribute;
}
function claimable(uint _tokenId) external view returns (uint) {
uint _last_token_time = (last_token_time / WEEK) * WEEK;
return _claimable(_tokenId, voting_escrow, _last_token_time);
}
function claim(uint _tokenId) external returns (uint) {
if (block.timestamp >= time_cursor) _checkpoint_total_supply();
uint _last_token_time = last_token_time;
_last_token_time = (_last_token_time / WEEK) * WEEK;
uint amount = _claim(_tokenId, voting_escrow, _last_token_time);
if (amount != 0) {
// if locked.end then send directly
IVotingEscrowV2.LockDetails memory _locked = IVotingEscrowV2(voting_escrow).lockDetails(_tokenId);
if (_locked.endTime <= block.timestamp && !_locked.isPermanent) {
address _nftOwner = IVotingEscrowV2(voting_escrow).ownerOf(_tokenId);
IERC20(token).transfer(_nftOwner, amount);
} else {
IVotingEscrowV2(voting_escrow).increaseAmount(_tokenId, amount);
}
token_last_balance -= amount;
}
return amount;
}
function claim_many(uint[] memory _tokenIds) external returns (bool) {
if (block.timestamp >= time_cursor) _checkpoint_total_supply();
uint _last_token_time = last_token_time;
_last_token_time = (_last_token_time / WEEK) * WEEK;
address _voting_escrow = voting_escrow;
uint total = 0;
for (uint i = 0; i < _tokenIds.length; i++) {
uint _tokenId = _tokenIds[i];
if (_tokenId == 0) break;
uint amount = _claim(_tokenId, _voting_escrow, _last_token_time);
if (amount != 0) {
// if locked.end then send directly
IVotingEscrowV2.LockDetails memory _locked = IVotingEscrowV2(_voting_escrow).lockDetails(_tokenId);
if (_locked.endTime < block.timestamp && !_locked.isPermanent) {
address _nftOwner = IVotingEscrowV2(_voting_escrow).ownerOf(_tokenId);
IERC20(token).transfer(_nftOwner, amount);
} else {
IVotingEscrowV2(_voting_escrow).increaseAmount(_tokenId, amount);
}
total += amount;
}
}
if (total != 0) {
token_last_balance -= total;
}
return true;
}
function setDepositor(address _depositor) external {
require(msg.sender == owner);
depositor = _depositor;
}
function setOwner(address _owner) external {
require(msg.sender == owner);
owner = _owner;
}
function withdrawERC20(address _token) external {
require(msg.sender == owner);
require(_token != address(0));
uint256 _balance = IERC20(_token).balanceOf(address(this));
IERC20(_token).transfer(msg.sender, _balance);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.0;
import "../IERC721Upgradeable.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721EnumerableUpgradeable is IERC721Upgradeable {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165Upgradeable.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721Upgradeable is IERC165Upgradeable {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// 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
pragma solidity 0.8.13;
interface IERC20 {
function totalSupply() external view returns (uint256);
function transfer(address recipient, uint amount) external returns (bool);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function balanceOf(address) external view returns (uint);
function transferFrom(address sender, address recipient, uint amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
interface IRewardsDistributor {
function checkpoint_token() external;
function voting_escrow() external view returns(address);
function checkpoint_total_supply() external;
function claimable(uint _tokenId) external view returns (uint);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IVersionable {
function VERSION() external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
library Math {
function max(uint a, uint b) internal pure returns (uint) {
return a >= b ? a : b;
}
function min(uint a, uint b) internal pure returns (uint) {
return a < b ? a : b;
}
function sqrt(uint y) internal pure returns (uint z) {
if (y > 3) {
z = y;
uint x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
function cbrt(uint256 n) internal pure returns (uint256) { unchecked {
uint256 x = 0;
for (uint256 y = 1 << 255; y > 0; y >>= 3) {
x <<= 1;
uint256 z = 3 * x * (x + 1) + 1;
if (n / y >= z) {
n -= y * z;
x += 1;
}
}
return x;
}}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, 'Math: Sub-underflow');
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
/**
* @title Non-Fungible Vesting Token Standard.
* @notice A non-fungible token standard used to vest ERC-20 tokens over a vesting release curve
* scheduled using timestamps.
* @dev Because this standard relies on timestamps for the vesting schedule, it's important to keep track of the
* tokens claimed per Vesting NFT so that a user cannot withdraw more tokens than allotted for a specific Vesting NFT.
* @custom:interface-id 0xbd3a202b
*/
interface IERC5725Upgradeable is IERC721Upgradeable {
/**
* This event is emitted when the payout is claimed through the claim function.
* @param tokenId the NFT tokenId of the assets being claimed.
* @param recipient The address which is receiving the payout.
* @param claimAmount The amount of tokens being claimed.
*/
event PayoutClaimed(uint256 indexed tokenId, address indexed recipient, uint256 claimAmount);
/**
* This event is emitted when an `owner` sets an address to manage token claims for all tokens.
* @param owner The address setting a manager to manage all tokens.
* @param spender The address being permitted to manage all tokens.
* @param approved A boolean indicating whether the spender is approved to claim for all tokens.
*/
event ClaimApprovalForAll(address indexed owner, address indexed spender, bool approved);
/**
* This event is emitted when an `owner` sets an address to manage token claims for a `tokenId`.
* @param owner The `owner` of `tokenId`.
* @param spender The address being permitted to manage a tokenId.
* @param tokenId The unique identifier of the token being managed.
* @param approved A boolean indicating whether the spender is approved to claim for `tokenId`.
*/
event ClaimApproval(address indexed owner, address indexed spender, uint256 indexed tokenId, bool approved);
/**
* @notice Claim the pending payout for the NFT.
* @dev MUST grant the claimablePayout value at the time of claim being called to `msg.sender`.
* MUST revert if not called by the token owner or approved users.
* MUST emit PayoutClaimed.
* SHOULD revert if there is nothing to claim.
* @param tokenId The NFT token id.
*/
function claim(uint256 tokenId) external;
/**
* @notice Number of tokens for the NFT which have been claimed at the current timestamp.
* @param tokenId The NFT token id.
* @return payout The total amount of payout tokens claimed for this NFT.
*/
function claimedPayout(uint256 tokenId) external view returns (uint256 payout);
/**
* @notice Number of tokens for the NFT which can be claimed at the current timestamp.
* @dev It is RECOMMENDED that this is calculated as the `vestedPayout()` subtracted from `payoutClaimed()`.
* @param tokenId The NFT token id.
* @return payout The amount of unlocked payout tokens for the NFT which have not yet been claimed.
*/
function claimablePayout(uint256 tokenId) external view returns (uint256 payout);
/**
* @notice Total amount of tokens which have been vested at the current timestamp.
* This number also includes vested tokens which have been claimed.
* @dev It is RECOMMENDED that this function calls `vestedPayoutAtTime`
* with `block.timestamp` as the `timestamp` parameter.
* @param tokenId The NFT token id.
* @return payout Total amount of tokens which have been vested at the current timestamp.
*/
function vestedPayout(uint256 tokenId) external view returns (uint256 payout);
/**
* @notice Total amount of vested tokens at the provided timestamp.
* This number also includes vested tokens which have been claimed.
* @dev `timestamp` MAY be both in the future and in the past.
* Zero MUST be returned if the timestamp is before the token was minted.
* @param tokenId The NFT token id.
* @param timestamp The timestamp to check on, can be both in the past and the future.
* @return payout Total amount of tokens which have been vested at the provided timestamp.
*/
function vestedPayoutAtTime(uint256 tokenId, uint256 timestamp) external view returns (uint256 payout);
/**
* @notice Number of tokens for an NFT which are currently vesting.
* @dev The sum of vestedPayout and vestingPayout SHOULD always be the total payout.
* @param tokenId The NFT token id.
* @return payout The number of tokens for the NFT which are vesting until a future date.
*/
function vestingPayout(uint256 tokenId) external view returns (uint256 payout);
/**
* @notice The start and end timestamps for the vesting of the provided NFT.
* MUST return the timestamp where no further increase in vestedPayout occurs for `vestingEnd`.
* @param tokenId The NFT token id.
* @return vestingStart The beginning of the vesting as a unix timestamp.
* @return vestingEnd The ending of the vesting as a unix timestamp.
*/
function vestingPeriod(uint256 tokenId) external view returns (uint256 vestingStart, uint256 vestingEnd);
/**
* @notice Token which is used to pay out the vesting claims.
* @param tokenId The NFT token id.
* @return token The token which is used to pay out the vesting claims.
*/
function payoutToken(uint256 tokenId) external view returns (address token);
/**
* @notice Sets a global `operator` with permission to manage all tokens owned by the current `msg.sender`.
* @param operator The address to let manage all tokens.
* @param approved A boolean indicating whether the spender is approved to claim for all tokens.
*/
function setClaimApprovalForAll(address operator, bool approved) external;
/**
* @notice Sets a tokenId `operator` with permission to manage a single `tokenId` owned by the `msg.sender`.
* @param operator The address to let manage a single `tokenId`.
* @param tokenId the `tokenId` to be managed.
* @param approved A boolean indicating whether the spender is approved to claim for all tokens.
*/
function setClaimApproval(address operator, bool approved, uint256 tokenId) external;
/**
* @notice Returns true if `owner` has set `operator` to manage all `tokenId`s.
* @param owner The owner allowing `operator` to manage all `tokenId`s.
* @param operator The address who is given permission to spend tokens on behalf of the `owner`.
*/
function isClaimApprovedForAll(address owner, address operator) external view returns (bool isClaimApproved);
/**
* @notice Returns the operating address for a `tokenId`.
* If `tokenId` is not managed, then returns the zero address.
* @param tokenId The NFT `tokenId` to query for a `tokenId` manager.
*/
function getClaimApproved(uint256 tokenId) external view returns (address operator);
}
interface IERC5725_ExtendedApproval is IERC5725Upgradeable {
/**
* @notice Returns true if `operator` is allowed to transfer the `tokenId` NFT.
* @param operator The address to check if it is approved for the transfer
* @param tokenId The token id to check if the operator is approved for
*/
function isApprovedOrOwner(address operator, uint tokenId) external view returns (bool);
/**
* @notice Returns true if `operator` is allowed to claim for the provided tokenId
* @param operator The address to check if it is approved for the claim or owner of the token
* @param tokenId The token id to check if the operator is approved for
*/
function isApprovedClaimOrOwner(address operator, uint256 tokenId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.0;
/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*
* _Available since v4.5._
*/
interface IVotes {
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/**
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) external view returns (uint256);
/**
* @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*/
function getPastVotes(address account, uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*/
function getPastTotalSupply(uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) external view returns (address);
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) external;
/**
* @notice Removed from the interface to avoid signature conflicts.
* @dev Delegates votes from signer to `delegatee`.
*/
// function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import {IVotes} from "./interfaces/IVotes.sol";
import {Checkpoints} from "./libraries/Checkpoints.sol";
import {IERC5725_ExtendedApproval} from "./erc5725/IERC5725Upgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721EnumerableUpgradeable.sol";
import {IVersionable} from "../../interfaces/IVersionable.sol";
/**
* @title Voting Escrow V2 Interface for Upgrades
*/
interface IVotingEscrowV2 is IVotes, IERC5725_ExtendedApproval, IERC721EnumerableUpgradeable, IVersionable {
struct LockDetails {
uint256 amount; /// @dev amount of tokens locked
uint256 startTime; /// @dev when locking started
uint256 endTime; /// @dev when locking ends
bool isPermanent; /// @dev if its a permanent lock
}
/// -----------------------------------------------------------------------
/// Events
/// -----------------------------------------------------------------------
event SupplyUpdated(uint256 oldSupply, uint256 newSupply);
/// @notice Lock events
event LockCreated(uint256 indexed tokenId, address indexed to, uint256 value, uint256 unlockTime, bool isPermanent);
event LockUpdated(uint256 indexed tokenId, uint256 value, uint256 unlockTime, bool isPermanent);
event LockMerged(
uint256 indexed fromTokenId,
uint256 indexed toTokenId,
uint256 totalValue,
uint256 unlockTime,
bool isPermanent
);
event LockSplit(uint256[] splitWeights, uint256 indexed _tokenId);
event LockDurationExtended(uint256 indexed tokenId, uint256 newUnlockTime, bool isPermanent);
event LockAmountIncreased(uint256 indexed tokenId, uint256 value);
event UnlockPermanent(uint256 indexed tokenId, address indexed sender, uint256 unlockTime);
/// @notice Delegate events
event LockDelegateChanged(
uint256 indexed tokenId,
address indexed delegator,
address fromDelegate,
address indexed toDelegate
);
/// -----------------------------------------------------------------------
/// Errors
/// -----------------------------------------------------------------------
error AlreadyVoted();
error InvalidNonce();
error InvalidDelegatee();
error InvalidSignature();
error InvalidSignatureS();
error InvalidWeights();
error LockDurationNotInFuture();
error LockDurationTooLong();
error LockExpired();
error LockNotExpired();
error LockHoldsValue();
error LockModifiedDelay();
error NotPermanentLock();
error PermanentLock();
error PermanentLockMismatch();
error SameNFT();
error SignatureExpired();
error ZeroAmount();
error NotLockOwner();
function supply() external view returns (uint);
function token() external view returns (IERC20Upgradeable);
function totalNftsMinted() external view returns (uint256);
function balanceOfNFT(uint256 _tokenId) external view returns (uint256);
function balanceOfNFTAt(uint256 _tokenId, uint256 _timestamp) external view returns (uint256);
function delegates(uint256 tokenId, uint48 timestamp) external view returns (address);
function lockDetails(uint256 tokenId) external view returns (LockDetails calldata);
function getPastEscrowPoint(
uint256 _tokenId,
uint256 _timePoint
) external view returns (Checkpoints.Point memory, uint48);
function getFirstEscrowPoint(uint256 _tokenId) external view returns (Checkpoints.Point memory, uint48);
function checkpoint() external;
function increaseAmount(uint256 _tokenId, uint256 _value) external;
function createLockFor(
uint256 _value,
uint256 _lockDuration,
address _to,
bool _permanent
) external returns (uint256);
function createDelegatedLockFor(
uint256 _value,
uint256 _lockDuration,
address _to,
address _delegatee,
bool _permanent
) external returns (uint256);
function split(uint256[] memory _weights, uint256 _tokenId) external;
function merge(uint256 _from, uint256 _to) external;
function burn(uint256 _tokenId) external;
function decimals() external view returns (uint8);
}// 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)
}
}
}{
"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":[{"internalType":"address","name":"_voting_escrow","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"CheckpointToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claim_epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"max_epoch","type":"uint256"}],"name":"Claimed","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpoint_token","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkpoint_total_supply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"claim_many","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"claimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"last_token_time","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_depositor","type":"address"}],"name":"setDepositor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"start_time","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"time_cursor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"time_cursor_of","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token_last_balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokens_per_week","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voting_escrow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60e060405262093a806080523480156200001857600080fd5b5060405162001c7d38038062001c7d8339810160408190526200003b91620001b9565b6080516000906200004d8142620001e0565b62000059919062000203565b90508060008190555080600381905550806001819055506000826001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000b1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000d79190620001b9565b6001600160a01b0381811660c081905290851660a081905266038d7ea4c680068054336001600160a01b0319918216811790925566038d7ea4c680058054909116909117905560405163095ea7b360e01b8152600481019190915260001960248201529192509063095ea7b3906044016020604051808303816000875af115801562000167573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200018d919062000231565b6200019757600080fd5b50505062000255565b6001600160a01b0381168114620001b657600080fd5b50565b600060208284031215620001cc57600080fd5b8151620001d981620001a0565b9392505050565b600082620001fe57634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156200022c57634e487b7160e01b600052601160045260246000fd5b500290565b6000602082840312156200024457600080fd5b81518015158114620001d957600080fd5b60805160a05160c05161196562000318600039600081816102b3015281816105240152818161082f01526110110152600081816102530152818161039a015281816106a4015281816106ea01528181610793015281816108c201528181610a1f0152610bbc0152600081816103630152818161066701528181610983015281816109c0015281816109e101528181610c3801528181610d9001528181610f50015281816110c30152818161110a01528181611351015261150e01526119656000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063b21ed502116100ad578063edf5999711610071578063edf5999714610275578063f2c098b714610288578063f4f3b2001461029b578063fc0c546a146102ae578063ffa1ad74146102d557600080fd5b8063b21ed50214610212578063b80777ea1461021a578063c7c4ff4614610222578063d1d58b251461023b578063dfe050311461024e57600080fd5b8063486d25fe116100f4578063486d25fe146101a75780637f58e8f8146101c7578063811a40fe146101d0578063834ee417146101d85780638da5cb5b146101e157600080fd5b8063127dcbd31461013157806313af40351461014d5780631f1db0431461016257806322b04bfc14610185578063379607f514610194575b600080fd5b61013a60015481565b6040519081526020015b60405180910390f35b61016061015b36600461156d565b610306565b005b6101756101703660046115d1565b61034b565b6040519015158152602001610144565b61013a66038d7ea4c680045481565b61013a6101a2366004611677565b61064f565b61013a6101b5366004611677565b60026020526000908152604090205481565b61013a60035481565b61016061094d565b61013a60005481565b66038d7ea4c68005546101fa906001600160a01b031681565b6040516001600160a01b039091168152602001610144565b610160610977565b61013a61097f565b66038d7ea4c68006546101fa906001600160a01b031681565b61013a610249366004611677565b6109bb565b6101fa7f000000000000000000000000000000000000000000000000000000000000000081565b61013a610283366004611677565b610a44565b61016061029636600461156d565b610a61565b6101606102a936600461156d565b610aa6565b6101fa7f000000000000000000000000000000000000000000000000000000000000000081565b6102f9604051806040016040528060058152602001640322e312e360dc1b81525081565b6040516101449190611690565b66038d7ea4c68005546001600160a01b0316331461032357600080fd5b66038d7ea4c6800580546001600160a01b0319166001600160a01b0392909216919091179055565b6000600154421061035e5761035e610bba565b6003547f000000000000000000000000000000000000000000000000000000000000000061038c81836116fb565b610396919061171d565b90507f00000000000000000000000000000000000000000000000000000000000000006000805b855181101561061f5760008682815181106103da576103da61173c565b60200260200101519050806000036103f2575061061f565b60006103ff828688610c6e565b9050801561060a57604051636318523760e01b8152600481018390526000906001600160a01b03871690636318523790602401608060405180830381865afa15801561044f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104739190611767565b905042816040015110801561048a57508060600151155b1561059a576040516331a9108f60e11b8152600481018490526000906001600160a01b03881690636352211e90602401602060405180830381865afa1580156104d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fb91906117d1565b60405163a9059cbb60e01b81526001600160a01b038083166004830152602482018690529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af115801561056f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059391906117ee565b50506105fc565b60405163b2383e5560e01b815260048101849052602481018390526001600160a01b0387169063b2383e5590604401600060405180830381600087803b1580156105e357600080fd5b505af11580156105f7573d6000803e3d6000fd5b505050505b6106068286611809565b9450505b5050808061061790611821565b9150506103bd565b508015610644578066038d7ea4c68004600082825461063e919061183a565b90915550505b506001949350505050565b6000600154421061066257610662610bba565b6003547f000000000000000000000000000000000000000000000000000000000000000061069081836116fb565b61069a919061171d565b905060006106c9847f000000000000000000000000000000000000000000000000000000000000000084610c6e565b9050801561094657604051636318523760e01b8152600481018590526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636318523790602401608060405180830381865afa158015610739573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075d9190611767565b90504281604001511115801561077557508060600151155b156108a5576040516331a9108f60e11b8152600481018690526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156107e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080691906117d1565b60405163a9059cbb60e01b81526001600160a01b038083166004830152602482018690529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af115801561087a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089e91906117ee565b5050610927565b60405163b2383e5560e01b815260048101869052602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b2383e5590604401600060405180830381600087803b15801561090e57600080fd5b505af1158015610922573d6000803e3d6000fd5b505050505b8166038d7ea4c68004600082825461093f919061183a565b9091555050505b9392505050565b66038d7ea4c68006546001600160a01b0316331461096d5761096d611851565b610975610ff9565b565b610975610bba565b60007f00000000000000000000000000000000000000000000000000000000000000006109ac81426116fb565b6109b6919061171d565b905090565b6000807f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000600354610a0d91906116fb565b610a17919061171d565b9050610946837f0000000000000000000000000000000000000000000000000000000000000000836112a8565b60048166038d7ea4c680008110610a5a57600080fd5b0154905081565b66038d7ea4c68005546001600160a01b03163314610a7e57600080fd5b66038d7ea4c6800680546001600160a01b0319166001600160a01b0392909216919091179055565b66038d7ea4c68005546001600160a01b03163314610ac357600080fd5b6001600160a01b038116610ad657600080fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b419190611867565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0383169063a9059cbb906044016020604051808303816000875af1158015610b91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb591906117ee565b505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c2c4c5c16040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610c1557600080fd5b505af1158015610c29573d6000803e3d6000fd5b505050506001544210610975577f0000000000000000000000000000000000000000000000000000000000000000610c5f61097f565b610c699190611809565b600155565b6040516306c423c160e41b815260048101849052426024820152600090819081906001600160a01b03861690636c423c1090604401608060405180830381865afa158015610cc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce49190611892565b9150506000805490508165ffffffffffff16600003610d095760009350505050610946565b60008781526002602052604081205490819003610de85760405163f778e0a360e01b8152600481018990526000906001600160a01b0389169063f778e0a390602401608060405180830381865afa158015610d68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8c9190611892565b91507f00000000000000000000000000000000000000000000000000000000000000009050806001610dc68265ffffffffffff8616611809565b610dd0919061183a565b610dda91906116fb565b610de4919061171d565b9150505b6003548110610dfe576000945050505050610946565b81811015610e095750805b60005b6032811015610f8b5786821015610f8b57604051637028a55d60e11b8152600481018a9052602481018390526000906001600160a01b038a169063e0514aba90604401602060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190611867565b905080600003610ea05750610f79565b8015610f4b57604051632394e7a360e21b8152600481018490526001600160a01b038a1690638e539e8c90602401602060405180830381865afa158015610eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0f9190611867565b60048466038d7ea4c680008110610f2857610f2861173c565b0154610f34908361171d565b610f3e91906116fb565b610f489087611809565b95505b610f757f000000000000000000000000000000000000000000000000000000000000000084611809565b9250505b80610f8381611821565b915050610e0c565b5060008881526002602090815260409182902083905581518a815290810186905290810182905265ffffffffffff841660608201527fcae2990aa9af8eb1c64713b7eddb3a80bf18e49a94a13fe0d0002b5d61d58f009060800160405180910390a150919695505050505050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611060573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110849190611867565b9050600066038d7ea4c68004548261109c919061183a565b66038d7ea4c6800483905560035490915060006110b9824261183a565b42600355905060007f00000000000000000000000000000000000000000000000000000000000000006110ec81856116fb565b6110f6919061171d565b90506000805b60148110156112665761112f7f000000000000000000000000000000000000000000000000000000000000000084611809565b9150814210156111b8578315801561114657508442145b15611180578560048466038d7ea4c6800081106111655761116561173c565b0160008282546111759190611809565b909155506112669050565b8361118b864261183a565b611195908861171d565b61119f91906116fb565b60048466038d7ea4c6800081106111655761116561173c565b831580156111c557508482145b156111ff578560048466038d7ea4c6800081106111e4576111e461173c565b0160008282546111f49190611809565b9091555061124d9050565b8361120a868461183a565b611214908861171d565b61121e91906116fb565b60048466038d7ea4c6800081106112375761123761173c565b0160008282546112479190611809565b90915550505b819450819250808061125e90611821565b9150506110fc565b5060408051428152602081018790527fce749457b74e10f393f2c6b1ce4261b78791376db5a3f501477a809f03f500d6910160405180910390a1505050505050565b60008054848252600260205260408220548291908083036113a75760405163f778e0a360e01b8152600481018890526000906001600160a01b0388169063f778e0a390602401608060405180830381865afa15801561130b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132f9190611892565b9150508065ffffffffffff1660000361134f576000945050505050610946565b7f00000000000000000000000000000000000000000000000000000000000000008060016113858265ffffffffffff8616611809565b61138f919061183a565b61139991906116fb565b6113a3919061171d565b9150505b60035481106113bc5760009350505050610946565b818110156113c75750805b60005b6032811015611549578582101561154957604051637028a55d60e11b815260048101899052602481018390526000906001600160a01b0389169063e0514aba90604401602060405180830381865afa15801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e9190611867565b90508060000361145e5750611549565b801561150957604051632394e7a360e21b8152600481018490526001600160a01b03891690638e539e8c90602401602060405180830381865afa1580156114a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cd9190611867565b60048466038d7ea4c6800081106114e6576114e661173c565b01546114f2908361171d565b6114fc91906116fb565b6115069086611809565b94505b6115337f000000000000000000000000000000000000000000000000000000000000000084611809565b925050808061154190611821565b9150506113ca565b50919695505050505050565b6001600160a01b038116811461156a57600080fd5b50565b60006020828403121561157f57600080fd5b813561094681611555565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156115c9576115c961158a565b604052919050565b600060208083850312156115e457600080fd5b823567ffffffffffffffff808211156115fc57600080fd5b818501915085601f83011261161057600080fd5b8135818111156116225761162261158a565b8060051b91506116338483016115a0565b818152918301840191848101908884111561164d57600080fd5b938501935b8385101561166b57843582529385019390850190611652565b98975050505050505050565b60006020828403121561168957600080fd5b5035919050565b600060208083528351808285015260005b818110156116bd578581018301518582016040015282016116a1565b818111156116cf576000604083870101525b50601f01601f1916929092016040019392505050565b634e487b7160e01b600052601160045260246000fd5b60008261171857634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615611737576117376116e5565b500290565b634e487b7160e01b600052603260045260246000fd5b8051801515811461176257600080fd5b919050565b60006080828403121561177957600080fd5b6040516080810181811067ffffffffffffffff8211171561179c5761179c61158a565b80604052508251815260208301516020820152604083015160408201526117c560608401611752565b60608201529392505050565b6000602082840312156117e357600080fd5b815161094681611555565b60006020828403121561180057600080fd5b61094682611752565b6000821982111561181c5761181c6116e5565b500190565b600060018201611833576118336116e5565b5060010190565b60008282101561184c5761184c6116e5565b500390565b634e487b7160e01b600052600160045260246000fd5b60006020828403121561187957600080fd5b5051919050565b8051600f81900b811461176257600080fd5b60008082840360808112156118a657600080fd5b60608112156118b457600080fd5b506040516060810181811067ffffffffffffffff821117156118d8576118d861158a565b6040526118e484611880565b81526118f260208501611880565b602082015261190360408501611880565b6040820152606084015190925065ffffffffffff8116811461192457600080fd5b80915050925092905056fea2646970667358221220d535ffd9556c89b984f83c53ea5d877912ab49e4e755ca85f02a55d0a5e230c864736f6c634300080d003300000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd2
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061012c5760003560e01c8063b21ed502116100ad578063edf5999711610071578063edf5999714610275578063f2c098b714610288578063f4f3b2001461029b578063fc0c546a146102ae578063ffa1ad74146102d557600080fd5b8063b21ed50214610212578063b80777ea1461021a578063c7c4ff4614610222578063d1d58b251461023b578063dfe050311461024e57600080fd5b8063486d25fe116100f4578063486d25fe146101a75780637f58e8f8146101c7578063811a40fe146101d0578063834ee417146101d85780638da5cb5b146101e157600080fd5b8063127dcbd31461013157806313af40351461014d5780631f1db0431461016257806322b04bfc14610185578063379607f514610194575b600080fd5b61013a60015481565b6040519081526020015b60405180910390f35b61016061015b36600461156d565b610306565b005b6101756101703660046115d1565b61034b565b6040519015158152602001610144565b61013a66038d7ea4c680045481565b61013a6101a2366004611677565b61064f565b61013a6101b5366004611677565b60026020526000908152604090205481565b61013a60035481565b61016061094d565b61013a60005481565b66038d7ea4c68005546101fa906001600160a01b031681565b6040516001600160a01b039091168152602001610144565b610160610977565b61013a61097f565b66038d7ea4c68006546101fa906001600160a01b031681565b61013a610249366004611677565b6109bb565b6101fa7f00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd281565b61013a610283366004611677565b610a44565b61016061029636600461156d565b610a61565b6101606102a936600461156d565b610aa6565b6101fa7f000000000000000000000000de8b64c180306e40aac177a6b642af7e8d7e39d581565b6102f9604051806040016040528060058152602001640322e312e360dc1b81525081565b6040516101449190611690565b66038d7ea4c68005546001600160a01b0316331461032357600080fd5b66038d7ea4c6800580546001600160a01b0319166001600160a01b0392909216919091179055565b6000600154421061035e5761035e610bba565b6003547f0000000000000000000000000000000000000000000000000000000000093a8061038c81836116fb565b610396919061171d565b90507f00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd26000805b855181101561061f5760008682815181106103da576103da61173c565b60200260200101519050806000036103f2575061061f565b60006103ff828688610c6e565b9050801561060a57604051636318523760e01b8152600481018390526000906001600160a01b03871690636318523790602401608060405180830381865afa15801561044f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104739190611767565b905042816040015110801561048a57508060600151155b1561059a576040516331a9108f60e11b8152600481018490526000906001600160a01b03881690636352211e90602401602060405180830381865afa1580156104d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fb91906117d1565b60405163a9059cbb60e01b81526001600160a01b038083166004830152602482018690529192507f000000000000000000000000de8b64c180306e40aac177a6b642af7e8d7e39d59091169063a9059cbb906044016020604051808303816000875af115801561056f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059391906117ee565b50506105fc565b60405163b2383e5560e01b815260048101849052602481018390526001600160a01b0387169063b2383e5590604401600060405180830381600087803b1580156105e357600080fd5b505af11580156105f7573d6000803e3d6000fd5b505050505b6106068286611809565b9450505b5050808061061790611821565b9150506103bd565b508015610644578066038d7ea4c68004600082825461063e919061183a565b90915550505b506001949350505050565b6000600154421061066257610662610bba565b6003547f0000000000000000000000000000000000000000000000000000000000093a8061069081836116fb565b61069a919061171d565b905060006106c9847f00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd284610c6e565b9050801561094657604051636318523760e01b8152600481018590526000907f00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd26001600160a01b031690636318523790602401608060405180830381865afa158015610739573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075d9190611767565b90504281604001511115801561077557508060600151155b156108a5576040516331a9108f60e11b8152600481018690526000907f00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd26001600160a01b031690636352211e90602401602060405180830381865afa1580156107e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080691906117d1565b60405163a9059cbb60e01b81526001600160a01b038083166004830152602482018690529192507f000000000000000000000000de8b64c180306e40aac177a6b642af7e8d7e39d59091169063a9059cbb906044016020604051808303816000875af115801561087a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089e91906117ee565b5050610927565b60405163b2383e5560e01b815260048101869052602481018390527f00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd26001600160a01b03169063b2383e5590604401600060405180830381600087803b15801561090e57600080fd5b505af1158015610922573d6000803e3d6000fd5b505050505b8166038d7ea4c68004600082825461093f919061183a565b9091555050505b9392505050565b66038d7ea4c68006546001600160a01b0316331461096d5761096d611851565b610975610ff9565b565b610975610bba565b60007f0000000000000000000000000000000000000000000000000000000000093a806109ac81426116fb565b6109b6919061171d565b905090565b6000807f0000000000000000000000000000000000000000000000000000000000093a807f0000000000000000000000000000000000000000000000000000000000093a80600354610a0d91906116fb565b610a17919061171d565b9050610946837f00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd2836112a8565b60048166038d7ea4c680008110610a5a57600080fd5b0154905081565b66038d7ea4c68005546001600160a01b03163314610a7e57600080fd5b66038d7ea4c6800680546001600160a01b0319166001600160a01b0392909216919091179055565b66038d7ea4c68005546001600160a01b03163314610ac357600080fd5b6001600160a01b038116610ad657600080fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b419190611867565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0383169063a9059cbb906044016020604051808303816000875af1158015610b91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb591906117ee565b505050565b7f00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd26001600160a01b031663c2c4c5c16040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610c1557600080fd5b505af1158015610c29573d6000803e3d6000fd5b505050506001544210610975577f0000000000000000000000000000000000000000000000000000000000093a80610c5f61097f565b610c699190611809565b600155565b6040516306c423c160e41b815260048101849052426024820152600090819081906001600160a01b03861690636c423c1090604401608060405180830381865afa158015610cc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce49190611892565b9150506000805490508165ffffffffffff16600003610d095760009350505050610946565b60008781526002602052604081205490819003610de85760405163f778e0a360e01b8152600481018990526000906001600160a01b0389169063f778e0a390602401608060405180830381865afa158015610d68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8c9190611892565b91507f0000000000000000000000000000000000000000000000000000000000093a809050806001610dc68265ffffffffffff8616611809565b610dd0919061183a565b610dda91906116fb565b610de4919061171d565b9150505b6003548110610dfe576000945050505050610946565b81811015610e095750805b60005b6032811015610f8b5786821015610f8b57604051637028a55d60e11b8152600481018a9052602481018390526000906001600160a01b038a169063e0514aba90604401602060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190611867565b905080600003610ea05750610f79565b8015610f4b57604051632394e7a360e21b8152600481018490526001600160a01b038a1690638e539e8c90602401602060405180830381865afa158015610eeb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0f9190611867565b60048466038d7ea4c680008110610f2857610f2861173c565b0154610f34908361171d565b610f3e91906116fb565b610f489087611809565b95505b610f757f0000000000000000000000000000000000000000000000000000000000093a8084611809565b9250505b80610f8381611821565b915050610e0c565b5060008881526002602090815260409182902083905581518a815290810186905290810182905265ffffffffffff841660608201527fcae2990aa9af8eb1c64713b7eddb3a80bf18e49a94a13fe0d0002b5d61d58f009060800160405180910390a150919695505050505050565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000de8b64c180306e40aac177a6b642af7e8d7e39d56001600160a01b0316906370a0823190602401602060405180830381865afa158015611060573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110849190611867565b9050600066038d7ea4c68004548261109c919061183a565b66038d7ea4c6800483905560035490915060006110b9824261183a565b42600355905060007f0000000000000000000000000000000000000000000000000000000000093a806110ec81856116fb565b6110f6919061171d565b90506000805b60148110156112665761112f7f0000000000000000000000000000000000000000000000000000000000093a8084611809565b9150814210156111b8578315801561114657508442145b15611180578560048466038d7ea4c6800081106111655761116561173c565b0160008282546111759190611809565b909155506112669050565b8361118b864261183a565b611195908861171d565b61119f91906116fb565b60048466038d7ea4c6800081106111655761116561173c565b831580156111c557508482145b156111ff578560048466038d7ea4c6800081106111e4576111e461173c565b0160008282546111f49190611809565b9091555061124d9050565b8361120a868461183a565b611214908861171d565b61121e91906116fb565b60048466038d7ea4c6800081106112375761123761173c565b0160008282546112479190611809565b90915550505b819450819250808061125e90611821565b9150506110fc565b5060408051428152602081018790527fce749457b74e10f393f2c6b1ce4261b78791376db5a3f501477a809f03f500d6910160405180910390a1505050505050565b60008054848252600260205260408220548291908083036113a75760405163f778e0a360e01b8152600481018890526000906001600160a01b0388169063f778e0a390602401608060405180830381865afa15801561130b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132f9190611892565b9150508065ffffffffffff1660000361134f576000945050505050610946565b7f0000000000000000000000000000000000000000000000000000000000093a808060016113858265ffffffffffff8616611809565b61138f919061183a565b61139991906116fb565b6113a3919061171d565b9150505b60035481106113bc5760009350505050610946565b818110156113c75750805b60005b6032811015611549578582101561154957604051637028a55d60e11b815260048101899052602481018390526000906001600160a01b0389169063e0514aba90604401602060405180830381865afa15801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e9190611867565b90508060000361145e5750611549565b801561150957604051632394e7a360e21b8152600481018490526001600160a01b03891690638e539e8c90602401602060405180830381865afa1580156114a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cd9190611867565b60048466038d7ea4c6800081106114e6576114e661173c565b01546114f2908361171d565b6114fc91906116fb565b6115069086611809565b94505b6115337f0000000000000000000000000000000000000000000000000000000000093a8084611809565b925050808061154190611821565b9150506113ca565b50919695505050505050565b6001600160a01b038116811461156a57600080fd5b50565b60006020828403121561157f57600080fd5b813561094681611555565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156115c9576115c961158a565b604052919050565b600060208083850312156115e457600080fd5b823567ffffffffffffffff808211156115fc57600080fd5b818501915085601f83011261161057600080fd5b8135818111156116225761162261158a565b8060051b91506116338483016115a0565b818152918301840191848101908884111561164d57600080fd5b938501935b8385101561166b57843582529385019390850190611652565b98975050505050505050565b60006020828403121561168957600080fd5b5035919050565b600060208083528351808285015260005b818110156116bd578581018301518582016040015282016116a1565b818111156116cf576000604083870101525b50601f01601f1916929092016040019392505050565b634e487b7160e01b600052601160045260246000fd5b60008261171857634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615611737576117376116e5565b500290565b634e487b7160e01b600052603260045260246000fd5b8051801515811461176257600080fd5b919050565b60006080828403121561177957600080fd5b6040516080810181811067ffffffffffffffff8211171561179c5761179c61158a565b80604052508251815260208301516020820152604083015160408201526117c560608401611752565b60608201529392505050565b6000602082840312156117e357600080fd5b815161094681611555565b60006020828403121561180057600080fd5b61094682611752565b6000821982111561181c5761181c6116e5565b500190565b600060018201611833576118336116e5565b5060010190565b60008282101561184c5761184c6116e5565b500390565b634e487b7160e01b600052600160045260246000fd5b60006020828403121561187957600080fd5b5051919050565b8051600f81900b811461176257600080fd5b60008082840360808112156118a657600080fd5b60608112156118b457600080fd5b506040516060810181811067ffffffffffffffff821117156118d8576118d861158a565b6040526118e484611880565b81526118f260208501611880565b602082015261190360408501611880565b6040820152606084015190925065ffffffffffff8116811461192457600080fd5b80915050925092905056fea2646970667358221220d535ffd9556c89b984f83c53ea5d877912ab49e4e755ca85f02a55d0a5e230c864736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd2
-----Decoded View---------------
Arg [0] : _voting_escrow (address): 0x58Aa310eE85d94b20De2e213b36DbB52F9898dD2
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000058aa310ee85d94b20de2e213b36dbb52f9898dd2
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
[ 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.