Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 19879413 | 111 days ago | IN | 0 ETH | 0.00928785 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
VotingEscrowMainchain
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { EnumerableMap } from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; import { IPVotingEscrowMainchain, IPVeToken } from "../interfaces/IVotingEscrow/IPVotingEscrowMainchain.sol"; import { Checkpoint, CheckpointHelper, Checkpoints, WeekMath } from "../libraries/VeHistoryLib.sol"; import { VeBalanceLib, VeBalance, LockedPosition } from "../libraries/VeBalanceLib.sol"; import { MiniHelpers } from "../libraries/MiniHelpers.sol"; import { Errors } from "../libraries/Errors.sol"; import { VotingEscrowTokenBase } from "./VotingEscrowTokenBase.sol"; import { OwnableUpgradeable, MsgSenderAppUpg } from "../CrossChainMsg/MsgSenderAppUpg.sol"; import { IChefIncentivesController } from "../interfaces/IIncentive/IChefIncentivesController.sol"; // // import { IVeChef } from "../interfaces/IIncentive/IVeChef.sol"; interface IPriceProvider { function updateAndBroadcastPrice(uint256[] calldata chainIds) external payable; } contract VotingEscrowMainchain is VotingEscrowTokenBase, IPVotingEscrowMainchain, MsgSenderAppUpg { using SafeERC20 for IERC20; using VeBalanceLib for VeBalance; using VeBalanceLib for LockedPosition; using Checkpoints for Checkpoints.History; using EnumerableMap for EnumerableMap.UintToAddressMap; bytes private constant EMPTY_BYTES = abi.encode(); bytes private constant SAMPLE_SUPPLY_UPDATE_MESSAGE = abi.encode(0, VeBalance(0, 0), EMPTY_BYTES); bytes private constant SAMPLE_POSITION_UPDATE_MESSAGE = abi.encode(0, VeBalance(0, 0), abi.encode(address(0), LockedPosition(0, 0))); IERC20 public protocolToken; IChefIncentivesController public veChef; IChefIncentivesController public cic; uint256 public executionGasLimit; address public keeper; uint128 public lastSlopeChangeAppliedAt; // [wTime] => slopeChanges mapping(uint128 => uint128) public slopeChanges; // Saving totalSupply checkpoint for each week, later can be used for reward accounting // [wTime] => totalSupply mapping(uint128 => uint128) public totalSupplyAt; // Saving VeBalance checkpoint for users of each week, can later use binary search // to ask for their vePendle balance at any wTime mapping(address => Checkpoints.History) internal userHistory; uint256[50] private __gap; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(IERC20 _protocolToken, address _msgSendEndpoint, uint256 _approxDstExecutionGas) public initializer { if (address(_protocolToken) == address(0)) revert Errors.ZeroAddress(); protocolToken = _protocolToken; __MsgSenderAppUpg_init(_msgSendEndpoint, _approxDstExecutionGas); } function setLastSlopeChangeAppliedAt() external onlyOwner { lastSlopeChangeAppliedAt = getCurrentWeekStart(); } function setKeeperConfig(address _keeper, uint256 _executionGasLimit) external onlyOwner { if (_keeper == address(0)) revert Errors.ZeroAddress(); keeper = _keeper; executionGasLimit = _executionGasLimit; emit KeeperConfigSet(_keeper, _executionGasLimit); } // function setVeChef(IChefIncentivesController _veChef) external onlyOwner { if (address(_veChef) == address(0)) revert Errors.ZeroAddress(); veChef = _veChef; emit VeChefSet(address(veChef)); } //@note in case UpdateInProgress needs to be integrated in the future function setCIC(IChefIncentivesController _cic) external onlyOwner { if (address(_cic) == address(0)) revert Errors.ZeroAddress(); cic = _cic; emit cicSet(address(cic)); } /// @notice basically a proxy function to call increaseLockPosition & broadcastUserPosition at the same time function increaseLockPositionAndBroadcast( uint128 additionalAmountToLock, uint128 newExpiry, uint256[] calldata chainIds ) external payable refundUnusedEth returns (uint128 newVeBalance) { newVeBalance = increaseLockPosition(additionalAmountToLock, newExpiry); broadcastUserPosition(msg.sender, chainIds); } /** * @notice increases the lock position of a user (amount and/or expiry). Applicable even when * user has no position or the current position has expired. * @param additionalAmountToLock pendle amount to be pulled in from user to lock. * @param newExpiry new lock expiry. Must be a valid week beginning, and resulting lock * duration (since `block.timestamp`) must be within the allowed range. * @dev Will revert if resulting position has zero lock amount. * @dev See `_increasePosition()` for details on inner workings. * @dev Sidechain broadcasting is not bundled since it can be done anytime after. */ function increaseLockPosition(uint128 additionalAmountToLock, uint128 newExpiry) public payable returns (uint128 newVeBalance) { address user = msg.sender; if (!WeekMath.isValidWTime(newExpiry)) revert Errors.InvalidWTime(newExpiry); if (MiniHelpers.isTimeInThePast(newExpiry)) revert Errors.ExpiryInThePast(newExpiry); if (newExpiry < positionData[user].expiry) revert Errors.VENotAllowedReduceExpiry(); if (newExpiry > block.timestamp + MAX_LOCK_TIME) revert Errors.VEExceededMaxLockTime(); if (newExpiry < block.timestamp + MIN_LOCK_TIME) revert Errors.VEInsufficientLockTime(); uint128 newTotalAmountLocked = additionalAmountToLock + positionData[user].amount; if (newTotalAmountLocked == 0) revert Errors.VEZeroAmountLocked(); uint128 additionalDurationToLock = newExpiry - positionData[user].expiry; if (additionalAmountToLock > 0) { protocolToken.safeTransferFrom(user, address(this), additionalAmountToLock); } newVeBalance = _increasePosition(user, additionalAmountToLock, additionalDurationToLock); if (veChef != IChefIncentivesController(address(0))) { veChef.handleWithdrawAfter(user, balanceOf(user)); } if (executionGasLimit > 0 && keeper != address(0)) { uint256 estimatedUpdateGas = (executionGasLimit * tx.gasprice * 80) / 100; // 80% of gas limit (bool success, ) = keeper.call{ value: estimatedUpdateGas }(""); if (!success) { revert Errors.EthTransferFailed(); } } emit UpdateRequestedFromVe(user, 0); emit NewLockPosition(user, newTotalAmountLocked, newExpiry); } /** * @notice Withdraws an expired lock position, returns locked PENDLE back to user * @dev reverts if position is not expired, or if no locked PENDLE to withdraw * @dev broadcast is not bundled since it can be done anytime after */ function withdraw() external returns (uint128 amount) { address user = msg.sender; if (!_isPositionExpired(user)) revert Errors.VEPositionNotExpired(); amount = positionData[user].amount; if (amount == 0) revert Errors.VEZeroPosition(); delete positionData[user]; protocolToken.safeTransfer(user, amount); if (veChef != IChefIncentivesController(address(0))) { veChef.handleWithdrawAfter(user, 0); } emit Withdraw(user, amount); } /** * @notice update & return the current totalSupply, but does not broadcast info to other chains * @dev See `broadcastTotalSupply()` and `broadcastUserPosition()` for broadcasting */ function totalSupplyCurrent() public virtual override(IPVeToken, VotingEscrowTokenBase) returns (uint128) { (VeBalance memory supply, ) = _applySlopeChange(); return supply.getCurrentValue(); } /// @notice updates and broadcast the current totalSupply to different chains function broadcastTotalSupply(uint256[] calldata chainIds) public payable refundUnusedEth { _broadcastPosition(address(0), chainIds); } /** * @notice updates and broadcast the position of `user` to different chains, also updates and * broadcasts totalSupply */ function broadcastUserPosition(address user, uint256[] calldata chainIds) public payable refundUnusedEth { if (user == address(0)) revert Errors.ZeroAddress(); _broadcastPosition(user, chainIds); } function getUserHistoryLength(address user) external view returns (uint256) { return userHistory[user].length(); } function getUserHistoryAt(address user, uint256 index) external view returns (Checkpoint memory) { return userHistory[user].get(index); } function getBroadcastSupplyFee(uint256[] calldata chainIds) external view returns (uint256 fee) { for (uint256 i = 0; i < chainIds.length; i++) { fee += _getSendMessageFee(chainIds[i], SAMPLE_SUPPLY_UPDATE_MESSAGE); } } function getBroadcastPositionFee(uint256[] calldata chainIds) external view returns (uint256 fee) { for (uint256 i = 0; i < chainIds.length; i++) { fee += _getSendMessageFee(chainIds[i], SAMPLE_POSITION_UPDATE_MESSAGE); } } /** * @notice increase the locking position of the user * @dev works by simply removing the old position from all relevant data (as if the user has * never locked) and then add in the new position */ function _increasePosition(address user, uint128 amountToIncrease, uint128 durationToIncrease) internal returns (uint128) { LockedPosition memory oldPosition = positionData[user]; (VeBalance memory newSupply, ) = _applySlopeChange(); if (!MiniHelpers.isCurrentlyExpired(oldPosition.expiry)) { // remove old position not yet expired VeBalance memory oldBalance = oldPosition.convertToVeBalance(); newSupply = newSupply.sub(oldBalance); slopeChanges[oldPosition.expiry] -= oldBalance.slope; } LockedPosition memory newPosition = LockedPosition(oldPosition.amount + amountToIncrease, oldPosition.expiry + durationToIncrease); VeBalance memory newBalance = newPosition.convertToVeBalance(); // add new position newSupply = newSupply.add(newBalance); slopeChanges[newPosition.expiry] += newBalance.slope; _totalSupply = newSupply; positionData[user] = newPosition; userHistory[user].push(newBalance); return newBalance.getCurrentValue(); } /** * @notice updates the totalSupply, processing all slope changes of past weeks. At the same time, * set the finalized totalSupplyAt */ function _applySlopeChange() internal returns (VeBalance memory, uint128) { VeBalance memory supply = _totalSupply; uint128 wTime = lastSlopeChangeAppliedAt; uint128 currentWeekStart = WeekMath.getCurrentWeekStart(); if (wTime >= currentWeekStart) { return (supply, wTime); } while (wTime < currentWeekStart) { wTime += WEEK; supply = supply.sub(slopeChanges[wTime], wTime); totalSupplyAt[wTime] = supply.getValueAt(wTime); } _totalSupply = supply; lastSlopeChangeAppliedAt = wTime; return (supply, wTime); } /// @notice broadcast position to all chains in chainIds function _broadcastPosition(address user, uint256[] calldata chainIds) internal { if (chainIds.length == 0) revert Errors.ArrayEmpty(); (VeBalance memory supply, ) = _applySlopeChange(); bytes memory userData = (user == address(0) ? EMPTY_BYTES : abi.encode(user, positionData[user])); for (uint256 i = 0; i < chainIds.length; ++i) { if (!destinationContracts.contains(chainIds[i])) revert Errors.ChainNotSupported(chainIds[i]); _broadcast(chainIds[i], uint128(block.timestamp), supply, userData); emit UpdateRequestedFromVeCrossChain(user, 0, chainIds[i]); } if (user != address(0)) { emit BroadcastUserPosition(user, chainIds); } emit BroadcastTotalSupply(supply, chainIds); } function _broadcast(uint256 chainId, uint128 msgTime, VeBalance memory supply, bytes memory userData) internal { _sendMessage(chainId, abi.encode(msgTime, supply, userData)); } function getCurrentWeekStart() public view returns (uint128) { return WeekMath.getCurrentWeekStart(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// 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.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) (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/structs/EnumerableMap.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. pragma solidity ^0.8.20; import {EnumerableSet} from "./EnumerableSet.sol"; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * The following map types are supported: * * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableMap. * ==== */ library EnumerableMap { using EnumerableSet for EnumerableSet.Bytes32Set; // To implement this library for multiple types with as little code repetition as possible, we write it in // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions, // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map. // This means that we can only create new EnumerableMaps for types that fit in bytes32. /** * @dev Query for a nonexistent map key. */ error EnumerableMapNonexistentKey(bytes32 key); struct Bytes32ToBytes32Map { // Storage of keys EnumerableSet.Bytes32Set _keys; mapping(bytes32 key => bytes32) _values; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { map._values[key] = value; return map._keys.add(key); } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { delete map._values[key]; return map._keys.remove(key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { return map._keys.contains(key); } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { return map._keys.length(); } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { bytes32 key = map._keys.at(index); return (key, map._values[key]); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { bytes32 value = map._values[key]; if (value == bytes32(0)) { return (contains(map, key), bytes32(0)); } else { return (true, value); } } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { bytes32 value = map._values[key]; if (value == 0 && !contains(map, key)) { revert EnumerableMapNonexistentKey(key); } return value; } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { return map._keys.values(); } // UintToUintMap struct UintToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(key))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintToAddressMap struct UintToAddressMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); return (success, address(uint160(uint256(value)))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint160(uint256(get(map._inner, bytes32(key))))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { bytes32[] memory store = keys(map._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressToUintMap struct AddressToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(AddressToUintMap storage map, address key) internal returns (bool) { return remove(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(AddressToUintMap storage map, address key) internal view returns (bool) { return contains(map._inner, bytes32(uint256(uint160(key)))); } /** * @dev Returns the number of elements in the map. O(1). */ function length(AddressToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (address(uint160(uint256(key))), uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(AddressToUintMap storage map, address key) internal view returns (uint256) { return uint256(get(map._inner, bytes32(uint256(uint160(key))))); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(AddressToUintMap storage map) internal view returns (address[] memory) { bytes32[] memory store = keys(map._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // Bytes32ToUintMap struct Bytes32ToUintMap { Bytes32ToBytes32Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { return set(map._inner, key, bytes32(value)); } /** * @dev Removes a value from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { return remove(map._inner, key); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { return contains(map._inner, key); } /** * @dev Returns the number of elements in the map. O(1). */ function length(Bytes32ToUintMap storage map) internal view returns (uint256) { return length(map._inner); } /** * @dev Returns the element stored at position `index` in the map. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { (bytes32 key, bytes32 value) = at(map._inner, index); return (key, uint256(value)); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { (bool success, bytes32 value) = tryGet(map._inner, key); return (success, uint256(value)); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { return uint256(get(map._inner, key)); } /** * @dev Return the an array containing all the keys * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. */ function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { bytes32[] memory store = keys(map._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; import { IPMsgSendEndpoint } from "../interfaces/ICrossChainMsg/IPMsgSendEndpoint.sol"; import { Errors } from "../libraries/Errors.sol"; import { EnumerableMap } from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; // solhint-disable no-empty-blocks abstract contract MsgSenderAppUpg is OwnableUpgradeable { using EnumerableMap for EnumerableMap.UintToAddressMap; using Address for address; uint256 public approxDstExecutionGas; IPMsgSendEndpoint public msgSendEndpoint; // destinationContracts mapping contains one address for each chainId only EnumerableMap.UintToAddressMap internal destinationContracts; uint256[50] private __gap; event DestinationContractAdded(uint256 chainId, address addr); event ApproxDstExecutionGasUpdated(uint256 gas); modifier refundUnusedEth() { _; if (address(this).balance > 0) { Address.sendValue(payable(msg.sender), address(this).balance); } } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function __MsgSenderAppUpg_init(address _msgSendEndpoint, uint256 _approxDstExecutionGas) internal onlyInitializing { msgSendEndpoint = IPMsgSendEndpoint(_msgSendEndpoint); approxDstExecutionGas = _approxDstExecutionGas; __Ownable_init(msg.sender); } function _sendMessage(uint256 chainId, bytes memory message) internal { assert(destinationContracts.contains(chainId)); address toAddr = destinationContracts.get(chainId); uint256 estimatedGasAmount = approxDstExecutionGas; uint256 fee = msgSendEndpoint.calcFee(toAddr, chainId, message, estimatedGasAmount); // LM contracts won't hold ETH on its own so this is fine if (address(this).balance < fee) revert Errors.InsufficientFeeToSendMsg(address(this).balance, fee); msgSendEndpoint.sendMessage{ value: fee }(toAddr, chainId, message, estimatedGasAmount); } function addDestinationContract(address _address, uint256 _chainId) public payable onlyOwner { destinationContracts.set(_chainId, _address); emit DestinationContractAdded(_chainId, _address); } function setApproxDstExecutionGas(uint256 gas) external onlyOwner { approxDstExecutionGas = gas; emit ApproxDstExecutionGasUpdated(gas); } function getAllDestinationContracts() public view returns (uint256[] memory chainIds, address[] memory addrs) { uint256 length = destinationContracts.length(); chainIds = new uint256[](length); addrs = new address[](length); for (uint256 i = 0; i < length; ++i) { (chainIds[i], addrs[i]) = destinationContracts.at(i); } } function _getSendMessageFee(uint256 chainId, bytes memory message) internal view returns (uint256) { return msgSendEndpoint.calcFee(destinationContracts.get(chainId), chainId, message, approxDstExecutionGas); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.0; interface IPMsgSendEndpoint { function calcFee( address dstAddress, uint256 dstChainId, bytes memory payload, uint256 estimatedGasAmount ) external view returns (uint256 fee); function sendMessage( address dstAddress, uint256 dstChainId, bytes calldata payload, uint256 estimatedGasAmount ) external payable; }
// SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.8.23; pragma experimental ABIEncoderV2; interface ICICUserDefinedTypes { // Info of each user. // reward = user.`amount` * pool.`accRewardPerShare` - `rewardDebt` struct UserInfo { uint256 amount; uint256 rewardDebt; uint256 lastClaimTime; } // Info of each pool. struct PoolInfo { uint256 totalSupply; uint256 allocPoint; // How many allocation points assigned to this pool. uint256 lastRewardTime; // Last second that reward distribution occurs. uint256 accRewardPerShare; // Accumulated rewards per share, times ACC_REWARD_PRECISION. See below. } // Info about token emissions for a given time period. struct EmissionPoint { uint128 startTimeOffset; uint128 rewardsPerSecond; } // Info about ending time of reward emissions struct EndingTime { uint256 estimatedTime; uint256 lastUpdatedTime; uint256 updateCadence; } enum EligibilityModes { // check on all rToken transfers FULL, // only check on Claim LIMITED, // 0 eligibility functions run DISABLED } /********************** Events ***********************/ // Emitted when rewardPerSecond is updated event RewardsPerSecondUpdated(uint256 indexed rewardsPerSecond); event BalanceUpdated(address indexed token, address indexed user, uint256 balance); event EmissionScheduleAppended(uint256[] startTimeOffsets, uint256[] rewardsPerSeconds); event Disqualified(address indexed user); event EligibilityModeUpdated(EligibilityModes indexed _newVal); event BatchAllocPointsUpdated(address[] _tokens, uint256[] _allocPoints); event AuthorizedContractUpdated(address _contract, bool _authorized); event EndingTimeUpdateCadence(uint256 indexed _lapse); event RewardDeposit(uint256 indexed _amount); event UpdateRequested(address indexed _user, uint256 feePaid); event KeeperConfigSet(address indexed keeper, uint256 executionGasLimit); event EmissionStarted(uint256 _startTime); event PoolAdded(address indexed _token, uint256 indexed _allocPoint); event WhitelistUpdated(address indexed _user, bool _status); event WhitelistToggled(bool _status); /********************** Errors ***********************/ error AddressZero(); error UnknownPool(); error PoolExists(); error AlreadyStarted(); error NotAllowed(); error ArrayLengthMismatch(); error InvalidStart(); error InvalidRToken(); error InsufficientPermission(); error AuthorizationAlreadySet(); error NotVeContract(); error NotWhitelisted(); error NotEligible(); error CadenceTooLong(); error EligibleRequired(); error NotValidPool(); error OutOfRewards(); error DuplicateSchedule(); error ValueZero(); error NotKeeper(); error InsufficientFee(); error TransferFailed(); error UpdateInProgress(); error ExemptedUser(); error EthTransferFailed(); error InvalidToken(); } interface IChefIncentivesController { /** * @dev Called by the corresponding asset on any update that affects the rewards distribution * @param user The address of the user **/ function handleActionBefore(address user) external; /** * @dev Called by the corresponding asset on any update that affects the rewards distribution * @param user The address of the user * @param userBalance The balance of the user of the asset in the lending pool **/ function handleWithdrawAfter(address user, uint256 userBalance) external; /** * @dev Called by the locking contracts after locking or unlocking happens * @param user The address of the user **/ function beforeLockUpdate(address user) external; /** * @notice Hook for lock update. * @dev Called by the locking contracts after locking or unlocking happens */ function afterLockUpdate(address _user) external; function addPool(address _token, uint256 _allocPoint) external; function claim(address _user, address[] calldata _tokens) external; // function disqualifyUser(address _user, address _hunter) external returns (uint256 bounty); // function bountyForUser(address _user) external view returns (uint256 bounty); function allPendingRewards(address _user) external view returns (uint256 pending); function claimAll(address _user) external; // function claimBounty(address _user, bool _execute) external returns (bool issueBaseBounty); function setEligibilityExempt(address _address, bool _value) external; function manualStopEmissionsFor(address _user, address[] memory _tokens) external; function manualStopAllEmissionsFor(address _user) external; function setAddressWLstatus(address user, bool status) external; function toggleWhitelist() external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; interface IPVeToken { // ============= USER INFO ============= function balanceOf(address user) external view returns (uint128); function positionData(address user) external view returns (uint128 amount, uint128 expiry); // ============= META DATA ============= function totalSupplyStored() external view returns (uint128); function totalSupplyCurrent() external returns (uint128); function totalSupplyAndBalanceCurrent(address user) external returns (uint128, uint128); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; import "./IPVeToken.sol"; import "../../libraries/VeBalanceLib.sol"; import "../../libraries/VeHistoryLib.sol"; interface IPVotingEscrowMainchain is IPVeToken { event NewLockPosition(address indexed user, uint128 amount, uint128 expiry); event Withdraw(address indexed user, uint128 amount); event BroadcastTotalSupply(VeBalance newTotalSupply, uint256[] chainIds); event BroadcastUserPosition(address indexed user, uint256[] chainIds); event UpdateRequestedFromVe(address indexed _user, uint256 feePaid); event UpdateRequestedFromVeCrossChain(address indexed _user, uint256 feePaid, uint256 chainId); event VeChefSet(address veChef); event KeeperConfigSet(address indexed keeper, uint256 indexed fee); event cicSet(address cic); // ============= ACTIONS ============= function increaseLockPosition(uint128 additionalAmountToLock, uint128 expiry) payable external returns (uint128); function withdraw() external returns (uint128); function totalSupplyAt(uint128 timestamp) external view returns (uint128); function getUserHistoryLength(address user) external view returns (uint256); function getUserHistoryAt(address user, uint256 index) external view returns (Checkpoint memory); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; library Errors { // Liquidity Mining error VEInvalidNewExpiry(uint256 newExpiry); error VEExceededMaxLockTime(); error VEInsufficientLockTime(); error VENotAllowedReduceExpiry(); error VEZeroAmountLocked(); error VEPositionNotExpired(); error VEZeroPosition(); error VEZeroSlope(uint128 bias, uint128 slope); error VEReceiveOldSupply(uint256 msgTime); error InvalidWTime(uint256 wTime); error ExpiryInThePast(uint256 expiry); error ChainNotSupported(uint256 chainId); error EthTransferFailed(); error UpdateInProgress(); // Cross-Chain error MsgNotFromSendEndpoint(uint16 srcChainId, bytes path); error MsgNotFromReceiveEndpoint(address sender); error InsufficientFeeToSendMsg(uint256 currentFee, uint256 requiredFee); error ApproxDstExecutionGasNotSet(); error InvalidRetryData(); // GENERIC MSG error ArrayLengthMismatch(); error ArrayEmpty(); error ArrayOutOfBounds(); error ZeroAddress(); error FailedToSendEther(); error InvalidMerkleProof(); error OnlyLayerZeroEndpoint(); error OnlyYT(); error OnlyYCFactory(); error OnlyWhitelisted(); error LzChainIdNotSet(uint256 dstChainId); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; library MiniHelpers { function isCurrentlyExpired(uint256 expiry) internal view returns (bool) { return (expiry <= block.timestamp); } function isExpired(uint256 expiry, uint256 blockTime) internal pure returns (bool) { return (expiry <= blockTime); } function isTimeInThePast(uint256 timestamp) internal view returns (bool) { return (timestamp <= block.timestamp); // same definition as isCurrentlyExpired } }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity ^0.8.23; /* solhint-disable private-vars-leading-underscore, reason-string */ library PMath { uint256 internal constant ONE = 1e18; // 18 decimal places int256 internal constant IONE = 1e18; // 18 decimal places function subMax0(uint256 a, uint256 b) internal pure returns (uint256) { unchecked { return (a >= b ? a - b : 0); } } function subNoNeg(int256 a, int256 b) internal pure returns (int256) { require(a >= b, "negative"); return a - b; // no unchecked since if b is very negative, a - b might overflow } function mulDown(uint256 a, uint256 b) internal pure returns (uint256) { uint256 product = a * b; unchecked { return product / ONE; } } function mulDown(int256 a, int256 b) internal pure returns (int256) { int256 product = a * b; unchecked { return product / IONE; } } function divDown(uint256 a, uint256 b) internal pure returns (uint256) { uint256 aInflated = a * ONE; unchecked { return aInflated / b; } } function divDown(int256 a, int256 b) internal pure returns (int256) { int256 aInflated = a * IONE; unchecked { return aInflated / b; } } function rawDivUp(uint256 a, uint256 b) internal pure returns (uint256) { return (a + b - 1) / b; } // @author Uniswap function sqrt(uint256 y) internal pure returns (uint256 z) { if (y > 3) { z = y; uint256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } function square(uint256 x) internal pure returns (uint256) { return x * x; } function squareDown(uint256 x) internal pure returns (uint256) { return mulDown(x, x); } function abs(int256 x) internal pure returns (uint256) { return uint256(x > 0 ? x : -x); } function neg(int256 x) internal pure returns (int256) { return x * (-1); } function neg(uint256 x) internal pure returns (int256) { return Int(x) * (-1); } function max(uint256 x, uint256 y) internal pure returns (uint256) { return (x > y ? x : y); } function max(int256 x, int256 y) internal pure returns (int256) { return (x > y ? x : y); } function min(uint256 x, uint256 y) internal pure returns (uint256) { return (x < y ? x : y); } function min(int256 x, int256 y) internal pure returns (int256) { return (x < y ? x : y); } /*/////////////////////////////////////////////////////////////// SIGNED CASTS //////////////////////////////////////////////////////////////*/ function Int(uint256 x) internal pure returns (int256) { require(x <= uint256(type(int256).max)); return int256(x); } function Int128(int256 x) internal pure returns (int128) { require(type(int128).min <= x && x <= type(int128).max); return int128(x); } function Int128(uint256 x) internal pure returns (int128) { return Int128(Int(x)); } /*/////////////////////////////////////////////////////////////// UNSIGNED CASTS //////////////////////////////////////////////////////////////*/ function Uint(int256 x) internal pure returns (uint256) { require(x >= 0); return uint256(x); } function Uint32(uint256 x) internal pure returns (uint32) { require(x <= type(uint32).max); return uint32(x); } function Uint64(uint256 x) internal pure returns (uint64) { require(x <= type(uint64).max); return uint64(x); } function Uint112(uint256 x) internal pure returns (uint112) { require(x <= type(uint112).max); return uint112(x); } function Uint96(uint256 x) internal pure returns (uint96) { require(x <= type(uint96).max); return uint96(x); } function Uint128(uint256 x) internal pure returns (uint128) { require(x <= type(uint128).max); return uint128(x); } function Uint192(uint256 x) internal pure returns (uint192) { require(x <= type(uint192).max); return uint192(x); } function isAApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) { return mulDown(b, ONE - eps) <= a && a <= mulDown(b, ONE + eps); } function isAGreaterApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) { return a >= b && a <= mulDown(b, ONE + eps); } function isASmallerApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) { return a <= b && a >= mulDown(b, ONE - eps); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; import "./PMath.sol"; import "./Errors.sol"; struct VeBalance { uint128 bias; uint128 slope; } struct LockedPosition { uint128 amount; uint128 expiry; } library VeBalanceLib { using PMath for uint256; uint128 internal constant MAX_LOCK_TIME = 104 weeks; uint256 internal constant USER_VOTE_MAX_WEIGHT = 10 ** 18; function add(VeBalance memory a, VeBalance memory b) internal pure returns (VeBalance memory res) { res.bias = a.bias + b.bias; res.slope = a.slope + b.slope; } function sub(VeBalance memory a, VeBalance memory b) internal pure returns (VeBalance memory res) { res.bias = a.bias - b.bias; res.slope = a.slope - b.slope; } function sub(VeBalance memory a, uint128 slope, uint128 expiry) internal pure returns (VeBalance memory res) { res.slope = a.slope - slope; res.bias = a.bias - slope * expiry; } function isExpired(VeBalance memory a) internal view returns (bool) { return a.slope * uint128(block.timestamp) >= a.bias; } function getCurrentValue(VeBalance memory a) internal view returns (uint128) { if (isExpired(a)) return 0; return getValueAt(a, uint128(block.timestamp)); } function getValueAt(VeBalance memory a, uint128 t) internal pure returns (uint128) { if (a.slope * t > a.bias) { return 0; } return a.bias - a.slope * t; } function getExpiry(VeBalance memory a) internal pure returns (uint128) { if (a.slope == 0) revert Errors.VEZeroSlope(a.bias, a.slope); return a.bias / a.slope; } function convertToVeBalance(LockedPosition memory position) internal pure returns (VeBalance memory res) { res.slope = position.amount / MAX_LOCK_TIME; res.bias = res.slope * position.expiry; } function convertToVeBalance(LockedPosition memory position, uint256 weight) internal pure returns (VeBalance memory res) { res.slope = ((position.amount * weight) / MAX_LOCK_TIME / USER_VOTE_MAX_WEIGHT).Uint128(); res.bias = res.slope * position.expiry; } function convertToVeBalance(uint128 amount, uint128 expiry) internal pure returns (uint128, uint128) { VeBalance memory balance = convertToVeBalance(LockedPosition(amount, expiry)); return (balance.bias, balance.slope); } }
// SPDX-License-Identifier: GPL-3.0-or-later // Forked from OpenZeppelin (v4.5.0) (utils/Checkpoints.sol) pragma solidity ^0.8.23; import { PMath } from "./PMath.sol"; import { VeBalanceLib, VeBalance } from "./VeBalanceLib.sol"; import { WeekMath } from "./WeekMath.sol"; struct Checkpoint { uint128 timestamp; VeBalance value; } library CheckpointHelper { function assignWith(Checkpoint memory a, Checkpoint memory b) internal pure { a.timestamp = b.timestamp; a.value = b.value; } } library Checkpoints { struct History { Checkpoint[] _checkpoints; } function length(History storage self) internal view returns (uint256) { return self._checkpoints.length; } function get(History storage self, uint256 index) internal view returns (Checkpoint memory) { return self._checkpoints[index]; } function push(History storage self, VeBalance memory value) internal { uint256 pos = self._checkpoints.length; if (pos > 0 && self._checkpoints[pos - 1].timestamp == WeekMath.getCurrentWeekStart()) { self._checkpoints[pos - 1].value = value; } else { self._checkpoints.push(Checkpoint({ timestamp: WeekMath.getCurrentWeekStart(), value: value })); } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; library WeekMath { uint128 internal constant WEEK = 7 days; function getWeekStartTimestamp(uint128 timestamp) internal pure returns (uint128) { return (timestamp / WEEK) * WEEK; } function getCurrentWeekStart() internal view returns (uint128) { return getWeekStartTimestamp(uint128(block.timestamp)); } function isValidWTime(uint256 time) internal pure returns (bool) { return time % WEEK == 0; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; import { IPVeToken } from "../interfaces/IVotingEscrow/IPVeToken.sol"; import { MiniHelpers } from "../libraries/MiniHelpers.sol"; import { VeBalanceLib, VeBalance, LockedPosition } from "../libraries/VeBalanceLib.sol"; import { WeekMath } from "../libraries/WeekMath.sol"; /** * @dev this contract is an abstract for its mainchain and sidechain variant * PRINCIPLE: * - All functions implemented in this contract should be either view or pure * to ensure that no writing logic is inherited by sidechain version * * - Mainchain version will handle the logic which are: * + Deposit, withdraw, increase lock, increase amount * + Mainchain logic will be ensured to have _totalSupply = linear sum of * all users' veBalance such that their locks are not yet expired * + Mainchain contract reserves 100% the right to write on sidechain * + No other transaction is allowed to write on sidechain storage */ abstract contract VotingEscrowTokenBase is IPVeToken { using VeBalanceLib for VeBalance; using VeBalanceLib for LockedPosition; uint128 public constant WEEK = 1 weeks; uint128 public constant MAX_LOCK_TIME = 104 weeks; uint128 public constant MIN_LOCK_TIME = 1 weeks; VeBalance internal _totalSupply; mapping(address => LockedPosition) public positionData; uint256[50] private __gap; constructor() {} function balanceOf(address user) public view virtual returns (uint128) { return positionData[user].convertToVeBalance().getCurrentValue(); } function totalSupplyStored() public view virtual returns (uint128) { return _totalSupply.getCurrentValue(); } function totalSupplyCurrent() public virtual returns (uint128); function _isPositionExpired(address user) internal view returns (bool) { return MiniHelpers.isCurrentlyExpired(positionData[user].expiry); } function totalSupplyAndBalanceCurrent(address user) external returns (uint128, uint128) { return (totalSupplyCurrent(), balanceOf(user)); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ArrayEmpty","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ChainNotSupported","type":"error"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"EnumerableMapNonexistentKey","type":"error"},{"inputs":[],"name":"EthTransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"ExpiryInThePast","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentFee","type":"uint256"},{"internalType":"uint256","name":"requiredFee","type":"uint256"}],"name":"InsufficientFeeToSendMsg","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"uint256","name":"wTime","type":"uint256"}],"name":"InvalidWTime","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"VEExceededMaxLockTime","type":"error"},{"inputs":[],"name":"VEInsufficientLockTime","type":"error"},{"inputs":[],"name":"VENotAllowedReduceExpiry","type":"error"},{"inputs":[],"name":"VEPositionNotExpired","type":"error"},{"inputs":[],"name":"VEZeroAmountLocked","type":"error"},{"inputs":[],"name":"VEZeroPosition","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gas","type":"uint256"}],"name":"ApproxDstExecutionGasUpdated","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint128","name":"bias","type":"uint128"},{"internalType":"uint128","name":"slope","type":"uint128"}],"indexed":false,"internalType":"struct VeBalance","name":"newTotalSupply","type":"tuple"},{"indexed":false,"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"BroadcastTotalSupply","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"BroadcastUserPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"DestinationContractAdded","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":"keeper","type":"address"},{"indexed":true,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"KeeperConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"expiry","type":"uint128"}],"name":"NewLockPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"feePaid","type":"uint256"}],"name":"UpdateRequestedFromVe","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"feePaid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"UpdateRequestedFromVeCrossChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"veChef","type":"address"}],"name":"VeChefSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cic","type":"address"}],"name":"cicSet","type":"event"},{"inputs":[],"name":"MAX_LOCK_TIME","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LOCK_TIME","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WEEK","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint256","name":"_chainId","type":"uint256"}],"name":"addDestinationContract","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"approxDstExecutionGas","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"broadcastTotalSupply","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"broadcastUserPosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"cic","outputs":[{"internalType":"contract IChefIncentivesController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"executionGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllDestinationContracts","outputs":[{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"},{"internalType":"address[]","name":"addrs","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"getBroadcastPositionFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"getBroadcastSupplyFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentWeekStart","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getUserHistoryAt","outputs":[{"components":[{"internalType":"uint128","name":"timestamp","type":"uint128"},{"components":[{"internalType":"uint128","name":"bias","type":"uint128"},{"internalType":"uint128","name":"slope","type":"uint128"}],"internalType":"struct VeBalance","name":"value","type":"tuple"}],"internalType":"struct Checkpoint","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserHistoryLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"additionalAmountToLock","type":"uint128"},{"internalType":"uint128","name":"newExpiry","type":"uint128"}],"name":"increaseLockPosition","outputs":[{"internalType":"uint128","name":"newVeBalance","type":"uint128"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint128","name":"additionalAmountToLock","type":"uint128"},{"internalType":"uint128","name":"newExpiry","type":"uint128"},{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"increaseLockPositionAndBroadcast","outputs":[{"internalType":"uint128","name":"newVeBalance","type":"uint128"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_protocolToken","type":"address"},{"internalType":"address","name":"_msgSendEndpoint","type":"address"},{"internalType":"uint256","name":"_approxDstExecutionGas","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSlopeChangeAppliedAt","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"msgSendEndpoint","outputs":[{"internalType":"contract IPMsgSendEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"positionData","outputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"expiry","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"gas","type":"uint256"}],"name":"setApproxDstExecutionGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IChefIncentivesController","name":"_cic","type":"address"}],"name":"setCIC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"uint256","name":"_executionGasLimit","type":"uint256"}],"name":"setKeeperConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setLastSlopeChangeAppliedAt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IChefIncentivesController","name":"_veChef","type":"address"}],"name":"setVeChef","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"","type":"uint128"}],"name":"slopeChanges","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"totalSupplyAndBalanceCurrent","outputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"","type":"uint128"}],"name":"totalSupplyAt","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyCurrent","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupplyStored","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"veChef","outputs":[{"internalType":"contract IChefIncentivesController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"uint128","name":"amount","type":"uint128"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001c6200002c565b620000266200002c565b620000e0565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156200007d5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000dd5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b612cb880620000f06000396000f3fe6080604052600436106102305760003560e01c8063947975d91161012e578063d88e92a9116100ab578063f4359ce51161006f578063f4359ce514610383578063fa78668f146106b4578063fb6a890f146106cc578063fc367c61146106ec578063fd00d9b21461070c57600080fd5b8063d88e92a914610609578063e139a48d1461063f578063e268b3a41461065f578063ef1c243a1461067f578063f2fde38b1461069457600080fd5b8063b92e106a116100f2578063b92e106a1461054f578063c8121ec214610562578063cb6b4f3c14610575578063cc471bb8146105d6578063d45f5e21146105e957600080fd5b8063947975d9146104ae57806398f3ca95146104e45780639c6f6203146104f95780639efc757514610519578063aced16611461052f57600080fd5b80633e39b650116101bc578063715018a611610180578063715018a6146103fa5780637c386c711461040f578063814b2cac1461043c5780638da5cb5b1461045c5780639406a93e1461049957600080fd5b80633e39b650146103605780633ff03207146103835780635ed434e61461039a5780635f4e2bc7146103ba57806370a08231146103da57600080fd5b8063210490281161020357806321049028146102c757806330d981af146102da57806339cb1f3e146103075780633b16c1261461032b5780633ccfd60b1461034b57600080fd5b80630b9efa221461023557806313036ed21461024a5780631794bb3c146102875780631a465fe1146102a7575b600080fd5b610248610243366004612655565b61072c565b005b34801561025657600080fd5b50606d5461026a906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561029357600080fd5b506102486102a23660046126aa565b610773565b3480156102b357600080fd5b50606b5461026a906001600160a01b031681565b6102486102d53660046126eb565b6108c8565b3480156102e657600080fd5b506102ef610922565b6040516001600160801b03909116815260200161027e565b34801561031357600080fd5b5061031d606e5481565b60405190815260200161027e565b34801561033757600080fd5b5061031d610346366004612717565b61093f565b34801561035757600080fd5b506102ef6109c6565b34801561036c57600080fd5b50610375610b28565b60405161027e929190612759565b34801561038f57600080fd5b506102ef62093a8081565b3480156103a657600080fd5b50606c5461026a906001600160a01b031681565b3480156103c657600080fd5b506102486103d53660046127dd565b610c2e565b3480156103e657600080fd5b506102ef6103f53660046127dd565b610cb2565b34801561040657600080fd5b50610248610d0b565b34801561041b57600080fd5b5061042f61042a3660046126eb565b610d1f565b60405161027e91906127fa565b34801561044857600080fd5b506070546102ef906001600160801b031681565b34801561046857600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031661026a565b3480156104a557600080fd5b506102ef610d50565b3480156104ba57600080fd5b506102ef6104c9366004612850565b6072602052600090815260409020546001600160801b031681565b3480156104f057600080fd5b50610248610d5f565b34801561050557600080fd5b506102486105143660046127dd565b610d91565b34801561052557600080fd5b5061031d60345481565b34801561053b57600080fd5b50606f5461026a906001600160a01b031681565b61024861055d366004612717565b610e0e565b6102ef61057036600461286b565b610e2e565b34801561058157600080fd5b506105b66105903660046127dd565b6001602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161027e565b6102ef6105e436600461289e565b61121c565b3480156105f557600080fd5b506102486106043660046128ff565b61124d565b34801561061557600080fd5b506102ef610624366004612850565b6071602052600090815260409020546001600160801b031681565b34801561064b57600080fd5b5061031d61065a366004612717565b61128a565b34801561066b57600080fd5b506105b661067a3660046127dd565b61134c565b34801561068b57600080fd5b506102ef611369565b3480156106a057600080fd5b506102486106af3660046127dd565b61139c565b3480156106c057600080fd5b506102ef6303bfc40081565b3480156106d857600080fd5b506102486106e73660046126eb565b6113da565b3480156106f857600080fd5b5061031d6107073660046127dd565b61145c565b34801561071857600080fd5b5060355461026a906001600160a01b031681565b6001600160a01b0383166107535760405163d92e233d60e01b815260040160405180910390fd5b61075e83838361147a565b471561076e5761076e33476116ba565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156107b95750825b905060008267ffffffffffffffff1660011480156107d65750303b155b9050811580156107e4575080155b156108025760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561082c57845460ff60401b1916600160401b1785555b6001600160a01b0388166108535760405163d92e233d60e01b815260040160405180910390fd5b606b80546001600160a01b0319166001600160a01b038a161790556108788787611751565b83156108be57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6108d0611782565b6108dc603682846117dd565b50604080518281526001600160a01b03841660208201527f877ba93ecbb9ffbb6703b2c680b4b134e86df5075e8e19b1e40db7b243cddc8b910160405180910390a15050565b60008061092d6117f3565b5090506109398161193a565b91505090565b6000805b828110156109bf576109ab84848381811061096057610960612918565b604080518082018252600080825260208281018290528351828152808201855294029590950135946109979450929091810161297e565b60405160208183030381529060405261195c565b6109b590836129dc565b9150600101610943565b5092915050565b6000336109d2816119e0565b6109ef576040516339ba104360e01b815260040160405180910390fd5b6001600160a01b0381166000908152600160205260408120546001600160801b03169250829003610a3357604051631e95654360e11b815260040160405180910390fd5b6001600160a01b03808216600090815260016020526040812055606b54610a659116826001600160801b038516611a11565b606c546001600160a01b031615610add57606c546040516348082da160e11b81526001600160a01b03838116600483015260006024830152909116906390105b4290604401600060405180830381600087803b158015610ac457600080fd5b505af1158015610ad8573d6000803e3d6000fd5b505050505b6040516001600160801b03831681526001600160a01b038216907f0e1bb0545c1ebb9fb680bde73514e572831de93b479c087ec1ef6c35c3a19fd69060200160405180910390a25090565b6060806000610b376036611a70565b90508067ffffffffffffffff811115610b5257610b526129ef565b604051908082528060200260200182016040528015610b7b578160200160208202803683370190505b5092508067ffffffffffffffff811115610b9757610b976129ef565b604051908082528060200260200182016040528015610bc0578160200160208202803683370190505b50915060005b81811015610c2857610bd9603682611a7b565b858381518110610beb57610beb612918565b60200260200101858481518110610c0457610c04612918565b6001600160a01b039093166020938402919091019092019190915252600101610bc6565b50509091565b610c36611782565b6001600160a01b038116610c5d5760405163d92e233d60e01b815260040160405180910390fd5b606d80546001600160a01b0319166001600160a01b0383169081179091556040519081527fbd027a3a5d1119abec461a0c6b37c09bfb209ebad862ee7825715f19d83f43a3906020015b60405180910390a150565b6001600160a01b03811660009081526001602090815260408083208151808301909252546001600160801b038082168352600160801b9091041691810191909152610d0590610d0090611a99565b61193a565b92915050565b610d13611782565b610d1d6000611aeb565b565b610d276125c1565b6001600160a01b0383166000908152607360205260409020610d499083611b5c565b9392505050565b6000610d5a611bd2565b905090565b610d67611782565b610d6f610d50565b607080546001600160801b0319166001600160801b0392909216919091179055565b610d99611782565b6001600160a01b038116610dc05760405163d92e233d60e01b815260040160405180910390fd5b606c80546001600160a01b0319166001600160a01b0383169081179091556040519081527f6f2cbcdac5a9171094f40ac4d7faa8eb8fffde4f88faf77b429b5e131a822b2d90602001610ca7565b610e1a6000838361147a565b4715610e2a57610e2a33476116ba565b5050565b600033610e436001600160801b038416611bdd565b610e7057604051637bf16ce960e11b81526001600160801b03841660048201526024015b60405180910390fd5b6001600160801b0383164210610ea45760405163d928003560e01b81526001600160801b0384166004820152602401610e67565b6001600160a01b0381166000908152600160205260409020546001600160801b03600160801b90910481169084161015610ef157604051631f8b0c5960e21b815260040160405180910390fd5b610eff6303bfc400426129dc565b836001600160801b03161115610f2857604051632739a01960e11b815260040160405180910390fd5b610f3562093a80426129dc565b836001600160801b03161015610f5e57604051630def6af560e21b815260040160405180910390fd5b6001600160a01b038116600090815260016020526040812054610f8a906001600160801b031686612a05565b9050806001600160801b0316600003610fb6576040516323fbc14f60e11b815260040160405180910390fd5b6001600160a01b038216600090815260016020526040812054610fe990600160801b90046001600160801b031686612a25565b90506001600160801b0386161561101b57606b5461101b906001600160a01b031684306001600160801b038a16611bf3565b611026838783611c32565b606c549094506001600160a01b0316156110bd57606c546001600160a01b03166390105b428461105581610cb2565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160801b03166024820152604401600060405180830381600087803b1580156110a457600080fd5b505af11580156110b8573d6000803e3d6000fd5b505050505b6000606e541180156110d95750606f546001600160a01b031615155b1561118157600060643a606e546110f09190612a45565b6110fb906050612a45565b6111059190612a72565b606f546040519192506000916001600160a01b039091169083908381818185875af1925050503d8060008114611157576040519150601f19603f3d011682016040523d82523d6000602084013e61115c565b606091505b505090508061117e57604051630db2c7f160e31b815260040160405180910390fd5b50505b826001600160a01b03167fe00d962aaacffce66f7cbbc35ae7329da97fa85a70b62b2bbea9cf250578a91360006040516111bd91815260200190565b60405180910390a2604080516001600160801b038085168252871660208201526001600160a01b038516917fb1a3371956c54dc1d83695b4a006b051c8313ee986e533b6b964e77c9066fc2c910160405180910390a250505092915050565b60006112288585610e2e565b905061123533848461072c565b47156112455761124533476116ba565b949350505050565b611255611782565b60348190556040518181527fd264acab81800cce6ee5a934aad5cafd89c988da2b259df39e16c1a2126272fa90602001610ca7565b6000805b828110156109bf576113388484838181106112ab576112ab612918565b905060200201356000604051806040016040528060006001600160801b0316815260200160006001600160801b03168152506000604051806040016040528060006001600160801b0316815260200160006001600160801b0316815250604051602001611319929190612a86565b60408051601f198184030181529082905261099793929160200161297e565b61134290836129dc565b915060010161128e565b600080611357610922565b61136084610cb2565b91509150915091565b60408051808201909152600080546001600160801b038082168452600160801b90910416602083015290610d5a9061193a565b6113a4611782565b6001600160a01b0381166113ce57604051631e4fbdf760e01b815260006004820152602401610e67565b6113d781611aeb565b50565b6113e2611782565b6001600160a01b0382166114095760405163d92e233d60e01b815260040160405180910390fd5b606f80546001600160a01b0319166001600160a01b038416908117909155606e8290556040518291907f544a7242fc597c067db41a92139a26290a56cd7b278e265c9c2b788055cb339b90600090a35050565b6001600160a01b038116600090815260736020526040812054610d05565b600081900361149c57604051633c4d929d60e21b815260040160405180910390fd5b60006114a66117f3565b50905060006001600160a01b03851615611511576001600160a01b03851660008181526001602090815260409182902082519182019390935291546001600160801b03811691830191909152608090811c606083015201604051602081830303815290604052611521565b6040805160008152602081019091525b905060005b838110156116245761155a85858381811061154357611543612918565b905060200201356036611e3290919063ffffffff16565b6115935784848281811061157057611570612918565b9050602002013560405163264e42cf60e01b8152600401610e6791815260200190565b6115b78585838181106115a8576115a8612918565b90506020020135428585611e3e565b856001600160a01b03167f9ad3c380be19d7daf4b32de18f2b34efa3be521430247691139be84ad368d43a60008787858181106115f6576115f6612918565b90506020020135604051611614929190918252602082015260400190565b60405180910390a2600101611526565b506001600160a01b0385161561167857846001600160a01b03167f82e92e1b0568d98f095fc0c76ccb0f2ac5b64534f69a2c706281e223b6477683858560405161166f929190612aeb565b60405180910390a25b7f5f9e7cb1ed2eca254f75b6e350699887aa8597e3a2ec9e0aa2b3504c211facbd8285856040516116ab93929190612aff565b60405180910390a15050505050565b804710156116dd5760405163cd78605960e01b8152306004820152602401610e67565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461172a576040519150601f19603f3d011682016040523d82523d6000602084013e61172f565b606091505b505090508061076e57604051630a12f52160e11b815260040160405180910390fd5b611759611e6b565b603580546001600160a01b0319166001600160a01b0384161790556034819055610e2a33611eb4565b336117b47f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610d1d5760405163118cdaa760e01b8152336004820152602401610e67565b600061124584846001600160a01b038516611ec5565b604080518082019091526000808252602082015260408051808201909152600080546001600160801b038082168452600160801b909104811660208401526070549192911682611841611bd2565b9050806001600160801b0316826001600160801b031610611866575090939092509050565b806001600160801b0316826001600160801b031610156118f75761188d62093a8083612a05565b6001600160801b038082166000908152607160205260409020549193506118b79185911684611ee2565b92506118c38383611f3c565b6001600160801b03838116600090815260726020526040902080546001600160801b03191692909116919091179055611866565b50815160208301516001600160801b03918216600160801b9183169190910217600055607080546001600160801b03191691831691909117905590939092509050565b600061194582611f8f565b1561195257506000919050565b610d058242611f3c565b6035546000906001600160a01b03166384fe172161197b603686611fc0565b85856034546040518563ffffffff1660e01b815260040161199f9493929190612b36565b602060405180830381865afa1580156119bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d499190612b6e565b6001600160a01b038116600090815260016020526040812054600160801b90046001600160801b0316421015610d05565b6040516001600160a01b0383811660248301526044820183905261076e91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611fcc565b6000610d058261202f565b6000808080611a8a868661203a565b909450925050505b9250929050565b60408051808201909152600080825260208201528151611abe906303bfc40090612b87565b6001600160801b03166020808301829052830151611adb91612bad565b6001600160801b03168152919050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b611b646125c1565b826000018281548110611b7957611b79612918565b6000918252602091829020604080518082018252600290930290910180546001600160801b03908116845282518084019093526001909101548082168352600160801b9004168184015291810191909152905092915050565b6000610d5a42612065565b6000611bec62093a8083612bd8565b1592915050565b6040516001600160a01b038481166024830152838116604483015260648201839052611c2c9186918216906323b872dd90608401611a3e565b50505050565b6001600160a01b03831660009081526001602090815260408083208151808301909252546001600160801b038082168352600160801b909104169181019190915281611c7c6117f3565b509050611c9682602001516001600160801b031642101590565b611d10576000611ca583611a99565b9050611cb1828261207f565b602080830151858201516001600160801b03908116600090815260719093526040832080549496509193919291611cea91859116612a25565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b60006040518060400160405280878560000151611d2d9190612a05565b6001600160801b03168152602001868560200151611d4b9190612a05565b6001600160801b0316905290506000611d6382611a99565b9050611d6f83826120d4565b602080830151848201516001600160801b03908116600090815260719093526040832080549497509193919291611da891859116612a05565b82546101009290920a6001600160801b038181021990931691831602179091558451602080870151918316600160801b92841683021760009081556001600160a01b038d1681526001825260408082208851898501519087169616909402949094179092556073905220611e1d915082612115565b611e268161193a565b98975050505050505050565b6000610d498383612242565b611c2c84848484604051602001611e5793929190612bec565b60405160208183030381529060405261224e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610d1d57604051631afcd79f60e31b815260040160405180910390fd5b611ebc611e6b565b6113d78161238f565b600082815260028401602052604081208290556112458484612397565b6040805180820190915260008082526020820152828460200151611f069190612a25565b6001600160801b03166020820152611f1e8284612bad565b8451611f2a9190612a25565b6001600160801b031681529392505050565b600082600001516001600160801b0316828460200151611f5c9190612bad565b6001600160801b03161115611f7357506000610d05565b818360200151611f839190612bad565b8351610d499190612a25565b600081600001516001600160801b0316428360200151611faf9190612bad565b6001600160801b0316101592915050565b6000610d4983836123a3565b6000611fe16001600160a01b038416836123ea565b905080516000141580156120065750808060200190518101906120049190612c1b565b155b1561076e57604051635274afe760e01b81526001600160a01b0384166004820152602401610e67565b6000610d05826123f8565b600080806120488585612402565b600081815260029690960160205260409095205494959350505050565b600062093a806120758184612b87565b610d059190612bad565b6040805180820190915260008082526020820152815183516120a19190612a25565b6001600160801b03168152602080830151908401516120c09190612a25565b6001600160801b0316602082015292915050565b6040805180820190915260008082526020820152815183516120f69190612a05565b6001600160801b03168152602080830151908401516120c09190612a05565b8154801580159061216a5750612129611bd2565b6001600160801b03168361213e600184612c3d565b8154811061214e5761214e612918565b60009182526020909120600290910201546001600160801b0316145b156121c957818361217c600184612c3d565b8154811061218c5761218c612918565b6000918252602091829020835193909201516001600160801b03908116600160801b02931692909217600160029093029091019190910155505050565b8260000160405180604001604052806121e0611bd2565b6001600160801b0390811682526020918201869052835460018181018655600095865294839020845160029092020180549183166001600160801b03199092169190911781559282015180519201518116600160801b02911617910155505050565b6000610d49838361240e565b612259603683611e32565b61226557612265612c50565b6000612272603684611fc0565b6034546035546040516384fe172160e01b815292935090916000916001600160a01b0316906384fe1721906122b1908690899089908890600401612b36565b602060405180830381865afa1580156122ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122f29190612b6e565b90508047101561231e5760405163704c5be560e11b815247600482015260248101829052604401610e67565b60355460405163b2267a7b60e01b81526001600160a01b039091169063b2267a7b9083906123569087908a908a908990600401612b36565b6000604051808303818588803b15801561236f57600080fd5b505af1158015612383573d6000803e3d6000fd5b50505050505050505050565b6113a4611e6b565b6000610d498383612426565b6000818152600283016020526040812054801580156123c957506123c78484612242565b155b15610d495760405163015ab34360e11b815260048101849052602401610e67565b6060610d4983836000612475565b6000610d05825490565b6000610d498383612512565b60008181526001830160205260408120541515610d49565b600081815260018301602052604081205461246d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610d05565b506000610d05565b60608147101561249a5760405163cd78605960e01b8152306004820152602401610e67565b600080856001600160a01b031684866040516124b69190612c66565b60006040518083038185875af1925050503d80600081146124f3576040519150601f19603f3d011682016040523d82523d6000602084013e6124f8565b606091505b509150915061250886838361253c565b9695505050505050565b600082600001828154811061252957612529612918565b9060005260206000200154905092915050565b6060826125515761254c82612598565b610d49565b815115801561256857506001600160a01b0384163b155b1561259157604051639996b31560e01b81526001600160a01b0385166004820152602401610e67565b5080610d49565b8051156125a85780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b604051806040016040528060006001600160801b031681526020016125f6604080518082019091526000808252602082015290565b905290565b6001600160a01b03811681146113d757600080fd5b60008083601f84011261262257600080fd5b50813567ffffffffffffffff81111561263a57600080fd5b6020830191508360208260051b8501011115611a9257600080fd5b60008060006040848603121561266a57600080fd5b8335612675816125fb565b9250602084013567ffffffffffffffff81111561269157600080fd5b61269d86828701612610565b9497909650939450505050565b6000806000606084860312156126bf57600080fd5b83356126ca816125fb565b925060208401356126da816125fb565b929592945050506040919091013590565b600080604083850312156126fe57600080fd5b8235612709816125fb565b946020939093013593505050565b6000806020838503121561272a57600080fd5b823567ffffffffffffffff81111561274157600080fd5b61274d85828601612610565b90969095509350505050565b604080825283519082018190526000906020906060840190828701845b8281101561279257815184529284019290840190600101612776565b5050508381038285015284518082528583019183019060005b818110156127d05783516001600160a01b0316835292840192918401916001016127ab565b5090979650505050505050565b6000602082840312156127ef57600080fd5b8135610d49816125fb565b81516001600160801b0316815260208083015160608301916109bf9084018280516001600160801b03908116835260209182015116910152565b80356001600160801b038116811461284b57600080fd5b919050565b60006020828403121561286257600080fd5b610d4982612834565b6000806040838503121561287e57600080fd5b61288783612834565b915061289560208401612834565b90509250929050565b600080600080606085870312156128b457600080fd5b6128bd85612834565b93506128cb60208601612834565b9250604085013567ffffffffffffffff8111156128e757600080fd5b6128f387828801612610565b95989497509550505050565b60006020828403121561291157600080fd5b5035919050565b634e487b7160e01b600052603260045260246000fd5b60005b83811015612949578181015183820152602001612931565b50506000910152565b6000815180845261296a81602086016020860161292e565b601f01601f19169290920160200192915050565b60ff841681526129a7602082018480516001600160801b03908116835260209182015116910152565b6080606082015260006129bd6080830184612952565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610d0557610d056129c6565b634e487b7160e01b600052604160045260246000fd5b6001600160801b038181168382160190808211156109bf576109bf6129c6565b6001600160801b038281168282160390808211156109bf576109bf6129c6565b8082028115828204841417610d0557610d056129c6565b634e487b7160e01b600052601260045260246000fd5b600082612a8157612a81612a5c565b500490565b6001600160a01b038316815260608101610d49602083018480516001600160801b03908116835260209182015116910152565b81835260006001600160fb1b03831115612ad257600080fd5b8260051b80836020870137939093016020019392505050565b602081526000611245602083018486612ab9565b612b1f818580516001600160801b03908116835260209182015116910152565b6060604082015260006129bd606083018486612ab9565b60018060a01b0385168152836020820152608060408201526000612b5d6080830185612952565b905082606083015295945050505050565b600060208284031215612b8057600080fd5b5051919050565b60006001600160801b0380841680612ba157612ba1612a5c565b92169190910492915050565b6001600160801b03818116838216028082169190828114612bd057612bd06129c6565b505092915050565b600082612be757612be7612a5c565b500690565b6001600160801b03841681526129a7602082018480516001600160801b03908116835260209182015116910152565b600060208284031215612c2d57600080fd5b81518015158114610d4957600080fd5b81810381811115610d0557610d056129c6565b634e487b7160e01b600052600160045260246000fd5b60008251612c7881846020870161292e565b919091019291505056fea26469706673582212201029725bcf30151b95d4bc46117989392312a3015db9b868c799264598ca099a64736f6c63430008170033
Deployed Bytecode
0x6080604052600436106102305760003560e01c8063947975d91161012e578063d88e92a9116100ab578063f4359ce51161006f578063f4359ce514610383578063fa78668f146106b4578063fb6a890f146106cc578063fc367c61146106ec578063fd00d9b21461070c57600080fd5b8063d88e92a914610609578063e139a48d1461063f578063e268b3a41461065f578063ef1c243a1461067f578063f2fde38b1461069457600080fd5b8063b92e106a116100f2578063b92e106a1461054f578063c8121ec214610562578063cb6b4f3c14610575578063cc471bb8146105d6578063d45f5e21146105e957600080fd5b8063947975d9146104ae57806398f3ca95146104e45780639c6f6203146104f95780639efc757514610519578063aced16611461052f57600080fd5b80633e39b650116101bc578063715018a611610180578063715018a6146103fa5780637c386c711461040f578063814b2cac1461043c5780638da5cb5b1461045c5780639406a93e1461049957600080fd5b80633e39b650146103605780633ff03207146103835780635ed434e61461039a5780635f4e2bc7146103ba57806370a08231146103da57600080fd5b8063210490281161020357806321049028146102c757806330d981af146102da57806339cb1f3e146103075780633b16c1261461032b5780633ccfd60b1461034b57600080fd5b80630b9efa221461023557806313036ed21461024a5780631794bb3c146102875780631a465fe1146102a7575b600080fd5b610248610243366004612655565b61072c565b005b34801561025657600080fd5b50606d5461026a906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561029357600080fd5b506102486102a23660046126aa565b610773565b3480156102b357600080fd5b50606b5461026a906001600160a01b031681565b6102486102d53660046126eb565b6108c8565b3480156102e657600080fd5b506102ef610922565b6040516001600160801b03909116815260200161027e565b34801561031357600080fd5b5061031d606e5481565b60405190815260200161027e565b34801561033757600080fd5b5061031d610346366004612717565b61093f565b34801561035757600080fd5b506102ef6109c6565b34801561036c57600080fd5b50610375610b28565b60405161027e929190612759565b34801561038f57600080fd5b506102ef62093a8081565b3480156103a657600080fd5b50606c5461026a906001600160a01b031681565b3480156103c657600080fd5b506102486103d53660046127dd565b610c2e565b3480156103e657600080fd5b506102ef6103f53660046127dd565b610cb2565b34801561040657600080fd5b50610248610d0b565b34801561041b57600080fd5b5061042f61042a3660046126eb565b610d1f565b60405161027e91906127fa565b34801561044857600080fd5b506070546102ef906001600160801b031681565b34801561046857600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031661026a565b3480156104a557600080fd5b506102ef610d50565b3480156104ba57600080fd5b506102ef6104c9366004612850565b6072602052600090815260409020546001600160801b031681565b3480156104f057600080fd5b50610248610d5f565b34801561050557600080fd5b506102486105143660046127dd565b610d91565b34801561052557600080fd5b5061031d60345481565b34801561053b57600080fd5b50606f5461026a906001600160a01b031681565b61024861055d366004612717565b610e0e565b6102ef61057036600461286b565b610e2e565b34801561058157600080fd5b506105b66105903660046127dd565b6001602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161027e565b6102ef6105e436600461289e565b61121c565b3480156105f557600080fd5b506102486106043660046128ff565b61124d565b34801561061557600080fd5b506102ef610624366004612850565b6071602052600090815260409020546001600160801b031681565b34801561064b57600080fd5b5061031d61065a366004612717565b61128a565b34801561066b57600080fd5b506105b661067a3660046127dd565b61134c565b34801561068b57600080fd5b506102ef611369565b3480156106a057600080fd5b506102486106af3660046127dd565b61139c565b3480156106c057600080fd5b506102ef6303bfc40081565b3480156106d857600080fd5b506102486106e73660046126eb565b6113da565b3480156106f857600080fd5b5061031d6107073660046127dd565b61145c565b34801561071857600080fd5b5060355461026a906001600160a01b031681565b6001600160a01b0383166107535760405163d92e233d60e01b815260040160405180910390fd5b61075e83838361147a565b471561076e5761076e33476116ba565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156107b95750825b905060008267ffffffffffffffff1660011480156107d65750303b155b9050811580156107e4575080155b156108025760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561082c57845460ff60401b1916600160401b1785555b6001600160a01b0388166108535760405163d92e233d60e01b815260040160405180910390fd5b606b80546001600160a01b0319166001600160a01b038a161790556108788787611751565b83156108be57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6108d0611782565b6108dc603682846117dd565b50604080518281526001600160a01b03841660208201527f877ba93ecbb9ffbb6703b2c680b4b134e86df5075e8e19b1e40db7b243cddc8b910160405180910390a15050565b60008061092d6117f3565b5090506109398161193a565b91505090565b6000805b828110156109bf576109ab84848381811061096057610960612918565b604080518082018252600080825260208281018290528351828152808201855294029590950135946109979450929091810161297e565b60405160208183030381529060405261195c565b6109b590836129dc565b9150600101610943565b5092915050565b6000336109d2816119e0565b6109ef576040516339ba104360e01b815260040160405180910390fd5b6001600160a01b0381166000908152600160205260408120546001600160801b03169250829003610a3357604051631e95654360e11b815260040160405180910390fd5b6001600160a01b03808216600090815260016020526040812055606b54610a659116826001600160801b038516611a11565b606c546001600160a01b031615610add57606c546040516348082da160e11b81526001600160a01b03838116600483015260006024830152909116906390105b4290604401600060405180830381600087803b158015610ac457600080fd5b505af1158015610ad8573d6000803e3d6000fd5b505050505b6040516001600160801b03831681526001600160a01b038216907f0e1bb0545c1ebb9fb680bde73514e572831de93b479c087ec1ef6c35c3a19fd69060200160405180910390a25090565b6060806000610b376036611a70565b90508067ffffffffffffffff811115610b5257610b526129ef565b604051908082528060200260200182016040528015610b7b578160200160208202803683370190505b5092508067ffffffffffffffff811115610b9757610b976129ef565b604051908082528060200260200182016040528015610bc0578160200160208202803683370190505b50915060005b81811015610c2857610bd9603682611a7b565b858381518110610beb57610beb612918565b60200260200101858481518110610c0457610c04612918565b6001600160a01b039093166020938402919091019092019190915252600101610bc6565b50509091565b610c36611782565b6001600160a01b038116610c5d5760405163d92e233d60e01b815260040160405180910390fd5b606d80546001600160a01b0319166001600160a01b0383169081179091556040519081527fbd027a3a5d1119abec461a0c6b37c09bfb209ebad862ee7825715f19d83f43a3906020015b60405180910390a150565b6001600160a01b03811660009081526001602090815260408083208151808301909252546001600160801b038082168352600160801b9091041691810191909152610d0590610d0090611a99565b61193a565b92915050565b610d13611782565b610d1d6000611aeb565b565b610d276125c1565b6001600160a01b0383166000908152607360205260409020610d499083611b5c565b9392505050565b6000610d5a611bd2565b905090565b610d67611782565b610d6f610d50565b607080546001600160801b0319166001600160801b0392909216919091179055565b610d99611782565b6001600160a01b038116610dc05760405163d92e233d60e01b815260040160405180910390fd5b606c80546001600160a01b0319166001600160a01b0383169081179091556040519081527f6f2cbcdac5a9171094f40ac4d7faa8eb8fffde4f88faf77b429b5e131a822b2d90602001610ca7565b610e1a6000838361147a565b4715610e2a57610e2a33476116ba565b5050565b600033610e436001600160801b038416611bdd565b610e7057604051637bf16ce960e11b81526001600160801b03841660048201526024015b60405180910390fd5b6001600160801b0383164210610ea45760405163d928003560e01b81526001600160801b0384166004820152602401610e67565b6001600160a01b0381166000908152600160205260409020546001600160801b03600160801b90910481169084161015610ef157604051631f8b0c5960e21b815260040160405180910390fd5b610eff6303bfc400426129dc565b836001600160801b03161115610f2857604051632739a01960e11b815260040160405180910390fd5b610f3562093a80426129dc565b836001600160801b03161015610f5e57604051630def6af560e21b815260040160405180910390fd5b6001600160a01b038116600090815260016020526040812054610f8a906001600160801b031686612a05565b9050806001600160801b0316600003610fb6576040516323fbc14f60e11b815260040160405180910390fd5b6001600160a01b038216600090815260016020526040812054610fe990600160801b90046001600160801b031686612a25565b90506001600160801b0386161561101b57606b5461101b906001600160a01b031684306001600160801b038a16611bf3565b611026838783611c32565b606c549094506001600160a01b0316156110bd57606c546001600160a01b03166390105b428461105581610cb2565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526001600160801b03166024820152604401600060405180830381600087803b1580156110a457600080fd5b505af11580156110b8573d6000803e3d6000fd5b505050505b6000606e541180156110d95750606f546001600160a01b031615155b1561118157600060643a606e546110f09190612a45565b6110fb906050612a45565b6111059190612a72565b606f546040519192506000916001600160a01b039091169083908381818185875af1925050503d8060008114611157576040519150601f19603f3d011682016040523d82523d6000602084013e61115c565b606091505b505090508061117e57604051630db2c7f160e31b815260040160405180910390fd5b50505b826001600160a01b03167fe00d962aaacffce66f7cbbc35ae7329da97fa85a70b62b2bbea9cf250578a91360006040516111bd91815260200190565b60405180910390a2604080516001600160801b038085168252871660208201526001600160a01b038516917fb1a3371956c54dc1d83695b4a006b051c8313ee986e533b6b964e77c9066fc2c910160405180910390a250505092915050565b60006112288585610e2e565b905061123533848461072c565b47156112455761124533476116ba565b949350505050565b611255611782565b60348190556040518181527fd264acab81800cce6ee5a934aad5cafd89c988da2b259df39e16c1a2126272fa90602001610ca7565b6000805b828110156109bf576113388484838181106112ab576112ab612918565b905060200201356000604051806040016040528060006001600160801b0316815260200160006001600160801b03168152506000604051806040016040528060006001600160801b0316815260200160006001600160801b0316815250604051602001611319929190612a86565b60408051601f198184030181529082905261099793929160200161297e565b61134290836129dc565b915060010161128e565b600080611357610922565b61136084610cb2565b91509150915091565b60408051808201909152600080546001600160801b038082168452600160801b90910416602083015290610d5a9061193a565b6113a4611782565b6001600160a01b0381166113ce57604051631e4fbdf760e01b815260006004820152602401610e67565b6113d781611aeb565b50565b6113e2611782565b6001600160a01b0382166114095760405163d92e233d60e01b815260040160405180910390fd5b606f80546001600160a01b0319166001600160a01b038416908117909155606e8290556040518291907f544a7242fc597c067db41a92139a26290a56cd7b278e265c9c2b788055cb339b90600090a35050565b6001600160a01b038116600090815260736020526040812054610d05565b600081900361149c57604051633c4d929d60e21b815260040160405180910390fd5b60006114a66117f3565b50905060006001600160a01b03851615611511576001600160a01b03851660008181526001602090815260409182902082519182019390935291546001600160801b03811691830191909152608090811c606083015201604051602081830303815290604052611521565b6040805160008152602081019091525b905060005b838110156116245761155a85858381811061154357611543612918565b905060200201356036611e3290919063ffffffff16565b6115935784848281811061157057611570612918565b9050602002013560405163264e42cf60e01b8152600401610e6791815260200190565b6115b78585838181106115a8576115a8612918565b90506020020135428585611e3e565b856001600160a01b03167f9ad3c380be19d7daf4b32de18f2b34efa3be521430247691139be84ad368d43a60008787858181106115f6576115f6612918565b90506020020135604051611614929190918252602082015260400190565b60405180910390a2600101611526565b506001600160a01b0385161561167857846001600160a01b03167f82e92e1b0568d98f095fc0c76ccb0f2ac5b64534f69a2c706281e223b6477683858560405161166f929190612aeb565b60405180910390a25b7f5f9e7cb1ed2eca254f75b6e350699887aa8597e3a2ec9e0aa2b3504c211facbd8285856040516116ab93929190612aff565b60405180910390a15050505050565b804710156116dd5760405163cd78605960e01b8152306004820152602401610e67565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461172a576040519150601f19603f3d011682016040523d82523d6000602084013e61172f565b606091505b505090508061076e57604051630a12f52160e11b815260040160405180910390fd5b611759611e6b565b603580546001600160a01b0319166001600160a01b0384161790556034819055610e2a33611eb4565b336117b47f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610d1d5760405163118cdaa760e01b8152336004820152602401610e67565b600061124584846001600160a01b038516611ec5565b604080518082019091526000808252602082015260408051808201909152600080546001600160801b038082168452600160801b909104811660208401526070549192911682611841611bd2565b9050806001600160801b0316826001600160801b031610611866575090939092509050565b806001600160801b0316826001600160801b031610156118f75761188d62093a8083612a05565b6001600160801b038082166000908152607160205260409020549193506118b79185911684611ee2565b92506118c38383611f3c565b6001600160801b03838116600090815260726020526040902080546001600160801b03191692909116919091179055611866565b50815160208301516001600160801b03918216600160801b9183169190910217600055607080546001600160801b03191691831691909117905590939092509050565b600061194582611f8f565b1561195257506000919050565b610d058242611f3c565b6035546000906001600160a01b03166384fe172161197b603686611fc0565b85856034546040518563ffffffff1660e01b815260040161199f9493929190612b36565b602060405180830381865afa1580156119bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d499190612b6e565b6001600160a01b038116600090815260016020526040812054600160801b90046001600160801b0316421015610d05565b6040516001600160a01b0383811660248301526044820183905261076e91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611fcc565b6000610d058261202f565b6000808080611a8a868661203a565b909450925050505b9250929050565b60408051808201909152600080825260208201528151611abe906303bfc40090612b87565b6001600160801b03166020808301829052830151611adb91612bad565b6001600160801b03168152919050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b611b646125c1565b826000018281548110611b7957611b79612918565b6000918252602091829020604080518082018252600290930290910180546001600160801b03908116845282518084019093526001909101548082168352600160801b9004168184015291810191909152905092915050565b6000610d5a42612065565b6000611bec62093a8083612bd8565b1592915050565b6040516001600160a01b038481166024830152838116604483015260648201839052611c2c9186918216906323b872dd90608401611a3e565b50505050565b6001600160a01b03831660009081526001602090815260408083208151808301909252546001600160801b038082168352600160801b909104169181019190915281611c7c6117f3565b509050611c9682602001516001600160801b031642101590565b611d10576000611ca583611a99565b9050611cb1828261207f565b602080830151858201516001600160801b03908116600090815260719093526040832080549496509193919291611cea91859116612a25565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b60006040518060400160405280878560000151611d2d9190612a05565b6001600160801b03168152602001868560200151611d4b9190612a05565b6001600160801b0316905290506000611d6382611a99565b9050611d6f83826120d4565b602080830151848201516001600160801b03908116600090815260719093526040832080549497509193919291611da891859116612a05565b82546101009290920a6001600160801b038181021990931691831602179091558451602080870151918316600160801b92841683021760009081556001600160a01b038d1681526001825260408082208851898501519087169616909402949094179092556073905220611e1d915082612115565b611e268161193a565b98975050505050505050565b6000610d498383612242565b611c2c84848484604051602001611e5793929190612bec565b60405160208183030381529060405261224e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610d1d57604051631afcd79f60e31b815260040160405180910390fd5b611ebc611e6b565b6113d78161238f565b600082815260028401602052604081208290556112458484612397565b6040805180820190915260008082526020820152828460200151611f069190612a25565b6001600160801b03166020820152611f1e8284612bad565b8451611f2a9190612a25565b6001600160801b031681529392505050565b600082600001516001600160801b0316828460200151611f5c9190612bad565b6001600160801b03161115611f7357506000610d05565b818360200151611f839190612bad565b8351610d499190612a25565b600081600001516001600160801b0316428360200151611faf9190612bad565b6001600160801b0316101592915050565b6000610d4983836123a3565b6000611fe16001600160a01b038416836123ea565b905080516000141580156120065750808060200190518101906120049190612c1b565b155b1561076e57604051635274afe760e01b81526001600160a01b0384166004820152602401610e67565b6000610d05826123f8565b600080806120488585612402565b600081815260029690960160205260409095205494959350505050565b600062093a806120758184612b87565b610d059190612bad565b6040805180820190915260008082526020820152815183516120a19190612a25565b6001600160801b03168152602080830151908401516120c09190612a25565b6001600160801b0316602082015292915050565b6040805180820190915260008082526020820152815183516120f69190612a05565b6001600160801b03168152602080830151908401516120c09190612a05565b8154801580159061216a5750612129611bd2565b6001600160801b03168361213e600184612c3d565b8154811061214e5761214e612918565b60009182526020909120600290910201546001600160801b0316145b156121c957818361217c600184612c3d565b8154811061218c5761218c612918565b6000918252602091829020835193909201516001600160801b03908116600160801b02931692909217600160029093029091019190910155505050565b8260000160405180604001604052806121e0611bd2565b6001600160801b0390811682526020918201869052835460018181018655600095865294839020845160029092020180549183166001600160801b03199092169190911781559282015180519201518116600160801b02911617910155505050565b6000610d49838361240e565b612259603683611e32565b61226557612265612c50565b6000612272603684611fc0565b6034546035546040516384fe172160e01b815292935090916000916001600160a01b0316906384fe1721906122b1908690899089908890600401612b36565b602060405180830381865afa1580156122ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122f29190612b6e565b90508047101561231e5760405163704c5be560e11b815247600482015260248101829052604401610e67565b60355460405163b2267a7b60e01b81526001600160a01b039091169063b2267a7b9083906123569087908a908a908990600401612b36565b6000604051808303818588803b15801561236f57600080fd5b505af1158015612383573d6000803e3d6000fd5b50505050505050505050565b6113a4611e6b565b6000610d498383612426565b6000818152600283016020526040812054801580156123c957506123c78484612242565b155b15610d495760405163015ab34360e11b815260048101849052602401610e67565b6060610d4983836000612475565b6000610d05825490565b6000610d498383612512565b60008181526001830160205260408120541515610d49565b600081815260018301602052604081205461246d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610d05565b506000610d05565b60608147101561249a5760405163cd78605960e01b8152306004820152602401610e67565b600080856001600160a01b031684866040516124b69190612c66565b60006040518083038185875af1925050503d80600081146124f3576040519150601f19603f3d011682016040523d82523d6000602084013e6124f8565b606091505b509150915061250886838361253c565b9695505050505050565b600082600001828154811061252957612529612918565b9060005260206000200154905092915050565b6060826125515761254c82612598565b610d49565b815115801561256857506001600160a01b0384163b155b1561259157604051639996b31560e01b81526001600160a01b0385166004820152602401610e67565b5080610d49565b8051156125a85780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b604051806040016040528060006001600160801b031681526020016125f6604080518082019091526000808252602082015290565b905290565b6001600160a01b03811681146113d757600080fd5b60008083601f84011261262257600080fd5b50813567ffffffffffffffff81111561263a57600080fd5b6020830191508360208260051b8501011115611a9257600080fd5b60008060006040848603121561266a57600080fd5b8335612675816125fb565b9250602084013567ffffffffffffffff81111561269157600080fd5b61269d86828701612610565b9497909650939450505050565b6000806000606084860312156126bf57600080fd5b83356126ca816125fb565b925060208401356126da816125fb565b929592945050506040919091013590565b600080604083850312156126fe57600080fd5b8235612709816125fb565b946020939093013593505050565b6000806020838503121561272a57600080fd5b823567ffffffffffffffff81111561274157600080fd5b61274d85828601612610565b90969095509350505050565b604080825283519082018190526000906020906060840190828701845b8281101561279257815184529284019290840190600101612776565b5050508381038285015284518082528583019183019060005b818110156127d05783516001600160a01b0316835292840192918401916001016127ab565b5090979650505050505050565b6000602082840312156127ef57600080fd5b8135610d49816125fb565b81516001600160801b0316815260208083015160608301916109bf9084018280516001600160801b03908116835260209182015116910152565b80356001600160801b038116811461284b57600080fd5b919050565b60006020828403121561286257600080fd5b610d4982612834565b6000806040838503121561287e57600080fd5b61288783612834565b915061289560208401612834565b90509250929050565b600080600080606085870312156128b457600080fd5b6128bd85612834565b93506128cb60208601612834565b9250604085013567ffffffffffffffff8111156128e757600080fd5b6128f387828801612610565b95989497509550505050565b60006020828403121561291157600080fd5b5035919050565b634e487b7160e01b600052603260045260246000fd5b60005b83811015612949578181015183820152602001612931565b50506000910152565b6000815180845261296a81602086016020860161292e565b601f01601f19169290920160200192915050565b60ff841681526129a7602082018480516001600160801b03908116835260209182015116910152565b6080606082015260006129bd6080830184612952565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610d0557610d056129c6565b634e487b7160e01b600052604160045260246000fd5b6001600160801b038181168382160190808211156109bf576109bf6129c6565b6001600160801b038281168282160390808211156109bf576109bf6129c6565b8082028115828204841417610d0557610d056129c6565b634e487b7160e01b600052601260045260246000fd5b600082612a8157612a81612a5c565b500490565b6001600160a01b038316815260608101610d49602083018480516001600160801b03908116835260209182015116910152565b81835260006001600160fb1b03831115612ad257600080fd5b8260051b80836020870137939093016020019392505050565b602081526000611245602083018486612ab9565b612b1f818580516001600160801b03908116835260209182015116910152565b6060604082015260006129bd606083018486612ab9565b60018060a01b0385168152836020820152608060408201526000612b5d6080830185612952565b905082606083015295945050505050565b600060208284031215612b8057600080fd5b5051919050565b60006001600160801b0380841680612ba157612ba1612a5c565b92169190910492915050565b6001600160801b03818116838216028082169190828114612bd057612bd06129c6565b505092915050565b600082612be757612be7612a5c565b500690565b6001600160801b03841681526129a7602082018480516001600160801b03908116835260209182015116910152565b600060208284031215612c2d57600080fd5b81518015158114610d4957600080fd5b81810381811115610d0557610d056129c6565b634e487b7160e01b600052600160045260246000fd5b60008251612c7881846020870161292e565b919091019291505056fea26469706673582212201029725bcf30151b95d4bc46117989392312a3015db9b868c799264598ca099a64736f6c63430008170033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.