Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ResolvStaking
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 833 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ERC20VotesUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol";
import {NoncesUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/NoncesUpgradeable.sol";
import {AccessControlDefaultAdminRulesUpgradeable} from "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlDefaultAdminRulesUpgradeable.sol";
import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IResolvStaking} from "../interfaces/staking/IResolvStaking.sol";
import {ResolvStakingStructs} from "./libraries/ResolvStakingStructs.sol";
import {ResolvStakingErrors} from "./libraries/ResolvStakingErrors.sol";
import {ResolvStakingEvents} from "./libraries/ResolvStakingEvents.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ResolvStakingCheckpoints} from "./libraries/ResolvStakingCheckpoints.sol";
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {IResolvStakingSilo} from "../interfaces/staking/IResolvStakingSilo.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
/**
* @title ResolvStaking
* @notice A staking contract that accepts RESOLV tokens and distributes rewards to stakers.
*/
/// @custom:oz-upgrades-unsafe-allow external-library-linking
contract ResolvStaking is IResolvStaking, ERC20PermitUpgradeable, ERC20VotesUpgradeable, AccessControlDefaultAdminRulesUpgradeable, ReentrancyGuardUpgradeable {
using SafeERC20 for IERC20;
using ResolvStakingCheckpoints for mapping(address user => ResolvStakingStructs.UserData);
bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE");
bytes32 public constant EMERGENCY_ROLE = keccak256("EMERGENCY_ROLE");
uint256 internal constant MAX_WITHDRAWAL_COOLDOWN = 33 days;
/// @notice Length of time over which rewards sent to this contract are distributed to stakers.
uint256 public constant REWARD_DURATION = 14 days;
/// @notice The RESOLV token that is staked.
IERC20 public stakeToken;
/// @notice The total effective supply of staked tokens (with WAHP applied).
uint256 public totalEffectiveSupply;
/// @notice Temporary tokens silo for pending withdrawals.
IResolvStakingSilo public silo;
address[] public rewardTokens;
mapping(address token => ResolvStakingStructs.Reward reward) public rewards;
bool public claimEnabled;
uint256 public withdrawalCooldown;
mapping(address user => ResolvStakingStructs.UserData) public usersData;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function depositWithPermit(
uint256 _amount,
address _receiver,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) external {
IERC20Permit resolvPermit = IERC20Permit(address(stakeToken));
// the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning.
// solhint-disable-next-line no-empty-blocks
try resolvPermit.permit(msg.sender, address(this), _amount, _deadline, _v, _r, _s) {} catch {}
deposit(_amount, _receiver);
}
/**
* @notice Withdraws staked tokens after the cooldown period.
* @param _claimRewards If true, claims pending rewards during withdrawal.
* @param _receiver The address to receive the withdrawn tokens.
* @dev Requires a pending withdrawal request to exist and cooldown period to be met.
*/
function withdraw(
bool _claimRewards,
address _receiver
) external nonReentrant {
ResolvStakingStructs.PendingWithdrawal storage pendingWithdrawal = usersData[msg.sender].pendingWithdrawal;
uint256 amount = pendingWithdrawal.amount;
require(amount != 0, ResolvStakingErrors.WithdrawalRequestNotFound());
require(block.timestamp >= pendingWithdrawal.cooldownEnd, ResolvStakingErrors.CooldownNotMet());
checkpoint(msg.sender, _claimRewards, _receiver, 0);
silo.withdraw(_receiver, amount);
pendingWithdrawal.amount = 0;
pendingWithdrawal.cooldownEnd = 0;
emit ResolvStakingEvents.Withdrawn(msg.sender, _receiver, amount, _claimRewards);
}
/**
* @notice Initiate a withdrawal of a specified amount of staked tokens.
* @param _amount The amount of staked tokens to withdraw.
* @dev The caller must have a balance of at least `_amount`
*/
// slither-disable-next-line pess-unprotected-initialize
function initiateWithdrawal(uint256 _amount) external nonReentrant {
require(_amount > 0, ResolvStakingErrors.InvalidAmount());
require(balanceOf(msg.sender) >= _amount, ResolvStakingErrors.InsufficientBalance());
ResolvStakingStructs.UserData storage userData = usersData[msg.sender];
checkpoint(msg.sender, false, address(0), - SafeCast.toInt256(_amount));
userData.pendingWithdrawal.amount += _amount;
userData.pendingWithdrawal.cooldownEnd = block.timestamp + withdrawalCooldown;
_burn(msg.sender, _amount);
stakeToken.safeTransfer(address(silo), _amount);
emit ResolvStakingEvents.WithdrawalInitiated(msg.sender, _amount);
}
/**
* @notice Claims rewards for the caller and sends them to the specified receiver.
* @param _receiver The address to receive the rewards. If zero, uses the caller's default receiver.
*/
function claim(address _user, address _receiver) external nonReentrant {
require(msg.sender == _user || msg.sender == usersData[_user].checkpointDelegatee,
ResolvStakingErrors.InvalidCheckpointCaller());
checkpoint(_user, true, _receiver, 0);
}
/**
* @notice Updates the user's reward checkpoint without claiming rewards.
* @param _user The address of the user.
*/
function updateCheckpoint(address _user) external nonReentrant {
if (_user != address(0)) {
require(msg.sender == _user || msg.sender == usersData[_user].checkpointDelegatee,
ResolvStakingErrors.InvalidCheckpointCaller());
}
checkpoint(_user, false, address(0), 0);
}
/**
* @notice Deposits a specified amount of reward tokens into the contract.
* @param _token The address of the reward token to deposit.
* @param _amount The amount of reward tokens to deposit.
* @param _duration The duration over which the rewards will be distributed (If zero, uses the default REWARD_DURATION).
* @dev Only callable by accounts with the DISTRIBUTOR_ROLE.
* Updates the reward rate and period finish for the reward token.
*/
function depositReward(
address _token,
uint256 _amount,
uint256 _duration
) external nonReentrant onlyRole(DISTRIBUTOR_ROLE) {
require(_amount > 0, ResolvStakingErrors.InvalidAmount());
require(totalEffectiveSupply > 0, ResolvStakingErrors.ZeroTotalEffectiveSupply());
ResolvStakingStructs.Reward storage reward = rewards[_token];
require(address(reward.token) != address(0), ResolvStakingErrors.RewardTokenNotFound(_token));
require(_duration <= REWARD_DURATION, ResolvStakingErrors.InvalidDuration());
uint256 duration = _duration == 0 ? REWARD_DURATION : _duration;
checkpoint(address(0), false, address(0), 0);
uint256 amountReceived = reward.token.balanceOf(address(this));
reward.token.safeTransferFrom(msg.sender, address(this), _amount);
amountReceived = reward.token.balanceOf(address(this)) - amountReceived;
uint256 periodFinish = reward.periodFinish;
if (block.timestamp >= periodFinish) {
reward.rewardRate = amountReceived * ResolvStakingStructs.REWARD_RATE_SCALE_FACTOR / duration;
} else {
uint256 remainingReward = (periodFinish - block.timestamp) * reward.rewardRate;
reward.rewardRate = (amountReceived * ResolvStakingStructs.REWARD_RATE_SCALE_FACTOR + remainingReward) / duration;
}
// This check doesn't guarantee that the contract has received sufficient rewards,
// as it can't differentiate unclaimed staker rewards from the balance.
// Although it helps avoid degenerate cases, it's insufficient on its own.
require(
reward.token.balanceOf(address(this)) * ResolvStakingStructs.REWARD_RATE_SCALE_FACTOR >= reward.rewardRate * duration,
ResolvStakingErrors.InsufficientRewardBalance()
);
reward.lastUpdate = block.timestamp;
reward.periodFinish = block.timestamp + duration;
emit ResolvStakingEvents.RewardTokenDeposited(_token, _amount);
}
/**
* @notice Set the rewards receiver for the caller.
* @param _receiver The address to set as the rewards receiver.
*/
function setRewardsReceiver(address _receiver) external {
usersData[msg.sender].rewardReceiver = _receiver;
emit ResolvStakingEvents.RewardsReceiverSet(msg.sender, _receiver);
}
/**
* @notice Sets the checkpoint delegatee for the caller.
* @param _delegatee The address to set as the delegatee.
*/
function setCheckpointDelegatee(address _delegatee) external {
usersData[msg.sender].checkpointDelegatee = _delegatee;
emit ResolvStakingEvents.CheckpointDelegateeSet(msg.sender, _delegatee);
}
/**
* @notice Adds a new reward token to the staking contract.
* @param _token The reward token to add.
*/
function addRewardToken(IERC20 _token) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(address(_token) != address(0), ResolvStakingErrors.ZeroAddress());
require(address(rewards[address(_token)].token) == address(0), ResolvStakingErrors.RewardTokenAlreadyAdded(address(_token)));
rewardTokens.push(address(_token));
rewards[address(_token)].token = _token;
emit ResolvStakingEvents.RewardAdded(address(_token));
}
/**
* @dev Allows the EMERGENCY_ROLE to emergency withdraw ERC20 tokens from the contract.
* @param _token The ERC20 token contract address to withdraw.
* @param _to The recipient address to receive the tokens.
* @param _amount The amount of tokens to withdraw.
*/
function emergencyWithdrawERC20(
IERC20 _token,
address _to,
uint256 _amount
) external onlyRole(EMERGENCY_ROLE) {
require(address(_token) != address(0), ResolvStakingErrors.ZeroAddress());
require(address(_to) != address(0), ResolvStakingErrors.ZeroAddress());
require(_amount > 0, ResolvStakingErrors.InvalidAmount());
_token.safeTransfer(_to, _amount);
emit ResolvStakingEvents.EmergencyWithdrawnERC20(address(_token), _to, _amount);
}
/**
* @notice Sets the claimEnabled flag.
* @param _enabled The new value for the claimEnabled flag.
*/
function setClaimEnabled(bool _enabled) external onlyRole(DEFAULT_ADMIN_ROLE) {
claimEnabled = _enabled;
emit ResolvStakingEvents.ClaimEnabledSet(_enabled);
}
function getUserAccumulatedRewardPerToken(address _user, address _token) external view returns (uint256 amount) {
return usersData[_user].accumulatedRewardsPerToken[_token];
}
function getUserClaimableAmounts(address _user, address _token) external view returns (uint256 amount) {
return usersData[_user].claimableAmounts[_token];
}
function getUserStakeAgeInfo(address _user) external view returns (ResolvStakingStructs.StakeAgeInfo memory info) {
return usersData[_user].stakeAgeInfo;
}
function getUserEffectiveBalance(address _user) external view returns (uint256 balance) {
return usersData[_user].effectiveBalance;
}
function getReward(address _token) external view returns (ResolvStakingStructs.Reward memory reward) {
return rewards[_token];
}
/**
* @notice Deposits RESOLV tokens for staking.
* @param _amount The amount of tokens to deposit.
* @param _receiver The address that will receive the staked tokens.
* @dev Updates reward checkpoints before minting tokens.
*/
function deposit(
uint256 _amount,
address _receiver
) public nonReentrant {
require(_amount > 0, ResolvStakingErrors.InvalidAmount());
require(_receiver != address(0), ResolvStakingErrors.ZeroAddress());
checkpoint(_receiver, false, address(0), SafeCast.toInt256(_amount));
stakeToken.safeTransferFrom(msg.sender, address(this), _amount);
_mint(_receiver, _amount);
emit ResolvStakingEvents.Deposited(msg.sender, _receiver, _amount);
}
function initialize(
string memory _name,
string memory _symbol,
IERC20 _stakeToken,
IResolvStakingSilo _silo,
uint256 _withdrawalCooldown
) public initializer {
__ERC20_init(_name, _symbol);
__ERC20Permit_init(_name);
__AccessControlDefaultAdminRules_init(1 days, msg.sender);
__ReentrancyGuard_init();
require(address(_stakeToken) != address(0), ResolvStakingErrors.ZeroAddress());
require(address(_silo) != address(0), ResolvStakingErrors.ZeroAddress());
stakeToken = _stakeToken;
silo = _silo;
setWithdrawalCooldown(_withdrawalCooldown);
}
/**
* @notice Sets the withdrawal cooldown period.
* @param _cooldown The new cooldown period.
*/
function setWithdrawalCooldown(uint256 _cooldown) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(_cooldown <= MAX_WITHDRAWAL_COOLDOWN, ResolvStakingErrors.InvalidWithdrawalCooldown());
withdrawalCooldown = _cooldown;
emit ResolvStakingEvents.WithdrawalCooldownSet(_cooldown);
}
function nonces(
address owner
) public view virtual override(NoncesUpgradeable, ERC20PermitUpgradeable) returns (uint256) {
return super.nonces(owner);
}
/**
* @dev This function always reverts with a NonTransferable error.
*/
function transfer(address, uint256) public pure override returns (bool) {
revert ResolvStakingErrors.NonTransferable();
}
/**
* @dev This function always reverts with a NonTransferable error.
*/
function transferFrom(address, address, uint256) public pure override returns (bool) {
revert ResolvStakingErrors.NonTransferable();
}
/**
* @notice Internal hook to update reward checkpoints when token balances change.
* @param _from The address transferring tokens.
* @param _to The address receiving tokens.
* @param _value The amount of tokens being transferred.
*/
function _update(
address _from,
address _to,
uint256 _value
) internal override(ERC20VotesUpgradeable, ERC20Upgradeable) {
super._update(_from, _to, _value);
}
/**
* @notice Updates the reward checkpoints for a user.
* @param _user The address of the user.
* @param _claim If true, claims any pending rewards.
* @param _rewardReceiver The address to receive rewards. If zero, uses the default receiver.
* @param _delta The change in the staked balance (positive for deposits, negative for withdrawals).
* @dev This function updates global reward indexes and user-specific reward data.
*/
// slither-disable-start reentrancy-no-eth
function checkpoint(
address _user,
bool _claim,
address _rewardReceiver,
int256 _delta
) internal {
require(!_claim || claimEnabled, ResolvStakingErrors.ClaimNotEnabled());
usersData.checkpoint(
rewards,
rewardTokens,
ResolvStakingCheckpoints.CheckpointParams({
user: _user,
rewardReceiver: _rewardReceiver,
totalSupply: totalSupply(),
totalEffectiveSupply: totalEffectiveSupply,
userStakedBalance: balanceOf(_user),
claim: _claim
}));
totalEffectiveSupply = usersData.updateEffectiveBalance(
ResolvStakingCheckpoints.UpdateEffectiveBalanceParams({
user: _user,
userStakedBalance: balanceOf(_user),
delta: _delta,
totalEffectiveSupply: totalEffectiveSupply
}));
}
// slither-disable-end reentrancy-no-eth
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
bytes32 previousAdminRole = getRoleAdmin(role);
$._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlDefaultAdminRules.sol)
pragma solidity ^0.8.20;
import {IAccessControlDefaultAdminRules} from "@openzeppelin/contracts/access/extensions/IAccessControlDefaultAdminRules.sol";
import {AccessControlUpgradeable} from "../AccessControlUpgradeable.sol";
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IERC5313} from "@openzeppelin/contracts/interfaces/IERC5313.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Extension of {AccessControl} that allows specifying special rules to manage
* the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions
* over other roles that may potentially have privileged rights in the system.
*
* If a specific role doesn't have an admin role assigned, the holder of the
* `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it.
*
* This contract implements the following risk mitigations on top of {AccessControl}:
*
* * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced.
* * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account.
* * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted.
* * The delay can be changed by scheduling, see {changeDefaultAdminDelay}.
* * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`.
*
* Example usage:
*
* ```solidity
* contract MyToken is AccessControlDefaultAdminRules {
* constructor() AccessControlDefaultAdminRules(
* 3 days,
* msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder
* ) {}
* }
* ```
*/
abstract contract AccessControlDefaultAdminRulesUpgradeable is Initializable, IAccessControlDefaultAdminRules, IERC5313, AccessControlUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControlDefaultAdminRules
struct AccessControlDefaultAdminRulesStorage {
// pending admin pair read/written together frequently
address _pendingDefaultAdmin;
uint48 _pendingDefaultAdminSchedule; // 0 == unset
uint48 _currentDelay;
address _currentDefaultAdmin;
// pending delay pair read/written together frequently
uint48 _pendingDelay;
uint48 _pendingDelaySchedule; // 0 == unset
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControlDefaultAdminRules")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlDefaultAdminRulesStorageLocation = 0xeef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400;
function _getAccessControlDefaultAdminRulesStorage() private pure returns (AccessControlDefaultAdminRulesStorage storage $) {
assembly {
$.slot := AccessControlDefaultAdminRulesStorageLocation
}
}
/**
* @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address.
*/
function __AccessControlDefaultAdminRules_init(uint48 initialDelay, address initialDefaultAdmin) internal onlyInitializing {
__AccessControlDefaultAdminRules_init_unchained(initialDelay, initialDefaultAdmin);
}
function __AccessControlDefaultAdminRules_init_unchained(uint48 initialDelay, address initialDefaultAdmin) internal onlyInitializing {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
if (initialDefaultAdmin == address(0)) {
revert AccessControlInvalidDefaultAdmin(address(0));
}
$._currentDelay = initialDelay;
_grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC5313-owner}.
*/
function owner() public view virtual returns (address) {
return defaultAdmin();
}
///
/// Override AccessControl role management
///
/**
* @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function grantRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super.grantRole(role, account);
}
/**
* @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function revokeRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super.revokeRole(role, account);
}
/**
* @dev See {AccessControl-renounceRole}.
*
* For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling
* {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule
* has also passed when calling this function.
*
* After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions.
*
* NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin},
* thereby disabling any functionality that is only available for it, and the possibility of reassigning a
* non-administrated role.
*/
function renounceRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
(address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();
if (newDefaultAdmin != address(0) || !_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
revert AccessControlEnforcedDefaultAdminDelay(schedule);
}
delete $._pendingDefaultAdminSchedule;
}
super.renounceRole(role, account);
}
/**
* @dev See {AccessControl-_grantRole}.
*
* For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the
* role has been previously renounced.
*
* NOTE: Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE`
* assignable again. Make sure to guarantee this is the expected behavior in your implementation.
*/
function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
if (role == DEFAULT_ADMIN_ROLE) {
if (defaultAdmin() != address(0)) {
revert AccessControlEnforcedDefaultAdminRules();
}
$._currentDefaultAdmin = account;
}
return super._grantRole(role, account);
}
/**
* @dev See {AccessControl-_revokeRole}.
*/
function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
delete $._currentDefaultAdmin;
}
return super._revokeRole(role, account);
}
/**
* @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {
if (role == DEFAULT_ADMIN_ROLE) {
revert AccessControlEnforcedDefaultAdminRules();
}
super._setRoleAdmin(role, adminRole);
}
///
/// AccessControlDefaultAdminRules accessors
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdmin() public view virtual returns (address) {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
return $._currentDefaultAdmin;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
return ($._pendingDefaultAdmin, $._pendingDefaultAdminSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdminDelay() public view virtual returns (uint48) {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
uint48 schedule = $._pendingDelaySchedule;
return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? $._pendingDelay : $._currentDelay;
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
schedule = $._pendingDelaySchedule;
return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? ($._pendingDelay, schedule) : (0, 0);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) {
return 5 days;
}
///
/// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_beginDefaultAdminTransfer(newAdmin);
}
/**
* @dev See {beginDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _beginDefaultAdminTransfer(address newAdmin) internal virtual {
uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay();
_setPendingDefaultAdmin(newAdmin, newSchedule);
emit DefaultAdminTransferScheduled(newAdmin, newSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_cancelDefaultAdminTransfer();
}
/**
* @dev See {cancelDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _cancelDefaultAdminTransfer() internal virtual {
_setPendingDefaultAdmin(address(0), 0);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function acceptDefaultAdminTransfer() public virtual {
(address newDefaultAdmin, ) = pendingDefaultAdmin();
if (_msgSender() != newDefaultAdmin) {
// Enforce newDefaultAdmin explicit acceptance.
revert AccessControlInvalidDefaultAdmin(_msgSender());
}
_acceptDefaultAdminTransfer();
}
/**
* @dev See {acceptDefaultAdminTransfer}.
*
* Internal function without access restriction.
*/
function _acceptDefaultAdminTransfer() internal virtual {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
(address newAdmin, uint48 schedule) = pendingDefaultAdmin();
if (!_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
revert AccessControlEnforcedDefaultAdminDelay(schedule);
}
_revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());
_grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
delete $._pendingDefaultAdmin;
delete $._pendingDefaultAdminSchedule;
}
///
/// AccessControlDefaultAdminRules public and internal setters for defaultAdminDelay/pendingDefaultAdminDelay
///
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_changeDefaultAdminDelay(newDelay);
}
/**
* @dev See {changeDefaultAdminDelay}.
*
* Internal function without access restriction.
*/
function _changeDefaultAdminDelay(uint48 newDelay) internal virtual {
uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay);
_setPendingDelay(newDelay, newSchedule);
emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule);
}
/**
* @inheritdoc IAccessControlDefaultAdminRules
*/
function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
_rollbackDefaultAdminDelay();
}
/**
* @dev See {rollbackDefaultAdminDelay}.
*
* Internal function without access restriction.
*/
function _rollbackDefaultAdminDelay() internal virtual {
_setPendingDelay(0, 0);
}
/**
* @dev Returns the amount of seconds to wait after the `newDelay` will
* become the new {defaultAdminDelay}.
*
* The value returned guarantees that if the delay is reduced, it will go into effect
* after a wait that honors the previously set delay.
*
* See {defaultAdminDelayIncreaseWait}.
*/
function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) {
uint48 currentDelay = defaultAdminDelay();
// When increasing the delay, we schedule the delay change to occur after a period of "new delay" has passed, up
// to a maximum given by defaultAdminDelayIncreaseWait, by default 5 days. For example, if increasing from 1 day
// to 3 days, the new delay will come into effect after 3 days. If increasing from 1 day to 10 days, the new
// delay will come into effect after 5 days. The 5 day wait period is intended to be able to fix an error like
// using milliseconds instead of seconds.
//
// When decreasing the delay, we wait the difference between "current delay" and "new delay". This guarantees
// that an admin transfer cannot be made faster than "current delay" at the time the delay change is scheduled.
// For example, if decreasing from 10 days to 3 days, the new delay will come into effect after 7 days.
return
newDelay > currentDelay
? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48
: currentDelay - newDelay;
}
///
/// Private setters
///
/**
* @dev Setter of the tuple for pending admin and its schedule.
*
* May emit a DefaultAdminTransferCanceled event.
*/
function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
(, uint48 oldSchedule) = pendingDefaultAdmin();
$._pendingDefaultAdmin = newAdmin;
$._pendingDefaultAdminSchedule = newSchedule;
// An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted.
if (_isScheduleSet(oldSchedule)) {
// Emit for implicit cancellations when another default admin was scheduled.
emit DefaultAdminTransferCanceled();
}
}
/**
* @dev Setter of the tuple for pending delay and its schedule.
*
* May emit a DefaultAdminDelayChangeCanceled event.
*/
function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private {
AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
uint48 oldSchedule = $._pendingDelaySchedule;
if (_isScheduleSet(oldSchedule)) {
if (_hasSchedulePassed(oldSchedule)) {
// Materialize a virtual delay
$._currentDelay = $._pendingDelay;
} else {
// Emit for implicit cancellations when another delay was scheduled.
emit DefaultAdminDelayChangeCanceled();
}
}
$._pendingDelay = newDelay;
$._pendingDelaySchedule = newSchedule;
}
///
/// Private helpers
///
/**
* @dev Defines if an `schedule` is considered set. For consistency purposes.
*/
function _isScheduleSet(uint48 schedule) private pure returns (bool) {
return schedule != 0;
}
/**
* @dev Defines if an `schedule` is considered passed. For consistency purposes.
*/
function _hasSchedulePassed(uint48 schedule) private view returns (bool) {
return schedule < block.timestamp;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/Votes.sol)
pragma solidity ^0.8.20;
import {IERC5805} from "@openzeppelin/contracts/interfaces/IERC5805.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {NoncesUpgradeable} from "../../utils/NoncesUpgradeable.sol";
import {EIP712Upgradeable} from "../../utils/cryptography/EIP712Upgradeable.sol";
import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be
* transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of
* "representative" that will pool delegated voting units from different accounts and can then use it to vote in
* decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to
* delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative.
*
* This contract is often combined with a token contract such that voting units correspond to token units. For an
* example, see {ERC721Votes}.
*
* The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed
* at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the
* cost of this history tracking optional.
*
* When using this module the derived contract must implement {_getVotingUnits} (for example, make it return
* {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the
* previous example, it would be included in {ERC721-_update}).
*/
abstract contract VotesUpgradeable is Initializable, ContextUpgradeable, EIP712Upgradeable, NoncesUpgradeable, IERC5805 {
using Checkpoints for Checkpoints.Trace208;
bytes32 private constant DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
/// @custom:storage-location erc7201:openzeppelin.storage.Votes
struct VotesStorage {
mapping(address account => address) _delegatee;
mapping(address delegatee => Checkpoints.Trace208) _delegateCheckpoints;
Checkpoints.Trace208 _totalCheckpoints;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Votes")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant VotesStorageLocation = 0xe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00;
function _getVotesStorage() private pure returns (VotesStorage storage $) {
assembly {
$.slot := VotesStorageLocation
}
}
/**
* @dev The clock was incorrectly modified.
*/
error ERC6372InconsistentClock();
/**
* @dev Lookup to future votes is not available.
*/
error ERC5805FutureLookup(uint256 timepoint, uint48 clock);
function __Votes_init() internal onlyInitializing {
}
function __Votes_init_unchained() internal onlyInitializing {
}
/**
* @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based
* checkpoints (and voting), in which case {CLOCK_MODE} should be overridden as well to match.
*/
function clock() public view virtual returns (uint48) {
return Time.blockNumber();
}
/**
* @dev Machine-readable description of the clock as specified in EIP-6372.
*/
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() public view virtual returns (string memory) {
// Check that the clock was not modified
if (clock() != Time.blockNumber()) {
revert ERC6372InconsistentClock();
}
return "mode=blocknumber&from=default";
}
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) public view virtual returns (uint256) {
VotesStorage storage $ = _getVotesStorage();
return $._delegateCheckpoints[account].latest();
}
/**
* @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.
*
* Requirements:
*
* - `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
*/
function getPastVotes(address account, uint256 timepoint) public view virtual returns (uint256) {
VotesStorage storage $ = _getVotesStorage();
uint48 currentTimepoint = clock();
if (timepoint >= currentTimepoint) {
revert ERC5805FutureLookup(timepoint, currentTimepoint);
}
return $._delegateCheckpoints[account].upperLookupRecent(SafeCast.toUint48(timepoint));
}
/**
* @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.
*
* Requirements:
*
* - `timepoint` must be in the past. If operating using block numbers, the block must be already mined.
*/
function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) {
VotesStorage storage $ = _getVotesStorage();
uint48 currentTimepoint = clock();
if (timepoint >= currentTimepoint) {
revert ERC5805FutureLookup(timepoint, currentTimepoint);
}
return $._totalCheckpoints.upperLookupRecent(SafeCast.toUint48(timepoint));
}
/**
* @dev Returns the current total supply of votes.
*/
function _getTotalSupply() internal view virtual returns (uint256) {
VotesStorage storage $ = _getVotesStorage();
return $._totalCheckpoints.latest();
}
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) public view virtual returns (address) {
VotesStorage storage $ = _getVotesStorage();
return $._delegatee[account];
}
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) public virtual {
address account = _msgSender();
_delegate(account, delegatee);
}
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (block.timestamp > expiry) {
revert VotesExpiredSignature(expiry);
}
address signer = ECDSA.recover(
_hashTypedDataV4(keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
v,
r,
s
);
_useCheckedNonce(signer, nonce);
_delegate(signer, delegatee);
}
/**
* @dev Delegate all of `account`'s voting units to `delegatee`.
*
* Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
*/
function _delegate(address account, address delegatee) internal virtual {
VotesStorage storage $ = _getVotesStorage();
address oldDelegate = delegates(account);
$._delegatee[account] = delegatee;
emit DelegateChanged(account, oldDelegate, delegatee);
_moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account));
}
/**
* @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`
* should be zero. Total supply of voting units will be adjusted with mints and burns.
*/
function _transferVotingUnits(address from, address to, uint256 amount) internal virtual {
VotesStorage storage $ = _getVotesStorage();
if (from == address(0)) {
_push($._totalCheckpoints, _add, SafeCast.toUint208(amount));
}
if (to == address(0)) {
_push($._totalCheckpoints, _subtract, SafeCast.toUint208(amount));
}
_moveDelegateVotes(delegates(from), delegates(to), amount);
}
/**
* @dev Moves delegated votes from one delegate to another.
*/
function _moveDelegateVotes(address from, address to, uint256 amount) private {
VotesStorage storage $ = _getVotesStorage();
if (from != to && amount > 0) {
if (from != address(0)) {
(uint256 oldValue, uint256 newValue) = _push(
$._delegateCheckpoints[from],
_subtract,
SafeCast.toUint208(amount)
);
emit DelegateVotesChanged(from, oldValue, newValue);
}
if (to != address(0)) {
(uint256 oldValue, uint256 newValue) = _push(
$._delegateCheckpoints[to],
_add,
SafeCast.toUint208(amount)
);
emit DelegateVotesChanged(to, oldValue, newValue);
}
}
}
/**
* @dev Get number of checkpoints for `account`.
*/
function _numCheckpoints(address account) internal view virtual returns (uint32) {
VotesStorage storage $ = _getVotesStorage();
return SafeCast.toUint32($._delegateCheckpoints[account].length());
}
/**
* @dev Get the `pos`-th checkpoint for `account`.
*/
function _checkpoints(
address account,
uint32 pos
) internal view virtual returns (Checkpoints.Checkpoint208 memory) {
VotesStorage storage $ = _getVotesStorage();
return $._delegateCheckpoints[account].at(pos);
}
function _push(
Checkpoints.Trace208 storage store,
function(uint208, uint208) view returns (uint208) op,
uint208 delta
) private returns (uint208, uint208) {
return store.push(clock(), op(store.latest(), delta));
}
function _add(uint208 a, uint208 b) private pure returns (uint208) {
return a + b;
}
function _subtract(uint208 a, uint208 b) private pure returns (uint208) {
return a - b;
}
/**
* @dev Must return the voting units held by an account.
*/
function _getVotingUnits(address) internal view virtual returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {
/// @custom:storage-location erc7201:openzeppelin.storage.ERC20
struct ERC20Storage {
mapping(address account => uint256) _balances;
mapping(address account => mapping(address spender => uint256)) _allowances;
uint256 _totalSupply;
string _name;
string _symbol;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;
function _getERC20Storage() private pure returns (ERC20Storage storage $) {
assembly {
$.slot := ERC20StorageLocation
}
}
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
ERC20Storage storage $ = _getERC20Storage();
$._name = name_;
$._symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
ERC20Storage storage $ = _getERC20Storage();
return $._name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
ERC20Storage storage $ = _getERC20Storage();
return $._symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
return $._totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
return $._balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
ERC20Storage storage $ = _getERC20Storage();
return $._allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
ERC20Storage storage $ = _getERC20Storage();
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
$._totalSupply += value;
} else {
uint256 fromBalance = $._balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
$._balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
$._totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
$._balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
ERC20Storage storage $ = _getERC20Storage();
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
$._allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)
pragma solidity ^0.8.20;
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712Upgradeable} from "../../../utils/cryptography/EIP712Upgradeable.sol";
import {NoncesUpgradeable} from "../../../utils/NoncesUpgradeable.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20Permit, EIP712Upgradeable, NoncesUpgradeable {
bytes32 private constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
/**
* @dev Permit deadline has expired.
*/
error ERC2612ExpiredSignature(uint256 deadline);
/**
* @dev Mismatched signature.
*/
error ERC2612InvalidSigner(address signer, address owner);
/**
* @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
*
* It's a good idea to use the same `name` that is defined as the ERC20 token name.
*/
function __ERC20Permit_init(string memory name) internal onlyInitializing {
__EIP712_init_unchained(name, "1");
}
function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {}
/**
* @inheritdoc IERC20Permit
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (block.timestamp > deadline) {
revert ERC2612ExpiredSignature(deadline);
}
bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
if (signer != owner) {
revert ERC2612InvalidSigner(signer, owner);
}
_approve(owner, spender, value);
}
/**
* @inheritdoc IERC20Permit
*/
function nonces(address owner) public view virtual override(IERC20Permit, NoncesUpgradeable) returns (uint256) {
return super.nonces(owner);
}
/**
* @inheritdoc IERC20Permit
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
return _domainSeparatorV4();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Votes.sol)
pragma solidity ^0.8.20;
import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
import {VotesUpgradeable} from "../../../governance/utils/VotesUpgradeable.sol";
import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";
/**
* @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,
* and supports token supply up to 2^208^ - 1, while COMP is limited to 2^96^ - 1.
*
* NOTE: This contract does not provide interface compatibility with Compound's COMP token.
*
* This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
* by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
* power can be queried through the public accessors {getVotes} and {getPastVotes}.
*
* By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
* requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
*/
abstract contract ERC20VotesUpgradeable is Initializable, ERC20Upgradeable, VotesUpgradeable {
/**
* @dev Total supply cap has been exceeded, introducing a risk of votes overflowing.
*/
error ERC20ExceededSafeSupply(uint256 increasedSupply, uint256 cap);
function __ERC20Votes_init() internal onlyInitializing {
}
function __ERC20Votes_init_unchained() internal onlyInitializing {
}
/**
* @dev Maximum token supply. Defaults to `type(uint208).max` (2^208^ - 1).
*
* This maximum is enforced in {_update}. It limits the total supply of the token, which is otherwise a uint256,
* so that checkpoints can be stored in the Trace208 structure used by {{Votes}}. Increasing this value will not
* remove the underlying limitation, and will cause {_update} to fail because of a math overflow in
* {_transferVotingUnits}. An override could be used to further restrict the total supply (to a lower value) if
* additional logic requires it. When resolving override conflicts on this function, the minimum should be
* returned.
*/
function _maxSupply() internal view virtual returns (uint256) {
return type(uint208).max;
}
/**
* @dev Move voting power when tokens are transferred.
*
* Emits a {IVotes-DelegateVotesChanged} event.
*/
function _update(address from, address to, uint256 value) internal virtual override {
super._update(from, to, value);
if (from == address(0)) {
uint256 supply = totalSupply();
uint256 cap = _maxSupply();
if (supply > cap) {
revert ERC20ExceededSafeSupply(supply, cap);
}
}
_transferVotingUnits(from, to, value);
}
/**
* @dev Returns the voting units of an `account`.
*
* WARNING: Overriding this function may compromise the internal vote accounting.
* `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change.
*/
function _getVotingUnits(address account) internal view virtual override returns (uint256) {
return balanceOf(account);
}
/**
* @dev Get number of checkpoints for `account`.
*/
function numCheckpoints(address account) public view virtual returns (uint32) {
return _numCheckpoints(account);
}
/**
* @dev Get the `pos`-th checkpoint for `account`.
*/
function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoints.Checkpoint208 memory) {
return _checkpoints(account, pos);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.20;
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*/
abstract contract EIP712Upgradeable is Initializable, IERC5267 {
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
/// @custom:storage-location erc7201:openzeppelin.storage.EIP712
struct EIP712Storage {
/// @custom:oz-renamed-from _HASHED_NAME
bytes32 _hashedName;
/// @custom:oz-renamed-from _HASHED_VERSION
bytes32 _hashedVersion;
string _name;
string _version;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.EIP712")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;
function _getEIP712Storage() private pure returns (EIP712Storage storage $) {
assembly {
$.slot := EIP712StorageLocation
}
}
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
__EIP712_init_unchained(name, version);
}
function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
EIP712Storage storage $ = _getEIP712Storage();
$._name = name;
$._version = version;
// Reset prior values in storage if upgrading
$._hashedName = 0;
$._hashedVersion = 0;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
return _buildDomainSeparator();
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {IERC-5267}.
*/
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
EIP712Storage storage $ = _getEIP712Storage();
// If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized
// and the EIP712 domain is not reliable, as it will be missing name and version.
require($._hashedName == 0 && $._hashedVersion == 0, "EIP712: Uninitialized");
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712Name() internal view virtual returns (string memory) {
EIP712Storage storage $ = _getEIP712Storage();
return $._name;
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712Version() internal view virtual returns (string memory) {
EIP712Storage storage $ = _getEIP712Storage();
return $._version;
}
/**
* @dev The hash of the name parameter for the EIP712 domain.
*
* NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.
*/
function _EIP712NameHash() internal view returns (bytes32) {
EIP712Storage storage $ = _getEIP712Storage();
string memory name = _EIP712Name();
if (bytes(name).length > 0) {
return keccak256(bytes(name));
} else {
// If the name is empty, the contract may have been upgraded without initializing the new storage.
// We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.
bytes32 hashedName = $._hashedName;
if (hashedName != 0) {
return hashedName;
} else {
return keccak256("");
}
}
}
/**
* @dev The hash of the version parameter for the EIP712 domain.
*
* NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.
*/
function _EIP712VersionHash() internal view returns (bytes32) {
EIP712Storage storage $ = _getEIP712Storage();
string memory version = _EIP712Version();
if (bytes(version).length > 0) {
return keccak256(bytes(version));
} else {
// If the version is empty, the contract may have been upgraded without initializing the new storage.
// We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.
bytes32 hashedVersion = $._hashedVersion;
if (hashedVersion != 0) {
return hashedVersion;
} else {
return keccak256("");
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides tracking nonces for addresses. Nonces will only increment.
*/
abstract contract NoncesUpgradeable is Initializable {
/**
* @dev The nonce used for an `account` is not the expected current nonce.
*/
error InvalidAccountNonce(address account, uint256 currentNonce);
/// @custom:storage-location erc7201:openzeppelin.storage.Nonces
struct NoncesStorage {
mapping(address account => uint256) _nonces;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Nonces")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00;
function _getNoncesStorage() private pure returns (NoncesStorage storage $) {
assembly {
$.slot := NoncesStorageLocation
}
}
function __Nonces_init() internal onlyInitializing {
}
function __Nonces_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns the next unused nonce for an address.
*/
function nonces(address owner) public view virtual returns (uint256) {
NoncesStorage storage $ = _getNoncesStorage();
return $._nonces[owner];
}
/**
* @dev Consumes a nonce.
*
* Returns the current value and increments nonce.
*/
function _useNonce(address owner) internal virtual returns (uint256) {
NoncesStorage storage $ = _getNoncesStorage();
// For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
// decremented or reset. This guarantees that the nonce never overflows.
unchecked {
// It is important to do x++ and not ++x here.
return $._nonces[owner]++;
}
}
/**
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
*/
function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
uint256 current = _useNonce(owner);
if (nonce != current) {
revert InvalidAccountNonce(owner, current);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlDefaultAdminRules.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "../IAccessControl.sol";
/**
* @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection.
*/
interface IAccessControlDefaultAdminRules is IAccessControl {
/**
* @dev The new default admin is not a valid default admin.
*/
error AccessControlInvalidDefaultAdmin(address defaultAdmin);
/**
* @dev At least one of the following rules was violated:
*
* - The `DEFAULT_ADMIN_ROLE` must only be managed by itself.
* - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time.
* - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps.
*/
error AccessControlEnforcedDefaultAdminRules();
/**
* @dev The delay for transferring the default admin delay is enforced and
* the operation must wait until `schedule`.
*
* NOTE: `schedule` can be 0 indicating there's no transfer scheduled.
*/
error AccessControlEnforcedDefaultAdminDelay(uint48 schedule);
/**
* @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next
* address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule`
* passes.
*/
event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule);
/**
* @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule.
*/
event DefaultAdminTransferCanceled();
/**
* @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next
* delay to be applied between default admin transfer after `effectSchedule` has passed.
*/
event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule);
/**
* @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass.
*/
event DefaultAdminDelayChangeCanceled();
/**
* @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder.
*/
function defaultAdmin() external view returns (address);
/**
* @dev Returns a tuple of a `newAdmin` and an accept schedule.
*
* After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role
* by calling {acceptDefaultAdminTransfer}, completing the role transfer.
*
* A zero value only in `acceptSchedule` indicates no pending admin transfer.
*
* NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced.
*/
function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule);
/**
* @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started.
*
* This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set
* the acceptance schedule.
*
* NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this
* function returns the new delay. See {changeDefaultAdminDelay}.
*/
function defaultAdminDelay() external view returns (uint48);
/**
* @dev Returns a tuple of `newDelay` and an effect schedule.
*
* After the `schedule` passes, the `newDelay` will get into effect immediately for every
* new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}.
*
* A zero value only in `effectSchedule` indicates no pending delay change.
*
* NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay}
* will be zero after the effect schedule.
*/
function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule);
/**
* @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance
* after the current timestamp plus a {defaultAdminDelay}.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* Emits a DefaultAdminRoleChangeStarted event.
*/
function beginDefaultAdminTransfer(address newAdmin) external;
/**
* @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
*
* A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* May emit a DefaultAdminTransferCanceled event.
*/
function cancelDefaultAdminTransfer() external;
/**
* @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
*
* After calling the function:
*
* - `DEFAULT_ADMIN_ROLE` should be granted to the caller.
* - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder.
* - {pendingDefaultAdmin} should be reset to zero values.
*
* Requirements:
*
* - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`.
* - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed.
*/
function acceptDefaultAdminTransfer() external;
/**
* @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting
* into effect after the current timestamp plus a {defaultAdminDelay}.
*
* This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this
* method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay}
* set before calling.
*
* The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then
* calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin}
* complete transfer (including acceptance).
*
* The schedule is designed for two scenarios:
*
* - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by
* {defaultAdminDelayIncreaseWait}.
* - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`.
*
* A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event.
*/
function changeDefaultAdminDelay(uint48 newDelay) external;
/**
* @dev Cancels a scheduled {defaultAdminDelay} change.
*
* Requirements:
*
* - Only can be called by the current {defaultAdmin}.
*
* May emit a DefaultAdminDelayChangeCanceled event.
*/
function rollbackDefaultAdminDelay() external;
/**
* @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay})
* to take effect. Default to 5 days.
*
* When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with
* the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds)
* that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can
* be overrode for a custom {defaultAdminDelay} increase scheduling.
*
* IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise,
* there's a risk of setting a high new delay that goes into effect almost immediately without the
* possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds).
*/
function defaultAdminDelayIncreaseWait() external view returns (uint48);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.20;
/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*/
interface IVotes {
/**
* @dev The signature used has expired.
*/
error VotesExpiredSignature(uint256 expiry);
/**
* @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 voting units.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes);
/**
* @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;
/**
* @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
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5313.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface for the Light Contract Ownership Standard.
*
* A standardized minimal interface required to identify an account that controls a contract
*/
interface IERC5313 {
/**
* @dev Gets the address of the owner.
*/
function owner() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol)
pragma solidity ^0.8.20;
import {IVotes} from "../governance/utils/IVotes.sol";
import {IERC6372} from "./IERC6372.sol";
interface IERC5805 is IERC6372, IVotes {}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol)
pragma solidity ^0.8.20;
interface IERC6372 {
/**
* @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
*/
function clock() external view returns (uint48);
/**
* @dev Description of the clock
*/
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @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 IERC165 {
/**
* @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 v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (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 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
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.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 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.
uint256 twos = denominator & (0 - denominator);
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 (unsignedRoundsUp(rounding) && 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
* towards zero.
*
* 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(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 SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol)
// This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
pragma solidity ^0.8.20;
import {Math} from "../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 {
/**
* @dev A value was attempted to be inserted on a past checkpoint.
*/
error CheckpointUnorderedInsertion();
struct Trace224 {
Checkpoint224[] _checkpoints;
}
struct Checkpoint224 {
uint32 _key;
uint224 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace224 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(uint32).max` key set will disable the
* library.
*/
function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) {
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(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 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(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 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(Trace224 storage self, uint32 key) internal view returns (uint224) {
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 ? 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(Trace224 storage self) internal view returns (uint224) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 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(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace224 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 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(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint224 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint224({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint224({_key: key, _value: value}));
return (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(
Checkpoint224[] storage self,
uint32 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(
Checkpoint224[] storage self,
uint32 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(
Checkpoint224[] storage self,
uint256 pos
) private pure returns (Checkpoint224 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
struct Trace208 {
Checkpoint208[] _checkpoints;
}
struct Checkpoint208 {
uint48 _key;
uint208 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace208 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(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) {
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(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 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(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 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(Trace208 storage self, uint48 key) internal view returns (uint208) {
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 ? 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(Trace208 storage self) internal view returns (uint208) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 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(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint208 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace208 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 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(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint208 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint208({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint208({_key: key, _value: value}));
return (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(
Checkpoint208[] 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(
Checkpoint208[] 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(
Checkpoint208[] storage self,
uint256 pos
) private pure returns (Checkpoint208 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
struct Trace160 {
Checkpoint160[] _checkpoints;
}
struct Checkpoint160 {
uint96 _key;
uint160 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace160 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(uint96).max` key set will disable the
* library.
*/
function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) {
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(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 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(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 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(Trace160 storage self, uint96 key) internal view returns (uint160) {
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 ? 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(Trace160 storage self) internal view returns (uint160) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 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(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace160 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 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(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint160 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint160({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint160({_key: key, _value: value}));
return (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(
Checkpoint160[] storage self,
uint96 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(
Checkpoint160[] storage self,
uint96 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(
Checkpoint160[] storage self,
uint256 pos
) private pure returns (Checkpoint160 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol)
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
import {SafeCast} from "../math/SafeCast.sol";
/**
* @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 SafeCast.toUint48(block.timestamp);
}
/**
* @dev Get the block number as a Timepoint.
*/
function blockNumber() internal view returns (uint48) {
return SafeCast.toUint48(block.number);
}
// ==================================================== Delay =====================================================
/**
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
* This allows updating the delay applied to some operation while keeping some guarantees.
*
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
* still apply for some time.
*
*
* The `Delay` type is 112 bits long, and packs the following:
*
* ```
* | [uint48]: effect date (timepoint)
* | | [uint32]: value before (duration)
* ↓ ↓ ↓ [uint32]: value after (duration)
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
* ```
*
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
* supported.
*/
type Delay is uint112;
/**
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
*/
function toDelay(uint32 duration) internal pure returns (Delay) {
return Delay.wrap(duration);
}
/**
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
*/
function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) {
(uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack();
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
}
/**
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
* effect timepoint is 0, then the pending value should not be considered.
*/
function getFull(Delay self) internal view returns (uint32, uint32, uint48) {
return _getFullAt(self, timestamp());
}
/**
* @dev Get the current value.
*/
function get(Delay self) internal view returns (uint32) {
(uint32 delay, , ) = self.getFull();
return delay;
}
/**
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
* new delay becomes effective.
*/
function withUpdate(
Delay self,
uint32 newValue,
uint32 minSetback
) internal view returns (Delay updatedDelay, uint48 effect) {
uint32 value = self.get();
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
effect = timestamp() + setback;
return (pack(value, newValue, effect), effect);
}
/**
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
*/
function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
uint112 raw = Delay.unwrap(self);
valueAfter = uint32(raw);
valueBefore = uint32(raw >> 32);
effect = uint48(raw >> 64);
return (valueBefore, valueAfter, effect);
}
/**
* @dev pack the components into a Delay object.
*/
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {ResolvStakingStructs} from "../../staking/libraries/ResolvStakingStructs.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IResolvStaking {
function depositWithPermit(
uint256 _amount,
address _receiver,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) external;
function deposit(
uint256 _amount,
address _receiver
) external;
function withdraw(
bool _claimRewards,
address _receiver
) external;
function initiateWithdrawal(uint256 _amount) external;
function claim(address _user, address _receiver) external;
function updateCheckpoint(address _user) external;
function depositReward(
address _token,
uint256 _amount,
uint256 _duration
) external;
function setRewardsReceiver(address _receiver) external;
function setCheckpointDelegatee(address _delegatee) external;
function addRewardToken(IERC20 _token) external;
function emergencyWithdrawERC20(
IERC20 _token,
address _to,
uint256 _amount
) external;
function setClaimEnabled(bool _enabled) external;
function setWithdrawalCooldown(uint256 _cooldown) external;
function getUserAccumulatedRewardPerToken(address _user, address _token) external view returns (uint256 amount);
function getUserClaimableAmounts(address _user, address _token) external view returns (uint256 amount);
function getUserStakeAgeInfo(address _user) external view returns (ResolvStakingStructs.StakeAgeInfo memory info);
function getUserEffectiveBalance(address _user) external view returns (uint256 balance);
function getReward(address _token) external view returns (ResolvStakingStructs.Reward memory reward);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
interface IResolvStakingSilo {
event Withdrawn(address indexed _to, uint256 _amount);
event EmergencyWithdrawnERC20(address indexed _token, address indexed _to, uint256 _amount);
error InvalidAmount();
error ZeroAddress();
error OnlyResolvStaking();
function withdraw(address _to, uint256 _amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ResolvStakingStructs} from "./ResolvStakingStructs.sol";
/**
* @title StakingCheckpoints Library
* @notice Library for managing staking checkpoints, reward calculations, and effective balance updates.
* @dev !IMPORTANT! Note that the OpenZeppelin Upgrades plugin does not control that the library is upgrade safe.
* Please review the code carefully and test it thoroughly before any upgrade.
* See: https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/52
*/
library ResolvStakingCheckpoints {
using SafeERC20 for IERC20;
/**
* @notice Parameters for updating staking checkpoints and rewards.
* @param user The address of the user.
* @param rewardReceiver The address to receive the reward tokens.
* @param totalSupply The total supply of staked tokens.
* @param totalEffectiveSupply The total effective balance of all users.
* @param userStakedBalance The staked token balance of the user.
* @param claim A flag indicating whether to claim rewards.
*/
struct CheckpointParams {
address user;
address rewardReceiver;
uint256 totalSupply;
uint256 totalEffectiveSupply;
uint256 userStakedBalance;
bool claim;
}
/**
* @notice Parameters for updating the effective balance of a user.
* @param user The address of the user.
* @param userStakedBalance The current staked balance of the user.
* @param delta The change in the staked balance (positive for deposits, negative for withdrawals).
* @param totalEffectiveSupply The total effective supply of all users.
*/
struct UpdateEffectiveBalanceParams {
address user;
uint256 userStakedBalance;
int256 delta;
uint256 totalEffectiveSupply;
}
event RewardClaimed(address indexed _user, address indexed _receiver, address indexed _token, uint256 _amount);
event EffectiveBalanceUpdated(address indexed _user, uint256 _effectiveBalance);
/**
* @notice Updates rewards data for a user across all reward tokens.
* @dev Calculates new rewards per token based on elapsed time, updates user claimable rewards,
and optionally transfers rewards.
*/
function checkpoint(
mapping(address user => ResolvStakingStructs.UserData) storage usersData,
mapping(address token => ResolvStakingStructs.Reward reward) storage rewards,
address[] storage rewardTokens,
ResolvStakingCheckpoints.CheckpointParams memory _params
) external {
ResolvStakingStructs.UserData storage userData = usersData[_params.user];
address receiver = _params.rewardReceiver;
uint256 userBalance = 0;
if (_params.user != address(0)) {
userBalance = userData.effectiveBalance == 0 ? _params.userStakedBalance : userData.effectiveBalance;
if (_params.claim && receiver == address(0)) {
// if receiver is not explicitly declared, check if a default receiver is set
receiver = userData.rewardReceiver;
if (receiver == address(0)) {
// if no default receiver is set, direct claims to the user
receiver = _params.user;
}
}
}
uint256 rewardTokensSize = rewardTokens.length;
for (uint256 i = 0; i < rewardTokensSize; i++) {
address token = rewardTokens[i];
ResolvStakingStructs.Reward storage reward = rewards[token];
updateRewardPerToken(reward, _params.totalEffectiveSupply);
if (_params.user != address(0)) {
uint256 userAccReward = userData.accumulatedRewardsPerToken[token];
uint256 newClaimable = 0;
if (userAccReward < reward.accumulatedRewardPerToken) {
userData.accumulatedRewardsPerToken[token] = reward.accumulatedRewardPerToken;
newClaimable = userBalance * (reward.accumulatedRewardPerToken - userAccReward)
/ ResolvStakingStructs.REWARD_RATE_SCALE_FACTOR;
}
uint256 totalClaimable = userData.claimableAmounts[token] + newClaimable;
if (totalClaimable > 0) {
if (_params.claim) {
uint256 transferred = safeRewardTransfer(token, receiver, totalClaimable);
userData.claimableAmounts[token] = totalClaimable > transferred ? totalClaimable - transferred : 0;
emit RewardClaimed(_params.user, receiver, token, transferred);
} else if (newClaimable > 0) {
userData.claimableAmounts[token] = totalClaimable;
}
}
}
}
}
/**
* @notice Updates the effective balance for a user's staking position.
* @param usersData A mapping of user addresses to their staking data.
* @param _params The parameters for updating the effective balance
* @return newTotalEffectiveSupply The new total effective supply after updating the user's effective balance.
* @dev Adjusts the stake age and calculates a future boost factor based on the elapsed staking time.
*/
function updateEffectiveBalance(
mapping(address user => ResolvStakingStructs.UserData) storage usersData,
UpdateEffectiveBalanceParams memory _params
) external returns (uint256 newTotalEffectiveSupply) {
if (_params.user == address(0)) {
newTotalEffectiveSupply = _params.totalEffectiveSupply;
return newTotalEffectiveSupply;
}
ResolvStakingStructs.UserData storage userData = usersData[_params.user];
// If the user had no stake and this is first deposit,
// just update lastUpdate and exit, for the proper calculation of elapsed time during the next deposit
if (_params.userStakedBalance == 0) {
userData.stakeAgeInfo.lastUpdate = block.timestamp;
userData.effectiveBalance = 0;
newTotalEffectiveSupply = _params.totalEffectiveSupply + SafeCast.toUint256(_params.delta);
return newTotalEffectiveSupply;
}
uint256 elapsed = block.timestamp - userData.stakeAgeInfo.lastUpdate;
userData.stakeAgeInfo.lastUpdate = block.timestamp;
userData.stakeAgeInfo.totalAccumulated += _params.userStakedBalance * elapsed;
// for deposits (delta >= 0), we add a baseline (here 1 second per new token) so that new tokens have a nonzero starting age.
// for withdrawals (delta < 0), we scale down proportionally. this maintains the same average age for the tokens that remain staked
uint256 newStakedBalance = _params.delta >= 0
? _params.userStakedBalance + SafeCast.toUint256(_params.delta)
: _params.userStakedBalance - SafeCast.toUint256(- _params.delta);
if (_params.delta > 0) {
userData.stakeAgeInfo.totalAccumulated += SafeCast.toUint256(_params.delta);
} else if (_params.delta < 0) {
userData.stakeAgeInfo.totalAccumulated = (userData.stakeAgeInfo.totalAccumulated * newStakedBalance) / _params.userStakedBalance;
}
uint256 avgAge = newStakedBalance > 0 ? userData.stakeAgeInfo.totalAccumulated / newStakedBalance : 0;
uint256 wahp = avgAge * ResolvStakingStructs.BOOST_FIXED_POINT / ResolvStakingStructs.ONE_YEAR;
uint256 boostFactor = Math.min(
ResolvStakingStructs.BOOST_FIXED_POINT + wahp,
2 * ResolvStakingStructs.BOOST_FIXED_POINT
);
uint256 oldEffectiveBalance = userData.effectiveBalance == 0 ? _params.userStakedBalance : userData.effectiveBalance;
uint256 newEffectiveBalance = newStakedBalance * boostFactor / ResolvStakingStructs.BOOST_FIXED_POINT;
userData.effectiveBalance = newEffectiveBalance;
newTotalEffectiveSupply = _params.totalEffectiveSupply + newEffectiveBalance - oldEffectiveBalance;
emit EffectiveBalanceUpdated(_params.user, userData.effectiveBalance);
return newTotalEffectiveSupply;
}
function updateRewardPerToken(
ResolvStakingStructs.Reward storage reward,
uint256 _totalEffectiveSupply
) internal {
uint256 accRewardPerToken = reward.accumulatedRewardPerToken;
uint256 lastUpdate = Math.min(block.timestamp, reward.periodFinish);
if (lastUpdate - reward.lastUpdate != 0 && _totalEffectiveSupply != 0) {
accRewardPerToken += reward.rewardRate * (lastUpdate - reward.lastUpdate) / _totalEffectiveSupply;
reward.accumulatedRewardPerToken = accRewardPerToken;
reward.lastUpdate = lastUpdate;
}
}
/**
* @notice Safely transfers reward tokens to a specified address.
* @dev Transfers the lesser of _amount and the available balance to avoid reverting.
* @param _token The reward token address.
* @param _to The address to receive the tokens.
* @param _amount The amount of tokens to transfer.
* @return transferred The actual amount transferred.
*/
function safeRewardTransfer(
address _token,
address _to,
uint256 _amount
) internal returns (uint256 transferred) {
uint256 balance = IERC20(_token).balanceOf(address(this));
transferred = _amount;
if (transferred > balance) {
transferred = balance;
}
IERC20(_token).safeTransfer(_to, transferred);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
library ResolvStakingErrors {
error RewardTokenAlreadyAdded(address _token);
error RewardTokenNotFound(address _token);
error InsufficientRewardBalance();
error InsufficientBalance();
error InvalidWithdrawalCooldown();
error WithdrawalRequestNotFound();
error CooldownNotMet();
error InvalidAmount();
error ZeroAddress();
error InvalidDuration();
error NonTransferable();
error ZeroTotalEffectiveSupply();
error InvalidCheckpointCaller();
error ClaimNotEnabled();
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
library ResolvStakingEvents {
event RewardAdded(address indexed _token);
event RewardsReceiverSet(address indexed _user, address indexed _receiver);
event CheckpointDelegateeSet(address indexed _user, address indexed _delegatee);
event RewardTokenDeposited(address indexed _token, uint256 _amount);
event EmergencyWithdrawnERC20(address indexed _token, address indexed _to, uint256 _amount);
event Deposited(address indexed _user, address indexed _receiver, uint256 _amount);
event Withdrawn(address indexed _user, address indexed _receiver, uint256 _amount, bool _claimRewards);
event WithdrawalInitiated(address indexed _user, uint256 _amount);
event WithdrawalCooldownSet(uint256 newCooldown);
event ClaimEnabledSet(bool enabled);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
library ResolvStakingStructs {
/**
* @notice Stores information about a reward token.
* @param token The reward token.
* @param rewardRate The emission rate per second.
* @param lastUpdate Timestamp of the last reward update.
* @param periodFinish Timestamp when the current reward period ends.
* @param accumulatedRewardPerToken Global accumulated reward per effective token (scaled by REWARD_DENOMINATOR).
*/
struct Reward {
IERC20 token;
uint256 periodFinish;
uint256 rewardRate;
uint256 lastUpdate;
uint256 accumulatedRewardPerToken;
}
/**
* @notice Stores information about a withdrawal request.
* @param amount The amount of tokens requested for withdrawal.
* @param requestTime The timestamp when the withdrawal request was made.
*/
struct PendingWithdrawal {
uint256 amount;
uint256 cooldownEnd;
}
/**
* @notice Stores stake age data for a user.
* @param totalAccumulated The accumulated "age" (in token-seconds) for the staked tokens.
* @param lastUpdate Timestamp of the last age update.
*/
struct StakeAgeInfo {
uint256 totalAccumulated;
uint256 lastUpdate;
}
/**
* @notice Stores user-specific data.
* @param rewardReceiver The address to receive rewards.
* @param accumulatedRewardsPerToken Mapping of token addresses to accumulated reward per token.
* @param claimableAmounts Mapping of token addresses to claimable amounts.
* @param pendingWithdrawal The pending withdrawal request of the user.
*/
struct UserData {
address rewardReceiver;
address checkpointDelegatee;
mapping(address token => uint256 accRewardPerToken) accumulatedRewardsPerToken;
mapping(address token => uint256 claimableAmount) claimableAmounts;
StakeAgeInfo stakeAgeInfo;
uint256 effectiveBalance;
ResolvStakingStructs.PendingWithdrawal pendingWithdrawal;
}
/**
* @notice Scale factor used in reward calculation math to reduce rounding errors caused by
* truncation during division.
*/
uint256 internal constant REWARD_RATE_SCALE_FACTOR = 1e24;
uint256 internal constant BOOST_FIXED_POINT = 1e18;
uint256 internal constant ONE_YEAR = 365 days;
}{
"optimizer": {
"enabled": true,
"runs": 833,
"details": {
"yulDetails": {
"optimizerSteps": "u"
}
}
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/staking/libraries/ResolvStakingCheckpoints.sol": {
"ResolvStakingCheckpoints": "0x253c6e08db15e2912cf3afe5a89f2a7a4d8f2784"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"uint48","name":"schedule","type":"uint48"}],"name":"AccessControlEnforcedDefaultAdminDelay","type":"error"},{"inputs":[],"name":"AccessControlEnforcedDefaultAdminRules","type":"error"},{"inputs":[{"internalType":"address","name":"defaultAdmin","type":"address"}],"name":"AccessControlInvalidDefaultAdmin","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"CheckpointUnorderedInsertion","type":"error"},{"inputs":[],"name":"ClaimNotEnabled","type":"error"},{"inputs":[],"name":"CooldownNotMet","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"uint256","name":"increasedSupply","type":"uint256"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"ERC20ExceededSafeSupply","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[{"internalType":"uint256","name":"timepoint","type":"uint256"},{"internalType":"uint48","name":"clock","type":"uint48"}],"name":"ERC5805FutureLookup","type":"error"},{"inputs":[],"name":"ERC6372InconsistentClock","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientRewardBalance","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentNonce","type":"uint256"}],"name":"InvalidAccountNonce","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidCheckpointCaller","type":"error"},{"inputs":[],"name":"InvalidDuration","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidWithdrawalCooldown","type":"error"},{"inputs":[],"name":"NonTransferable","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"RewardTokenAlreadyAdded","type":"error"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"RewardTokenNotFound","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintToInt","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"VotesExpiredSignature","type":"error"},{"inputs":[],"name":"WithdrawalRequestNotFound","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroTotalEffectiveSupply","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_delegatee","type":"address"}],"name":"CheckpointDelegateeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"ClaimEnabledSet","type":"event"},{"anonymous":false,"inputs":[],"name":"DefaultAdminDelayChangeCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint48","name":"newDelay","type":"uint48"},{"indexed":false,"internalType":"uint48","name":"effectSchedule","type":"uint48"}],"name":"DefaultAdminDelayChangeScheduled","type":"event"},{"anonymous":false,"inputs":[],"name":"DefaultAdminTransferCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"},{"indexed":false,"internalType":"uint48","name":"acceptSchedule","type":"uint48"}],"name":"DefaultAdminTransferScheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousVotes","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVotes","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"EmergencyWithdrawnERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"RewardTokenDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"}],"name":"RewardsReceiverSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCooldown","type":"uint256"}],"name":"WithdrawalCooldownSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"WithdrawalInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_claimRewards","type":"bool"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"CLOCK_MODE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISTRIBUTOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMERGENCY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"}],"name":"addRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"beginDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"newDelay","type":"uint48"}],"name":"changeDefaultAdminDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"pos","type":"uint32"}],"name":"checkpoints","outputs":[{"components":[{"internalType":"uint48","name":"_key","type":"uint48"},{"internalType":"uint208","name":"_value","type":"uint208"}],"internalType":"struct Checkpoints.Checkpoint208","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clock","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultAdminDelay","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultAdminDelayIncreaseWait","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"depositReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"depositWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"emergencyWithdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"timepoint","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timepoint","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getReward","outputs":[{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"periodFinish","type":"uint256"},{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"lastUpdate","type":"uint256"},{"internalType":"uint256","name":"accumulatedRewardPerToken","type":"uint256"}],"internalType":"struct ResolvStakingStructs.Reward","name":"reward","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getUserAccumulatedRewardPerToken","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getUserClaimableAmounts","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getUserEffectiveBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getUserStakeAgeInfo","outputs":[{"components":[{"internalType":"uint256","name":"totalAccumulated","type":"uint256"},{"internalType":"uint256","name":"lastUpdate","type":"uint256"}],"internalType":"struct ResolvStakingStructs.StakeAgeInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"contract IERC20","name":"_stakeToken","type":"address"},{"internalType":"contract IResolvStakingSilo","name":"_silo","type":"address"},{"internalType":"uint256","name":"_withdrawalCooldown","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"initiateWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingDefaultAdmin","outputs":[{"internalType":"address","name":"newAdmin","type":"address"},{"internalType":"uint48","name":"schedule","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingDefaultAdminDelay","outputs":[{"internalType":"uint48","name":"newDelay","type":"uint48"},{"internalType":"uint48","name":"schedule","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"rewards","outputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"periodFinish","type":"uint256"},{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"lastUpdate","type":"uint256"},{"internalType":"uint256","name":"accumulatedRewardPerToken","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rollbackDefaultAdminDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegatee","type":"address"}],"name":"setCheckpointDelegatee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setClaimEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"}],"name":"setRewardsReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cooldown","type":"uint256"}],"name":"setWithdrawalCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"silo","outputs":[{"internalType":"contract IResolvStakingSilo","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakeToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalEffectiveSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"updateCheckpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"usersData","outputs":[{"internalType":"address","name":"rewardReceiver","type":"address"},{"internalType":"address","name":"checkpointDelegatee","type":"address"},{"components":[{"internalType":"uint256","name":"totalAccumulated","type":"uint256"},{"internalType":"uint256","name":"lastUpdate","type":"uint256"}],"internalType":"struct ResolvStakingStructs.StakeAgeInfo","name":"stakeAgeInfo","type":"tuple"},{"internalType":"uint256","name":"effectiveBalance","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"cooldownEnd","type":"uint256"}],"internalType":"struct ResolvStakingStructs.PendingWithdrawal","name":"pendingWithdrawal","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_claimRewards","type":"bool"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60806040523461002257610011610027565b604051615c4d6101598239615c4d90f35b600080fd5b61002f6100aa565b565b61003e9060401c60ff1690565b90565b61003e9054610031565b61003e905b6001600160401b031690565b61003e905461004b565b61003e90610050906001600160401b031682565b9061008a61003e6100a692610066565b82546001600160401b0319166001600160401b03919091161790565b9055565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a006100d481610041565b610146576100e18161005c565b6001600160401b03919082908116036100f8575050565b816101277fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2936101419361007a565b604051918291826001600160401b03909116815260200190565b0390a1565b63f92ee8a960e01b6000908152600490fdfe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610482578063022d63fb1461047d5780630560ab691461047857806306fdde03146104735780630700037d1461046e578063095ea7b3146104695780630aa6220b146104645780631263dfc41461045f57806312edde5e1461045a57806318160ddd146104555780631c03e6cc1461045057806320df43591461044b57806321c0b3421461044657806323b872dd14610441578063248a9ca31461043c57806326195826146104375780632866ed21146104325780632f2ff15d1461042d578063313ce567146104285780633644e5151461042357806336568abe1461041e5780633a46b1a8146104195780634bf5d7e91461041457806350921b231461040f57806351ed6a301461040a57806355b8fb8114610405578063587cde1e1461040057806359d5409d146103fb5780635ade228a146103f65780635c19a95c146103f157806360c9e243146103ec578063634e93da146103e7578063649a5ec7146103e25780636e553f65146103dd5780636fcfff45146103d8578063702f5e19146103d357806370a08231146103ce5780637bb7bed1146103c95780637ecebe00146103c45780637f539dff146103bf57806384b0196e146103ba57806384ef8ffc146103b55780638da5cb5b146103b05780638e539e8c146103ab57806391d14854146103a657806391ddadf4146103a157806392929a091461039c57806395d89b4114610397578063981372e1146103925780639ab24eb01461038d578063a1eda53c14610388578063a217fddf14610383578063a9059cbb1461037e578063ad7ea0a914610379578063c00007b014610374578063c2b2faa11461036f578063c3cda5201461036a578063c9aba0aa14610365578063cc8463c814610360578063cefc14291461035b578063cf6eefb714610356578063d248824814610351578063d505accf1461034c578063d547741f14610347578063d602b9fd14610342578063d6c89c601461033d578063dd62ed3e14610338578063e1e1384714610333578063eb3beb291461032e578063f0bd87cc146103295763f1127ed80361049a576116c1565b611621565b611606565b6115e1565b6115a9565b61158e565b61156a565b611551565b611532565b6114b7565b611489565b611452565b611437565b61141b565b61131e565b6112e2565b6112bb565b611249565b611211565b6111f6565b6111b6565b611173565b61115b565b611140565b611128565b6110e4565b6110c8565b6110ad565b611092565b611077565b611043565b610f3e565b610f23565b610f08565b610e91565b610e79565b610e47565b610e2e565b610e16565b610dcf565b610db6565b610d75565b610d5a565b610d1d565b610ce8565b610ccf565b610c8f565b610c3d565b610bb9565b610b9d565b610b84565b610b69565b610b3a565b610b21565b610aea565b610aac565b610a91565b610a7b565b610a39565b6109dd565b6109c5565b61096f565b610957565b61091c565b6108ef565b6108d3565b61086c565b6107b5565b610718565b610505565b6104c9565b6001600160e01b031981165b0361049a57565b600080fd5b905035906104ac82610487565b565b9060208282031261049a576104c29161049f565b90565b9052565b3461049a576104f66104e46104df3660046104ae565b6116e9565b60405191829182901515815260200190565b0390f35b600091031261049a57565b3461049a576105153660046104fa565b6104f661052061172a565b6040515b9182918265ffffffffffff909116815260200190565b6001600160a01b031690565b6001600160a01b038116610493565b905035906104ac82610546565b9060208282031261049a576104c291610555565b61053a6104c26104c2926001600160a01b031690565b6104c290610576565b6104c29061058c565b906105a890610595565b600052602052604060002090565b6104c29061053a565b6104c290546105b6565b6104c29081565b6104c290546105c9565b634e487b7160e01b600052604160045260246000fd5b90601f01601f1916810190811067ffffffffffffffff82111761061257604052565b6105da565b906104ac61062460405190565b92836105f0565b6104c26040610617565b906104ac61065d600161064661062b565b94610657610653826105d0565b8752565b016105d0565b6020840152565b61066f90600761059e565b610678816105bf565b91610685600183016105bf565b9161069260048201610635565b916104c260076106a4600685016105d0565b9301610635565b805182526104ac919060209081905b0151910152565b909594926104ac9461070a6107119261070060a0966106f060e088019c60008901906001600160a01b03169052565b6001600160a01b03166020870152565b60408501906106ab565b6080830152565b01906106ab565b3461049a576104f661073361072e366004610562565b610664565b9161074095939560405190565b958695866106c1565b60005b83811061075c5750506000910152565b818101518382015260200161074c565b61078d6107966020936107a093610781815190565b80835293849260200190565b95869101610749565b601f01601f191690565b0190565b60208082526104c29291019061076c565b3461049a576107c53660046104fa565b6104f66107d061182e565b604051918291826107a4565b6107e790600461059e565b6107f0816105bf565b916107fd600183016105d0565b9161080a600282016105d0565b916104c2600461081c600385016105d0565b93016105d0565b6104c590610595565b909594926104ac946108616108689261085a60809661085360a088019c6000890190610823565b6020870152565b6040850152565b6060830152565b0152565b3461049a576104f6610887610882366004610562565b6107dc565b9161089495939560405190565b9586958661082c565b80610493565b905035906104ac8261089d565b919060408382031261049a576104c29060206108cc8286610555565b94016108a3565b3461049a576104f66104e46108e93660046108b0565b9061185b565b3461049a576108ff3660046104fa565b610907611886565b604051005b6040810192916104ac91906106ab565b3461049a576104f6610937610932366004610562565b6118b5565b6040519182918261090c565b9060208282031261049a576104c2916108a3565b3461049a5761090761096a366004610943565b611aac565b3461049a5761097f3660046104fa565b6104f661098a611ab5565b6040515b9182918290815260200190565b610493816105b6565b905035906104ac8261099b565b9060208282031261049a576104c2916109a4565b3461049a576109076109d83660046109b1565b611c90565b3461049a576109ed3660046104fa565b6104f67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2661098a565b919060408382031261049a576104c2906020610a328286610555565b9401610555565b3461049a57610907610a4c366004610a16565b90611d16565b909160608284031261049a576104c2610a6b8484610555565b9360406108cc8260208701610555565b3461049a57610a8b366004610a52565b91611d20565b3461049a576104f661098a610aa7366004610943565b611d38565b3461049a57610907610abf366004610562565b611d74565b6104c2916008021c5b60ff1690565b906104c29154610ac4565b6104c260006005610ad3565b3461049a57610afa3660046104fa565b6104f66104e4610ade565b919060408382031261049a576104c2906020610a3282866108a3565b3461049a57610907610b34366004610b05565b90611dca565b3461049a57610b4a3660046104fa565b6104f6610b55611e04565b6040519182918260ff909116815260200190565b3461049a57610b793660046104fa565b6104f661098a611e0e565b3461049a57610907610b97366004610b05565b90611e69565b3461049a576104f661098a610bb33660046108b0565b90611f8d565b3461049a57610bc93660046104fa565b6104f66107d0612059565b60ff8116610493565b905035906104ac82610bd4565b909160c08284031261049a57610c0083836108a3565b92610c0e8160208501610555565b92610c1c82604083016108a3565b926104c2610c2d8460608501610bdd565b9360a06108cc82608087016108a3565b3461049a57610907610c50366004610bea565b949390939291926120f3565b6104c2916008021c61053a565b906104c29154610c5c565b6104c2600080610c69565b6020810192916104ac9190610823565b3461049a57610c9f3660046104fa565b6104f6610caa610c74565b60405191829182610c7f565b909160608284031261049a576104c2610a6b84846109a4565b3461049a57610907610ce2366004610cb6565b91612240565b3461049a576104f6610d03610cfe366004610562565b61224b565b604051918291826001600160a01b03909116815260200190565b3461049a576104f661098a610d33366004610a16565b90612285565b6104c26104c26104c29290565b6104c262127500610d39565b6104c2610d46565b3461049a57610d6a3660046104fa565b6104f661098a610d52565b3461049a57610907610d88366004610562565b61229f565b909160608284031261049a576104c2610da68484610555565b9360406108cc82602087016108a3565b3461049a57610907610dc9366004610d8d565b91612708565b3461049a57610907610de2366004610562565b61272b565b65ffffffffffff8116610493565b905035906104ac82610de7565b9060208282031261049a576104c291610df5565b3461049a57610907610e29366004610e02565b61274c565b3461049a57610907610e41366004610b05565b906127fc565b3461049a576104f6610e62610e5d366004610562565b612806565b6040519182918263ffffffff909116815260200190565b3461049a57610907610e8c366004610562565b61288f565b3461049a576104f661098a610ea7366004610562565b612898565b634e487b7160e01b600052603260045260246000fd5b8054821015610ee557610edc600191600052602060002090565b91020190600090565b610eac565b60035481101561049a57610f026104c2916003610ec2565b90610c69565b3461049a576104f6610d03610f1e366004610943565b610eea565b3461049a576104f661098a610f39366004610562565b6128d0565b3461049a576104f661098a610f54366004610562565b6128d9565b90610f79610f72610f68845190565b8084529260200190565b9260200190565b9060005b818110610f8a5750505090565b909192610fa7610fa06001928651815260200190565b9460200190565b929101610f7d565b9395919461101f6110176110369561100961102f956104c29c9a610ffc60e08c019260008d01907fff00000000000000000000000000000000000000000000000000000000000000169052565b8a820360208c015261076c565b9088820360408a015261076c565b976060870152565b6001600160a01b03166080850152565b60a0830152565b60c0818403910152610f59565b3461049a576110533660046104fa565b6104f661105e612983565b9361106e97959793919360405190565b97889788610faf565b3461049a576110873660046104fa565b6104f6610d03612a33565b3461049a576110a23660046104fa565b6104f6610d03612a4c565b3461049a576104f661098a6110c3366004610943565b612a54565b3461049a576104f66104e46110de366004610b05565b90612acf565b3461049a576110f43660046104fa565b6104f6610520612b11565b801515610493565b905035906104ac826110ff565b9060208282031261049a576104c291611107565b3461049a5761090761113b366004611114565b612b82565b3461049a576111503660046104fa565b6104f66107d0612b8b565b3461049a5761090761116e366004610943565b612c35565b3461049a576104f661098a611189366004610562565b612c3e565b65ffffffffffff90911681526040810192916104ac916020905b019065ffffffffffff169052565b3461049a576111c63660046104fa565b6111ce612cc2565b906104f66111db60405190565b9283928361118e565b6104c26000610d39565b6104c26111e4565b3461049a576112063660046104fa565b6104f661098a6111ee565b3461049a576112213660046108b0565b90611d20565b6104c2916008021c81565b906104c29154611227565b6104c260006001611232565b3461049a576112593660046104fa565b6104f661098a61123d565b906080806104ac9361127e60008201516000860190610823565b61128d60208201516020860152565b61129c60408201516040860152565b6106ba60608201516060860152565b60a0810192916104ac9190611264565b3461049a576104f66112d66112d1366004610562565b612df0565b604051918291826112ab565b3461049a576109076112f5366004610562565b612e0c565b909160c08284031261049a576113108383610555565b92610c0e81602085016108a3565b3461049a576109076113313660046112fa565b94939093929192612e8a565b67ffffffffffffffff811161061257602090601f01601f19160190565b90826000939282370152565b9092919261137b6113768261133d565b610617565b938185528183011161049a576104ac91602085019061135a565b9080601f8301121561049a578160206104c293359101611366565b919060a08382031261049a57823567ffffffffffffffff811161049a57816113d9918501611395565b92602081013567ffffffffffffffff811161049a57826113fa918301611395565b926104c261140b84604085016109a4565b9360806108cc82606087016109a4565b3461049a5761090761142e3660046113b0565b939290926131cb565b3461049a576114473660046104fa565b6104f66105206131d8565b3461049a576114623660046104fa565b61090761324b565b6001600160a01b0390911681526040810192916104ac916020906111a8565b3461049a576114993660046104fa565b6114a1613297565b906104f66114ae60405190565b9283928361146a565b3461049a576104f661098a6114cd366004610a16565b906132b9565b60e08183031261049a576114e78282610555565b926114f58360208401610555565b9261150381604085016108a3565b9261151182606083016108a3565b926104c26115228460808501610bdd565b9360c06108cc8260a087016108a3565b3461049a576109076115453660046114d3565b95949094939193613347565b3461049a57610907611564366004610b05565b9061340e565b3461049a5761157a3660046104fa565b61090761343f565b6104c260006006611232565b3461049a5761159e3660046104fa565b6104f661098a611582565b3461049a576104f661098a6115bf366004610a16565b90613447565b919060408382031261049a576104c2906020610a328286611107565b3461049a576109076115f43660046115c5565b90613621565b6104c260006002610c69565b3461049a576116163660046104fa565b6104f6610caa6115fa565b3461049a576116313660046104fa565b6104f67ffbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c61098a565b63ffffffff8116610493565b905035906104ac8261165a565b919060408382031261049a576104c290602061168f8286610555565b9401611666565b6040810192916104ac9190805165ffffffffffff1682526020908101516001600160d01b0316910152565b3461049a576104f66116dd6116d7366004611673565b9061362b565b60405191829182611696565b6318a4c3c360e11b6001600160e01b0319821614908115611708575090565b6104c2915061363e565b61171f6104c26104c29290565b65ffffffffffff1690565b6104c262069780611712565b634e487b7160e01b600052602260045260246000fd5b906001600283049216801561176c575b602083101461176757565b611736565b91607f169161175c565b805460009392916117936117898361174c565b8085529360200190565b91600181169081156117e557506001146117ac57505050565b6117bf9192939450600052602060002090565b916000925b8184106117d15750500190565b8054848401526020909301926001016117c4565b92949550505060ff1916825215156020020190565b906104c291611776565b906104ac61181e9261181560405190565b938480926117fa565b03836105f0565b6104c290611804565b6104c260037f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace005b01611825565b611866919033613678565b600190565b61187b6118766111e4565b613685565b6104ac6104ac613690565b6104ac61186b565b61189661062b565b906000825260006020830152565b6104c261188e565b6104c290610635565b60046118ce6104c2926118c66118a4565b50600761059e565b016118ac565b6118e5906118e06136ad565b61199c565b6104ac61370b565b156118f457565b63162908e360e11b600090815260045b036000fd5b1561191057565b631e9acf1760e31b6000908152600490fd5b61053a6104c26104c29290565b6104c290611922565b634e487b7160e01b600052601160045260246000fd5b600160ff1b811461195f5760000390565b611938565b9190820180921161195f57565b90600019905b9181191691161790565b906119916104c261199892610d39565b8254611971565b9055565b611a7081611a5860006119b96119b182610d39565b845b116118ed565b6119d76119c533612898565b84906119d0565b9190565b1015611909565b611a4960076119e96104c2338361059e565b611a0e6119f58561192f565b611a06611a0189613739565b61194e565b908633613892565b01611a2d838201611a2787611a22836105d0565b611964565b90611981565b6001611a42611a3c60066105d0565b42611964565b9101611981565b611a538333613a2d565b6105bf565b611a6a611a6560026105bf565b610595565b90613aa4565b7f6d92f7d3303f995bf21956bb0c51b388bae348eaf45c23debd2cfa3fcd9ec646611aa7611a9d33610595565b9261098e60405190565b0390a2565b6104ac906118d4565b6104c260027f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00610657565b6104ac90611aef6118766111e4565b611bc3565b15611afb57565b63d92e233d60e01b6000908152600490fd5b15611b155750565b63cabd13bf60e01b60009081526001600160a01b039091166004526024036000fd5b91906008611977910291611b516001600160a01b03841b90565b921b90565b9190611b676104c261199893610595565b908354611b37565b90815491680100000000000000008310156106125782611b979160016104ac95018155610ec2565b90611b56565b906001600160a01b0390611977565b90611bbc6104c261199892610595565b8254611b9d565b611c5f90611a65611bd382610595565b91611c4183611be2600061192f565b611c026001600160a01b0382165b6001600160a01b0384165b1415611af4565b611c3b611c2e611c21611a656000611c1b87600461059e565b016105bf565b926001600160a01b031690565b916001600160a01b031690565b14611b0d565b611c4c836003611b6f565b6000611c5984600461059e565b01611bac565b7fb13fd610fe4e1b384966826794a9b2f6100ad031f352cc5ec6f22667f6074980611c8960405190565b8080611aa7565b6104ac90611ae0565b906118e591611ca66136ad565b611cc4565b15611cb257565b6303624cab60e31b6000908152600490fd5b6104ac916001600160a01b03821633148015611cf6575b611ce490611cab565b6001611cf06000610d39565b92613892565b50611ce4611d0d61053a6001611c1b86600761059e565b33149050611cdb565b906104ac91611c99565b639cbe235760e01b6000908152600490fd5b906105a8565b60016106576104c292611d49600090565b5060007f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268005b01611d32565b611d85816000611c5933600761059e565b611d97611d9133610595565b91610595565b907f8eb3f1a8f49a22a9fcda79d30a2cf0bde5f65585f6530392b5a8deb6df472239611dc260405190565b80805b0390a3565b90611dd66104c26111e4565b8214611de5576104ac91613b0a565b631fe1e13d60e11b6000908152600490fd5b610acd6104c26104c29290565b6104c26012611df7565b6104c2613b14565b91906008611977910291611b5165ffffffffffff841b90565b61171f6104c26104c29265ffffffffffff1690565b9190611e556104c261199893611e2f565b908354611e16565b6104ac91600091611e44565b9190600080516020615bf883398151915292611e866104c26111e4565b811480611f31575b611e9e575b6104ac929350613b3d565b611ea6613297565b60009591611eb9611c2e61053a8961192f565b14158015611f1f575b8015611f09575b611ee7575060146104ac9495611edf9201611e5d565b839250611e93565b6319ca5ebb60e01b865265ffffffffffff1660048601528480602481015b0390fd5b50611f1a611f1682613b2e565b1590565b611ec9565b50611f2c611f1682613b1c565b611ec2565b50611f3d61053a612a33565b6001600160a01b03831614611e8e565b6104c26104c26104c29265ffffffffffff1690565b9081526040810192916104ac916020906111a8565b6104c26104c26104c2926001600160d01b031690565b7fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00611fb6612b11565b611fbf81611f4d565b841015611ff2575091611fe7611fe16104c2611fed9460016104c2970161059e565b91613b95565b90613c0c565b611f77565b637669fc0f60e11b60009081529061190490856004611f62565b906120196113768361133d565b918252565b612028601d61200c565b7f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b6104c261201e565b612061612b11565b61207b61206f61171f613cf1565b9165ffffffffffff1690565b03612088576104c2612051565b6301bfc1c560e61b6000908152600490fd5b949290979695939160e0860198600087016120bc916001600160a01b03169052565b6001600160a01b031660208601526040850152606084015260ff16608083015260a082015260c00152565b6040513d6000823e3d90fd5b929193909361210b611a65611a65611a6560006105bf565b61211430610595565b92813b1561049a576000809461214d6104ac9a899461213260405190565b998a988997889663d505accf60e01b8852336004890161209a565b03925af19081612163575b50156127fc576127fc565b61217c9060005b61217481836105f0565b8101906104fa565b38612158565b503d61216a565b6104ac9291906121b87fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b26613685565b611dc56122366122307ff563e0862357d06e5752eb37b7057a0b8b5aca7410305cfd9b45865523e48c6d93611a6587876121f184610595565b9361221e611bf0612202600061192f565b61053a6001600160a01b0382166001600160a01b038a16611bfb565b61222b6119b16000610d39565b613aa4565b93610595565b9361098e60405190565b906104ac9291612189565b611a536104c29161225a600090565b5060007fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d005b0161059e565b6104c291600361227f61229a936118c6600090565b6105d0565b6104ac9033613cfa565b613cfa565b906118e592916122bc6136ad565b6104ac9291906122eb7ffbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c613685565b6123de565b156122f757565b631786352f60e01b6000908152600490fd5b156123115750565b630c82a8d360e11b60009081526001600160a01b039091166004526024036000fd5b1561233a57565b637616640160e01b6000908152600490fd5b905051906104ac8261089d565b9060208282031261049a576104c29161234c565b9190820391821161195f57565b8181029291811591840414171561195f57565b6104c269d3c21bcecceda1000000610d39565b634e487b7160e01b600052601260045260246000fd5b81156123c0570490565b6123a0565b156123cc57565b63f16eeebd60e01b6000908152600490fd5b90916000916123f56123ef84610d39565b856119b3565b61241461240260016105d0565b61240e6119cc86610d39565b116122f0565b6124226104c282600461059e565b9061249584830194612436611a65876105bf565b9461245e846124448461192f565b976124576001600160a01b038a16611c2e565b1415612309565b612466610d46565b9061247382821115612333565b61247c83610d39565b81036127005750945b61248e82610d39565b9181613892565b6124a1611a65856105bf565b916370a08231946124b130610595565b60206124bc60405190565b80966124c88a60e01b90565b82526001600160a01b038416600483015260249082905afa948515612689576000956126df575b5061250588826124fe856105bf565b3390613dbb565b612511611a65836105bf565b96602061251d60405190565b80996125298460e01b90565b82526001600160a01b038516600483015260249082905afa8015612689576125aa611a656020958a61256e6125d89b6125c19661257a9f6000916126c2575b5061236d565b89600181019e8f6105d0565b80421061268e575050611a539161259c6125a19261259661238d565b9061237a565b6123b6565b60028a01611981565b916125b460405190565b9788948593849360e01b90565b83526001600160a01b031660048301526024820190565b03915afa94851561268957611a27611aa795611a3c611a659461265061262e7fac1f5f240b57fc014c4875ec0fa399f96ca891f85156ba195e6512ccd4ada5489b611a9d9a60009161265a575b5061259661238d565b6126496119cc6104c287612644600288016105d0565b61237a565b10156123c5565b6003429101611981565b61267c915060203d602011612682575b61267481836105f0565b810190612359565b38612625565b503d61266a565b6120e7565b9261259c611a279293611a226126b960026126ad611a5399429061236d565b970196612596886105d0565b9161259661238d565b6126d991508b3d8d116126825761267481836105f0565b38612568565b6126f991955060203d6020116126825761267481836105f0565b93386124ef565b905094612485565b906104ac92916122ae565b6104ac906127226118766111e4565b6104ac90613e13565b6104ac90612713565b6104ac906127436118766111e4565b6104ac90613e69565b6104ac90612734565b906118e5916127626136ad565b906127c2826127b160006127786119b182610d39565b611a536127848261192f565b6127a06001600160a01b0382166001600160a01b038916611bfb565b6127a985613739565b908388613892565b6127ba30610595565b903390613dbb565b6127cc8282613eb7565b7f8752a472e571a816aea92eec8dae9baf628e840f4929fbcc2d155e6233ff68a7611dc561223661223033610595565b906104ac91612755565b6104c290613f06565b6118e59061281b6136ad565b6104ac90600061282a8161192f565b906001600160a01b0382166001600160a01b0384160361284e575b611cf081610d39565b6001600160a01b0383163314801561286f575b61286a90611cab565b612845565b5061286a61288661053a6001611c1b87600761059e565b33149050612861565b6104ac9061280f565b61229a6104c2916128a7600090565b5060007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0061227f565b6104c290613f25565b60066106576104c2926118c6600090565b156128f157565b60405162461bcd60e51b815260206004820152601560248201527f4549503731323a20556e696e697469616c697a656400000000000000000000006044820152606490fd5b67ffffffffffffffff81116106125760208091020190565b9061201961137683612936565b369037565b906104ac6129766129708461294e565b93612936565b601f19016020840161295b565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1006129ce6129b0826105d0565b916000926129c06119cc85610d39565b149081612a13575b506128ea565b6129d6613f2e565b916129df613f59565b916129e930610595565b90612a046129ff6129f983610d39565b92610d39565b612960565b600f60f81b9594934693929190565b612a2091506001016105d0565b612a2c6119cc84610d39565b14386129c8565b6104c26001600080516020615bf8833981519152611c1b565b6104c2612a33565b7fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00612a7d612b11565b612a8681611f4d565b831015612aa257506104c291611fe7611fe16002611fed940190565b637669fc0f60e11b60009081529061190490846004611f62565b6104c290610acd565b6104c29054612abc565b6104c291600061227f612b0c93612ae4600090565b50827f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800611d6e565b612ac5565b6104c2613cf1565b6104ac90612b286118766111e4565b612b4d565b9060ff90611977565b90612b466104c261199892151590565b8254612b2d565b612b7d7f101b4adbfe4d35c7130bee2f41b462c38a341aa5beb5260ffe5d9e70d9419b38916104e4816005612b36565b0390a1565b6104ac90612b19565b6104c260047f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00611855565b6104ac90612bc56118766111e4565b612bef565b6104c2622b8180610d39565b15612bdd57565b630130feaf60e01b6000908152600490fd5b612b7d7f982c3d0e05826c3b614ce6f221c1481582ffdb40d24913c094f3194e9a850c4391612c2a612c226104c2612bca565b821115612bd6565b61098a816006611981565b6104ac90612bb6565b611fed612c7c6104c26104c293612c53600090565b5060017fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0061227f565b613f84565b6104c29060d01c61171f565b6104c29054612c81565b612ca66104c291939293611712565b92611712565b6104c29060a01c61171f565b6104c29054612cac565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840190612ced82612c8d565b91612cf783613b1c565b80612d21575b60009015612d0f57506119cc90612cb8565b612d1d929350809150612c97565b9091565b50612d2e611f1684613b2e565b612cfd565b6104c260a0610617565b612d45612d33565b906000825260208080808086016000815201600081520160008152016000905250565b6104c2612d3d565b906104c5906105b6565b906104ac612de06004612d8b612d33565b94612d9e612d98826105bf565b87612d70565b612db4612dad600183016105d0565b6020880152565b612dca612dc3600283016105d0565b6040880152565b610657612dd9600383016105d0565b6060880152565b6080840152565b6104c290612d7a565b612e076104c291612dff612d68565b50600461059e565b612de7565b612e1d816001611c5933600761059e565b612e29611d9133610595565b907fcb61187188bc2f5921221326cae4d727940252f625f88065d3ac54ae24f6b845611dc260405190565b6108686104ac94612e83606094989795612e73608086019a6000870152565b6001600160a01b03166020850152565b6040830152565b91959491939092864211612f205791612f19916122a993612f1486612efc896104ac9b9c612ef0612ed87fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf90565b91612ee260405190565b958694602086019485612e54565b908103825203826105f0565b612f0e612f07825190565b9160200190565b20613fbf565b613fe8565b9182614009565b632341d78760e11b60009081526004889052602490fd5b6104c29060401c610acd565b6104c29054612f37565b6104c2905b67ffffffffffffffff1690565b6104c29054612f4d565b612f526104c26104c29290565b9067ffffffffffffffff90611977565b612f526104c26104c29267ffffffffffffffff1690565b90612fad6104c261199892612f86565b8254612f76565b9068ff00000000000000009060401b611977565b90612fd86104c261199892151590565b8254612fb4565b6104c590612f69565b6020810192916104ac9190612fdf565b92939091907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00948592613036613030611f1686612f43565b94612f5f565b9460009661304388612f69565b67ffffffffffffffff8816148061313e575b6001976130726130648a612f69565b9167ffffffffffffffff1690565b14908161311a575b155b9081613111575b5061310257906130b094939291866130a78a61309e8b612f69565b9c019b8c612f9d565b6130f357613145565b6130b957505050565b6130e7612b7d927fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d294612fc8565b60405191829182612fe8565b6130fd888b612fc8565b613145565b63f92ee8a960e01b8852600488fd5b15905038613083565b905061307c61312830610595565b3b6131356119cc8c610d39565b1491905061307a565b5085613055565b61116e926131646131c49261315f6104ac9897958261404e565b61409a565b61317a61317362015180611712565b33906140ba565b6131826140d7565b6131bd61318e82610595565b6131ae61319b600061192f565b91611bfb6001600160a01b038416611c2e565b611bfb611c2e611c2187610595565b6000611bac565b6002611bac565b906104ac94939291612ff8565b600080516020615bf88339815191527feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840161321181612c8d565b61321a81613b1c565b908161323b575b5015613231576104c29150612cb8565b506104c290612c8d565b6132459150613b2e565b38613221565b613253613297565b5061325d33611c2e565b6001600160a01b0382160361327557506104ac6140eb565b636116401160e11b60009081526001600160a01b039091166004526024036000fd5b600080516020615bf8833981519152906104c26132b3836105bf565b92612cb8565b6104c291600261227f61229a936118c6600090565b919461070a6108689298979561331660a0966133066104ac9a6132f660c08a019e60008b0152565b6001600160a01b03166020890152565b6001600160a01b03166040870152565b6060850152565b6001600160a01b0390911681526040810192916104ac916020905b01906001600160a01b03169052565b95919396949092966133568890565b42116133f757612f1484612efc896133b89798999a9b612ef06133967f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c990565b916133a08461418a565b8d6133aa60405190565b9788966020880196876132ce565b936001600160a01b0381166001600160a01b038616036133dd576104ac939450613678565b6325c0072360e11b6000908152906119049086600461331d565b63313c898160e11b60009081526004899052602490fd5b9061341a6104c26111e4565b8214611de5576104ac916141eb565b6134346118766111e4565b6104ac6104ac6141f5565b6104ac613429565b6104c29161348361229a9261345a600090565b5060017f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0061227f565b61059e565b906118e5916134956136ad565b6134e9565b156134a157565b63514447b560e01b6000908152600490fd5b156134ba57565b63078a94c560e01b6000908152600490fd5b6001600160a01b0390911681526040810192916104ac9160200152565b906134f960076107a0338261059e565b613502816105d0565b92600061351961351182610d39565b86141561349a565b600183019061353561352d6104c2846105d0565b4210156134b3565b61354961354182610d39565b868533613892565b613556611a6560026105bf565b91823b1561049a578161356860405190565b93849063f3fef3a360e01b82528183816135868d8d600484016134cc565b03925af18015612689577fc4c505caef12dcdaeed94682f15951aec519a413367f049d55af5861129950d0956135d7946135d292613605575b506135c984610d39565b93849101611981565b611981565b6135e361223033610595565b93611dc56135f060405190565b92839283908152901515602082015260400190565b61361b90853d87116121825761217481836105f0565b386135bf565b906104ac91613488565b906104c2916136386118a4565b50614212565b637965db0b60e01b6001600160e01b031982161490811561365d575090565b6104c291506001600160e01b0319166301ffc9a760e01b1490565b916001916104ac9361422a565b6104ac90339061431b565b6104ac61369d6000611712565b806143c8565b6104c26002610d39565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006136d7816105d0565b6136df6136a3565b9081146136ef576104ac91611981565b633ee5aeb560e01b6000908152600490fd5b6104c26001610d39565b6104ac7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006000611a42613701565b6137656104c27f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610d39565b8111613774576104c290610d39565b63123baf0360e11b6000908152600491909152602490fd5b1561379357565b63af95b1d160e01b6000908152600490fd5b6104c260c0610617565b80516001600160a01b031682526104ac919060a09081906020818101516001600160a01b0316908501526137e860408201516040860152565b6137f760608201516060860152565b61380660808201516080860152565b01511515910152565b6138366104ac94612e8360609498979561382f61012086019a6000870152565b6020850152565b01906137af565b6104c26080610617565b80516001600160a01b031682526104ac9190606090819061386d60208201516020860152565b6106ba60408201516040860152565b90815260a0810192916104ac9160200190613847565b9080158015613a18575b6138a59061378c565b600773253c6e08db15e2912cf3afe5a89f2a7a4d8f2784916138c5611ab5565b6138cf60016105d0565b6138d886612898565b916138e16137a5565b6001600160a01b0388168152976001600160a01b03166020890152604088015260608701526080860152151560a0850152813b1561049a5760006139459461392860405190565b958691829190633a98477f60e01b8352600360048781860161380f565b0381855af48015612689576139c5956020956139a392613a02575b5061331661396d86612898565b9161399c61397b60016105d0565b9361399661398761383d565b6001600160a01b03909a168a52565b89890152565b6040870152565b6040518095819482936139ba63e8d7fc4460e01b90565b84526004840161387c565b03915af48015612689576104ac916000916139e3575b506001611981565b6139fc915060203d6020116126825761267481836105f0565b386139db565b613a1290600061217481836105f0565b38613960565b506138a5613a266005612ac5565b905061389c565b9190600092613a3b8461192f565b906001600160a01b0382166001600160a01b03821614613a60576104ac939450614485565b634b637e8f60e11b85526001600160a01b0382166004860152602485fd5b613a97613a916104c29263ffffffff1690565b60e01b90565b6001600160e01b03191690565b613ae7600492613ad86104ac95613abe63a9059cbb613a7e565b92613ac860405190565b96879460208601908152016134cc565b602082018103825203836105f0565b6144b1565b906104ac91613afd61187682611d38565b90613b0791614530565b50565b906104ac91613aec565b6104c26145cb565b613b2961206f6000611712565b141590565b613b39425b91611f4d565b1090565b90613b473361053a565b6001600160a01b03821603613b5f57613b079161462e565b63334bd91960e11b6000908152600490fd5b6104c590611df7565b9160206104ac92949361086860408201966000830190613b71565b613ba465ffffffffffff611f4d565b8111613bb3576104c290611712565b6306dfcc6560e41b6000908152906119049060306004613b7a565b6104c29061171f565b6104c29054613bce565b6104c29060301c5b6001600160d01b031690565b6104c29054613be1565b613be96104c26104c29290565b8054613c3d90600092613c1e84610d39565b8483613c2a6005610d39565b8111613c85575b509091015b94856147ba565b613c4682610d39565b8103613c5757506104c29150613bff565b6104c292613c72613c7f92613c6c6001610d39565b9061236d565b9060005260206000200190565b01613bf5565b80613c6c613c92926146bf565b613cb361171f83613cad848883015b60005260206000200190565b01613bd7565b65ffffffffffff89161015613cd257613c3692939450935b9291613c31565b613c369250613ceb90613ce56001610d39565b90611964565b92613ccb565b6104c243613b95565b6104ac91613d917fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0092613d4283613d3d836000613d368261224b565b980161059e565b611bac565b613d4b81610595565b613d5485610595565b613d5d85610595565b917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f613d8860405190565b600090a4614830565b9161484c565b6001600160a01b039182168152911660208201526060810192916104ac9160400152565b90613ae790613ad86104ac95600495613dd76323b872dd613a7e565b93613de160405190565b9788956020870190815201613d97565b613e029065ffffffffffff1661206f565b019065ffffffffffff821161195f57565b7f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed6611aa7613e5f613e54613e4642613b95565b613e4e6131d8565b90613df1565b93611a6585826149d7565b9261052460405190565b7ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b90613ea0613e9742613b95565b613e4e83614a70565b90613eab82826143c8565b612b7d6111db60405190565b9190600092613ec58461192f565b6001600160a01b0381166001600160a01b03831614613ee9576104ac939450614485565b63ec442f0560e01b85526001600160a01b03166004850152602484fd5b613f20613f1b6104c26104c293612c53600090565b614ac1565b614afe565b6104c290614b35565b6104c260027fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100611855565b6104c260037fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100611855565b8054613f906000610d39565b8103613fa25750506104c26000613bff565b613c7f600091613ca16119cc846104c2960192613c6c6001610d39565b6104c290613fcb613b14565b6042916040519161190160f01b8352600283015260228201522090565b916104c2939161400093613ffa600090565b50614b76565b90929192614c6c565b6140128161418a565b9182900361401e575050565b6301d4b62360e61b6000908152916119049160046134cc565b906104ac91614044614d1f565b906104ac91614f2d565b906104ac91614037565b6104ac90614064614d1f565b614088565b614073600161200c565b603160f81b602082015290565b6104c2614069565b6104ac90614094614080565b90614fb8565b6104ac90614058565b906104ac916140b0614d1f565b906104ac91615040565b906104ac916140a3565b6140cc614d1f565b6104ac6104ac615052565b6104ac6140c4565b6104ac91600091611b56565b600080516020615bf8833981519152614102613297565b61410e611f1682613b1c565b8015614178575b614157575060006104ac9261414560149361412e6111e4565b61413f614139612a33565b8261462e565b50614530565b50016141526000826140df565b611e5d565b6319ca5ebb60e01b600090815265ffffffffffff9091166004526024036000fd5b50614185611f1682613b2e565b614115565b6141ba9060005b5060007f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb0061227f565b6104c26141c6826105d0565b9160018301611a27565b906104ac916141e161187682611d38565b90613b079161462e565b906104ac916141d0565b6104ac614202600061192f565b61420c6000611712565b906149d7565b906142256104c26104c293612c536118a4565b6150a1565b9091926142547f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0090565b600061425f8161192f565b6001600160a01b0381166001600160a01b038616146142fe576001600160a01b0381166001600160a01b038716146142e1575050846135d2856134838660016142a8960161059e565b6142b157505050565b611dc56122366122307f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92593610595565b634a1406b160e11b82526001600160a01b03166004820152602490fd5b63e602df0560e01b82526001600160a01b03166004820152602490fd5b90614329611f168284612acf565b614331575050565b63e2517d3f60e01b6000908152916119049160046134cc565b907fffffffffffff00000000000000000000000000000000000000000000000000009060d01b611977565b906143856104c261199892611e2f565b825461434a565b9079ffffffffffff00000000000000000000000000000000000000009060a01b611977565b906143c16104c261199892611e2f565b825461438c565b6104ac91907feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984019061442190600080516020615bf883398151915261440b84612c8d565b61441481613b1c565b614426575b5050826143b1565b614375565b61442f90613b2e565b156144515761444a90600061444386612cb8565b9101614375565b3880614419565b507f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec561447c60405190565b600090a161444a565b906104ac92916150c0565b905051906104ac826110ff565b9060208282031261049a576104c291614490565b6144bd6144c491610595565b9182615131565b906144cd825190565b916000926144dd6119cc85610d39565b1415908161450c575b506144ef575050565b635274afe760e01b82526001600160a01b03166004820152602490fd5b61452a915080602061451f611f16935190565b81830101910161449d565b386144e6565b9190600080516020615bf88339815191529261454d6104c26111e4565b811461455f575b6104c2929350615145565b614567612a33565b600090614579611c2e61053a8461192f565b0361459857506145908260016104c2959601611bac565b839250614554565b631fe1e13d60e11b8152600490fd5b909594926104ac946108616133389261085a60809661085360a088019c6000890152565b7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61461f6145f76151de565b6145ff615274565b90612ef061460c30610595565b60405195869460208601944692866145a7565b61462a612f07825190565b2090565b6104c29190600080516020615bf883398151915261464d6104c26111e4565b821480614674575b614660575b506152d5565b6000600161466e92016140df565b3861465a565b5061468061053a612a33565b6001600160a01b03841614614655565b6104c2906146a46119cc6104c29460ff1690565b901c90565b6104c2906146ba6119cc6104c29490565b901b90565b6146c96000610d39565b81146147af5760016146da82615354565b6146e382611df7565b8080808080966146f4828098614690565b906146fe90610d39565b90614708916146a9565b614712818a6123b6565b019061471d91614690565b61472781896123b6565b019061473291614690565b61473c81886123b6565b019061474791614690565b61475181876123b6565b019061475c91614690565b61476681866123b6565b019061477191614690565b61477b81856123b6565b019061478691614690565b61479081846123b6565b019061479b91614690565b90816147a6916123b6565b6104c291615500565b506104c26000610d39565b939190926147c6600090565b505b80821015614828576147da8183615512565b906147f16000613cad848960005260206000200190565b61480265ffffffffffff871661206f565b11156148115750915b916147c8565b92915061482290613ce56001610d39565b9061480b565b925050915090565b6104c290612898565b9081526040810192916104ac9160200152565b7fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d009291906001600160a01b0382166001600160a01b0382161415806149c5575b614897575b50505050565b6148cd906148a5600061192f565b906001600160a01b0382166001600160a01b03821603614961575b506001600160a01b031690565b6001600160a01b038216036148e3575b80614891565b614940611d916149337fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7249461492a6119cc61492487600161493a9b0161059e565b9261556f565b60015b906155a9565b9590611f77565b94611f77565b9261495661494d60405190565b92839283614839565b0390a23880806148dd565b7fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724816149af611d9161493361499c61493a9660018d0161059e565b6149a86119cc8c61556f565b600261492d565b926149bc61494d60405190565b0390a2386148c0565b506149d06000610d39565b831161488c565b614a11614a16926149f3600080516020615bf883398151915290565b92614a0c6000614a01613297565b969050019182611bac565b6143b1565b613b1c565b614a1c57565b7f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109614a4660405190565b8080612b7d565b614a5e9065ffffffffffff1661206f565b90039065ffffffffffff821161195f57565b614a786131d8565b65ffffffffffff811665ffffffffffff83161115614ab75750614ab26104c291614aac613b33614aa661172a565b92611f4d565b90615500565b611712565b906104c291614a4d565b60006104c291614acf600090565b50015490565b6104c26104c26104c29263ffffffff1690565b614af56104c26104c29290565b63ffffffff1690565b614b0b63ffffffff614ad5565b8111614b1a576104c290614ae8565b6306dfcc6560e41b6000908152906119049060206004613b7a565b61229a6104c291614191600090565b6104c290610d39565b6108686104ac94612e83606094989795614b6c608086019a6000870152565b60ff166020850152565b9091614b8184614b44565b614bad6119cc7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0610d39565b11614c295790614bcf60209460009493614bc660405190565b94859485614b4d565b838052039060015afa1561268957600051600091614bec8361192f565b6001600160a01b0381166001600160a01b03841614614c155750614c0f83610d39565b91929190565b915091614c2190610d39565b909160019190565b505050614c36600061192f565b9160039190565b634e487b7160e01b600052602160045260246000fd5b60041115614c5d57565b614c3d565b906104ac82614c53565b90600091614c7983614c62565b614c8282614c62565b03614c8c57505050565b614c966001614c62565b614c9f82614c62565b03614cb35763f645eedf60e01b8352600483fd5b614cbd6002614c62565b614cc682614c62565b03614cef5750611f05614cd98392614b44565b63fce698f760e01b835260048301526024820190565b614d02614cfc6003614c62565b91614c62565b14614d0b575050565b6335e2f38360e21b82526004820152602490fd5b614d2a611f16615606565b614d3057565b631afcd79f60e31b6000908152600490fd5b906104ac91614d4f614d1f565b614eec565b634e487b7160e01b600052600060045260246000fd5b9160001960089290920291821b911b611977565b9190614d8f6104c261199893610d39565b908354614d6a565b6104ac91600091614d7e565b818110614dae575050565b80614dbc6000600193614d97565b01614da3565b9190601f8111614dd157505050565b614de36104ac93600052602060002090565b906020601f840181900483019310614e05575b6020601f909101040190614da3565b9091508190614df6565b90614e18815190565b9067ffffffffffffffff821161061257614e3c82614e36855461174c565b85614dc2565b602090601f8311600114614e7757611998929160009183614e6c575b5050600019600883021c1916906002021790565b015190503880614e58565b601f19831691614e8c85600052602060002090565b9260005b818110614eca57509160029391856001969410614eb1575b50505002019055565b01516000196008601f8516021c19169055388080614ea8565b91936020600181928787015181550195019201614e90565b906104ac91614e0f565b9060046104ac92614f27614f1d7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0090565b9160038301614ee2565b01614ee2565b906104ac91614d42565b906104ac91614f44614d1f565b614f57565b906119916104c26119989290565b614f9b6104ac92614f92614f887fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10090565b9360028501614ee2565b60038301614ee2565b6001614fa76000610d39565b91614fb28382614f49565b01614f49565b906104ac91614f37565b906104ac91614fcf614d1f565b6000929190600080516020615bf8833981519152614fec8561192f565b6001600160a01b0381166001600160a01b03851614615023575090613b0793946150169201614375565b61501e6111e4565b614530565b636116401160e11b86526001600160a01b03166004860152602485fd5b906104ac91614fc2565b6118e5614d1f565b6104ac61504a565b906104ac615088600061506b61062b565b94613c7f61507a838301613bd7565b65ffffffffffff1687840152565b6001600160d01b03166020840152565b6104c29061505a565b6104c29160006150ba926150b36118a4565b5001610ec2565b50615098565b9291906150ce828286615656565b6000936150dd61053a8661192f565b6001600160a01b038216146150f8575b6104ac9394506157b7565b615100611ab5565b6151086157a7565b908181116151175750506150ed565b611f0587928392630e58ae9360e11b845260048401614839565b6104c29161513f6000610d39565b91615897565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800615173611f168484612acf565b156151d657600161518f84600061227f86826151949701611d32565b612b36565b6151a2611d91612230339390565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d6151cd60405190565b600090a4600190565b505050600090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10061520a6104c2613f2e565b90615213825190565b6152206119cc6000610d39565b1115615232575061462a612f07825190565b61523c91506105d0565b6152466000610d39565b811461524f5790565b507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1006152a06104c2613f59565b906152a9825190565b6152b66119cc6000610d39565b11156152c8575061462a612f07825190565b61523c91506001016105d0565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006153008383612acf565b156151d657600061518f848261227f868261531b9701611d32565b615329611d91612230339390565b917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b6151cd60405190565b60006154496119cc6129f961536884610d39565b9461537c6153766080611df7565b82614690565b8681116154e9575b506153926153766040611df7565b61539b86610d39565b81116154d2575b506153b06153766020611df7565b6153b986610d39565b81116154bb575b506153ce6153766010611df7565b6153d786610d39565b81116154a4575b506153ec6153766008611df7565b6153f586610d39565b811161548d575b5061540a6153766004611df7565b61541386610d39565b8111615476575b506154286153766002611df7565b61543186610d39565b811161545f575b506154436001611df7565b90614690565b116154515790565b6104c2906107a06001610d39565b61546f9150956107a06002610d39565b9438615438565b6154869150956107a06004610d39565b943861541a565b61549d9150956107a06008610d39565b94386153fc565b6154b49150956107a06010610d39565b94386153de565b6154cb9150956107a06020610d39565b94386153c0565b6154e29150956107a06040610d39565b94386153a2565b6154f99150956107a06080610d39565b9438615384565b908082101561550d575090565b905090565b613ce56104c292615521600090565b5080831692186155316002610d39565b906123b6565b615552906001600160d01b03165b916001600160d01b031690565b9003906001600160d01b03821161195f57565b6104c29190615537565b61557f6001600160d01b03611f77565b811161558e576104c290613bff565b6306dfcc6560e41b6000908152906119049060d06004613b7a565b906155d2612d1d936155b9600090565b506155c2612b11565b926155cc85613f84565b90615bd2565b916158f0565b6155ea906001600160d01b0316615545565b01906001600160d01b03821161195f57565b6104c291906155d8565b6104c27ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00612f43565b6001600160a01b0390911681526060810193926104ac929091604091610868906020830152565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace008260006156838161192f565b6001600160a01b0381166001600160a01b0386160361572857938361223693612230936156e37fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9861053a8c611a276002611dc59c0191611a22836105d0565b6001600160a01b0383160361570c5750506002611a659101611a2789615708836105d0565b0390565b9061571b91611a65930161059e565b611a27896107a0836105d0565b90809250830161573b61229a868361059e565b87811061578c579386612236946156e36122309561053a8a966135d27fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9c8f61578690611dc59e0390565b9261059e565b83611f058982938963391434e360e21b85526004850161562f565b6104c26001600160d01b03611f77565b906158386158326104ac94936157ea7fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0090565b61581c6157f7600061192f565b6001600160a01b0381166001600160a01b03851614615857576001600160a01b031690565b6001600160a01b0386161461583e575b5061224b565b9161224b565b9061484c565b600261585191016149a86119cc8861556f565b5061582c565b61586a6002840161492a6119cc8b61556f565b50506001600160a01b031690565b3d15615892576158873d61200c565b903d6000602084013e565b606090565b919291906158a430610595565b93808531106158d1576104c293945081600092916020849351920190855af16158cb615878565b9161590d565b63cd78605960e01b60009081526001600160a01b038616600452602490fd5b906159086000612d1d9493615903600090565b500190565b615a4a565b906159185750615b8d565b81519060009161592a6119cc84610d39565b1480615957575b61593a57505090565b639996b31560e01b82526001600160a01b03166004820152602490fd5b50803b6159666119cc84610d39565b14615931565b9065ffffffffffff90611977565b9061598a6104c261199892611e2f565b825461596c565b9065ffffffffffff199060301b611977565b613be96104c26104c2926001600160d01b031690565b906159c96104c2611998926159a3565b8254615991565b6104ac91615a02906020906159f46159ee825165ffffffffffff1690565b8561597a565b01516001600160d01b031690565b906159b9565b9190615a17576104ac916159d0565b614d54565b90815491680100000000000000008310156106125782615a449160016104ac95018155610ec2565b90615a08565b919291805490600091615a5c83610d39565b811115615b5057615a8e615a89615a7c615a766001610d39565b8461236d565b8460005260206000200190565b615098565b93838501615aa2815165ffffffffffff1690565b615ab365ffffffffffff841661206f565b11615b415792879260209592615ad36119cc98965165ffffffffffff1690565b615ae465ffffffffffff831661206f565b03615b0757506159f4939291613c72615b0192613c6c6001610d39565b016159b9565b615b3c9450615b299150615b1961062b565b9384019065ffffffffffff169052565b6001600160d01b03881682860152615a1c565b6159f4565b632520601d60e01b8552600485fd5b506119cc92615b8891615b74615b6461062b565b65ffffffffffff90931685840152565b6001600160d01b0387166020830152615a1c565b613bff565b8051600090615b9e6119cc83610d39565b1115615bad5750805190602001fd5b630a12f52160e11b8152600490fd5b634e487b7160e01b600052605160045260246000fd5b91909180600214615bed57600103615bbc576104c2916155fc565b506104c29161556556feeef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400a26469706673582212202b8be60664d531f888cd07ac50a79b2216a1b039f1c1b2caef61afaf0fe2750d64736f6c634300081c0033
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610482578063022d63fb1461047d5780630560ab691461047857806306fdde03146104735780630700037d1461046e578063095ea7b3146104695780630aa6220b146104645780631263dfc41461045f57806312edde5e1461045a57806318160ddd146104555780631c03e6cc1461045057806320df43591461044b57806321c0b3421461044657806323b872dd14610441578063248a9ca31461043c57806326195826146104375780632866ed21146104325780632f2ff15d1461042d578063313ce567146104285780633644e5151461042357806336568abe1461041e5780633a46b1a8146104195780634bf5d7e91461041457806350921b231461040f57806351ed6a301461040a57806355b8fb8114610405578063587cde1e1461040057806359d5409d146103fb5780635ade228a146103f65780635c19a95c146103f157806360c9e243146103ec578063634e93da146103e7578063649a5ec7146103e25780636e553f65146103dd5780636fcfff45146103d8578063702f5e19146103d357806370a08231146103ce5780637bb7bed1146103c95780637ecebe00146103c45780637f539dff146103bf57806384b0196e146103ba57806384ef8ffc146103b55780638da5cb5b146103b05780638e539e8c146103ab57806391d14854146103a657806391ddadf4146103a157806392929a091461039c57806395d89b4114610397578063981372e1146103925780639ab24eb01461038d578063a1eda53c14610388578063a217fddf14610383578063a9059cbb1461037e578063ad7ea0a914610379578063c00007b014610374578063c2b2faa11461036f578063c3cda5201461036a578063c9aba0aa14610365578063cc8463c814610360578063cefc14291461035b578063cf6eefb714610356578063d248824814610351578063d505accf1461034c578063d547741f14610347578063d602b9fd14610342578063d6c89c601461033d578063dd62ed3e14610338578063e1e1384714610333578063eb3beb291461032e578063f0bd87cc146103295763f1127ed80361049a576116c1565b611621565b611606565b6115e1565b6115a9565b61158e565b61156a565b611551565b611532565b6114b7565b611489565b611452565b611437565b61141b565b61131e565b6112e2565b6112bb565b611249565b611211565b6111f6565b6111b6565b611173565b61115b565b611140565b611128565b6110e4565b6110c8565b6110ad565b611092565b611077565b611043565b610f3e565b610f23565b610f08565b610e91565b610e79565b610e47565b610e2e565b610e16565b610dcf565b610db6565b610d75565b610d5a565b610d1d565b610ce8565b610ccf565b610c8f565b610c3d565b610bb9565b610b9d565b610b84565b610b69565b610b3a565b610b21565b610aea565b610aac565b610a91565b610a7b565b610a39565b6109dd565b6109c5565b61096f565b610957565b61091c565b6108ef565b6108d3565b61086c565b6107b5565b610718565b610505565b6104c9565b6001600160e01b031981165b0361049a57565b600080fd5b905035906104ac82610487565b565b9060208282031261049a576104c29161049f565b90565b9052565b3461049a576104f66104e46104df3660046104ae565b6116e9565b60405191829182901515815260200190565b0390f35b600091031261049a57565b3461049a576105153660046104fa565b6104f661052061172a565b6040515b9182918265ffffffffffff909116815260200190565b6001600160a01b031690565b6001600160a01b038116610493565b905035906104ac82610546565b9060208282031261049a576104c291610555565b61053a6104c26104c2926001600160a01b031690565b6104c290610576565b6104c29061058c565b906105a890610595565b600052602052604060002090565b6104c29061053a565b6104c290546105b6565b6104c29081565b6104c290546105c9565b634e487b7160e01b600052604160045260246000fd5b90601f01601f1916810190811067ffffffffffffffff82111761061257604052565b6105da565b906104ac61062460405190565b92836105f0565b6104c26040610617565b906104ac61065d600161064661062b565b94610657610653826105d0565b8752565b016105d0565b6020840152565b61066f90600761059e565b610678816105bf565b91610685600183016105bf565b9161069260048201610635565b916104c260076106a4600685016105d0565b9301610635565b805182526104ac919060209081905b0151910152565b909594926104ac9461070a6107119261070060a0966106f060e088019c60008901906001600160a01b03169052565b6001600160a01b03166020870152565b60408501906106ab565b6080830152565b01906106ab565b3461049a576104f661073361072e366004610562565b610664565b9161074095939560405190565b958695866106c1565b60005b83811061075c5750506000910152565b818101518382015260200161074c565b61078d6107966020936107a093610781815190565b80835293849260200190565b95869101610749565b601f01601f191690565b0190565b60208082526104c29291019061076c565b3461049a576107c53660046104fa565b6104f66107d061182e565b604051918291826107a4565b6107e790600461059e565b6107f0816105bf565b916107fd600183016105d0565b9161080a600282016105d0565b916104c2600461081c600385016105d0565b93016105d0565b6104c590610595565b909594926104ac946108616108689261085a60809661085360a088019c6000890190610823565b6020870152565b6040850152565b6060830152565b0152565b3461049a576104f6610887610882366004610562565b6107dc565b9161089495939560405190565b9586958661082c565b80610493565b905035906104ac8261089d565b919060408382031261049a576104c29060206108cc8286610555565b94016108a3565b3461049a576104f66104e46108e93660046108b0565b9061185b565b3461049a576108ff3660046104fa565b610907611886565b604051005b6040810192916104ac91906106ab565b3461049a576104f6610937610932366004610562565b6118b5565b6040519182918261090c565b9060208282031261049a576104c2916108a3565b3461049a5761090761096a366004610943565b611aac565b3461049a5761097f3660046104fa565b6104f661098a611ab5565b6040515b9182918290815260200190565b610493816105b6565b905035906104ac8261099b565b9060208282031261049a576104c2916109a4565b3461049a576109076109d83660046109b1565b611c90565b3461049a576109ed3660046104fa565b6104f67fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b2661098a565b919060408382031261049a576104c2906020610a328286610555565b9401610555565b3461049a57610907610a4c366004610a16565b90611d16565b909160608284031261049a576104c2610a6b8484610555565b9360406108cc8260208701610555565b3461049a57610a8b366004610a52565b91611d20565b3461049a576104f661098a610aa7366004610943565b611d38565b3461049a57610907610abf366004610562565b611d74565b6104c2916008021c5b60ff1690565b906104c29154610ac4565b6104c260006005610ad3565b3461049a57610afa3660046104fa565b6104f66104e4610ade565b919060408382031261049a576104c2906020610a3282866108a3565b3461049a57610907610b34366004610b05565b90611dca565b3461049a57610b4a3660046104fa565b6104f6610b55611e04565b6040519182918260ff909116815260200190565b3461049a57610b793660046104fa565b6104f661098a611e0e565b3461049a57610907610b97366004610b05565b90611e69565b3461049a576104f661098a610bb33660046108b0565b90611f8d565b3461049a57610bc93660046104fa565b6104f66107d0612059565b60ff8116610493565b905035906104ac82610bd4565b909160c08284031261049a57610c0083836108a3565b92610c0e8160208501610555565b92610c1c82604083016108a3565b926104c2610c2d8460608501610bdd565b9360a06108cc82608087016108a3565b3461049a57610907610c50366004610bea565b949390939291926120f3565b6104c2916008021c61053a565b906104c29154610c5c565b6104c2600080610c69565b6020810192916104ac9190610823565b3461049a57610c9f3660046104fa565b6104f6610caa610c74565b60405191829182610c7f565b909160608284031261049a576104c2610a6b84846109a4565b3461049a57610907610ce2366004610cb6565b91612240565b3461049a576104f6610d03610cfe366004610562565b61224b565b604051918291826001600160a01b03909116815260200190565b3461049a576104f661098a610d33366004610a16565b90612285565b6104c26104c26104c29290565b6104c262127500610d39565b6104c2610d46565b3461049a57610d6a3660046104fa565b6104f661098a610d52565b3461049a57610907610d88366004610562565b61229f565b909160608284031261049a576104c2610da68484610555565b9360406108cc82602087016108a3565b3461049a57610907610dc9366004610d8d565b91612708565b3461049a57610907610de2366004610562565b61272b565b65ffffffffffff8116610493565b905035906104ac82610de7565b9060208282031261049a576104c291610df5565b3461049a57610907610e29366004610e02565b61274c565b3461049a57610907610e41366004610b05565b906127fc565b3461049a576104f6610e62610e5d366004610562565b612806565b6040519182918263ffffffff909116815260200190565b3461049a57610907610e8c366004610562565b61288f565b3461049a576104f661098a610ea7366004610562565b612898565b634e487b7160e01b600052603260045260246000fd5b8054821015610ee557610edc600191600052602060002090565b91020190600090565b610eac565b60035481101561049a57610f026104c2916003610ec2565b90610c69565b3461049a576104f6610d03610f1e366004610943565b610eea565b3461049a576104f661098a610f39366004610562565b6128d0565b3461049a576104f661098a610f54366004610562565b6128d9565b90610f79610f72610f68845190565b8084529260200190565b9260200190565b9060005b818110610f8a5750505090565b909192610fa7610fa06001928651815260200190565b9460200190565b929101610f7d565b9395919461101f6110176110369561100961102f956104c29c9a610ffc60e08c019260008d01907fff00000000000000000000000000000000000000000000000000000000000000169052565b8a820360208c015261076c565b9088820360408a015261076c565b976060870152565b6001600160a01b03166080850152565b60a0830152565b60c0818403910152610f59565b3461049a576110533660046104fa565b6104f661105e612983565b9361106e97959793919360405190565b97889788610faf565b3461049a576110873660046104fa565b6104f6610d03612a33565b3461049a576110a23660046104fa565b6104f6610d03612a4c565b3461049a576104f661098a6110c3366004610943565b612a54565b3461049a576104f66104e46110de366004610b05565b90612acf565b3461049a576110f43660046104fa565b6104f6610520612b11565b801515610493565b905035906104ac826110ff565b9060208282031261049a576104c291611107565b3461049a5761090761113b366004611114565b612b82565b3461049a576111503660046104fa565b6104f66107d0612b8b565b3461049a5761090761116e366004610943565b612c35565b3461049a576104f661098a611189366004610562565b612c3e565b65ffffffffffff90911681526040810192916104ac916020905b019065ffffffffffff169052565b3461049a576111c63660046104fa565b6111ce612cc2565b906104f66111db60405190565b9283928361118e565b6104c26000610d39565b6104c26111e4565b3461049a576112063660046104fa565b6104f661098a6111ee565b3461049a576112213660046108b0565b90611d20565b6104c2916008021c81565b906104c29154611227565b6104c260006001611232565b3461049a576112593660046104fa565b6104f661098a61123d565b906080806104ac9361127e60008201516000860190610823565b61128d60208201516020860152565b61129c60408201516040860152565b6106ba60608201516060860152565b60a0810192916104ac9190611264565b3461049a576104f66112d66112d1366004610562565b612df0565b604051918291826112ab565b3461049a576109076112f5366004610562565b612e0c565b909160c08284031261049a576113108383610555565b92610c0e81602085016108a3565b3461049a576109076113313660046112fa565b94939093929192612e8a565b67ffffffffffffffff811161061257602090601f01601f19160190565b90826000939282370152565b9092919261137b6113768261133d565b610617565b938185528183011161049a576104ac91602085019061135a565b9080601f8301121561049a578160206104c293359101611366565b919060a08382031261049a57823567ffffffffffffffff811161049a57816113d9918501611395565b92602081013567ffffffffffffffff811161049a57826113fa918301611395565b926104c261140b84604085016109a4565b9360806108cc82606087016109a4565b3461049a5761090761142e3660046113b0565b939290926131cb565b3461049a576114473660046104fa565b6104f66105206131d8565b3461049a576114623660046104fa565b61090761324b565b6001600160a01b0390911681526040810192916104ac916020906111a8565b3461049a576114993660046104fa565b6114a1613297565b906104f66114ae60405190565b9283928361146a565b3461049a576104f661098a6114cd366004610a16565b906132b9565b60e08183031261049a576114e78282610555565b926114f58360208401610555565b9261150381604085016108a3565b9261151182606083016108a3565b926104c26115228460808501610bdd565b9360c06108cc8260a087016108a3565b3461049a576109076115453660046114d3565b95949094939193613347565b3461049a57610907611564366004610b05565b9061340e565b3461049a5761157a3660046104fa565b61090761343f565b6104c260006006611232565b3461049a5761159e3660046104fa565b6104f661098a611582565b3461049a576104f661098a6115bf366004610a16565b90613447565b919060408382031261049a576104c2906020610a328286611107565b3461049a576109076115f43660046115c5565b90613621565b6104c260006002610c69565b3461049a576116163660046104fa565b6104f6610caa6115fa565b3461049a576116313660046104fa565b6104f67ffbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c61098a565b63ffffffff8116610493565b905035906104ac8261165a565b919060408382031261049a576104c290602061168f8286610555565b9401611666565b6040810192916104ac9190805165ffffffffffff1682526020908101516001600160d01b0316910152565b3461049a576104f66116dd6116d7366004611673565b9061362b565b60405191829182611696565b6318a4c3c360e11b6001600160e01b0319821614908115611708575090565b6104c2915061363e565b61171f6104c26104c29290565b65ffffffffffff1690565b6104c262069780611712565b634e487b7160e01b600052602260045260246000fd5b906001600283049216801561176c575b602083101461176757565b611736565b91607f169161175c565b805460009392916117936117898361174c565b8085529360200190565b91600181169081156117e557506001146117ac57505050565b6117bf9192939450600052602060002090565b916000925b8184106117d15750500190565b8054848401526020909301926001016117c4565b92949550505060ff1916825215156020020190565b906104c291611776565b906104ac61181e9261181560405190565b938480926117fa565b03836105f0565b6104c290611804565b6104c260037f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace005b01611825565b611866919033613678565b600190565b61187b6118766111e4565b613685565b6104ac6104ac613690565b6104ac61186b565b61189661062b565b906000825260006020830152565b6104c261188e565b6104c290610635565b60046118ce6104c2926118c66118a4565b50600761059e565b016118ac565b6118e5906118e06136ad565b61199c565b6104ac61370b565b156118f457565b63162908e360e11b600090815260045b036000fd5b1561191057565b631e9acf1760e31b6000908152600490fd5b61053a6104c26104c29290565b6104c290611922565b634e487b7160e01b600052601160045260246000fd5b600160ff1b811461195f5760000390565b611938565b9190820180921161195f57565b90600019905b9181191691161790565b906119916104c261199892610d39565b8254611971565b9055565b611a7081611a5860006119b96119b182610d39565b845b116118ed565b6119d76119c533612898565b84906119d0565b9190565b1015611909565b611a4960076119e96104c2338361059e565b611a0e6119f58561192f565b611a06611a0189613739565b61194e565b908633613892565b01611a2d838201611a2787611a22836105d0565b611964565b90611981565b6001611a42611a3c60066105d0565b42611964565b9101611981565b611a538333613a2d565b6105bf565b611a6a611a6560026105bf565b610595565b90613aa4565b7f6d92f7d3303f995bf21956bb0c51b388bae348eaf45c23debd2cfa3fcd9ec646611aa7611a9d33610595565b9261098e60405190565b0390a2565b6104ac906118d4565b6104c260027f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00610657565b6104ac90611aef6118766111e4565b611bc3565b15611afb57565b63d92e233d60e01b6000908152600490fd5b15611b155750565b63cabd13bf60e01b60009081526001600160a01b039091166004526024036000fd5b91906008611977910291611b516001600160a01b03841b90565b921b90565b9190611b676104c261199893610595565b908354611b37565b90815491680100000000000000008310156106125782611b979160016104ac95018155610ec2565b90611b56565b906001600160a01b0390611977565b90611bbc6104c261199892610595565b8254611b9d565b611c5f90611a65611bd382610595565b91611c4183611be2600061192f565b611c026001600160a01b0382165b6001600160a01b0384165b1415611af4565b611c3b611c2e611c21611a656000611c1b87600461059e565b016105bf565b926001600160a01b031690565b916001600160a01b031690565b14611b0d565b611c4c836003611b6f565b6000611c5984600461059e565b01611bac565b7fb13fd610fe4e1b384966826794a9b2f6100ad031f352cc5ec6f22667f6074980611c8960405190565b8080611aa7565b6104ac90611ae0565b906118e591611ca66136ad565b611cc4565b15611cb257565b6303624cab60e31b6000908152600490fd5b6104ac916001600160a01b03821633148015611cf6575b611ce490611cab565b6001611cf06000610d39565b92613892565b50611ce4611d0d61053a6001611c1b86600761059e565b33149050611cdb565b906104ac91611c99565b639cbe235760e01b6000908152600490fd5b906105a8565b60016106576104c292611d49600090565b5060007f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268005b01611d32565b611d85816000611c5933600761059e565b611d97611d9133610595565b91610595565b907f8eb3f1a8f49a22a9fcda79d30a2cf0bde5f65585f6530392b5a8deb6df472239611dc260405190565b80805b0390a3565b90611dd66104c26111e4565b8214611de5576104ac91613b0a565b631fe1e13d60e11b6000908152600490fd5b610acd6104c26104c29290565b6104c26012611df7565b6104c2613b14565b91906008611977910291611b5165ffffffffffff841b90565b61171f6104c26104c29265ffffffffffff1690565b9190611e556104c261199893611e2f565b908354611e16565b6104ac91600091611e44565b9190600080516020615bf883398151915292611e866104c26111e4565b811480611f31575b611e9e575b6104ac929350613b3d565b611ea6613297565b60009591611eb9611c2e61053a8961192f565b14158015611f1f575b8015611f09575b611ee7575060146104ac9495611edf9201611e5d565b839250611e93565b6319ca5ebb60e01b865265ffffffffffff1660048601528480602481015b0390fd5b50611f1a611f1682613b2e565b1590565b611ec9565b50611f2c611f1682613b1c565b611ec2565b50611f3d61053a612a33565b6001600160a01b03831614611e8e565b6104c26104c26104c29265ffffffffffff1690565b9081526040810192916104ac916020906111a8565b6104c26104c26104c2926001600160d01b031690565b7fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00611fb6612b11565b611fbf81611f4d565b841015611ff2575091611fe7611fe16104c2611fed9460016104c2970161059e565b91613b95565b90613c0c565b611f77565b637669fc0f60e11b60009081529061190490856004611f62565b906120196113768361133d565b918252565b612028601d61200c565b7f6d6f64653d626c6f636b6e756d6265722666726f6d3d64656661756c74000000602082015290565b6104c261201e565b612061612b11565b61207b61206f61171f613cf1565b9165ffffffffffff1690565b03612088576104c2612051565b6301bfc1c560e61b6000908152600490fd5b949290979695939160e0860198600087016120bc916001600160a01b03169052565b6001600160a01b031660208601526040850152606084015260ff16608083015260a082015260c00152565b6040513d6000823e3d90fd5b929193909361210b611a65611a65611a6560006105bf565b61211430610595565b92813b1561049a576000809461214d6104ac9a899461213260405190565b998a988997889663d505accf60e01b8852336004890161209a565b03925af19081612163575b50156127fc576127fc565b61217c9060005b61217481836105f0565b8101906104fa565b38612158565b503d61216a565b6104ac9291906121b87fbf233dd2aafeb4d50879c4aa5c81e96d92f6e6945c906a58f9f2d1c1631b4b26613685565b611dc56122366122307ff563e0862357d06e5752eb37b7057a0b8b5aca7410305cfd9b45865523e48c6d93611a6587876121f184610595565b9361221e611bf0612202600061192f565b61053a6001600160a01b0382166001600160a01b038a16611bfb565b61222b6119b16000610d39565b613aa4565b93610595565b9361098e60405190565b906104ac9291612189565b611a536104c29161225a600090565b5060007fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d005b0161059e565b6104c291600361227f61229a936118c6600090565b6105d0565b6104ac9033613cfa565b613cfa565b906118e592916122bc6136ad565b6104ac9291906122eb7ffbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c613685565b6123de565b156122f757565b631786352f60e01b6000908152600490fd5b156123115750565b630c82a8d360e11b60009081526001600160a01b039091166004526024036000fd5b1561233a57565b637616640160e01b6000908152600490fd5b905051906104ac8261089d565b9060208282031261049a576104c29161234c565b9190820391821161195f57565b8181029291811591840414171561195f57565b6104c269d3c21bcecceda1000000610d39565b634e487b7160e01b600052601260045260246000fd5b81156123c0570490565b6123a0565b156123cc57565b63f16eeebd60e01b6000908152600490fd5b90916000916123f56123ef84610d39565b856119b3565b61241461240260016105d0565b61240e6119cc86610d39565b116122f0565b6124226104c282600461059e565b9061249584830194612436611a65876105bf565b9461245e846124448461192f565b976124576001600160a01b038a16611c2e565b1415612309565b612466610d46565b9061247382821115612333565b61247c83610d39565b81036127005750945b61248e82610d39565b9181613892565b6124a1611a65856105bf565b916370a08231946124b130610595565b60206124bc60405190565b80966124c88a60e01b90565b82526001600160a01b038416600483015260249082905afa948515612689576000956126df575b5061250588826124fe856105bf565b3390613dbb565b612511611a65836105bf565b96602061251d60405190565b80996125298460e01b90565b82526001600160a01b038516600483015260249082905afa8015612689576125aa611a656020958a61256e6125d89b6125c19661257a9f6000916126c2575b5061236d565b89600181019e8f6105d0565b80421061268e575050611a539161259c6125a19261259661238d565b9061237a565b6123b6565b60028a01611981565b916125b460405190565b9788948593849360e01b90565b83526001600160a01b031660048301526024820190565b03915afa94851561268957611a27611aa795611a3c611a659461265061262e7fac1f5f240b57fc014c4875ec0fa399f96ca891f85156ba195e6512ccd4ada5489b611a9d9a60009161265a575b5061259661238d565b6126496119cc6104c287612644600288016105d0565b61237a565b10156123c5565b6003429101611981565b61267c915060203d602011612682575b61267481836105f0565b810190612359565b38612625565b503d61266a565b6120e7565b9261259c611a279293611a226126b960026126ad611a5399429061236d565b970196612596886105d0565b9161259661238d565b6126d991508b3d8d116126825761267481836105f0565b38612568565b6126f991955060203d6020116126825761267481836105f0565b93386124ef565b905094612485565b906104ac92916122ae565b6104ac906127226118766111e4565b6104ac90613e13565b6104ac90612713565b6104ac906127436118766111e4565b6104ac90613e69565b6104ac90612734565b906118e5916127626136ad565b906127c2826127b160006127786119b182610d39565b611a536127848261192f565b6127a06001600160a01b0382166001600160a01b038916611bfb565b6127a985613739565b908388613892565b6127ba30610595565b903390613dbb565b6127cc8282613eb7565b7f8752a472e571a816aea92eec8dae9baf628e840f4929fbcc2d155e6233ff68a7611dc561223661223033610595565b906104ac91612755565b6104c290613f06565b6118e59061281b6136ad565b6104ac90600061282a8161192f565b906001600160a01b0382166001600160a01b0384160361284e575b611cf081610d39565b6001600160a01b0383163314801561286f575b61286a90611cab565b612845565b5061286a61288661053a6001611c1b87600761059e565b33149050612861565b6104ac9061280f565b61229a6104c2916128a7600090565b5060007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0061227f565b6104c290613f25565b60066106576104c2926118c6600090565b156128f157565b60405162461bcd60e51b815260206004820152601560248201527f4549503731323a20556e696e697469616c697a656400000000000000000000006044820152606490fd5b67ffffffffffffffff81116106125760208091020190565b9061201961137683612936565b369037565b906104ac6129766129708461294e565b93612936565b601f19016020840161295b565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1006129ce6129b0826105d0565b916000926129c06119cc85610d39565b149081612a13575b506128ea565b6129d6613f2e565b916129df613f59565b916129e930610595565b90612a046129ff6129f983610d39565b92610d39565b612960565b600f60f81b9594934693929190565b612a2091506001016105d0565b612a2c6119cc84610d39565b14386129c8565b6104c26001600080516020615bf8833981519152611c1b565b6104c2612a33565b7fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d00612a7d612b11565b612a8681611f4d565b831015612aa257506104c291611fe7611fe16002611fed940190565b637669fc0f60e11b60009081529061190490846004611f62565b6104c290610acd565b6104c29054612abc565b6104c291600061227f612b0c93612ae4600090565b50827f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800611d6e565b612ac5565b6104c2613cf1565b6104ac90612b286118766111e4565b612b4d565b9060ff90611977565b90612b466104c261199892151590565b8254612b2d565b612b7d7f101b4adbfe4d35c7130bee2f41b462c38a341aa5beb5260ffe5d9e70d9419b38916104e4816005612b36565b0390a1565b6104ac90612b19565b6104c260047f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00611855565b6104ac90612bc56118766111e4565b612bef565b6104c2622b8180610d39565b15612bdd57565b630130feaf60e01b6000908152600490fd5b612b7d7f982c3d0e05826c3b614ce6f221c1481582ffdb40d24913c094f3194e9a850c4391612c2a612c226104c2612bca565b821115612bd6565b61098a816006611981565b6104ac90612bb6565b611fed612c7c6104c26104c293612c53600090565b5060017fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0061227f565b613f84565b6104c29060d01c61171f565b6104c29054612c81565b612ca66104c291939293611712565b92611712565b6104c29060a01c61171f565b6104c29054612cac565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840190612ced82612c8d565b91612cf783613b1c565b80612d21575b60009015612d0f57506119cc90612cb8565b612d1d929350809150612c97565b9091565b50612d2e611f1684613b2e565b612cfd565b6104c260a0610617565b612d45612d33565b906000825260208080808086016000815201600081520160008152016000905250565b6104c2612d3d565b906104c5906105b6565b906104ac612de06004612d8b612d33565b94612d9e612d98826105bf565b87612d70565b612db4612dad600183016105d0565b6020880152565b612dca612dc3600283016105d0565b6040880152565b610657612dd9600383016105d0565b6060880152565b6080840152565b6104c290612d7a565b612e076104c291612dff612d68565b50600461059e565b612de7565b612e1d816001611c5933600761059e565b612e29611d9133610595565b907fcb61187188bc2f5921221326cae4d727940252f625f88065d3ac54ae24f6b845611dc260405190565b6108686104ac94612e83606094989795612e73608086019a6000870152565b6001600160a01b03166020850152565b6040830152565b91959491939092864211612f205791612f19916122a993612f1486612efc896104ac9b9c612ef0612ed87fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf90565b91612ee260405190565b958694602086019485612e54565b908103825203826105f0565b612f0e612f07825190565b9160200190565b20613fbf565b613fe8565b9182614009565b632341d78760e11b60009081526004889052602490fd5b6104c29060401c610acd565b6104c29054612f37565b6104c2905b67ffffffffffffffff1690565b6104c29054612f4d565b612f526104c26104c29290565b9067ffffffffffffffff90611977565b612f526104c26104c29267ffffffffffffffff1690565b90612fad6104c261199892612f86565b8254612f76565b9068ff00000000000000009060401b611977565b90612fd86104c261199892151590565b8254612fb4565b6104c590612f69565b6020810192916104ac9190612fdf565b92939091907ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00948592613036613030611f1686612f43565b94612f5f565b9460009661304388612f69565b67ffffffffffffffff8816148061313e575b6001976130726130648a612f69565b9167ffffffffffffffff1690565b14908161311a575b155b9081613111575b5061310257906130b094939291866130a78a61309e8b612f69565b9c019b8c612f9d565b6130f357613145565b6130b957505050565b6130e7612b7d927fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d294612fc8565b60405191829182612fe8565b6130fd888b612fc8565b613145565b63f92ee8a960e01b8852600488fd5b15905038613083565b905061307c61312830610595565b3b6131356119cc8c610d39565b1491905061307a565b5085613055565b61116e926131646131c49261315f6104ac9897958261404e565b61409a565b61317a61317362015180611712565b33906140ba565b6131826140d7565b6131bd61318e82610595565b6131ae61319b600061192f565b91611bfb6001600160a01b038416611c2e565b611bfb611c2e611c2187610595565b6000611bac565b6002611bac565b906104ac94939291612ff8565b600080516020615bf88339815191527feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840161321181612c8d565b61321a81613b1c565b908161323b575b5015613231576104c29150612cb8565b506104c290612c8d565b6132459150613b2e565b38613221565b613253613297565b5061325d33611c2e565b6001600160a01b0382160361327557506104ac6140eb565b636116401160e11b60009081526001600160a01b039091166004526024036000fd5b600080516020615bf8833981519152906104c26132b3836105bf565b92612cb8565b6104c291600261227f61229a936118c6600090565b919461070a6108689298979561331660a0966133066104ac9a6132f660c08a019e60008b0152565b6001600160a01b03166020890152565b6001600160a01b03166040870152565b6060850152565b6001600160a01b0390911681526040810192916104ac916020905b01906001600160a01b03169052565b95919396949092966133568890565b42116133f757612f1484612efc896133b89798999a9b612ef06133967f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c990565b916133a08461418a565b8d6133aa60405190565b9788966020880196876132ce565b936001600160a01b0381166001600160a01b038616036133dd576104ac939450613678565b6325c0072360e11b6000908152906119049086600461331d565b63313c898160e11b60009081526004899052602490fd5b9061341a6104c26111e4565b8214611de5576104ac916141eb565b6134346118766111e4565b6104ac6104ac6141f5565b6104ac613429565b6104c29161348361229a9261345a600090565b5060017f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0061227f565b61059e565b906118e5916134956136ad565b6134e9565b156134a157565b63514447b560e01b6000908152600490fd5b156134ba57565b63078a94c560e01b6000908152600490fd5b6001600160a01b0390911681526040810192916104ac9160200152565b906134f960076107a0338261059e565b613502816105d0565b92600061351961351182610d39565b86141561349a565b600183019061353561352d6104c2846105d0565b4210156134b3565b61354961354182610d39565b868533613892565b613556611a6560026105bf565b91823b1561049a578161356860405190565b93849063f3fef3a360e01b82528183816135868d8d600484016134cc565b03925af18015612689577fc4c505caef12dcdaeed94682f15951aec519a413367f049d55af5861129950d0956135d7946135d292613605575b506135c984610d39565b93849101611981565b611981565b6135e361223033610595565b93611dc56135f060405190565b92839283908152901515602082015260400190565b61361b90853d87116121825761217481836105f0565b386135bf565b906104ac91613488565b906104c2916136386118a4565b50614212565b637965db0b60e01b6001600160e01b031982161490811561365d575090565b6104c291506001600160e01b0319166301ffc9a760e01b1490565b916001916104ac9361422a565b6104ac90339061431b565b6104ac61369d6000611712565b806143c8565b6104c26002610d39565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006136d7816105d0565b6136df6136a3565b9081146136ef576104ac91611981565b633ee5aeb560e01b6000908152600490fd5b6104c26001610d39565b6104ac7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006000611a42613701565b6137656104c27f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610d39565b8111613774576104c290610d39565b63123baf0360e11b6000908152600491909152602490fd5b1561379357565b63af95b1d160e01b6000908152600490fd5b6104c260c0610617565b80516001600160a01b031682526104ac919060a09081906020818101516001600160a01b0316908501526137e860408201516040860152565b6137f760608201516060860152565b61380660808201516080860152565b01511515910152565b6138366104ac94612e8360609498979561382f61012086019a6000870152565b6020850152565b01906137af565b6104c26080610617565b80516001600160a01b031682526104ac9190606090819061386d60208201516020860152565b6106ba60408201516040860152565b90815260a0810192916104ac9160200190613847565b9080158015613a18575b6138a59061378c565b600773253c6e08db15e2912cf3afe5a89f2a7a4d8f2784916138c5611ab5565b6138cf60016105d0565b6138d886612898565b916138e16137a5565b6001600160a01b0388168152976001600160a01b03166020890152604088015260608701526080860152151560a0850152813b1561049a5760006139459461392860405190565b958691829190633a98477f60e01b8352600360048781860161380f565b0381855af48015612689576139c5956020956139a392613a02575b5061331661396d86612898565b9161399c61397b60016105d0565b9361399661398761383d565b6001600160a01b03909a168a52565b89890152565b6040870152565b6040518095819482936139ba63e8d7fc4460e01b90565b84526004840161387c565b03915af48015612689576104ac916000916139e3575b506001611981565b6139fc915060203d6020116126825761267481836105f0565b386139db565b613a1290600061217481836105f0565b38613960565b506138a5613a266005612ac5565b905061389c565b9190600092613a3b8461192f565b906001600160a01b0382166001600160a01b03821614613a60576104ac939450614485565b634b637e8f60e11b85526001600160a01b0382166004860152602485fd5b613a97613a916104c29263ffffffff1690565b60e01b90565b6001600160e01b03191690565b613ae7600492613ad86104ac95613abe63a9059cbb613a7e565b92613ac860405190565b96879460208601908152016134cc565b602082018103825203836105f0565b6144b1565b906104ac91613afd61187682611d38565b90613b0791614530565b50565b906104ac91613aec565b6104c26145cb565b613b2961206f6000611712565b141590565b613b39425b91611f4d565b1090565b90613b473361053a565b6001600160a01b03821603613b5f57613b079161462e565b63334bd91960e11b6000908152600490fd5b6104c590611df7565b9160206104ac92949361086860408201966000830190613b71565b613ba465ffffffffffff611f4d565b8111613bb3576104c290611712565b6306dfcc6560e41b6000908152906119049060306004613b7a565b6104c29061171f565b6104c29054613bce565b6104c29060301c5b6001600160d01b031690565b6104c29054613be1565b613be96104c26104c29290565b8054613c3d90600092613c1e84610d39565b8483613c2a6005610d39565b8111613c85575b509091015b94856147ba565b613c4682610d39565b8103613c5757506104c29150613bff565b6104c292613c72613c7f92613c6c6001610d39565b9061236d565b9060005260206000200190565b01613bf5565b80613c6c613c92926146bf565b613cb361171f83613cad848883015b60005260206000200190565b01613bd7565b65ffffffffffff89161015613cd257613c3692939450935b9291613c31565b613c369250613ceb90613ce56001610d39565b90611964565b92613ccb565b6104c243613b95565b6104ac91613d917fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0092613d4283613d3d836000613d368261224b565b980161059e565b611bac565b613d4b81610595565b613d5485610595565b613d5d85610595565b917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f613d8860405190565b600090a4614830565b9161484c565b6001600160a01b039182168152911660208201526060810192916104ac9160400152565b90613ae790613ad86104ac95600495613dd76323b872dd613a7e565b93613de160405190565b9788956020870190815201613d97565b613e029065ffffffffffff1661206f565b019065ffffffffffff821161195f57565b7f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed6611aa7613e5f613e54613e4642613b95565b613e4e6131d8565b90613df1565b93611a6585826149d7565b9261052460405190565b7ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b90613ea0613e9742613b95565b613e4e83614a70565b90613eab82826143c8565b612b7d6111db60405190565b9190600092613ec58461192f565b6001600160a01b0381166001600160a01b03831614613ee9576104ac939450614485565b63ec442f0560e01b85526001600160a01b03166004850152602484fd5b613f20613f1b6104c26104c293612c53600090565b614ac1565b614afe565b6104c290614b35565b6104c260027fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100611855565b6104c260037fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100611855565b8054613f906000610d39565b8103613fa25750506104c26000613bff565b613c7f600091613ca16119cc846104c2960192613c6c6001610d39565b6104c290613fcb613b14565b6042916040519161190160f01b8352600283015260228201522090565b916104c2939161400093613ffa600090565b50614b76565b90929192614c6c565b6140128161418a565b9182900361401e575050565b6301d4b62360e61b6000908152916119049160046134cc565b906104ac91614044614d1f565b906104ac91614f2d565b906104ac91614037565b6104ac90614064614d1f565b614088565b614073600161200c565b603160f81b602082015290565b6104c2614069565b6104ac90614094614080565b90614fb8565b6104ac90614058565b906104ac916140b0614d1f565b906104ac91615040565b906104ac916140a3565b6140cc614d1f565b6104ac6104ac615052565b6104ac6140c4565b6104ac91600091611b56565b600080516020615bf8833981519152614102613297565b61410e611f1682613b1c565b8015614178575b614157575060006104ac9261414560149361412e6111e4565b61413f614139612a33565b8261462e565b50614530565b50016141526000826140df565b611e5d565b6319ca5ebb60e01b600090815265ffffffffffff9091166004526024036000fd5b50614185611f1682613b2e565b614115565b6141ba9060005b5060007f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb0061227f565b6104c26141c6826105d0565b9160018301611a27565b906104ac916141e161187682611d38565b90613b079161462e565b906104ac916141d0565b6104ac614202600061192f565b61420c6000611712565b906149d7565b906142256104c26104c293612c536118a4565b6150a1565b9091926142547f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0090565b600061425f8161192f565b6001600160a01b0381166001600160a01b038616146142fe576001600160a01b0381166001600160a01b038716146142e1575050846135d2856134838660016142a8960161059e565b6142b157505050565b611dc56122366122307f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92593610595565b634a1406b160e11b82526001600160a01b03166004820152602490fd5b63e602df0560e01b82526001600160a01b03166004820152602490fd5b90614329611f168284612acf565b614331575050565b63e2517d3f60e01b6000908152916119049160046134cc565b907fffffffffffff00000000000000000000000000000000000000000000000000009060d01b611977565b906143856104c261199892611e2f565b825461434a565b9079ffffffffffff00000000000000000000000000000000000000009060a01b611977565b906143c16104c261199892611e2f565b825461438c565b6104ac91907feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984019061442190600080516020615bf883398151915261440b84612c8d565b61441481613b1c565b614426575b5050826143b1565b614375565b61442f90613b2e565b156144515761444a90600061444386612cb8565b9101614375565b3880614419565b507f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec561447c60405190565b600090a161444a565b906104ac92916150c0565b905051906104ac826110ff565b9060208282031261049a576104c291614490565b6144bd6144c491610595565b9182615131565b906144cd825190565b916000926144dd6119cc85610d39565b1415908161450c575b506144ef575050565b635274afe760e01b82526001600160a01b03166004820152602490fd5b61452a915080602061451f611f16935190565b81830101910161449d565b386144e6565b9190600080516020615bf88339815191529261454d6104c26111e4565b811461455f575b6104c2929350615145565b614567612a33565b600090614579611c2e61053a8461192f565b0361459857506145908260016104c2959601611bac565b839250614554565b631fe1e13d60e11b8152600490fd5b909594926104ac946108616133389261085a60809661085360a088019c6000890152565b7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61461f6145f76151de565b6145ff615274565b90612ef061460c30610595565b60405195869460208601944692866145a7565b61462a612f07825190565b2090565b6104c29190600080516020615bf883398151915261464d6104c26111e4565b821480614674575b614660575b506152d5565b6000600161466e92016140df565b3861465a565b5061468061053a612a33565b6001600160a01b03841614614655565b6104c2906146a46119cc6104c29460ff1690565b901c90565b6104c2906146ba6119cc6104c29490565b901b90565b6146c96000610d39565b81146147af5760016146da82615354565b6146e382611df7565b8080808080966146f4828098614690565b906146fe90610d39565b90614708916146a9565b614712818a6123b6565b019061471d91614690565b61472781896123b6565b019061473291614690565b61473c81886123b6565b019061474791614690565b61475181876123b6565b019061475c91614690565b61476681866123b6565b019061477191614690565b61477b81856123b6565b019061478691614690565b61479081846123b6565b019061479b91614690565b90816147a6916123b6565b6104c291615500565b506104c26000610d39565b939190926147c6600090565b505b80821015614828576147da8183615512565b906147f16000613cad848960005260206000200190565b61480265ffffffffffff871661206f565b11156148115750915b916147c8565b92915061482290613ce56001610d39565b9061480b565b925050915090565b6104c290612898565b9081526040810192916104ac9160200152565b7fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d009291906001600160a01b0382166001600160a01b0382161415806149c5575b614897575b50505050565b6148cd906148a5600061192f565b906001600160a01b0382166001600160a01b03821603614961575b506001600160a01b031690565b6001600160a01b038216036148e3575b80614891565b614940611d916149337fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7249461492a6119cc61492487600161493a9b0161059e565b9261556f565b60015b906155a9565b9590611f77565b94611f77565b9261495661494d60405190565b92839283614839565b0390a23880806148dd565b7fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724816149af611d9161493361499c61493a9660018d0161059e565b6149a86119cc8c61556f565b600261492d565b926149bc61494d60405190565b0390a2386148c0565b506149d06000610d39565b831161488c565b614a11614a16926149f3600080516020615bf883398151915290565b92614a0c6000614a01613297565b969050019182611bac565b6143b1565b613b1c565b614a1c57565b7f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109614a4660405190565b8080612b7d565b614a5e9065ffffffffffff1661206f565b90039065ffffffffffff821161195f57565b614a786131d8565b65ffffffffffff811665ffffffffffff83161115614ab75750614ab26104c291614aac613b33614aa661172a565b92611f4d565b90615500565b611712565b906104c291614a4d565b60006104c291614acf600090565b50015490565b6104c26104c26104c29263ffffffff1690565b614af56104c26104c29290565b63ffffffff1690565b614b0b63ffffffff614ad5565b8111614b1a576104c290614ae8565b6306dfcc6560e41b6000908152906119049060206004613b7a565b61229a6104c291614191600090565b6104c290610d39565b6108686104ac94612e83606094989795614b6c608086019a6000870152565b60ff166020850152565b9091614b8184614b44565b614bad6119cc7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0610d39565b11614c295790614bcf60209460009493614bc660405190565b94859485614b4d565b838052039060015afa1561268957600051600091614bec8361192f565b6001600160a01b0381166001600160a01b03841614614c155750614c0f83610d39565b91929190565b915091614c2190610d39565b909160019190565b505050614c36600061192f565b9160039190565b634e487b7160e01b600052602160045260246000fd5b60041115614c5d57565b614c3d565b906104ac82614c53565b90600091614c7983614c62565b614c8282614c62565b03614c8c57505050565b614c966001614c62565b614c9f82614c62565b03614cb35763f645eedf60e01b8352600483fd5b614cbd6002614c62565b614cc682614c62565b03614cef5750611f05614cd98392614b44565b63fce698f760e01b835260048301526024820190565b614d02614cfc6003614c62565b91614c62565b14614d0b575050565b6335e2f38360e21b82526004820152602490fd5b614d2a611f16615606565b614d3057565b631afcd79f60e31b6000908152600490fd5b906104ac91614d4f614d1f565b614eec565b634e487b7160e01b600052600060045260246000fd5b9160001960089290920291821b911b611977565b9190614d8f6104c261199893610d39565b908354614d6a565b6104ac91600091614d7e565b818110614dae575050565b80614dbc6000600193614d97565b01614da3565b9190601f8111614dd157505050565b614de36104ac93600052602060002090565b906020601f840181900483019310614e05575b6020601f909101040190614da3565b9091508190614df6565b90614e18815190565b9067ffffffffffffffff821161061257614e3c82614e36855461174c565b85614dc2565b602090601f8311600114614e7757611998929160009183614e6c575b5050600019600883021c1916906002021790565b015190503880614e58565b601f19831691614e8c85600052602060002090565b9260005b818110614eca57509160029391856001969410614eb1575b50505002019055565b01516000196008601f8516021c19169055388080614ea8565b91936020600181928787015181550195019201614e90565b906104ac91614e0f565b9060046104ac92614f27614f1d7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0090565b9160038301614ee2565b01614ee2565b906104ac91614d42565b906104ac91614f44614d1f565b614f57565b906119916104c26119989290565b614f9b6104ac92614f92614f887fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10090565b9360028501614ee2565b60038301614ee2565b6001614fa76000610d39565b91614fb28382614f49565b01614f49565b906104ac91614f37565b906104ac91614fcf614d1f565b6000929190600080516020615bf8833981519152614fec8561192f565b6001600160a01b0381166001600160a01b03851614615023575090613b0793946150169201614375565b61501e6111e4565b614530565b636116401160e11b86526001600160a01b03166004860152602485fd5b906104ac91614fc2565b6118e5614d1f565b6104ac61504a565b906104ac615088600061506b61062b565b94613c7f61507a838301613bd7565b65ffffffffffff1687840152565b6001600160d01b03166020840152565b6104c29061505a565b6104c29160006150ba926150b36118a4565b5001610ec2565b50615098565b9291906150ce828286615656565b6000936150dd61053a8661192f565b6001600160a01b038216146150f8575b6104ac9394506157b7565b615100611ab5565b6151086157a7565b908181116151175750506150ed565b611f0587928392630e58ae9360e11b845260048401614839565b6104c29161513f6000610d39565b91615897565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800615173611f168484612acf565b156151d657600161518f84600061227f86826151949701611d32565b612b36565b6151a2611d91612230339390565b917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d6151cd60405190565b600090a4600190565b505050600090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10061520a6104c2613f2e565b90615213825190565b6152206119cc6000610d39565b1115615232575061462a612f07825190565b61523c91506105d0565b6152466000610d39565b811461524f5790565b507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1006152a06104c2613f59565b906152a9825190565b6152b66119cc6000610d39565b11156152c8575061462a612f07825190565b61523c91506001016105d0565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006153008383612acf565b156151d657600061518f848261227f868261531b9701611d32565b615329611d91612230339390565b917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b6151cd60405190565b60006154496119cc6129f961536884610d39565b9461537c6153766080611df7565b82614690565b8681116154e9575b506153926153766040611df7565b61539b86610d39565b81116154d2575b506153b06153766020611df7565b6153b986610d39565b81116154bb575b506153ce6153766010611df7565b6153d786610d39565b81116154a4575b506153ec6153766008611df7565b6153f586610d39565b811161548d575b5061540a6153766004611df7565b61541386610d39565b8111615476575b506154286153766002611df7565b61543186610d39565b811161545f575b506154436001611df7565b90614690565b116154515790565b6104c2906107a06001610d39565b61546f9150956107a06002610d39565b9438615438565b6154869150956107a06004610d39565b943861541a565b61549d9150956107a06008610d39565b94386153fc565b6154b49150956107a06010610d39565b94386153de565b6154cb9150956107a06020610d39565b94386153c0565b6154e29150956107a06040610d39565b94386153a2565b6154f99150956107a06080610d39565b9438615384565b908082101561550d575090565b905090565b613ce56104c292615521600090565b5080831692186155316002610d39565b906123b6565b615552906001600160d01b03165b916001600160d01b031690565b9003906001600160d01b03821161195f57565b6104c29190615537565b61557f6001600160d01b03611f77565b811161558e576104c290613bff565b6306dfcc6560e41b6000908152906119049060d06004613b7a565b906155d2612d1d936155b9600090565b506155c2612b11565b926155cc85613f84565b90615bd2565b916158f0565b6155ea906001600160d01b0316615545565b01906001600160d01b03821161195f57565b6104c291906155d8565b6104c27ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00612f43565b6001600160a01b0390911681526060810193926104ac929091604091610868906020830152565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace008260006156838161192f565b6001600160a01b0381166001600160a01b0386160361572857938361223693612230936156e37fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9861053a8c611a276002611dc59c0191611a22836105d0565b6001600160a01b0383160361570c5750506002611a659101611a2789615708836105d0565b0390565b9061571b91611a65930161059e565b611a27896107a0836105d0565b90809250830161573b61229a868361059e565b87811061578c579386612236946156e36122309561053a8a966135d27fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9c8f61578690611dc59e0390565b9261059e565b83611f058982938963391434e360e21b85526004850161562f565b6104c26001600160d01b03611f77565b906158386158326104ac94936157ea7fe8b26c30fad74198956032a3533d903385d56dd795af560196f9c78d4af40d0090565b61581c6157f7600061192f565b6001600160a01b0381166001600160a01b03851614615857576001600160a01b031690565b6001600160a01b0386161461583e575b5061224b565b9161224b565b9061484c565b600261585191016149a86119cc8861556f565b5061582c565b61586a6002840161492a6119cc8b61556f565b50506001600160a01b031690565b3d15615892576158873d61200c565b903d6000602084013e565b606090565b919291906158a430610595565b93808531106158d1576104c293945081600092916020849351920190855af16158cb615878565b9161590d565b63cd78605960e01b60009081526001600160a01b038616600452602490fd5b906159086000612d1d9493615903600090565b500190565b615a4a565b906159185750615b8d565b81519060009161592a6119cc84610d39565b1480615957575b61593a57505090565b639996b31560e01b82526001600160a01b03166004820152602490fd5b50803b6159666119cc84610d39565b14615931565b9065ffffffffffff90611977565b9061598a6104c261199892611e2f565b825461596c565b9065ffffffffffff199060301b611977565b613be96104c26104c2926001600160d01b031690565b906159c96104c2611998926159a3565b8254615991565b6104ac91615a02906020906159f46159ee825165ffffffffffff1690565b8561597a565b01516001600160d01b031690565b906159b9565b9190615a17576104ac916159d0565b614d54565b90815491680100000000000000008310156106125782615a449160016104ac95018155610ec2565b90615a08565b919291805490600091615a5c83610d39565b811115615b5057615a8e615a89615a7c615a766001610d39565b8461236d565b8460005260206000200190565b615098565b93838501615aa2815165ffffffffffff1690565b615ab365ffffffffffff841661206f565b11615b415792879260209592615ad36119cc98965165ffffffffffff1690565b615ae465ffffffffffff831661206f565b03615b0757506159f4939291613c72615b0192613c6c6001610d39565b016159b9565b615b3c9450615b299150615b1961062b565b9384019065ffffffffffff169052565b6001600160d01b03881682860152615a1c565b6159f4565b632520601d60e01b8552600485fd5b506119cc92615b8891615b74615b6461062b565b65ffffffffffff90931685840152565b6001600160d01b0387166020830152615a1c565b613bff565b8051600090615b9e6119cc83610d39565b1115615bad5750805190602001fd5b630a12f52160e11b8152600490fd5b634e487b7160e01b600052605160045260246000fd5b91909180600214615bed57600103615bbc576104c2916155fc565b506104c29161556556feeef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400a26469706673582212202b8be60664d531f888cd07ac50a79b2216a1b039f1c1b2caef61afaf0fe2750d64736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.