Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 9 from a total of 9 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Approve | 13267509 | 12 hrs ago | IN | 0 S | 0.00253495 | ||||
Set Peer | 13256911 | 13 hrs ago | IN | 0 S | 0.00262878 | ||||
Set Peer | 13256898 | 13 hrs ago | IN | 0 S | 0.00262878 | ||||
Set Peer | 13256880 | 13 hrs ago | IN | 0 S | 0.00262878 | ||||
Transfer | 13256426 | 13 hrs ago | IN | 0 S | 0.00306823 | ||||
Transfer | 13256134 | 13 hrs ago | IN | 0 S | 0.00306823 | ||||
Add To Whitelist | 13256120 | 13 hrs ago | IN | 0 S | 0.00290229 | ||||
Add To Whitelist | 13256102 | 13 hrs ago | IN | 0 S | 0.00290229 | ||||
Initialize | 13241174 | 15 hrs ago | IN | 0 S | 0.0106806 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
13241142 | 15 hrs ago | Contract Creation | 0 S |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
SummerToken
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 50 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ISummerToken} from "../interfaces/ISummerToken.sol"; import {ISummerGovernor} from "../interfaces/ISummerGovernor.sol"; import {ISummerVestingWalletFactory} from "../interfaces/ISummerVestingWalletFactory.sol"; import {IGovernanceRewardsManager} from "../interfaces/IGovernanceRewardsManager.sol"; import {IOFT, SendParam, OFTReceipt, MessagingReceipt, MessagingFee} from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol"; import {IVotes} from "@openzeppelin/contracts/governance/utils/IVotes.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; import {ERC20Capped} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol"; import {Nonces} from "@openzeppelin/contracts/utils/Nonces.sol"; import {Votes} from "@openzeppelin/contracts/governance/utils/Votes.sol"; import {OFT, OFTCore} from "@layerzerolabs/oft-evm/contracts/OFT.sol"; import {GovernanceRewardsManager} from "./GovernanceRewardsManager.sol"; import {SummerVestingWalletFactory} from "./SummerVestingWalletFactory.sol"; import {DecayController} from "./DecayController.sol"; import {VotingDecayLibrary} from "@summerfi/voting-decay/VotingDecayLibrary.sol"; import {ProtocolAccessManaged} from "@summerfi/access-contracts/contracts/ProtocolAccessManaged.sol"; import {Constants} from "@summerfi/constants/Constants.sol"; import {Percentage} from "@summerfi/percentage-solidity/contracts/Percentage.sol"; /** * @title SummerToken * @dev Implementation of the Summer governance token with vesting, cross-chain, and voting decay capabilities. * Delegation of voting power is restricted to the hub chain only. * @custom:security-contact [email protected] */ contract SummerToken is OFT, ERC20Burnable, ERC20Votes, ERC20Permit, ERC20Capped, ProtocolAccessManaged, DecayController, ISummerToken { using VotingDecayLibrary for VotingDecayLibrary.DecayState; /*////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////*/ /// @notice The chain ID of the hub chain where governance actions are permitted uint32 public immutable hubChainId; address public vestingWalletFactory; address public rewardsManager; VotingDecayLibrary.DecayState internal decayState; uint256 public immutable transferEnableDate; bool public transfersEnabled; mapping(address account => bool isWhitelisted) public whitelistedAddresses; uint256 private constant SECONDS_PER_YEAR = 365.25 days; uint40 private constant MIN_DECAY_FREE_WINDOW = 30 days; uint40 private constant MAX_DECAY_FREE_WINDOW = 365.25 days; /// @notice Whether the contract has been initialized bool private _initialized; /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ /** * @dev Modifier to restrict certain functions to only be called on the hub chain. * This ensures that governance actions like delegation can only happen on the * designated hub chain. */ modifier onlyHubChain() { if (block.chainid != hubChainId) { revert NotHubChain(block.chainid, hubChainId); } _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /** * @dev Initializes the Summer token with minimal required parameters * @param params ConstructorParams struct containing basic token configuration */ constructor( ConstructorParams memory params ) OFT(params.name, params.symbol, params.lzEndpoint, params.initialOwner) ERC20Permit(params.name) ERC20Capped(params.maxSupply) ProtocolAccessManaged(params.accessManager) DecayController(address(this)) Ownable(params.initialOwner) { rewardsManager = address( new GovernanceRewardsManager(address(this), params.accessManager) ); _setRewardsManager(rewardsManager); hubChainId = params.hubChainId; transferEnableDate = params.transferEnableDate; } /** * @dev Completes the token initialization with remaining parameters * @param params InitializeParams struct containing additional configuration */ function initialize(InitializeParams memory params) external onlyOwner { if (_initialized) { revert AlreadyInitialized(); } _validateDecayRate(params.initialYearlyDecayRate); _validateDecayFreeWindow(params.initialDecayFreeWindow); vestingWalletFactory = params.vestingWalletFactory; // Convert yearly rate to per-second rate uint256 perSecondRate = Percentage.unwrap( params.initialYearlyDecayRate ) / SECONDS_PER_YEAR; decayState.initialize( params.initialDecayFreeWindow, perSecondRate, params.initialDecayFunction ); _mint(msg.sender, params.initialSupply); _initialized = true; } /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @dev Override the send function to add whitelist checks with self-transfer allowance */ function send( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) external payable override(IOFT, OFTCore) returns ( MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt ) { // Convert bytes32 to address using uint256 cast address to = address(uint160(uint256(_sendParam.to))); // Allow transfers if: // 1. Transfers are enabled globally, or // 2. The target address is whitelisted, or // 3. The sender is sending to themselves if ( !transfersEnabled && !whitelistedAddresses[to] && to != msg.sender ) { revert TransferNotAllowed(); } // Debit the sender's balance (uint256 amountSentLD, uint256 amountReceivedLD) = _debit( msg.sender, _sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid ); // Build the message and options for LayerZero (bytes memory message, bytes memory options) = _buildMsgAndOptions( _sendParam, amountReceivedLD ); // Send the message to the LayerZero endpoint msgReceipt = _lzSend( _sendParam.dstEid, message, options, _fee, _refundAddress ); // Formulate the OFT receipt oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD); emit OFTSent( msgReceipt.guid, _sendParam.dstEid, msg.sender, amountSentLD, amountReceivedLD ); } /// @inheritdoc ISummerToken function getDecayFreeWindow() external view returns (uint40) { return decayState.decayFreeWindow; } /// @inheritdoc ISummerToken function getDecayFactor(address account) external view returns (uint256) { return decayState.getDecayFactor(account, _getDelegateTo); } /// @inheritdoc ISummerToken function getPastDecayFactor( address account, uint256 timepoint ) external view returns (uint256) { return decayState.getHistoricalDecayFactor(account, timepoint); } /// @inheritdoc ISummerToken function getDelegationChainLength( address account ) external view returns (uint256) { return decayState.getDelegationChainLength(account, _getDelegateTo); } /// @inheritdoc ISummerToken function getDecayRatePerYear() external view returns (Percentage) { // Convert per-second rate to yearly rate using simple multiplication // Note: We use simple multiplication rather than compound rate calculation // because: // 1. It's more intuitive for governance participants // 2. The decay rate is meant to be a simple linear reduction // 3. For typical decay rates, the difference is minimal uint256 yearlyRate = _getDecayRatePerSecond() * SECONDS_PER_YEAR; return Percentage.wrap(yearlyRate); } /*////////////////////////////////////////////////////////////// EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISummerToken function setDecayRatePerYear( Percentage newYearlyRate ) external onlyGovernor { _validateDecayRate(newYearlyRate); // Convert yearly rate to per-second rate uint256 perSecondRate = Percentage.unwrap(newYearlyRate) / SECONDS_PER_YEAR; decayState.setDecayRatePerSecond(perSecondRate); } /// @inheritdoc ISummerToken function setDecayFreeWindow(uint40 newWindow) external onlyGovernor { _validateDecayFreeWindow(newWindow); decayState.setDecayFreeWindow(newWindow); } /// @inheritdoc ISummerToken function setDecayFunction( VotingDecayLibrary.DecayFunction newFunction ) external onlyGovernor { decayState.setDecayFunction(newFunction); } /// @inheritdoc ISummerToken function updateDecayFactor(address account) external onlyDecayController { decayState.updateDecayFactor(account, _getDelegateTo); } /// @inheritdoc ISummerToken function enableTransfers() external onlyGovernor { if (transfersEnabled) { revert TransfersAlreadyEnabled(); } if (block.timestamp < transferEnableDate) { revert TransfersCannotBeEnabledYet(); } transfersEnabled = true; emit TransfersEnabled(); } /// @inheritdoc ISummerToken function addToWhitelist(address account) external onlyGovernor { whitelistedAddresses[account] = true; emit AddressWhitelisted(account); } /// @inheritdoc ISummerToken function removeFromWhitelist(address account) external onlyGovernor { whitelistedAddresses[account] = false; emit AddressRemovedFromWhitelist(account); } /*////////////////////////////////////////////////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @dev Delegates voting power to a specified address. Can only be called on the hub chain. * @param delegatee The address to delegate voting power to * @dev Updates the decay factor for the caller * @custom:restriction This function can only be called on the hub chain */ function delegate( address delegatee ) public override(IVotes, Votes) updateDecay(_msgSender()) onlyHubChain { if (delegatee == address(0)) { uint256 stakingBalance = IGovernanceRewardsManager(rewardsManager) .balanceOf(_msgSender()); if (stakingBalance > 0) { revert CannotUndelegateWhileStaked(); } } // Only initialize delegatee if they don't have decay info yet if (delegatee != address(0) && !decayState.hasDecayInfo(delegatee)) { decayState.initializeAccount(delegatee); } super.delegate(delegatee); } /** * @dev Required override to resolve inheritance conflict between IERC20Permit, ERC20Permit, and Nonces contracts. * This implementation simply calls the parent implementation and exists solely to satisfy the compiler. * @param owner The address to get nonces for * @return The current nonce for the specified owner */ function nonces( address owner ) public view override(IERC20Permit, ERC20Permit, Nonces) returns (uint256) { return super.nonces(owner); } function clock() public view override returns (uint48) { return uint48(block.timestamp); } function CLOCK_MODE() public pure override returns (string memory) { return "mode=timestamp"; } /// @inheritdoc ISummerToken function getVotes( address account ) public view override(ISummerToken, Votes) returns (uint256) { uint256 rawVotingPower = super.getVotes(account); return decayState.getVotingPower(account, rawVotingPower, _getDelegateTo); } /// @inheritdoc ISummerToken function getPastVotes( address account, uint256 timepoint ) public view override(ISummerToken, Votes) returns (uint256) { uint256 pastVotingUnits = super.getPastVotes(account, timepoint); uint256 historicalDecayFactor = decayState.getHistoricalDecayFactor( account, timepoint ); return (pastVotingUnits * historicalDecayFactor) / Constants.WAD; } /// @inheritdoc ISummerToken function getRawVotesAt( address account, uint256 timestamp ) public view returns (uint256) { return timestamp == 0 ? super.getVotes(account) : super.getPastVotes(account, timestamp); } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @dev Internal helper to get the per-second decay rate /// @return The decay rate per second function _getDecayRatePerSecond() internal view returns (uint256) { return decayState.decayRatePerSecond; } /** * @dev Returns the delegate address for a given account, implementing VotingDecayLibrary's abstract method * @param account The address to check delegation for * @return The delegate address for the account * @custom:relationship-to-votingdecay * - Required by VotingDecayLibrary to track delegation chains * - Used in decay factor calculations to follow delegation paths * - Supports VotingDecayLibrary's MAX_DELEGATION_DEPTH enforcement * @custom:implementation-notes * - Delegates are used both for voting power and decay factor inheritance * - Returns zero address if account has not delegated * - Uses OpenZeppelin's ERC20Votes delegation system via super.delegates() */ function _getDelegateTo(address account) internal view returns (address) { return super.delegates(account); } /** * @dev Internal function to update token balances. * @param from The address to transfer tokens from. * @param to The address to transfer tokens to. * @param amount The amount of tokens to transfer. */ function _update( address from, address to, uint256 amount ) internal override(ERC20, ERC20Votes, ERC20Capped) { if (!_canTransfer(from, to)) { revert TransferNotAllowed(); } super._update(from, to, amount); } function _canTransfer( address from, address to ) internal view returns (bool) { // Allow minting and burning if (from == address(0) || to == address(0)) return true; // Allow transfers if globally enabled if (transfersEnabled) return true; // Allow transfers involving whitelisted addresses if (whitelistedAddresses[from] || whitelistedAddresses[to]) return true; return false; } /** * @dev Burns tokens from the sender's specified balance. * @param _from The address to debit the tokens from. * @param _amountLD The amount of tokens to send in local decimals. * @param _minAmountLD The minimum amount to send in local decimals. * @param _dstEid The destination chain ID. * @return amountSentLD The amount sent in local decimals. * @return amountReceivedLD The amount received in local decimals on the remote. */ function _debit( address _from, uint256 _amountLD, uint256 _minAmountLD, uint32 _dstEid ) internal override returns (uint256 amountSentLD, uint256 amountReceivedLD) { (amountSentLD, amountReceivedLD) = _debitView( _amountLD, _minAmountLD, _dstEid ); // @dev In NON-default OFT, amountSentLD could be 100, with a 10% fee, the amountReceivedLD amount is 90, // therefore amountSentLD CAN differ from amountReceivedLD. // @dev Default OFT burns on src. _burn(_from, amountSentLD); } /** * @dev Overrides the default _getVotingUnits function to include all user tokens in voting power, including locked * up tokens in vesting wallets * @param account The address to get voting units for * @return uint256 The total number of voting units for the account * @custom:internal-logic * - Retrieves the direct token balance of the account * - Checks if the account has an associated vesting wallet * - If a vesting wallet exists, adds its balance to the account's direct balance * @custom:effects * - Does not modify any state, view function only * @custom:security-considerations * - Ensures that tokens in vesting contracts still contribute to voting power * - May increase the voting power of accounts with vesting wallets compared to standard ERC20Votes implementation * - Consider the implications of this increased voting power on governance decisions * @custom:gas-considerations * - This function performs an additional storage read and potential balance check compared to the standard * implementation * - May slightly increase gas costs for voting-related operations */ function _getVotingUnits( address account ) internal view override returns (uint256) { // Get raw voting units first uint256 directBalance = balanceOf(account); uint256 stakingBalance = IGovernanceRewardsManager(rewardsManager) .balanceOf(account); uint256 vestingBalance = ISummerVestingWalletFactory( vestingWalletFactory ).vestingWallets(account) != address(0) ? balanceOf( ISummerVestingWalletFactory(vestingWalletFactory) .vestingWallets(account) ) : 0; return directBalance + stakingBalance + vestingBalance; } /** * @dev Transfers, mints, or burns voting units while managing delegate votes. * @param from The address transferring voting units (zero address for mints) * @param to The address receiving voting units (zero address for burns) * @param amount The amount of voting units to transfer * @custom:internal-logic * - Skips vote tracking for transfers involving the rewards manager * - Updates total supply checkpoints for mints and burns * - Moves delegate votes between accounts * @custom:security-considerations * - Ensures voting power is correctly tracked when tokens move between accounts * - Special handling for staking/unstaking to prevent double-counting */ function _transferVotingUnits( address from, address to, uint256 amount ) internal override { bool isRewardsManagerTransfer = _handleRewardsManagerVotingTransfer( from, to ); bool isVestingWalletTransfer = _handleVestingWalletVotingTransfer( from, to, amount ); if (!isRewardsManagerTransfer && !isVestingWalletTransfer) { super._transferVotingUnits(from, to, amount); } } /** * @dev Handles voting power transfers involving vesting wallets * @param from Source address * @param to Destination address * @param amount Amount of voting units to transfer * @return bool True if the transfer was handled (vesting wallet case), false otherwise * @custom:internal-logic * - Checks if either from/to is a vesting wallet * - Handles voting power redirections for vesting wallet transfers */ function _handleVestingWalletVotingTransfer( address from, address to, uint256 amount ) internal returns (bool) { // Case 1: Transfer TO vesting wallet address vestingWalletOwner = ISummerVestingWalletFactory( vestingWalletFactory ).vestingWalletOwners(to); if (vestingWalletOwner != address(0)) { // Skip if transfer is from the owner (they already have voting power) if (from != vestingWalletOwner) { // Transfer voting power to beneficiary instead of vesting wallet super._transferVotingUnits(from, vestingWalletOwner, amount); } return true; } // Case 2: Transfer FROM vesting wallet address fromVestingWalletOwner = ISummerVestingWalletFactory( vestingWalletFactory ).vestingWalletOwners(from); if (fromVestingWalletOwner != address(0)) { // Skip if transfer is to the beneficiary (they already have voting power) if (to == fromVestingWalletOwner) { return true; } // Transfer voting power from beneficiary to recipient super._transferVotingUnits(fromVestingWalletOwner, to, amount); return true; } return false; } /** * @dev Handles voting power transfers involving the rewards manager * @param from Source address * @param to Destination address * @return bool True if vote tracking should be skipped (rewards manager case), false if normal vote tracking should occur * @custom:internal-logic * - Returns true to skip vote tracking for two specific cases: * 1. When tokens come FROM the wrapped staking token (used for both unstaking and reward claims) * 2. When staking: transfers TO the rewards manager * - Returns false for all other transfers, allowing normal vote tracking * @custom:rationale * - Staking/unstaking/reward operations are handled separately by the rewards manager * - The wrapped staking token is used as the source for both unstaking and claiming rewards * - Skipping vote tracking here prevents double-counting of voting power since * the rewards manager maintains its own balance tracking for staked tokens */ function _handleRewardsManagerVotingTransfer( address from, address to ) internal view virtual returns (bool) { // Skip vote tracking for unstaking/rewards (from wrapped token) and staking (to rewards manager) if ( from == IGovernanceRewardsManager(rewardsManager).wrappedStakingToken() || to == address(rewardsManager) ) { return true; } return false; } /// @dev Validates that the decay rate is between 1% and 50% /// @param rate The yearly decay rate to validate function _validateDecayRate(Percentage rate) internal pure { uint256 unwrappedRate = Percentage.unwrap(rate); if (unwrappedRate > Constants.WAD / 2) { revert DecayRateTooHigh(unwrappedRate); } } /// @dev Validates that the decay free window is between 30 days and 365.25 days /// @param window The window duration to validate function _validateDecayFreeWindow(uint40 window) internal pure { if (window < MIN_DECAY_FREE_WINDOW || window > MAX_DECAY_FREE_WINDOW) { revert InvalidDecayFreeWindow(window); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { IMessageLibManager } from "./IMessageLibManager.sol"; import { IMessagingComposer } from "./IMessagingComposer.sol"; import { IMessagingChannel } from "./IMessagingChannel.sol"; import { IMessagingContext } from "./IMessagingContext.sol"; struct MessagingParams { uint32 dstEid; bytes32 receiver; bytes message; bytes options; bool payInLzToken; } struct MessagingReceipt { bytes32 guid; uint64 nonce; MessagingFee fee; } struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; } struct Origin { uint32 srcEid; bytes32 sender; uint64 nonce; } interface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext { event PacketSent(bytes encodedPayload, bytes options, address sendLibrary); event PacketVerified(Origin origin, address receiver, bytes32 payloadHash); event PacketDelivered(Origin origin, address receiver); event LzReceiveAlert( address indexed receiver, address indexed executor, Origin origin, bytes32 guid, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); event LzTokenSet(address token); event DelegateSet(address sender, address delegate); function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory); function send( MessagingParams calldata _params, address _refundAddress ) external payable returns (MessagingReceipt memory); function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external; function verifiable(Origin calldata _origin, address _receiver) external view returns (bool); function initializable(Origin calldata _origin, address _receiver) external view returns (bool); function lzReceive( Origin calldata _origin, address _receiver, bytes32 _guid, bytes calldata _message, bytes calldata _extraData ) external payable; // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external; function setLzToken(address _lzToken) external; function lzToken() external view returns (address); function nativeToken() external view returns (address); function setDelegate(address _delegate) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { Origin } from "./ILayerZeroEndpointV2.sol"; interface ILayerZeroReceiver { function allowInitializePath(Origin calldata _origin) external view returns (bool); function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64); function lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { SetConfigParam } from "./IMessageLibManager.sol"; enum MessageLibType { Send, Receive, SendAndReceive } interface IMessageLib is IERC165 { function setConfig(address _oapp, SetConfigParam[] calldata _config) external; function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view returns (bytes memory config); function isSupportedEid(uint32 _eid) external view returns (bool); // message libs of same major version are compatible function version() external view returns (uint64 major, uint8 minor, uint8 endpointVersion); function messageLibType() external view returns (MessageLibType); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; struct SetConfigParam { uint32 eid; uint32 configType; bytes config; } interface IMessageLibManager { struct Timeout { address lib; uint256 expiry; } event LibraryRegistered(address newLib); event DefaultSendLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry); event SendLibrarySet(address sender, uint32 eid, address newLib); event ReceiveLibrarySet(address receiver, uint32 eid, address newLib); event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout); function registerLibrary(address _lib) external; function isRegisteredLibrary(address _lib) external view returns (bool); function getRegisteredLibraries() external view returns (address[] memory); function setDefaultSendLibrary(uint32 _eid, address _newLib) external; function defaultSendLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _gracePeriod) external; function defaultReceiveLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external; function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry); function isSupportedEid(uint32 _eid) external view returns (bool); function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool); /// ------------------- OApp interfaces ------------------- function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external; function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib); function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool); function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external; function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault); function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _expiry) external; function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry); function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external; function getConfig( address _oapp, address _lib, uint32 _eid, uint32 _configType ) external view returns (bytes memory config); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingChannel { event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce); event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); function eid() external view returns (uint32); // this is an emergency function if a message cannot be verified for some reasons // required to provide _nextNonce to avoid race condition function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external; function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32); function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64); function inboundPayloadHash( address _receiver, uint32 _srcEid, bytes32 _sender, uint64 _nonce ) external view returns (bytes32); function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingComposer { event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message); event ComposeDelivered(address from, address to, bytes32 guid, uint16 index); event LzComposeAlert( address indexed from, address indexed to, address indexed executor, bytes32 guid, uint16 index, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); function composeQueue( address _from, address _to, bytes32 _guid, uint16 _index ) external view returns (bytes32 messageHash); function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external; function lzCompose( address _from, address _to, bytes32 _guid, uint16 _index, bytes calldata _message, bytes calldata _extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingContext { function isSendingMessage() external view returns (bool); function getSendContext() external view returns (uint32 dstEid, address sender); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { MessagingFee } from "./ILayerZeroEndpointV2.sol"; import { IMessageLib } from "./IMessageLib.sol"; struct Packet { uint64 nonce; uint32 srcEid; address sender; uint32 dstEid; bytes32 receiver; bytes32 guid; bytes message; } interface ISendLib is IMessageLib { function send( Packet calldata _packet, bytes calldata _options, bool _payInLzToken ) external returns (MessagingFee memory, bytes memory encodedPacket); function quote( Packet calldata _packet, bytes calldata _options, bool _payInLzToken ) external view returns (MessagingFee memory); function setTreasury(address _treasury) external; function withdrawFee(address _to, uint256 _amount) external; function withdrawLzTokenFee(address _lzToken, address _to, uint256 _amount) external; }
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; library AddressCast { error AddressCast_InvalidSizeForAddress(); error AddressCast_InvalidAddress(); function toBytes32(bytes calldata _addressBytes) internal pure returns (bytes32 result) { if (_addressBytes.length > 32) revert AddressCast_InvalidAddress(); result = bytes32(_addressBytes); unchecked { uint256 offset = 32 - _addressBytes.length; result = result >> (offset * 8); } } function toBytes32(address _address) internal pure returns (bytes32 result) { result = bytes32(uint256(uint160(_address))); } function toBytes(bytes32 _addressBytes32, uint256 _size) internal pure returns (bytes memory result) { if (_size == 0 || _size > 32) revert AddressCast_InvalidSizeForAddress(); result = new bytes(_size); unchecked { uint256 offset = 256 - _size * 8; assembly { mstore(add(result, 32), shl(offset, _addressBytes32)) } } } function toAddress(bytes32 _addressBytes32) internal pure returns (address result) { result = address(uint160(uint256(_addressBytes32))); } function toAddress(bytes calldata _addressBytes) internal pure returns (address result) { if (_addressBytes.length != 20) revert AddressCast_InvalidAddress(); result = address(bytes20(_addressBytes)); } }
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import { Packet } from "../../interfaces/ISendLib.sol"; import { AddressCast } from "../../libs/AddressCast.sol"; library PacketV1Codec { using AddressCast for address; using AddressCast for bytes32; uint8 internal constant PACKET_VERSION = 1; // header (version + nonce + path) // version uint256 private constant PACKET_VERSION_OFFSET = 0; // nonce uint256 private constant NONCE_OFFSET = 1; // path uint256 private constant SRC_EID_OFFSET = 9; uint256 private constant SENDER_OFFSET = 13; uint256 private constant DST_EID_OFFSET = 45; uint256 private constant RECEIVER_OFFSET = 49; // payload (guid + message) uint256 private constant GUID_OFFSET = 81; // keccak256(nonce + path) uint256 private constant MESSAGE_OFFSET = 113; function encode(Packet memory _packet) internal pure returns (bytes memory encodedPacket) { encodedPacket = abi.encodePacked( PACKET_VERSION, _packet.nonce, _packet.srcEid, _packet.sender.toBytes32(), _packet.dstEid, _packet.receiver, _packet.guid, _packet.message ); } function encodePacketHeader(Packet memory _packet) internal pure returns (bytes memory) { return abi.encodePacked( PACKET_VERSION, _packet.nonce, _packet.srcEid, _packet.sender.toBytes32(), _packet.dstEid, _packet.receiver ); } function encodePayload(Packet memory _packet) internal pure returns (bytes memory) { return abi.encodePacked(_packet.guid, _packet.message); } function header(bytes calldata _packet) internal pure returns (bytes calldata) { return _packet[0:GUID_OFFSET]; } function version(bytes calldata _packet) internal pure returns (uint8) { return uint8(bytes1(_packet[PACKET_VERSION_OFFSET:NONCE_OFFSET])); } function nonce(bytes calldata _packet) internal pure returns (uint64) { return uint64(bytes8(_packet[NONCE_OFFSET:SRC_EID_OFFSET])); } function srcEid(bytes calldata _packet) internal pure returns (uint32) { return uint32(bytes4(_packet[SRC_EID_OFFSET:SENDER_OFFSET])); } function sender(bytes calldata _packet) internal pure returns (bytes32) { return bytes32(_packet[SENDER_OFFSET:DST_EID_OFFSET]); } function senderAddressB20(bytes calldata _packet) internal pure returns (address) { return sender(_packet).toAddress(); } function dstEid(bytes calldata _packet) internal pure returns (uint32) { return uint32(bytes4(_packet[DST_EID_OFFSET:RECEIVER_OFFSET])); } function receiver(bytes calldata _packet) internal pure returns (bytes32) { return bytes32(_packet[RECEIVER_OFFSET:GUID_OFFSET]); } function receiverB20(bytes calldata _packet) internal pure returns (address) { return receiver(_packet).toAddress(); } function guid(bytes calldata _packet) internal pure returns (bytes32) { return bytes32(_packet[GUID_OFFSET:MESSAGE_OFFSET]); } function message(bytes calldata _packet) internal pure returns (bytes calldata) { return bytes(_packet[MESSAGE_OFFSET:]); } function payload(bytes calldata _packet) internal pure returns (bytes calldata) { return bytes(_packet[GUID_OFFSET:]); } function payloadHash(bytes calldata _packet) internal pure returns (bytes32) { return keccak256(payload(_packet)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ILayerZeroEndpointV2 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; /** * @title IOAppCore */ interface IOAppCore { // Custom error messages error OnlyPeer(uint32 eid, bytes32 sender); error NoPeer(uint32 eid); error InvalidEndpointCall(); error InvalidDelegate(); // Event emitted when a peer (OApp) is set for a corresponding endpoint event PeerSet(uint32 eid, bytes32 peer); /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. */ function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion); /** * @notice Retrieves the LayerZero endpoint associated with the OApp. * @return iEndpoint The LayerZero endpoint as an interface. */ function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint); /** * @notice Retrieves the peer (OApp) associated with a corresponding endpoint. * @param _eid The endpoint ID. * @return peer The peer address (OApp instance) associated with the corresponding endpoint. */ function peers(uint32 _eid) external view returns (bytes32 peer); /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. */ function setPeer(uint32 _eid, bytes32 _peer) external; /** * @notice Sets the delegate address for the OApp Core. * @param _delegate The address of the delegate to be set. */ function setDelegate(address _delegate) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title IOAppMsgInspector * @dev Interface for the OApp Message Inspector, allowing examination of message and options contents. */ interface IOAppMsgInspector { // Custom error message for inspection failure error InspectionFailed(bytes message, bytes options); /** * @notice Allows the inspector to examine LayerZero message contents and optionally throw a revert if invalid. * @param _message The message payload to be inspected. * @param _options Additional options or parameters for inspection. * @return valid A boolean indicating whether the inspection passed (true) or failed (false). * * @dev Optionally done as a revert, OR use the boolean provided to handle the failure. */ function inspect(bytes calldata _message, bytes calldata _options) external view returns (bool valid); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @dev Struct representing enforced option parameters. */ struct EnforcedOptionParam { uint32 eid; // Endpoint ID uint16 msgType; // Message Type bytes options; // Additional options } /** * @title IOAppOptionsType3 * @dev Interface for the OApp with Type 3 Options, allowing the setting and combining of enforced options. */ interface IOAppOptionsType3 { // Custom error message for invalid options error InvalidOptions(bytes options); // Event emitted when enforced options are set event EnforcedOptionSet(EnforcedOptionParam[] _enforcedOptions); /** * @notice Sets enforced options for specific endpoint and message type combinations. * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options. */ function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external; /** * @notice Combines options for a given endpoint and message type. * @param _eid The endpoint ID. * @param _msgType The OApp message type. * @param _extraOptions Additional options passed by the caller. * @return options The combination of caller specified options AND enforced options. */ function combineOptions( uint32 _eid, uint16 _msgType, bytes calldata _extraOptions ) external view returns (bytes memory options); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol"; interface IOAppReceiver is ILayerZeroReceiver { /** * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint. * @param _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @param _message The lzReceive payload. * @param _sender The sender address. * @return isSender Is a valid sender. * * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer. * @dev The default sender IS the OAppReceiver implementer. */ function isComposeMsgSender( Origin calldata _origin, bytes calldata _message, address _sender ) external view returns (bool isSender); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IOAppOptionsType3, EnforcedOptionParam } from "../interfaces/IOAppOptionsType3.sol"; /** * @title OAppOptionsType3 * @dev Abstract contract implementing the IOAppOptionsType3 interface with type 3 options. */ abstract contract OAppOptionsType3 is IOAppOptionsType3, Ownable { uint16 internal constant OPTION_TYPE_3 = 3; // @dev The "msgType" should be defined in the child contract. mapping(uint32 eid => mapping(uint16 msgType => bytes enforcedOption)) public enforcedOptions; /** * @dev Sets the enforced options for specific endpoint and message type combinations. * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options. * * @dev Only the owner/admin of the OApp can call this function. * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc. * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType. * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose(). */ function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) public virtual onlyOwner { _setEnforcedOptions(_enforcedOptions); } /** * @dev Sets the enforced options for specific endpoint and message type combinations. * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options. * * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc. * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType. * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose(). */ function _setEnforcedOptions(EnforcedOptionParam[] memory _enforcedOptions) internal virtual { for (uint256 i = 0; i < _enforcedOptions.length; i++) { // @dev Enforced options are only available for optionType 3, as type 1 and 2 dont support combining. _assertOptionsType3(_enforcedOptions[i].options); enforcedOptions[_enforcedOptions[i].eid][_enforcedOptions[i].msgType] = _enforcedOptions[i].options; } emit EnforcedOptionSet(_enforcedOptions); } /** * @notice Combines options for a given endpoint and message type. * @param _eid The endpoint ID. * @param _msgType The OAPP message type. * @param _extraOptions Additional options passed by the caller. * @return options The combination of caller specified options AND enforced options. * * @dev If there is an enforced lzReceive option: * - {gasLimit: 200k, msg.value: 1 ether} AND a caller supplies a lzReceive option: {gasLimit: 100k, msg.value: 0.5 ether} * - The resulting options will be {gasLimit: 300k, msg.value: 1.5 ether} when the message is executed on the remote lzReceive() function. * @dev This presence of duplicated options is handled off-chain in the verifier/executor. */ function combineOptions( uint32 _eid, uint16 _msgType, bytes calldata _extraOptions ) public view virtual returns (bytes memory) { bytes memory enforced = enforcedOptions[_eid][_msgType]; // No enforced options, pass whatever the caller supplied, even if it's empty or legacy type 1/2 options. if (enforced.length == 0) return _extraOptions; // No caller options, return enforced if (_extraOptions.length == 0) return enforced; // @dev If caller provided _extraOptions, must be type 3 as its the ONLY type that can be combined. if (_extraOptions.length >= 2) { _assertOptionsType3(_extraOptions); // @dev Remove the first 2 bytes containing the type from the _extraOptions and combine with enforced. return bytes.concat(enforced, _extraOptions[2:]); } // No valid set of options was found. revert InvalidOptions(_extraOptions); } /** * @dev Internal function to assert that options are of type 3. * @param _options The options to be checked. */ function _assertOptionsType3(bytes memory _options) internal pure virtual { uint16 optionsType; assembly { optionsType := mload(add(_options, 2)) } if (optionsType != OPTION_TYPE_3) revert InvalidOptions(_options); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; // @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers // solhint-disable-next-line no-unused-import import { OAppSender, MessagingFee, MessagingReceipt } from "./OAppSender.sol"; // @dev Import the 'Origin' so it's exposed to OApp implementers // solhint-disable-next-line no-unused-import import { OAppReceiver, Origin } from "./OAppReceiver.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OApp * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality. */ abstract contract OApp is OAppSender, OAppReceiver { /** * @dev Constructor to initialize the OApp with the provided endpoint and owner. * @param _endpoint The address of the LOCAL LayerZero endpoint. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. */ constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {} /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol implementation. * @return receiverVersion The version of the OAppReceiver.sol implementation. */ function oAppVersion() public pure virtual override(OAppSender, OAppReceiver) returns (uint64 senderVersion, uint64 receiverVersion) { return (SENDER_VERSION, RECEIVER_VERSION); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol"; /** * @title OAppCore * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations. */ abstract contract OAppCore is IOAppCore, Ownable { // The LayerZero endpoint associated with the given OApp ILayerZeroEndpointV2 public immutable endpoint; // Mapping to store peers associated with corresponding endpoints mapping(uint32 eid => bytes32 peer) public peers; /** * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate. * @param _endpoint The address of the LOCAL Layer Zero endpoint. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. * * @dev The delegate typically should be set as the owner of the contract. */ constructor(address _endpoint, address _delegate) { endpoint = ILayerZeroEndpointV2(_endpoint); if (_delegate == address(0)) revert InvalidDelegate(); endpoint.setDelegate(_delegate); } /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. * * @dev Only the owner/admin of the OApp can call this function. * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp. * @dev Set this to bytes32(0) to remove the peer address. * @dev Peer is a bytes32 to accommodate non-evm chains. */ function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner { _setPeer(_eid, _peer); } /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. * * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp. * @dev Set this to bytes32(0) to remove the peer address. * @dev Peer is a bytes32 to accommodate non-evm chains. */ function _setPeer(uint32 _eid, bytes32 _peer) internal virtual { peers[_eid] = _peer; emit PeerSet(_eid, _peer); } /** * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set. * ie. the peer is set to bytes32(0). * @param _eid The endpoint ID. * @return peer The address of the peer associated with the specified endpoint. */ function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) { bytes32 peer = peers[_eid]; if (peer == bytes32(0)) revert NoPeer(_eid); return peer; } /** * @notice Sets the delegate address for the OApp. * @param _delegate The address of the delegate to be set. * * @dev Only the owner/admin of the OApp can call this function. * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract. */ function setDelegate(address _delegate) public onlyOwner { endpoint.setDelegate(_delegate); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { IOAppReceiver, Origin } from "./interfaces/IOAppReceiver.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OAppReceiver * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers. */ abstract contract OAppReceiver is IOAppReceiver, OAppCore { // Custom error message for when the caller is not the registered endpoint/ error OnlyEndpoint(address addr); // @dev The version of the OAppReceiver implementation. // @dev Version is bumped when changes are made to this contract. uint64 internal constant RECEIVER_VERSION = 2; /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. * * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented. * ie. this is a RECEIVE only OApp. * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions. */ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) { return (0, RECEIVER_VERSION); } /** * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint. * @dev _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @dev _message The lzReceive payload. * @param _sender The sender address. * @return isSender Is a valid sender. * * @dev Applications can optionally choose to implement separate composeMsg senders that are NOT the bridging layer. * @dev The default sender IS the OAppReceiver implementer. */ function isComposeMsgSender( Origin calldata /*_origin*/, bytes calldata /*_message*/, address _sender ) public view virtual returns (bool) { return _sender == address(this); } /** * @notice Checks if the path initialization is allowed based on the provided origin. * @param origin The origin information containing the source endpoint and sender address. * @return Whether the path has been initialized. * * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received. * @dev This defaults to assuming if a peer has been set, its initialized. * Can be overridden by the OApp if there is other logic to determine this. */ function allowInitializePath(Origin calldata origin) public view virtual returns (bool) { return peers[origin.srcEid] == origin.sender; } /** * @notice Retrieves the next nonce for a given source endpoint and sender address. * @dev _srcEid The source endpoint ID. * @dev _sender The sender address. * @return nonce The next nonce. * * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement. * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered. * @dev This is also enforced by the OApp. * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0. */ function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) { return 0; } /** * @dev Entry point for receiving messages or packets from the endpoint. * @param _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @param _guid The unique identifier for the received LayerZero message. * @param _message The payload of the received message. * @param _executor The address of the executor for the received message. * @param _extraData Additional arbitrary data provided by the corresponding executor. * * @dev Entry point for receiving msg/packet from the LayerZero endpoint. */ function lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) public payable virtual { // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp. if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender); // Ensure that the sender matches the expected peer for the source endpoint. if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender); // Call the internal OApp implementation of lzReceive. _lzReceive(_origin, _guid, _message, _executor, _extraData); } /** * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation. */ function _lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OAppSender * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint. */ abstract contract OAppSender is OAppCore { using SafeERC20 for IERC20; // Custom error messages error NotEnoughNative(uint256 msgValue); error LzTokenUnavailable(); // @dev The version of the OAppSender implementation. // @dev Version is bumped when changes are made to this contract. uint64 internal constant SENDER_VERSION = 1; /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. * * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented. * ie. this is a SEND only OApp. * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions */ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) { return (SENDER_VERSION, 0); } /** * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens. * @return fee The calculated MessagingFee for the message. * - nativeFee: The native fee for the message. * - lzTokenFee: The LZ token fee for the message. */ function _quote( uint32 _dstEid, bytes memory _message, bytes memory _options, bool _payInLzToken ) internal view virtual returns (MessagingFee memory fee) { return endpoint.quote( MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken), address(this) ); } /** * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _fee The calculated LayerZero fee for the message. * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. * @param _refundAddress The address to receive any excess fee values sent to the endpoint. * @return receipt The receipt for the sent message. * - guid: The unique identifier for the sent message. * - nonce: The nonce of the sent message. * - fee: The LayerZero fee incurred for the message. */ function _lzSend( uint32 _dstEid, bytes memory _message, bytes memory _options, MessagingFee memory _fee, address _refundAddress ) internal virtual returns (MessagingReceipt memory receipt) { // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint. uint256 messageValue = _payNative(_fee.nativeFee); if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee); return // solhint-disable-next-line check-send-result endpoint.send{ value: messageValue }( MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0), _refundAddress ); } /** * @dev Internal function to pay the native fee associated with the message. * @param _nativeFee The native fee to be paid. * @return nativeFee The amount of native currency paid. * * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction, * this will need to be overridden because msg.value would contain multiple lzFees. * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency. * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees. * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time. */ function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) { if (msg.value != _nativeFee) revert NotEnoughNative(msg.value); return _nativeFee; } /** * @dev Internal function to pay the LZ token fee associated with the message. * @param _lzTokenFee The LZ token fee to be paid. * * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint. * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend(). */ function _payLzToken(uint256 _lzTokenFee) internal virtual { // @dev Cannot cache the token because it is not immutable in the endpoint. address lzToken = endpoint.lzToken(); if (lzToken == address(0)) revert LzTokenUnavailable(); // Pay LZ token fee by sending tokens to the endpoint. IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; // @dev Import the Origin so it's exposed to OAppPreCrimeSimulator implementers. // solhint-disable-next-line no-unused-import import { InboundPacket, Origin } from "../libs/Packet.sol"; /** * @title IOAppPreCrimeSimulator Interface * @dev Interface for the preCrime simulation functionality in an OApp. */ interface IOAppPreCrimeSimulator { // @dev simulation result used in PreCrime implementation error SimulationResult(bytes result); error OnlySelf(); /** * @dev Emitted when the preCrime contract address is set. * @param preCrimeAddress The address of the preCrime contract. */ event PreCrimeSet(address preCrimeAddress); /** * @dev Retrieves the address of the preCrime contract implementation. * @return The address of the preCrime contract. */ function preCrime() external view returns (address); /** * @dev Retrieves the address of the OApp contract. * @return The address of the OApp contract. */ function oApp() external view returns (address); /** * @dev Sets the preCrime contract address. * @param _preCrime The address of the preCrime contract. */ function setPreCrime(address _preCrime) external; /** * @dev Mocks receiving a packet, then reverts with a series of data to infer the state/result. * @param _packets An array of LayerZero InboundPacket objects representing received packets. */ function lzReceiveAndRevert(InboundPacket[] calldata _packets) external payable; /** * @dev checks if the specified peer is considered 'trusted' by the OApp. * @param _eid The endpoint Id to check. * @param _peer The peer to check. * @return Whether the peer passed is considered 'trusted' by the OApp. */ function isPeer(uint32 _eid, bytes32 _peer) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; struct PreCrimePeer { uint32 eid; bytes32 preCrime; bytes32 oApp; } // TODO not done yet interface IPreCrime { error OnlyOffChain(); // for simulate() error PacketOversize(uint256 max, uint256 actual); error PacketUnsorted(); error SimulationFailed(bytes reason); // for preCrime() error SimulationResultNotFound(uint32 eid); error InvalidSimulationResult(uint32 eid, bytes reason); error CrimeFound(bytes crime); function getConfig(bytes[] calldata _packets, uint256[] calldata _packetMsgValues) external returns (bytes memory); function simulate( bytes[] calldata _packets, uint256[] calldata _packetMsgValues ) external payable returns (bytes memory); function buildSimulationResult() external view returns (bytes memory); function preCrime( bytes[] calldata _packets, uint256[] calldata _packetMsgValues, bytes[] calldata _simulations ) external; function version() external view returns (uint64 major, uint8 minor); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol"; /** * @title InboundPacket * @dev Structure representing an inbound packet received by the contract. */ struct InboundPacket { Origin origin; // Origin information of the packet. uint32 dstEid; // Destination endpointId of the packet. address receiver; // Receiver address for the packet. bytes32 guid; // Unique identifier of the packet. uint256 value; // msg.value of the packet. address executor; // Executor address for the packet. bytes message; // Message payload of the packet. bytes extraData; // Additional arbitrary data for the packet. } /** * @title PacketDecoder * @dev Library for decoding LayerZero packets. */ library PacketDecoder { using PacketV1Codec for bytes; /** * @dev Decode an inbound packet from the given packet data. * @param _packet The packet data to decode. * @return packet An InboundPacket struct representing the decoded packet. */ function decode(bytes calldata _packet) internal pure returns (InboundPacket memory packet) { packet.origin = Origin(_packet.srcEid(), _packet.sender(), _packet.nonce()); packet.dstEid = _packet.dstEid(); packet.receiver = _packet.receiverB20(); packet.guid = _packet.guid(); packet.message = _packet.message(); } /** * @dev Decode multiple inbound packets from the given packet data and associated message values. * @param _packets An array of packet data to decode. * @param _packetMsgValues An array of associated message values for each packet. * @return packets An array of InboundPacket structs representing the decoded packets. */ function decode( bytes[] calldata _packets, uint256[] memory _packetMsgValues ) internal pure returns (InboundPacket[] memory packets) { packets = new InboundPacket[](_packets.length); for (uint256 i = 0; i < _packets.length; i++) { bytes calldata packet = _packets[i]; packets[i] = PacketDecoder.decode(packet); // @dev Allows the verifier to specify the msg.value that gets passed in lzReceive. packets[i].value = _packetMsgValues[i]; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IPreCrime } from "./interfaces/IPreCrime.sol"; import { IOAppPreCrimeSimulator, InboundPacket, Origin } from "./interfaces/IOAppPreCrimeSimulator.sol"; /** * @title OAppPreCrimeSimulator * @dev Abstract contract serving as the base for preCrime simulation functionality in an OApp. */ abstract contract OAppPreCrimeSimulator is IOAppPreCrimeSimulator, Ownable { // The address of the preCrime implementation. address public preCrime; /** * @dev Retrieves the address of the OApp contract. * @return The address of the OApp contract. * * @dev The simulator contract is the base contract for the OApp by default. * @dev If the simulator is a separate contract, override this function. */ function oApp() external view virtual returns (address) { return address(this); } /** * @dev Sets the preCrime contract address. * @param _preCrime The address of the preCrime contract. */ function setPreCrime(address _preCrime) public virtual onlyOwner { preCrime = _preCrime; emit PreCrimeSet(_preCrime); } /** * @dev Interface for pre-crime simulations. Always reverts at the end with the simulation results. * @param _packets An array of InboundPacket objects representing received packets to be delivered. * * @dev WARNING: MUST revert at the end with the simulation results. * @dev Gives the preCrime implementation the ability to mock sending packets to the lzReceive function, * WITHOUT actually executing them. */ function lzReceiveAndRevert(InboundPacket[] calldata _packets) public payable virtual { for (uint256 i = 0; i < _packets.length; i++) { InboundPacket calldata packet = _packets[i]; // Ignore packets that are not from trusted peers. if (!isPeer(packet.origin.srcEid, packet.origin.sender)) continue; // @dev Because a verifier is calling this function, it doesnt have access to executor params: // - address _executor // - bytes calldata _extraData // preCrime will NOT work for OApps that rely on these two parameters inside of their _lzReceive(). // They are instead stubbed to default values, address(0) and bytes("") // @dev Calling this.lzReceiveSimulate removes ability for assembly return 0 callstack exit, // which would cause the revert to be ignored. this.lzReceiveSimulate{ value: packet.value }( packet.origin, packet.guid, packet.message, packet.executor, packet.extraData ); } // @dev Revert with the simulation results. msg.sender must implement IPreCrime.buildSimulationResult(). revert SimulationResult(IPreCrime(msg.sender).buildSimulationResult()); } /** * @dev Is effectively an internal function because msg.sender must be address(this). * Allows resetting the call stack for 'internal' calls. * @param _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @param _guid The unique identifier of the packet. * @param _message The message payload of the packet. * @param _executor The executor address for the packet. * @param _extraData Additional data for the packet. */ function lzReceiveSimulate( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) external payable virtual { // @dev Ensure ONLY can be called 'internally'. if (msg.sender != address(this)) revert OnlySelf(); _lzReceiveSimulate(_origin, _guid, _message, _executor, _extraData); } /** * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive. * @param _origin The origin information. * - srcEid: The source chain endpoint ID. * - sender: The sender address from the src chain. * - nonce: The nonce of the LayerZero message. * @param _guid The GUID of the LayerZero message. * @param _message The LayerZero message. * @param _executor The address of the off-chain executor. * @param _extraData Arbitrary data passed by the msg executor. * * @dev Enables the preCrime simulator to mock sending lzReceive() messages, * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver. */ function _lzReceiveSimulate( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) internal virtual; /** * @dev checks if the specified peer is considered 'trusted' by the OApp. * @param _eid The endpoint Id to check. * @param _peer The peer to check. * @return Whether the peer passed is considered 'trusted' by the OApp. */ function isPeer(uint32 _eid, bytes32 _peer) public view virtual returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { MessagingReceipt, MessagingFee } from "@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol"; /** * @dev Struct representing token parameters for the OFT send() operation. */ struct SendParam { uint32 dstEid; // Destination endpoint ID. bytes32 to; // Recipient address. uint256 amountLD; // Amount to send in local decimals. uint256 minAmountLD; // Minimum amount to send in local decimals. bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message. bytes composeMsg; // The composed message for the send() operation. bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations. } /** * @dev Struct representing OFT limit information. * @dev These amounts can change dynamically and are up the specific oft implementation. */ struct OFTLimit { uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient. uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient. } /** * @dev Struct representing OFT receipt information. */ struct OFTReceipt { uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals. // @dev In non-default implementations, the amountReceivedLD COULD differ from this value. uint256 amountReceivedLD; // Amount of tokens to be received on the remote side. } /** * @dev Struct representing OFT fee details. * @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI. */ struct OFTFeeDetail { int256 feeAmountLD; // Amount of the fee in local decimals. string description; // Description of the fee. } /** * @title IOFT * @dev Interface for the OftChain (OFT) token. * @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well. * @dev This specific interface ID is '0x02e49c2c'. */ interface IOFT { // Custom error messages error InvalidLocalDecimals(); error SlippageExceeded(uint256 amountLD, uint256 minAmountLD); // Events event OFTSent( bytes32 indexed guid, // GUID of the OFT message. uint32 dstEid, // Destination Endpoint ID. address indexed fromAddress, // Address of the sender on the src chain. uint256 amountSentLD, // Amount of tokens sent in local decimals. uint256 amountReceivedLD // Amount of tokens received in local decimals. ); event OFTReceived( bytes32 indexed guid, // GUID of the OFT message. uint32 srcEid, // Source Endpoint ID. address indexed toAddress, // Address of the recipient on the dst chain. uint256 amountReceivedLD // Amount of tokens received in local decimals. ); /** * @notice Retrieves interfaceID and the version of the OFT. * @return interfaceId The interface ID. * @return version The version. * * @dev interfaceId: This specific interface ID is '0x02e49c2c'. * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs. * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented. * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1) */ function oftVersion() external view returns (bytes4 interfaceId, uint64 version); /** * @notice Retrieves the address of the token associated with the OFT. * @return token The address of the ERC20 token implementation. */ function token() external view returns (address); /** * @notice Indicates whether the OFT contract requires approval of the 'token()' to send. * @return requiresApproval Needs approval of the underlying token implementation. * * @dev Allows things like wallet implementers to determine integration requirements, * without understanding the underlying token implementation. */ function approvalRequired() external view returns (bool); /** * @notice Retrieves the shared decimals of the OFT. * @return sharedDecimals The shared decimals of the OFT. */ function sharedDecimals() external view returns (uint8); /** * @notice Provides a quote for OFT-related operations. * @param _sendParam The parameters for the send operation. * @return limit The OFT limit information. * @return oftFeeDetails The details of OFT fees. * @return receipt The OFT receipt information. */ function quoteOFT( SendParam calldata _sendParam ) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory); /** * @notice Provides a quote for the send() operation. * @param _sendParam The parameters for the send() operation. * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token. * @return fee The calculated LayerZero messaging fee from the send() operation. * * @dev MessagingFee: LayerZero msg fee * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. */ function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory); /** * @notice Executes the send() operation. * @param _sendParam The parameters for the send operation. * @param _fee The fee information supplied by the caller. * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. * @param _refundAddress The address to receive any excess funds from fees etc. on the src. * @return receipt The LayerZero messaging receipt from the send() operation. * @return oftReceipt The OFT receipt information. * * @dev MessagingReceipt: LayerZero msg receipt * - guid: The unique identifier for the sent message. * - nonce: The nonce of the sent message. * - fee: The LayerZero fee incurred for the message. */ function send( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) external payable returns (MessagingReceipt memory, OFTReceipt memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; library OFTComposeMsgCodec { // Offset constants for decoding composed messages uint8 private constant NONCE_OFFSET = 8; uint8 private constant SRC_EID_OFFSET = 12; uint8 private constant AMOUNT_LD_OFFSET = 44; uint8 private constant COMPOSE_FROM_OFFSET = 76; /** * @dev Encodes a OFT composed message. * @param _nonce The nonce value. * @param _srcEid The source endpoint ID. * @param _amountLD The amount in local decimals. * @param _composeMsg The composed message. * @return _msg The encoded Composed message. */ function encode( uint64 _nonce, uint32 _srcEid, uint256 _amountLD, bytes memory _composeMsg // 0x[composeFrom][composeMsg] ) internal pure returns (bytes memory _msg) { _msg = abi.encodePacked(_nonce, _srcEid, _amountLD, _composeMsg); } /** * @dev Retrieves the nonce for the composed message. * @param _msg The message. * @return The nonce value. */ function nonce(bytes calldata _msg) internal pure returns (uint64) { return uint64(bytes8(_msg[:NONCE_OFFSET])); } /** * @dev Retrieves the source endpoint ID for the composed message. * @param _msg The message. * @return The source endpoint ID. */ function srcEid(bytes calldata _msg) internal pure returns (uint32) { return uint32(bytes4(_msg[NONCE_OFFSET:SRC_EID_OFFSET])); } /** * @dev Retrieves the amount in local decimals from the composed message. * @param _msg The message. * @return The amount in local decimals. */ function amountLD(bytes calldata _msg) internal pure returns (uint256) { return uint256(bytes32(_msg[SRC_EID_OFFSET:AMOUNT_LD_OFFSET])); } /** * @dev Retrieves the composeFrom value from the composed message. * @param _msg The message. * @return The composeFrom value. */ function composeFrom(bytes calldata _msg) internal pure returns (bytes32) { return bytes32(_msg[AMOUNT_LD_OFFSET:COMPOSE_FROM_OFFSET]); } /** * @dev Retrieves the composed message. * @param _msg The message. * @return The composed message. */ function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) { return _msg[COMPOSE_FROM_OFFSET:]; } /** * @dev Converts an address to bytes32. * @param _addr The address to convert. * @return The bytes32 representation of the address. */ function addressToBytes32(address _addr) internal pure returns (bytes32) { return bytes32(uint256(uint160(_addr))); } /** * @dev Converts bytes32 to an address. * @param _b The bytes32 value to convert. * @return The address representation of bytes32. */ function bytes32ToAddress(bytes32 _b) internal pure returns (address) { return address(uint160(uint256(_b))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; library OFTMsgCodec { // Offset constants for encoding and decoding OFT messages uint8 private constant SEND_TO_OFFSET = 32; uint8 private constant SEND_AMOUNT_SD_OFFSET = 40; /** * @dev Encodes an OFT LayerZero message. * @param _sendTo The recipient address. * @param _amountShared The amount in shared decimals. * @param _composeMsg The composed message. * @return _msg The encoded message. * @return hasCompose A boolean indicating whether the message has a composed payload. */ function encode( bytes32 _sendTo, uint64 _amountShared, bytes memory _composeMsg ) internal view returns (bytes memory _msg, bool hasCompose) { hasCompose = _composeMsg.length > 0; // @dev Remote chains will want to know the composed function caller ie. msg.sender on the src. _msg = hasCompose ? abi.encodePacked(_sendTo, _amountShared, addressToBytes32(msg.sender), _composeMsg) : abi.encodePacked(_sendTo, _amountShared); } /** * @dev Checks if the OFT message is composed. * @param _msg The OFT message. * @return A boolean indicating whether the message is composed. */ function isComposed(bytes calldata _msg) internal pure returns (bool) { return _msg.length > SEND_AMOUNT_SD_OFFSET; } /** * @dev Retrieves the recipient address from the OFT message. * @param _msg The OFT message. * @return The recipient address. */ function sendTo(bytes calldata _msg) internal pure returns (bytes32) { return bytes32(_msg[:SEND_TO_OFFSET]); } /** * @dev Retrieves the amount in shared decimals from the OFT message. * @param _msg The OFT message. * @return The amount in shared decimals. */ function amountSD(bytes calldata _msg) internal pure returns (uint64) { return uint64(bytes8(_msg[SEND_TO_OFFSET:SEND_AMOUNT_SD_OFFSET])); } /** * @dev Retrieves the composed message from the OFT message. * @param _msg The OFT message. * @return The composed message. */ function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) { return _msg[SEND_AMOUNT_SD_OFFSET:]; } /** * @dev Converts an address to bytes32. * @param _addr The address to convert. * @return The bytes32 representation of the address. */ function addressToBytes32(address _addr) internal pure returns (bytes32) { return bytes32(uint256(uint160(_addr))); } /** * @dev Converts bytes32 to an address. * @param _b The bytes32 value to convert. * @return The address representation of bytes32. */ function bytes32ToAddress(bytes32 _b) internal pure returns (address) { return address(uint160(uint256(_b))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IOFT, OFTCore } from "./OFTCore.sol"; /** * @title OFT Contract * @dev OFT is an ERC-20 token that extends the functionality of the OFTCore contract. */ abstract contract OFT is OFTCore, ERC20 { /** * @dev Constructor for the OFT contract. * @param _name The name of the OFT. * @param _symbol The symbol of the OFT. * @param _lzEndpoint The LayerZero endpoint address. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. */ constructor( string memory _name, string memory _symbol, address _lzEndpoint, address _delegate ) ERC20(_name, _symbol) OFTCore(decimals(), _lzEndpoint, _delegate) {} /** * @dev Retrieves the address of the underlying ERC20 implementation. * @return The address of the OFT token. * * @dev In the case of OFT, address(this) and erc20 are the same contract. */ function token() public view returns (address) { return address(this); } /** * @notice Indicates whether the OFT contract requires approval of the 'token()' to send. * @return requiresApproval Needs approval of the underlying token implementation. * * @dev In the case of OFT where the contract IS the token, approval is NOT required. */ function approvalRequired() external pure virtual returns (bool) { return false; } /** * @dev Burns tokens from the sender's specified balance. * @param _from The address to debit the tokens from. * @param _amountLD The amount of tokens to send in local decimals. * @param _minAmountLD The minimum amount to send in local decimals. * @param _dstEid The destination chain ID. * @return amountSentLD The amount sent in local decimals. * @return amountReceivedLD The amount received in local decimals on the remote. */ function _debit( address _from, uint256 _amountLD, uint256 _minAmountLD, uint32 _dstEid ) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) { (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid); // @dev In NON-default OFT, amountSentLD could be 100, with a 10% fee, the amountReceivedLD amount is 90, // therefore amountSentLD CAN differ from amountReceivedLD. // @dev Default OFT burns on src. _burn(_from, amountSentLD); } /** * @dev Credits tokens to the specified address. * @param _to The address to credit the tokens to. * @param _amountLD The amount of tokens to credit in local decimals. * @dev _srcEid The source chain ID. * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals. */ function _credit( address _to, uint256 _amountLD, uint32 /*_srcEid*/ ) internal virtual override returns (uint256 amountReceivedLD) { if (_to == address(0x0)) _to = address(0xdead); // _mint(...) does not support address(0x0) // @dev Default OFT mints on dst. _mint(_to, _amountLD); // @dev In the case of NON-default OFT, the _amountLD MIGHT not be == amountReceivedLD. return _amountLD; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { OApp, Origin } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; import { OAppOptionsType3 } from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OAppOptionsType3.sol"; import { IOAppMsgInspector } from "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppMsgInspector.sol"; import { OAppPreCrimeSimulator } from "@layerzerolabs/oapp-evm/contracts/precrime/OAppPreCrimeSimulator.sol"; import { IOFT, SendParam, OFTLimit, OFTReceipt, OFTFeeDetail, MessagingReceipt, MessagingFee } from "./interfaces/IOFT.sol"; import { OFTMsgCodec } from "./libs/OFTMsgCodec.sol"; import { OFTComposeMsgCodec } from "./libs/OFTComposeMsgCodec.sol"; /** * @title OFTCore * @dev Abstract contract for the OftChain (OFT) token. */ abstract contract OFTCore is IOFT, OApp, OAppPreCrimeSimulator, OAppOptionsType3 { using OFTMsgCodec for bytes; using OFTMsgCodec for bytes32; // @notice Provides a conversion rate when swapping between denominations of SD and LD // - shareDecimals == SD == shared Decimals // - localDecimals == LD == local decimals // @dev Considers that tokens have different decimal amounts on various chains. // @dev eg. // For a token // - locally with 4 decimals --> 1.2345 => uint(12345) // - remotely with 2 decimals --> 1.23 => uint(123) // - The conversion rate would be 10 ** (4 - 2) = 100 // @dev If you want to send 1.2345 -> (uint 12345), you CANNOT represent that value on the remote, // you can only display 1.23 -> uint(123). // @dev To preserve the dust that would otherwise be lost on that conversion, // we need to unify a denomination that can be represented on ALL chains inside of the OFT mesh uint256 public immutable decimalConversionRate; // @notice Msg types that are used to identify the various OFT operations. // @dev This can be extended in child contracts for non-default oft operations // @dev These values are used in things like combineOptions() in OAppOptionsType3.sol. uint16 public constant SEND = 1; uint16 public constant SEND_AND_CALL = 2; // Address of an optional contract to inspect both 'message' and 'options' address public msgInspector; event MsgInspectorSet(address inspector); /** * @dev Constructor. * @param _localDecimals The decimals of the token on the local chain (this chain). * @param _endpoint The address of the LayerZero endpoint. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. */ constructor(uint8 _localDecimals, address _endpoint, address _delegate) OApp(_endpoint, _delegate) { if (_localDecimals < sharedDecimals()) revert InvalidLocalDecimals(); decimalConversionRate = 10 ** (_localDecimals - sharedDecimals()); } /** * @notice Retrieves interfaceID and the version of the OFT. * @return interfaceId The interface ID. * @return version The version. * * @dev interfaceId: This specific interface ID is '0x02e49c2c'. * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs. * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented. * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1) */ function oftVersion() external pure virtual returns (bytes4 interfaceId, uint64 version) { return (type(IOFT).interfaceId, 1); } /** * @dev Retrieves the shared decimals of the OFT. * @return The shared decimals of the OFT. * * @dev Sets an implicit cap on the amount of tokens, over uint64.max() will need some sort of outbound cap / totalSupply cap * Lowest common decimal denominator between chains. * Defaults to 6 decimal places to provide up to 18,446,744,073,709.551615 units (max uint64). * For tokens exceeding this totalSupply(), they will need to override the sharedDecimals function with something smaller. * ie. 4 sharedDecimals would be 1,844,674,407,370,955.1615 */ function sharedDecimals() public view virtual returns (uint8) { return 6; } /** * @dev Sets the message inspector address for the OFT. * @param _msgInspector The address of the message inspector. * * @dev This is an optional contract that can be used to inspect both 'message' and 'options'. * @dev Set it to address(0) to disable it, or set it to a contract address to enable it. */ function setMsgInspector(address _msgInspector) public virtual onlyOwner { msgInspector = _msgInspector; emit MsgInspectorSet(_msgInspector); } /** * @notice Provides a quote for OFT-related operations. * @param _sendParam The parameters for the send operation. * @return oftLimit The OFT limit information. * @return oftFeeDetails The details of OFT fees. * @return oftReceipt The OFT receipt information. */ function quoteOFT( SendParam calldata _sendParam ) external view virtual returns (OFTLimit memory oftLimit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory oftReceipt) { uint256 minAmountLD = 0; // Unused in the default implementation. uint256 maxAmountLD = type(uint64).max; // Unused in the default implementation. oftLimit = OFTLimit(minAmountLD, maxAmountLD); // Unused in the default implementation; reserved for future complex fee details. oftFeeDetails = new OFTFeeDetail[](0); // @dev This is the same as the send() operation, but without the actual send. // - amountSentLD is the amount in local decimals that would be sent from the sender. // - amountReceivedLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance. // @dev The amountSentLD MIGHT not equal the amount the user actually receives. HOWEVER, the default does. (uint256 amountSentLD, uint256 amountReceivedLD) = _debitView( _sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid ); oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD); } /** * @notice Provides a quote for the send() operation. * @param _sendParam The parameters for the send() operation. * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token. * @return msgFee The calculated LayerZero messaging fee from the send() operation. * * @dev MessagingFee: LayerZero msg fee * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. */ function quoteSend( SendParam calldata _sendParam, bool _payInLzToken ) external view virtual returns (MessagingFee memory msgFee) { // @dev mock the amount to receive, this is the same operation used in the send(). // The quote is as similar as possible to the actual send() operation. (, uint256 amountReceivedLD) = _debitView(_sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid); // @dev Builds the options and OFT message to quote in the endpoint. (bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD); // @dev Calculates the LayerZero fee for the send() operation. return _quote(_sendParam.dstEid, message, options, _payInLzToken); } /** * @dev Executes the send operation. * @param _sendParam The parameters for the send operation. * @param _fee The calculated fee for the send() operation. * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. * @param _refundAddress The address to receive any excess funds. * @return msgReceipt The receipt for the send operation. * @return oftReceipt The OFT receipt information. * * @dev MessagingReceipt: LayerZero msg receipt * - guid: The unique identifier for the sent message. * - nonce: The nonce of the sent message. * - fee: The LayerZero fee incurred for the message. */ function send( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) external payable virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) { // @dev Applies the token transfers regarding this send() operation. // - amountSentLD is the amount in local decimals that was ACTUALLY sent/debited from the sender. // - amountReceivedLD is the amount in local decimals that will be received/credited to the recipient on the remote OFT instance. (uint256 amountSentLD, uint256 amountReceivedLD) = _debit( msg.sender, _sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid ); // @dev Builds the options and OFT message to quote in the endpoint. (bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD); // @dev Sends the message to the LayerZero endpoint and returns the LayerZero msg receipt. msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress); // @dev Formulate the OFT receipt. oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD); emit OFTSent(msgReceipt.guid, _sendParam.dstEid, msg.sender, amountSentLD, amountReceivedLD); } /** * @dev Internal function to build the message and options. * @param _sendParam The parameters for the send() operation. * @param _amountLD The amount in local decimals. * @return message The encoded message. * @return options The encoded options. */ function _buildMsgAndOptions( SendParam calldata _sendParam, uint256 _amountLD ) internal view virtual returns (bytes memory message, bytes memory options) { bool hasCompose; // @dev This generated message has the msg.sender encoded into the payload so the remote knows who the caller is. (message, hasCompose) = OFTMsgCodec.encode( _sendParam.to, _toSD(_amountLD), // @dev Must be include a non empty bytes if you want to compose, EVEN if you dont need it on the remote. // EVEN if you dont require an arbitrary payload to be sent... eg. '0x01' _sendParam.composeMsg ); // @dev Change the msg type depending if its composed or not. uint16 msgType = hasCompose ? SEND_AND_CALL : SEND; // @dev Combine the callers _extraOptions with the enforced options via the OAppOptionsType3. options = combineOptions(_sendParam.dstEid, msgType, _sendParam.extraOptions); // @dev Optionally inspect the message and options depending if the OApp owner has set a msg inspector. // @dev If it fails inspection, needs to revert in the implementation. ie. does not rely on return boolean address inspector = msgInspector; // caches the msgInspector to avoid potential double storage read if (inspector != address(0)) IOAppMsgInspector(inspector).inspect(message, options); } /** * @dev Internal function to handle the receive on the LayerZero endpoint. * @param _origin The origin information. * - srcEid: The source chain endpoint ID. * - sender: The sender address from the src chain. * - nonce: The nonce of the LayerZero message. * @param _guid The unique identifier for the received LayerZero message. * @param _message The encoded message. * @dev _executor The address of the executor. * @dev _extraData Additional data. */ function _lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address /*_executor*/, // @dev unused in the default implementation. bytes calldata /*_extraData*/ // @dev unused in the default implementation. ) internal virtual override { // @dev The src sending chain doesnt know the address length on this chain (potentially non-evm) // Thus everything is bytes32() encoded in flight. address toAddress = _message.sendTo().bytes32ToAddress(); // @dev Credit the amountLD to the recipient and return the ACTUAL amount the recipient received in local decimals uint256 amountReceivedLD = _credit(toAddress, _toLD(_message.amountSD()), _origin.srcEid); if (_message.isComposed()) { // @dev Proprietary composeMsg format for the OFT. bytes memory composeMsg = OFTComposeMsgCodec.encode( _origin.nonce, _origin.srcEid, amountReceivedLD, _message.composeMsg() ); // @dev Stores the lzCompose payload that will be executed in a separate tx. // Standardizes functionality for executing arbitrary contract invocation on some non-evm chains. // @dev The off-chain executor will listen and process the msg based on the src-chain-callers compose options passed. // @dev The index is used when a OApp needs to compose multiple msgs on lzReceive. // For default OFT implementation there is only 1 compose msg per lzReceive, thus its always 0. endpoint.sendCompose(toAddress, _guid, 0 /* the index of the composed message*/, composeMsg); } emit OFTReceived(_guid, _origin.srcEid, toAddress, amountReceivedLD); } /** * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive. * @param _origin The origin information. * - srcEid: The source chain endpoint ID. * - sender: The sender address from the src chain. * - nonce: The nonce of the LayerZero message. * @param _guid The unique identifier for the received LayerZero message. * @param _message The LayerZero message. * @param _executor The address of the off-chain executor. * @param _extraData Arbitrary data passed by the msg executor. * * @dev Enables the preCrime simulator to mock sending lzReceive() messages, * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver. */ function _lzReceiveSimulate( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) internal virtual override { _lzReceive(_origin, _guid, _message, _executor, _extraData); } /** * @dev Check if the peer is considered 'trusted' by the OApp. * @param _eid The endpoint ID to check. * @param _peer The peer to check. * @return Whether the peer passed is considered 'trusted' by the OApp. * * @dev Enables OAppPreCrimeSimulator to check whether a potential Inbound Packet is from a trusted source. */ function isPeer(uint32 _eid, bytes32 _peer) public view virtual override returns (bool) { return peers[_eid] == _peer; } /** * @dev Internal function to remove dust from the given local decimal amount. * @param _amountLD The amount in local decimals. * @return amountLD The amount after removing dust. * * @dev Prevents the loss of dust when moving amounts between chains with different decimals. * @dev eg. uint(123) with a conversion rate of 100 becomes uint(100). */ function _removeDust(uint256 _amountLD) internal view virtual returns (uint256 amountLD) { return (_amountLD / decimalConversionRate) * decimalConversionRate; } /** * @dev Internal function to convert an amount from shared decimals into local decimals. * @param _amountSD The amount in shared decimals. * @return amountLD The amount in local decimals. */ function _toLD(uint64 _amountSD) internal view virtual returns (uint256 amountLD) { return _amountSD * decimalConversionRate; } /** * @dev Internal function to convert an amount from local decimals into shared decimals. * @param _amountLD The amount in local decimals. * @return amountSD The amount in shared decimals. */ function _toSD(uint256 _amountLD) internal view virtual returns (uint64 amountSD) { return uint64(_amountLD / decimalConversionRate); } /** * @dev Internal function to mock the amount mutation from a OFT debit() operation. * @param _amountLD The amount to send in local decimals. * @param _minAmountLD The minimum amount to send in local decimals. * @dev _dstEid The destination endpoint ID. * @return amountSentLD The amount sent, in local decimals. * @return amountReceivedLD The amount to be received on the remote chain, in local decimals. * * @dev This is where things like fees would be calculated and deducted from the amount to be received on the remote. */ function _debitView( uint256 _amountLD, uint256 _minAmountLD, uint32 /*_dstEid*/ ) internal view virtual returns (uint256 amountSentLD, uint256 amountReceivedLD) { // @dev Remove the dust so nothing is lost on the conversion between chains with different decimals for the token. amountSentLD = _removeDust(_amountLD); // @dev The amount to send is the same as amount received in the default implementation. amountReceivedLD = amountSentLD; // @dev Check for slippage. if (amountReceivedLD < _minAmountLD) { revert SlippageExceeded(amountReceivedLD, _minAmountLD); } } /** * @dev Internal function to perform a debit operation. * @param _from The address to debit. * @param _amountLD The amount to send in local decimals. * @param _minAmountLD The minimum amount to send in local decimals. * @param _dstEid The destination endpoint ID. * @return amountSentLD The amount sent in local decimals. * @return amountReceivedLD The amount received in local decimals on the remote. * * @dev Defined here but are intended to be overriden depending on the OFT implementation. * @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD. */ function _debit( address _from, uint256 _amountLD, uint256 _minAmountLD, uint32 _dstEid ) internal virtual returns (uint256 amountSentLD, uint256 amountReceivedLD); /** * @dev Internal function to perform a credit operation. * @param _to The address to credit. * @param _amountLD The amount to credit in local decimals. * @param _srcEid The source endpoint ID. * @return amountReceivedLD The amount ACTUALLY received in local decimals. * * @dev Defined here but are intended to be overriden depending on the OFT implementation. * @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD. */ function _credit( address _to, uint256 _amountLD, uint32 _srcEid ) internal virtual returns (uint256 amountReceivedLD); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC-165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role). * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.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 Ownable is Context { address private _owner; /** * @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. */ constructor(address initialOwner) { 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) { 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 { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (finance/VestingWallet.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol"; import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol"; import {Address} from "../utils/Address.sol"; import {Context} from "../utils/Context.sol"; import {Ownable} from "../access/Ownable.sol"; /** * @dev A vesting wallet is an ownable contract that can receive native currency and ERC-20 tokens, and release these * assets to the wallet owner, also referred to as "beneficiary", according to a vesting schedule. * * Any assets transferred to this contract will follow the vesting schedule as if they were locked from the beginning. * Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly) * be immediately releasable. * * By setting the duration to 0, one can configure this contract to behave like an asset timelock that hold tokens for * a beneficiary until a specified time. * * NOTE: Since the wallet is {Ownable}, and ownership can be transferred, it is possible to sell unvested tokens. * Preventing this in a smart contract is difficult, considering that: 1) a beneficiary address could be a * counterfactually deployed contract, 2) there is likely to be a migration path for EOAs to become contracts in the * near future. * * NOTE: When using this contract with any token whose balance is adjusted automatically (i.e. a rebase token), make * sure to account the supply/balance adjustment in the vesting schedule to ensure the vested amount is as intended. */ contract VestingWallet is Context, Ownable { event EtherReleased(uint256 amount); event ERC20Released(address indexed token, uint256 amount); uint256 private _released; mapping(address token => uint256) private _erc20Released; uint64 private immutable _start; uint64 private immutable _duration; /** * @dev Sets the beneficiary (owner), the start timestamp and the vesting duration (in seconds) of the vesting * wallet. */ constructor(address beneficiary, uint64 startTimestamp, uint64 durationSeconds) payable Ownable(beneficiary) { _start = startTimestamp; _duration = durationSeconds; } /** * @dev The contract should be able to receive Eth. */ receive() external payable virtual {} /** * @dev Getter for the start timestamp. */ function start() public view virtual returns (uint256) { return _start; } /** * @dev Getter for the vesting duration. */ function duration() public view virtual returns (uint256) { return _duration; } /** * @dev Getter for the end timestamp. */ function end() public view virtual returns (uint256) { return start() + duration(); } /** * @dev Amount of eth already released */ function released() public view virtual returns (uint256) { return _released; } /** * @dev Amount of token already released */ function released(address token) public view virtual returns (uint256) { return _erc20Released[token]; } /** * @dev Getter for the amount of releasable eth. */ function releasable() public view virtual returns (uint256) { return vestedAmount(uint64(block.timestamp)) - released(); } /** * @dev Getter for the amount of releasable `token` tokens. `token` should be the address of an * {IERC20} contract. */ function releasable(address token) public view virtual returns (uint256) { return vestedAmount(token, uint64(block.timestamp)) - released(token); } /** * @dev Release the native token (ether) that have already vested. * * Emits a {EtherReleased} event. */ function release() public virtual { uint256 amount = releasable(); _released += amount; emit EtherReleased(amount); Address.sendValue(payable(owner()), amount); } /** * @dev Release the tokens that have already vested. * * Emits a {ERC20Released} event. */ function release(address token) public virtual { uint256 amount = releasable(token); _erc20Released[token] += amount; emit ERC20Released(token, amount); SafeERC20.safeTransfer(IERC20(token), owner(), amount); } /** * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve. */ function vestedAmount(uint64 timestamp) public view virtual returns (uint256) { return _vestingSchedule(address(this).balance + released(), timestamp); } /** * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve. */ function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) { return _vestingSchedule(IERC20(token).balanceOf(address(this)) + released(token), timestamp); } /** * @dev Virtual implementation of the vesting formula. This returns the amount vested, as a function of time, for * an asset given its total historical allocation. */ function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) { if (timestamp < start()) { return 0; } else if (timestamp >= end()) { return totalAllocation; } else { return (totalAllocation * (timestamp - start())) / duration(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorCountingSimple.sol) pragma solidity ^0.8.20; import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} for simple, 3 options, vote counting. */ abstract contract GovernorCountingSimple is Governor { /** * @dev Supported vote types. Matches Governor Bravo ordering. */ enum VoteType { Against, For, Abstain } struct ProposalVote { uint256 againstVotes; uint256 forVotes; uint256 abstainVotes; mapping(address voter => bool) hasVoted; } mapping(uint256 proposalId => ProposalVote) private _proposalVotes; /** * @dev See {IGovernor-COUNTING_MODE}. */ // solhint-disable-next-line func-name-mixedcase function COUNTING_MODE() public pure virtual override returns (string memory) { return "support=bravo&quorum=for,abstain"; } /** * @dev See {IGovernor-hasVoted}. */ function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { return _proposalVotes[proposalId].hasVoted[account]; } /** * @dev Accessor to the internal vote counts. */ function proposalVotes( uint256 proposalId ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) { ProposalVote storage proposalVote = _proposalVotes[proposalId]; return (proposalVote.againstVotes, proposalVote.forVotes, proposalVote.abstainVotes); } /** * @dev See {Governor-_quorumReached}. */ function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { ProposalVote storage proposalVote = _proposalVotes[proposalId]; return quorum(proposalSnapshot(proposalId)) <= proposalVote.forVotes + proposalVote.abstainVotes; } /** * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes. */ function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) { ProposalVote storage proposalVote = _proposalVotes[proposalId]; return proposalVote.forVotes > proposalVote.againstVotes; } /** * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo). */ function _countVote( uint256 proposalId, address account, uint8 support, uint256 totalWeight, bytes memory // params ) internal virtual override returns (uint256) { ProposalVote storage proposalVote = _proposalVotes[proposalId]; if (proposalVote.hasVoted[account]) { revert GovernorAlreadyCastVote(account); } proposalVote.hasVoted[account] = true; if (support == uint8(VoteType.Against)) { proposalVote.againstVotes += totalWeight; } else if (support == uint8(VoteType.For)) { proposalVote.forVotes += totalWeight; } else if (support == uint8(VoteType.Abstain)) { proposalVote.abstainVotes += totalWeight; } else { revert GovernorInvalidVoteType(); } return totalWeight; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorSettings.sol) pragma solidity ^0.8.20; import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} for settings updatable through governance. */ abstract contract GovernorSettings is Governor { // amount of token uint256 private _proposalThreshold; // timepoint: limited to uint48 in core (same as clock() type) uint48 private _votingDelay; // duration: limited to uint32 in core uint32 private _votingPeriod; event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay); event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod); event ProposalThresholdSet(uint256 oldProposalThreshold, uint256 newProposalThreshold); /** * @dev Initialize the governance parameters. */ constructor(uint48 initialVotingDelay, uint32 initialVotingPeriod, uint256 initialProposalThreshold) { _setVotingDelay(initialVotingDelay); _setVotingPeriod(initialVotingPeriod); _setProposalThreshold(initialProposalThreshold); } /** * @dev See {IGovernor-votingDelay}. */ function votingDelay() public view virtual override returns (uint256) { return _votingDelay; } /** * @dev See {IGovernor-votingPeriod}. */ function votingPeriod() public view virtual override returns (uint256) { return _votingPeriod; } /** * @dev See {Governor-proposalThreshold}. */ function proposalThreshold() public view virtual override returns (uint256) { return _proposalThreshold; } /** * @dev Update the voting delay. This operation can only be performed through a governance proposal. * * Emits a {VotingDelaySet} event. */ function setVotingDelay(uint48 newVotingDelay) public virtual onlyGovernance { _setVotingDelay(newVotingDelay); } /** * @dev Update the voting period. This operation can only be performed through a governance proposal. * * Emits a {VotingPeriodSet} event. */ function setVotingPeriod(uint32 newVotingPeriod) public virtual onlyGovernance { _setVotingPeriod(newVotingPeriod); } /** * @dev Update the proposal threshold. This operation can only be performed through a governance proposal. * * Emits a {ProposalThresholdSet} event. */ function setProposalThreshold(uint256 newProposalThreshold) public virtual onlyGovernance { _setProposalThreshold(newProposalThreshold); } /** * @dev Internal setter for the voting delay. * * Emits a {VotingDelaySet} event. */ function _setVotingDelay(uint48 newVotingDelay) internal virtual { emit VotingDelaySet(_votingDelay, newVotingDelay); _votingDelay = newVotingDelay; } /** * @dev Internal setter for the voting period. * * Emits a {VotingPeriodSet} event. */ function _setVotingPeriod(uint32 newVotingPeriod) internal virtual { if (newVotingPeriod == 0) { revert GovernorInvalidVotingPeriod(0); } emit VotingPeriodSet(_votingPeriod, newVotingPeriod); _votingPeriod = newVotingPeriod; } /** * @dev Internal setter for the proposal threshold. * * Emits a {ProposalThresholdSet} event. */ function _setProposalThreshold(uint256 newProposalThreshold) internal virtual { emit ProposalThresholdSet(_proposalThreshold, newProposalThreshold); _proposalThreshold = newProposalThreshold; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorTimelockControl.sol) pragma solidity ^0.8.20; import {IGovernor, Governor} from "../Governor.sol"; import {TimelockController} from "../TimelockController.sol"; import {IERC165} from "../../interfaces/IERC165.sol"; import {SafeCast} from "../../utils/math/SafeCast.sol"; /** * @dev Extension of {Governor} that binds the execution process to an instance of {TimelockController}. This adds a * delay, enforced by the {TimelockController} to all successful proposal (in addition to the voting duration). The * {Governor} needs the proposer (and ideally the executor and canceller) roles for the {Governor} to work properly. * * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be * inaccessible from a proposal, unless executed via {Governor-relay}. * * WARNING: Setting up the TimelockController to have additional proposers or cancellers besides the governor is very * risky, as it grants them the ability to: 1) execute operations as the timelock, and thus possibly performing * operations or accessing funds that are expected to only be accessible through a vote, and 2) block governance * proposals that have been approved by the voters, effectively executing a Denial of Service attack. */ abstract contract GovernorTimelockControl is Governor { TimelockController private _timelock; mapping(uint256 proposalId => bytes32) private _timelockIds; /** * @dev Emitted when the timelock controller used for proposal execution is modified. */ event TimelockChange(address oldTimelock, address newTimelock); /** * @dev Set the timelock. */ constructor(TimelockController timelockAddress) { _updateTimelock(timelockAddress); } /** * @dev Overridden version of the {Governor-state} function that considers the status reported by the timelock. */ function state(uint256 proposalId) public view virtual override returns (ProposalState) { ProposalState currentState = super.state(proposalId); if (currentState != ProposalState.Queued) { return currentState; } bytes32 queueid = _timelockIds[proposalId]; if (_timelock.isOperationPending(queueid)) { return ProposalState.Queued; } else if (_timelock.isOperationDone(queueid)) { // This can happen if the proposal is executed directly on the timelock. return ProposalState.Executed; } else { // This can happen if the proposal is canceled directly on the timelock. return ProposalState.Canceled; } } /** * @dev Public accessor to check the address of the timelock */ function timelock() public view virtual returns (address) { return address(_timelock); } /** * @dev See {IGovernor-proposalNeedsQueuing}. */ function proposalNeedsQueuing(uint256) public view virtual override returns (bool) { return true; } /** * @dev Function to queue a proposal to the timelock. */ function _queueOperations( uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal virtual override returns (uint48) { uint256 delay = _timelock.getMinDelay(); bytes32 salt = _timelockSalt(descriptionHash); _timelockIds[proposalId] = _timelock.hashOperationBatch(targets, values, calldatas, 0, salt); _timelock.scheduleBatch(targets, values, calldatas, 0, salt, delay); return SafeCast.toUint48(block.timestamp + delay); } /** * @dev Overridden version of the {Governor-_executeOperations} function that runs the already queued proposal * through the timelock. */ function _executeOperations( uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal virtual override { // execute _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, _timelockSalt(descriptionHash)); // cleanup for refund delete _timelockIds[proposalId]; } /** * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it has already * been queued. */ // This function can reenter through the external call to the timelock, but we assume the timelock is trusted and // well behaved (according to TimelockController) and this will not happen. // slither-disable-next-line reentrancy-no-eth function _cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal virtual override returns (uint256) { uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); bytes32 timelockId = _timelockIds[proposalId]; if (timelockId != 0) { // cancel _timelock.cancel(timelockId); // cleanup delete _timelockIds[proposalId]; } return proposalId; } /** * @dev Address through which the governor executes action. In this case, the timelock. */ function _executor() internal view virtual override returns (address) { return address(_timelock); } /** * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates * must be proposed, scheduled, and executed through governance proposals. * * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. */ function updateTimelock(TimelockController newTimelock) external virtual onlyGovernance { _updateTimelock(newTimelock); } function _updateTimelock(TimelockController newTimelock) private { emit TimelockChange(address(_timelock), address(newTimelock)); _timelock = newTimelock; } /** * @dev Computes the {TimelockController} operation salt. * * It is computed with the governor address itself to avoid collisions across governor instances using the * same timelock. */ function _timelockSalt(bytes32 descriptionHash) private view returns (bytes32) { return bytes20(address(this)) ^ descriptionHash; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorVotes.sol) pragma solidity ^0.8.20; import {Governor} from "../Governor.sol"; import {IVotes} from "../utils/IVotes.sol"; import {IERC5805} from "../../interfaces/IERC5805.sol"; import {SafeCast} from "../../utils/math/SafeCast.sol"; import {Time} from "../../utils/types/Time.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} * token. */ abstract contract GovernorVotes is Governor { IERC5805 private immutable _token; constructor(IVotes tokenAddress) { _token = IERC5805(address(tokenAddress)); } /** * @dev The token that voting power is sourced from. */ function token() public view virtual returns (IERC5805) { return _token; } /** * @dev Clock (as specified in ERC-6372) is set to match the token's clock. Fallback to block numbers if the token * does not implement ERC-6372. */ function clock() public view virtual override returns (uint48) { try token().clock() returns (uint48 timepoint) { return timepoint; } catch { return Time.blockNumber(); } } /** * @dev Machine-readable description of the clock as specified in ERC-6372. */ // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() public view virtual override returns (string memory) { try token().CLOCK_MODE() returns (string memory clockmode) { return clockmode; } catch { return "mode=blocknumber&from=default"; } } /** * Read the voting weight from the token's built in snapshot mechanism (see {Governor-_getVotes}). */ function _getVotes( address account, uint256 timepoint, bytes memory /*params*/ ) internal view virtual override returns (uint256) { return token().getPastVotes(account, timepoint); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorVotesQuorumFraction.sol) pragma solidity ^0.8.20; import {GovernorVotes} from "./GovernorVotes.sol"; import {SafeCast} from "../../utils/math/SafeCast.sol"; import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a * fraction of the total supply. */ abstract contract GovernorVotesQuorumFraction is GovernorVotes { using Checkpoints for Checkpoints.Trace208; Checkpoints.Trace208 private _quorumNumeratorHistory; event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator); /** * @dev The quorum set is not a valid fraction. */ error GovernorInvalidQuorumFraction(uint256 quorumNumerator, uint256 quorumDenominator); /** * @dev Initialize quorum as a fraction of the token's total supply. * * The fraction is specified as `numerator / denominator`. By default the denominator is 100, so quorum is * specified as a percent: a numerator of 10 corresponds to quorum being 10% of total supply. The denominator can be * customized by overriding {quorumDenominator}. */ constructor(uint256 quorumNumeratorValue) { _updateQuorumNumerator(quorumNumeratorValue); } /** * @dev Returns the current quorum numerator. See {quorumDenominator}. */ function quorumNumerator() public view virtual returns (uint256) { return _quorumNumeratorHistory.latest(); } /** * @dev Returns the quorum numerator at a specific timepoint. See {quorumDenominator}. */ function quorumNumerator(uint256 timepoint) public view virtual returns (uint256) { uint256 length = _quorumNumeratorHistory._checkpoints.length; // Optimistic search, check the latest checkpoint Checkpoints.Checkpoint208 storage latest = _quorumNumeratorHistory._checkpoints[length - 1]; uint48 latestKey = latest._key; uint208 latestValue = latest._value; if (latestKey <= timepoint) { return latestValue; } // Otherwise, do the binary search return _quorumNumeratorHistory.upperLookupRecent(SafeCast.toUint48(timepoint)); } /** * @dev Returns the quorum denominator. Defaults to 100, but may be overridden. */ function quorumDenominator() public view virtual returns (uint256) { return 100; } /** * @dev Returns the quorum for a timepoint, in terms of number of votes: `supply * numerator / denominator`. */ function quorum(uint256 timepoint) public view virtual override returns (uint256) { return (token().getPastTotalSupply(timepoint) * quorumNumerator(timepoint)) / quorumDenominator(); } /** * @dev Changes the quorum numerator. * * Emits a {QuorumNumeratorUpdated} event. * * Requirements: * * - Must be called through a governance proposal. * - New numerator must be smaller or equal to the denominator. */ function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance { _updateQuorumNumerator(newQuorumNumerator); } /** * @dev Changes the quorum numerator. * * Emits a {QuorumNumeratorUpdated} event. * * Requirements: * * - New numerator must be smaller or equal to the denominator. */ function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual { uint256 denominator = quorumDenominator(); if (newQuorumNumerator > denominator) { revert GovernorInvalidQuorumFraction(newQuorumNumerator, denominator); } uint256 oldQuorumNumerator = quorumNumerator(); _quorumNumeratorHistory.push(clock(), SafeCast.toUint208(newQuorumNumerator)); emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/Governor.sol) pragma solidity ^0.8.20; import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; import {EIP712} from "../utils/cryptography/EIP712.sol"; import {SignatureChecker} from "../utils/cryptography/SignatureChecker.sol"; import {IERC165, ERC165} from "../utils/introspection/ERC165.sol"; import {SafeCast} from "../utils/math/SafeCast.sol"; import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; import {Address} from "../utils/Address.sol"; import {Context} from "../utils/Context.sol"; import {Nonces} from "../utils/Nonces.sol"; import {IGovernor, IERC6372} from "./IGovernor.sol"; /** * @dev Core of the governance system, designed to be extended through various modules. * * This contract is abstract and requires several functions to be implemented in various modules: * * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote} * - A voting module must implement {_getVotes} * - Additionally, {votingPeriod} must also be implemented */ abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC721Receiver, IERC1155Receiver { using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,uint8 support,address voter,uint256 nonce)"); bytes32 public constant EXTENDED_BALLOT_TYPEHASH = keccak256( "ExtendedBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason,bytes params)" ); struct ProposalCore { address proposer; uint48 voteStart; uint32 voteDuration; bool executed; bool canceled; uint48 etaSeconds; } bytes32 private constant ALL_PROPOSAL_STATES_BITMAP = bytes32((2 ** (uint8(type(ProposalState).max) + 1)) - 1); string private _name; mapping(uint256 proposalId => ProposalCore) private _proposals; // This queue keeps track of the governor operating on itself. Calls to functions protected by the {onlyGovernance} // modifier needs to be whitelisted in this queue. Whitelisting is set in {execute}, consumed by the // {onlyGovernance} modifier and eventually reset after {_executeOperations} completes. This ensures that the // execution of {onlyGovernance} protected calls can only be achieved through successful proposals. DoubleEndedQueue.Bytes32Deque private _governanceCall; /** * @dev Restricts a function so it can only be executed through governance proposals. For example, governance * parameter setters in {GovernorSettings} are protected using this modifier. * * The governance executing address may be different from the Governor's own address, for example it could be a * timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these * functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus, * for example, additional timelock proposers are not able to change governance parameters without going through the * governance protocol (since v4.6). */ modifier onlyGovernance() { _checkGovernance(); _; } /** * @dev Sets the value for {name} and {version} */ constructor(string memory name_) EIP712(name_, version()) { _name = name_; } /** * @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract) */ receive() external payable virtual { if (_executor() != address(this)) { revert GovernorDisabledDeposit(); } } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { return interfaceId == type(IGovernor).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IGovernor-name}. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev See {IGovernor-version}. */ function version() public view virtual returns (string memory) { return "1"; } /** * @dev See {IGovernor-hashProposal}. * * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id * can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in * advance, before the proposal is submitted. * * Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the * same proposal (with same operation and same description) will have the same id if submitted on multiple governors * across multiple networks. This also means that in order to execute the same operation twice (on the same * governor) the proposer will have to change the description in order to avoid proposal id conflicts. */ function hashProposal( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public pure virtual returns (uint256) { return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash))); } /** * @dev See {IGovernor-state}. */ function state(uint256 proposalId) public view virtual returns (ProposalState) { // We read the struct fields into the stack at once so Solidity emits a single SLOAD ProposalCore storage proposal = _proposals[proposalId]; bool proposalExecuted = proposal.executed; bool proposalCanceled = proposal.canceled; if (proposalExecuted) { return ProposalState.Executed; } if (proposalCanceled) { return ProposalState.Canceled; } uint256 snapshot = proposalSnapshot(proposalId); if (snapshot == 0) { revert GovernorNonexistentProposal(proposalId); } uint256 currentTimepoint = clock(); if (snapshot >= currentTimepoint) { return ProposalState.Pending; } uint256 deadline = proposalDeadline(proposalId); if (deadline >= currentTimepoint) { return ProposalState.Active; } else if (!_quorumReached(proposalId) || !_voteSucceeded(proposalId)) { return ProposalState.Defeated; } else if (proposalEta(proposalId) == 0) { return ProposalState.Succeeded; } else { return ProposalState.Queued; } } /** * @dev See {IGovernor-proposalThreshold}. */ function proposalThreshold() public view virtual returns (uint256) { return 0; } /** * @dev See {IGovernor-proposalSnapshot}. */ function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256) { return _proposals[proposalId].voteStart; } /** * @dev See {IGovernor-proposalDeadline}. */ function proposalDeadline(uint256 proposalId) public view virtual returns (uint256) { return _proposals[proposalId].voteStart + _proposals[proposalId].voteDuration; } /** * @dev See {IGovernor-proposalProposer}. */ function proposalProposer(uint256 proposalId) public view virtual returns (address) { return _proposals[proposalId].proposer; } /** * @dev See {IGovernor-proposalEta}. */ function proposalEta(uint256 proposalId) public view virtual returns (uint256) { return _proposals[proposalId].etaSeconds; } /** * @dev See {IGovernor-proposalNeedsQueuing}. */ function proposalNeedsQueuing(uint256) public view virtual returns (bool) { return false; } /** * @dev Reverts if the `msg.sender` is not the executor. In case the executor is not this contract * itself, the function reverts if `msg.data` is not whitelisted as a result of an {execute} * operation. See {onlyGovernance}. */ function _checkGovernance() internal virtual { if (_executor() != _msgSender()) { revert GovernorOnlyExecutor(_msgSender()); } if (_executor() != address(this)) { bytes32 msgDataHash = keccak256(_msgData()); // loop until popping the expected operation - throw if deque is empty (operation not authorized) while (_governanceCall.popFront() != msgDataHash) {} } } /** * @dev Amount of votes already cast passes the threshold limit. */ function _quorumReached(uint256 proposalId) internal view virtual returns (bool); /** * @dev Is the proposal successful or not. */ function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); /** * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`. */ function _getVotes(address account, uint256 timepoint, bytes memory params) internal view virtual returns (uint256); /** * @dev Register a vote for `proposalId` by `account` with a given `support`, voting `weight` and voting `params`. * * Note: Support is generic and can represent various things depending on the voting system used. */ function _countVote( uint256 proposalId, address account, uint8 support, uint256 totalWeight, bytes memory params ) internal virtual returns (uint256); /** * @dev Default additional encoded parameters used by castVote methods that don't include them * * Note: Should be overridden by specific implementations to use an appropriate value, the * meaning of the additional params, in the context of that implementation */ function _defaultParams() internal view virtual returns (bytes memory) { return ""; } /** * @dev See {IGovernor-propose}. This function has opt-in frontrunning protection, described in {_isValidDescriptionForProposer}. */ function propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description ) public virtual returns (uint256) { address proposer = _msgSender(); // check description restriction if (!_isValidDescriptionForProposer(proposer, description)) { revert GovernorRestrictedProposer(proposer); } // check proposal threshold uint256 votesThreshold = proposalThreshold(); if (votesThreshold > 0) { uint256 proposerVotes = getVotes(proposer, clock() - 1); if (proposerVotes < votesThreshold) { revert GovernorInsufficientProposerVotes(proposer, proposerVotes, votesThreshold); } } return _propose(targets, values, calldatas, description, proposer); } /** * @dev Internal propose mechanism. Can be overridden to add more logic on proposal creation. * * Emits a {IGovernor-ProposalCreated} event. */ function _propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description, address proposer ) internal virtual returns (uint256 proposalId) { proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description))); if (targets.length != values.length || targets.length != calldatas.length || targets.length == 0) { revert GovernorInvalidProposalLength(targets.length, calldatas.length, values.length); } if (_proposals[proposalId].voteStart != 0) { revert GovernorUnexpectedProposalState(proposalId, state(proposalId), bytes32(0)); } uint256 snapshot = clock() + votingDelay(); uint256 duration = votingPeriod(); ProposalCore storage proposal = _proposals[proposalId]; proposal.proposer = proposer; proposal.voteStart = SafeCast.toUint48(snapshot); proposal.voteDuration = SafeCast.toUint32(duration); emit ProposalCreated( proposalId, proposer, targets, values, new string[](targets.length), calldatas, snapshot, snapshot + duration, description ); // Using a named return variable to avoid stack too deep errors } /** * @dev See {IGovernor-queue}. */ function queue( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public virtual returns (uint256) { uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Succeeded)); uint48 etaSeconds = _queueOperations(proposalId, targets, values, calldatas, descriptionHash); if (etaSeconds != 0) { _proposals[proposalId].etaSeconds = etaSeconds; emit ProposalQueued(proposalId, etaSeconds); } else { revert GovernorQueueNotImplemented(); } return proposalId; } /** * @dev Internal queuing mechanism. Can be overridden (without a super call) to modify the way queuing is * performed (for example adding a vault/timelock). * * This is empty by default, and must be overridden to implement queuing. * * This function returns a timestamp that describes the expected ETA for execution. If the returned value is 0 * (which is the default value), the core will consider queueing did not succeed, and the public {queue} function * will revert. * * NOTE: Calling this function directly will NOT check the current state of the proposal, or emit the * `ProposalQueued` event. Queuing a proposal should be done using {queue}. */ function _queueOperations( uint256 /*proposalId*/, address[] memory /*targets*/, uint256[] memory /*values*/, bytes[] memory /*calldatas*/, bytes32 /*descriptionHash*/ ) internal virtual returns (uint48) { return 0; } /** * @dev See {IGovernor-execute}. */ function execute( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public payable virtual returns (uint256) { uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); _validateStateBitmap( proposalId, _encodeStateBitmap(ProposalState.Succeeded) | _encodeStateBitmap(ProposalState.Queued) ); // mark as executed before calls to avoid reentrancy _proposals[proposalId].executed = true; // before execute: register governance call in queue. if (_executor() != address(this)) { for (uint256 i = 0; i < targets.length; ++i) { if (targets[i] == address(this)) { _governanceCall.pushBack(keccak256(calldatas[i])); } } } _executeOperations(proposalId, targets, values, calldatas, descriptionHash); // after execute: cleanup governance call queue. if (_executor() != address(this) && !_governanceCall.empty()) { _governanceCall.clear(); } emit ProposalExecuted(proposalId); return proposalId; } /** * @dev Internal execution mechanism. Can be overridden (without a super call) to modify the way execution is * performed (for example adding a vault/timelock). * * NOTE: Calling this function directly will NOT check the current state of the proposal, set the executed flag to * true or emit the `ProposalExecuted` event. Executing a proposal should be done using {execute} or {_execute}. */ function _executeOperations( uint256 /* proposalId */, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 /*descriptionHash*/ ) internal virtual { for (uint256 i = 0; i < targets.length; ++i) { (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); Address.verifyCallResult(success, returndata); } } /** * @dev See {IGovernor-cancel}. */ function cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public virtual returns (uint256) { // The proposalId will be recomputed in the `_cancel` call further down. However we need the value before we // do the internal call, because we need to check the proposal state BEFORE the internal `_cancel` call // changes it. The `hashProposal` duplication has a cost that is limited, and that we accept. uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); // public cancel restrictions (on top of existing _cancel restrictions). _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Pending)); if (_msgSender() != proposalProposer(proposalId)) { revert GovernorOnlyProposer(_msgSender()); } return _cancel(targets, values, calldatas, descriptionHash); } /** * @dev Internal cancel mechanism with minimal restrictions. A proposal can be cancelled in any state other than * Canceled, Expired, or Executed. Once cancelled a proposal can't be re-submitted. * * Emits a {IGovernor-ProposalCanceled} event. */ function _cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal virtual returns (uint256) { uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); _validateStateBitmap( proposalId, ALL_PROPOSAL_STATES_BITMAP ^ _encodeStateBitmap(ProposalState.Canceled) ^ _encodeStateBitmap(ProposalState.Expired) ^ _encodeStateBitmap(ProposalState.Executed) ); _proposals[proposalId].canceled = true; emit ProposalCanceled(proposalId); return proposalId; } /** * @dev See {IGovernor-getVotes}. */ function getVotes(address account, uint256 timepoint) public view virtual returns (uint256) { return _getVotes(account, timepoint, _defaultParams()); } /** * @dev See {IGovernor-getVotesWithParams}. */ function getVotesWithParams( address account, uint256 timepoint, bytes memory params ) public view virtual returns (uint256) { return _getVotes(account, timepoint, params); } /** * @dev See {IGovernor-castVote}. */ function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256) { address voter = _msgSender(); return _castVote(proposalId, voter, support, ""); } /** * @dev See {IGovernor-castVoteWithReason}. */ function castVoteWithReason( uint256 proposalId, uint8 support, string calldata reason ) public virtual returns (uint256) { address voter = _msgSender(); return _castVote(proposalId, voter, support, reason); } /** * @dev See {IGovernor-castVoteWithReasonAndParams}. */ function castVoteWithReasonAndParams( uint256 proposalId, uint8 support, string calldata reason, bytes memory params ) public virtual returns (uint256) { address voter = _msgSender(); return _castVote(proposalId, voter, support, reason, params); } /** * @dev See {IGovernor-castVoteBySig}. */ function castVoteBySig( uint256 proposalId, uint8 support, address voter, bytes memory signature ) public virtual returns (uint256) { bool valid = SignatureChecker.isValidSignatureNow( voter, _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter)))), signature ); if (!valid) { revert GovernorInvalidSignature(voter); } return _castVote(proposalId, voter, support, ""); } /** * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}. */ function castVoteWithReasonAndParamsBySig( uint256 proposalId, uint8 support, address voter, string calldata reason, bytes memory params, bytes memory signature ) public virtual returns (uint256) { bool valid = SignatureChecker.isValidSignatureNow( voter, _hashTypedDataV4( keccak256( abi.encode( EXTENDED_BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter), keccak256(bytes(reason)), keccak256(params) ) ) ), signature ); if (!valid) { revert GovernorInvalidSignature(voter); } return _castVote(proposalId, voter, support, reason, params); } /** * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams(). * * Emits a {IGovernor-VoteCast} event. */ function _castVote( uint256 proposalId, address account, uint8 support, string memory reason ) internal virtual returns (uint256) { return _castVote(proposalId, account, support, reason, _defaultParams()); } /** * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. * * Emits a {IGovernor-VoteCast} event. */ function _castVote( uint256 proposalId, address account, uint8 support, string memory reason, bytes memory params ) internal virtual returns (uint256) { _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Active)); uint256 totalWeight = _getVotes(account, proposalSnapshot(proposalId), params); uint256 votedWeight = _countVote(proposalId, account, support, totalWeight, params); if (params.length == 0) { emit VoteCast(account, proposalId, support, votedWeight, reason); } else { emit VoteCastWithParams(account, proposalId, support, votedWeight, reason, params); } return votedWeight; } /** * @dev Relays a transaction or function call to an arbitrary target. In cases where the governance executor * is some contract other than the governor itself, like when using a timelock, this function can be invoked * in a governance proposal to recover tokens or Ether that was sent to the governor contract by mistake. * Note that if the executor is simply the governor itself, use of `relay` is redundant. */ function relay(address target, uint256 value, bytes calldata data) external payable virtual onlyGovernance { (bool success, bytes memory returndata) = target.call{value: value}(data); Address.verifyCallResult(success, returndata); } /** * @dev Address through which the governor executes action. Will be overloaded by module that execute actions * through another contract such as a timelock. */ function _executor() internal view virtual returns (address) { return address(this); } /** * @dev See {IERC721Receiver-onERC721Received}. * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). */ function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { if (_executor() != address(this)) { revert GovernorDisabledDeposit(); } return this.onERC721Received.selector; } /** * @dev See {IERC1155Receiver-onERC1155Received}. * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). */ function onERC1155Received(address, address, uint256, uint256, bytes memory) public virtual returns (bytes4) { if (_executor() != address(this)) { revert GovernorDisabledDeposit(); } return this.onERC1155Received.selector; } /** * @dev See {IERC1155Receiver-onERC1155BatchReceived}. * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). */ function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual returns (bytes4) { if (_executor() != address(this)) { revert GovernorDisabledDeposit(); } return this.onERC1155BatchReceived.selector; } /** * @dev Encodes a `ProposalState` into a `bytes32` representation where each bit enabled corresponds to * the underlying position in the `ProposalState` enum. For example: * * 0x000...10000 * ^^^^^^------ ... * ^----- Succeeded * ^---- Defeated * ^--- Canceled * ^-- Active * ^- Pending */ function _encodeStateBitmap(ProposalState proposalState) internal pure returns (bytes32) { return bytes32(1 << uint8(proposalState)); } /** * @dev Check that the current state of a proposal matches the requirements described by the `allowedStates` bitmap. * This bitmap should be built using `_encodeStateBitmap`. * * If requirements are not met, reverts with a {GovernorUnexpectedProposalState} error. */ function _validateStateBitmap(uint256 proposalId, bytes32 allowedStates) private view returns (ProposalState) { ProposalState currentState = state(proposalId); if (_encodeStateBitmap(currentState) & allowedStates == bytes32(0)) { revert GovernorUnexpectedProposalState(proposalId, currentState, allowedStates); } return currentState; } /* * @dev Check if the proposer is authorized to submit a proposal with the given description. * * If the proposal description ends with `#proposer=0x???`, where `0x???` is an address written as a hex string * (case insensitive), then the submission of this proposal will only be authorized to said address. * * This is used for frontrunning protection. By adding this pattern at the end of their proposal, one can ensure * that no other address can submit the same proposal. An attacker would have to either remove or change that part, * which would result in a different proposal id. * * If the description does not match this pattern, it is unrestricted and anyone can submit it. This includes: * - If the `0x???` part is not a valid hex string. * - If the `0x???` part is a valid hex string, but does not contain exactly 40 hex digits. * - If it ends with the expected suffix followed by newlines or other whitespace. * - If it ends with some other similar suffix, e.g. `#other=abc`. * - If it does not end with any such suffix. */ function _isValidDescriptionForProposer( address proposer, string memory description ) internal view virtual returns (bool) { uint256 len = bytes(description).length; // Length is too short to contain a valid proposer suffix if (len < 52) { return true; } // Extract what would be the `#proposer=0x` marker beginning the suffix bytes12 marker; assembly ("memory-safe") { // - Start of the string contents in memory = description + 32 // - First character of the marker = len - 52 // - Length of "#proposer=0x0000000000000000000000000000000000000000" = 52 // - We read the memory word starting at the first character of the marker: // - (description + 32) + (len - 52) = description + (len - 20) // - Note: Solidity will ignore anything past the first 12 bytes marker := mload(add(description, sub(len, 20))) } // If the marker is not found, there is no proposer suffix to check if (marker != bytes12("#proposer=0x")) { return true; } // Parse the 40 characters following the marker as uint160 uint160 recovered = 0; for (uint256 i = len - 40; i < len; ++i) { (bool isHex, uint8 value) = _tryHexToUint(bytes(description)[i]); // If any of the characters is not a hex digit, ignore the suffix entirely if (!isHex) { return true; } recovered = (recovered << 4) | value; } return recovered == uint160(proposer); } /** * @dev Try to parse a character from a string as a hex value. Returns `(true, value)` if the char is in * `[0-9a-fA-F]` and `(false, 0)` otherwise. Value is guaranteed to be in the range `0 <= value < 16` */ function _tryHexToUint(bytes1 char) private pure returns (bool isHex, uint8 value) { uint8 c = uint8(char); unchecked { // Case 0-9 if (47 < c && c < 58) { return (true, c - 48); } // Case A-F else if (64 < c && c < 71) { return (true, c - 55); } // Case a-f else if (96 < c && c < 103) { return (true, c - 87); } // Else: not a hex char else { return (false, 0); } } } /** * @inheritdoc IERC6372 */ function clock() public view virtual returns (uint48); /** * @inheritdoc IERC6372 */ // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() public view virtual returns (string memory); /** * @inheritdoc IGovernor */ function votingDelay() public view virtual returns (uint256); /** * @inheritdoc IGovernor */ function votingPeriod() public view virtual returns (uint256); /** * @inheritdoc IGovernor */ function quorum(uint256 timepoint) public view virtual returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/IGovernor.sol) pragma solidity ^0.8.20; import {IERC165} from "../interfaces/IERC165.sol"; import {IERC6372} from "../interfaces/IERC6372.sol"; /** * @dev Interface of the {Governor} core. * * NOTE: Event parameters lack the `indexed` keyword for compatibility with GovernorBravo events. * Making event parameters `indexed` affects how events are decoded, potentially breaking existing indexers. */ interface IGovernor is IERC165, IERC6372 { enum ProposalState { Pending, Active, Canceled, Defeated, Succeeded, Queued, Expired, Executed } /** * @dev Empty proposal or a mismatch between the parameters length for a proposal call. */ error GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values); /** * @dev The vote was already cast. */ error GovernorAlreadyCastVote(address voter); /** * @dev Token deposits are disabled in this contract. */ error GovernorDisabledDeposit(); /** * @dev The `account` is not a proposer. */ error GovernorOnlyProposer(address account); /** * @dev The `account` is not the governance executor. */ error GovernorOnlyExecutor(address account); /** * @dev The `proposalId` doesn't exist. */ error GovernorNonexistentProposal(uint256 proposalId); /** * @dev The current state of a proposal is not the required for performing an operation. * The `expectedStates` is a bitmap with the bits enabled for each ProposalState enum position * counting from right to left. * * NOTE: If `expectedState` is `bytes32(0)`, the proposal is expected to not be in any state (i.e. not exist). * This is the case when a proposal that is expected to be unset is already initiated (the proposal is duplicated). * * See {Governor-_encodeStateBitmap}. */ error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates); /** * @dev The voting period set is not a valid period. */ error GovernorInvalidVotingPeriod(uint256 votingPeriod); /** * @dev The `proposer` does not have the required votes to create a proposal. */ error GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold); /** * @dev The `proposer` is not allowed to create a proposal. */ error GovernorRestrictedProposer(address proposer); /** * @dev The vote type used is not valid for the corresponding counting module. */ error GovernorInvalidVoteType(); /** * @dev The provided params buffer is not supported by the counting module. */ error GovernorInvalidVoteParams(); /** * @dev Queue operation is not implemented for this governor. Execute should be called directly. */ error GovernorQueueNotImplemented(); /** * @dev The proposal hasn't been queued yet. */ error GovernorNotQueuedProposal(uint256 proposalId); /** * @dev The proposal has already been queued. */ error GovernorAlreadyQueuedProposal(uint256 proposalId); /** * @dev The provided signature is not valid for the expected `voter`. * If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}. */ error GovernorInvalidSignature(address voter); /** * @dev Emitted when a proposal is created. */ event ProposalCreated( uint256 proposalId, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 voteStart, uint256 voteEnd, string description ); /** * @dev Emitted when a proposal is queued. */ event ProposalQueued(uint256 proposalId, uint256 etaSeconds); /** * @dev Emitted when a proposal is executed. */ event ProposalExecuted(uint256 proposalId); /** * @dev Emitted when a proposal is canceled. */ event ProposalCanceled(uint256 proposalId); /** * @dev Emitted when a vote is cast without params. * * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. */ event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason); /** * @dev Emitted when a vote is cast with params. * * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. * `params` are additional encoded parameters. Their interpretation also depends on the voting module used. */ event VoteCastWithParams( address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason, bytes params ); /** * @notice module:core * @dev Name of the governor instance (used in building the EIP-712 domain separator). */ function name() external view returns (string memory); /** * @notice module:core * @dev Version of the governor instance (used in building the EIP-712 domain separator). Default: "1" */ function version() external view returns (string memory); /** * @notice module:voting * @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`. * * There are 2 standard keys: `support` and `quorum`. * * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`. * - `quorum=bravo` means that only For votes are counted towards quorum. * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum. * * If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique * name that describes the behavior. For example: * * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain. * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote. * * NOTE: The string can be decoded by the standard * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`] * JavaScript class. */ // solhint-disable-next-line func-name-mixedcase function COUNTING_MODE() external view returns (string memory); /** * @notice module:core * @dev Hashing function used to (re)build the proposal id from the proposal details.. */ function hashProposal( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external pure returns (uint256); /** * @notice module:core * @dev Current state of a proposal, following Compound's convention */ function state(uint256 proposalId) external view returns (ProposalState); /** * @notice module:core * @dev The number of votes required in order for a voter to become a proposer. */ function proposalThreshold() external view returns (uint256); /** * @notice module:core * @dev Timepoint used to retrieve user's votes and quorum. If using block number (as per Compound's Comp), the * snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the * following block. */ function proposalSnapshot(uint256 proposalId) external view returns (uint256); /** * @notice module:core * @dev Timepoint at which votes close. If using block number, votes close at the end of this block, so it is * possible to cast a vote during this block. */ function proposalDeadline(uint256 proposalId) external view returns (uint256); /** * @notice module:core * @dev The account that created a proposal. */ function proposalProposer(uint256 proposalId) external view returns (address); /** * @notice module:core * @dev The time when a queued proposal becomes executable ("ETA"). Unlike {proposalSnapshot} and * {proposalDeadline}, this doesn't use the governor clock, and instead relies on the executor's clock which may be * different. In most cases this will be a timestamp. */ function proposalEta(uint256 proposalId) external view returns (uint256); /** * @notice module:core * @dev Whether a proposal needs to be queued before execution. */ function proposalNeedsQueuing(uint256 proposalId) external view returns (bool); /** * @notice module:user-config * @dev Delay, between the proposal is created and the vote starts. The unit this duration is expressed in depends * on the clock (see ERC-6372) this contract uses. * * This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a * proposal starts. * * NOTE: While this interface returns a uint256, timepoints are stored as uint48 following the ERC-6372 clock type. * Consequently this value must fit in a uint48 (when added to the current clock). See {IERC6372-clock}. */ function votingDelay() external view returns (uint256); /** * @notice module:user-config * @dev Delay between the vote start and vote end. The unit this duration is expressed in depends on the clock * (see ERC-6372) this contract uses. * * NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting * duration compared to the voting delay. * * NOTE: This value is stored when the proposal is submitted so that possible changes to the value do not affect * proposals that have already been submitted. The type used to save it is a uint32. Consequently, while this * interface returns a uint256, the value it returns should fit in a uint32. */ function votingPeriod() external view returns (uint256); /** * @notice module:user-config * @dev Minimum number of cast voted required for a proposal to be successful. * * NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the * quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}). */ function quorum(uint256 timepoint) external view returns (uint256); /** * @notice module:reputation * @dev Voting power of an `account` at a specific `timepoint`. * * Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or * multiple), {ERC20Votes} tokens. */ function getVotes(address account, uint256 timepoint) external view returns (uint256); /** * @notice module:reputation * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters. */ function getVotesWithParams( address account, uint256 timepoint, bytes memory params ) external view returns (uint256); /** * @notice module:voting * @dev Returns whether `account` has cast a vote on `proposalId`. */ function hasVoted(uint256 proposalId, address account) external view returns (bool); /** * @dev Create a new proposal. Vote start after a delay specified by {IGovernor-votingDelay} and lasts for a * duration specified by {IGovernor-votingPeriod}. * * Emits a {ProposalCreated} event. * * NOTE: The state of the Governor and `targets` may change between the proposal creation and its execution. * This may be the result of third party actions on the targeted contracts, or other governor proposals. * For example, the balance of this contract could be updated or its access control permissions may be modified, * possibly compromising the proposal's ability to execute successfully (e.g. the governor doesn't have enough * value to cover a proposal with multiple transfers). */ function propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description ) external returns (uint256 proposalId); /** * @dev Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing * is not necessary, this function may revert. * Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached. * * Emits a {ProposalQueued} event. */ function queue( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external returns (uint256 proposalId); /** * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the * deadline to be reached. Depending on the governor it might also be required that the proposal was queued and * that some delay passed. * * Emits a {ProposalExecuted} event. * * NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock. */ function execute( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external payable returns (uint256 proposalId); /** * @dev Cancel a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e. * before the vote starts. * * Emits a {ProposalCanceled} event. */ function cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external returns (uint256 proposalId); /** * @dev Cast a vote * * Emits a {VoteCast} event. */ function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance); /** * @dev Cast a vote with a reason * * Emits a {VoteCast} event. */ function castVoteWithReason( uint256 proposalId, uint8 support, string calldata reason ) external returns (uint256 balance); /** * @dev Cast a vote with a reason and additional encoded parameters * * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. */ function castVoteWithReasonAndParams( uint256 proposalId, uint8 support, string calldata reason, bytes memory params ) external returns (uint256 balance); /** * @dev Cast a vote using the voter's signature, including ERC-1271 signature support. * * Emits a {VoteCast} event. */ function castVoteBySig( uint256 proposalId, uint8 support, address voter, bytes memory signature ) external returns (uint256 balance); /** * @dev Cast a vote with a reason and additional encoded parameters using the voter's signature, * including ERC-1271 signature support. * * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. */ function castVoteWithReasonAndParamsBySig( uint256 proposalId, uint8 support, address voter, string calldata reason, bytes memory params, bytes memory signature ) external returns (uint256 balance); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/TimelockController.sol) pragma solidity ^0.8.20; import {AccessControl} from "../access/AccessControl.sol"; import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol"; import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol"; import {Address} from "../utils/Address.sol"; /** * @dev Contract module which acts as a timelocked controller. When set as the * owner of an `Ownable` smart contract, it enforces a timelock on all * `onlyOwner` maintenance operations. This gives time for users of the * controlled contract to exit before a potentially dangerous maintenance * operation is applied. * * By default, this contract is self administered, meaning administration tasks * have to go through the timelock process. The proposer (resp executor) role * is in charge of proposing (resp executing) operations. A common use case is * to position this {TimelockController} as the owner of a smart contract, with * a multisig or a DAO as the sole proposer. */ contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); uint256 internal constant _DONE_TIMESTAMP = uint256(1); mapping(bytes32 id => uint256) private _timestamps; uint256 private _minDelay; enum OperationState { Unset, Waiting, Ready, Done } /** * @dev Mismatch between the parameters length for an operation call. */ error TimelockInvalidOperationLength(uint256 targets, uint256 payloads, uint256 values); /** * @dev The schedule operation doesn't meet the minimum delay. */ error TimelockInsufficientDelay(uint256 delay, uint256 minDelay); /** * @dev The current state of an operation is not as required. * The `expectedStates` is a bitmap with the bits enabled for each OperationState enum position * counting from right to left. * * See {_encodeStateBitmap}. */ error TimelockUnexpectedOperationState(bytes32 operationId, bytes32 expectedStates); /** * @dev The predecessor to an operation not yet done. */ error TimelockUnexecutedPredecessor(bytes32 predecessorId); /** * @dev The caller account is not authorized. */ error TimelockUnauthorizedCaller(address caller); /** * @dev Emitted when a call is scheduled as part of operation `id`. */ event CallScheduled( bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data, bytes32 predecessor, uint256 delay ); /** * @dev Emitted when a call is performed as part of operation `id`. */ event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data); /** * @dev Emitted when new proposal is scheduled with non-zero salt. */ event CallSalt(bytes32 indexed id, bytes32 salt); /** * @dev Emitted when operation `id` is cancelled. */ event Cancelled(bytes32 indexed id); /** * @dev Emitted when the minimum delay for future operations is modified. */ event MinDelayChange(uint256 oldDuration, uint256 newDuration); /** * @dev Initializes the contract with the following parameters: * * - `minDelay`: initial minimum delay in seconds for operations * - `proposers`: accounts to be granted proposer and canceller roles * - `executors`: accounts to be granted executor role * - `admin`: optional account to be granted admin role; disable with zero address * * IMPORTANT: The optional admin can aid with initial configuration of roles after deployment * without being subject to delay, but this role should be subsequently renounced in favor of * administration through timelocked proposals. Previous versions of this contract would assign * this admin to the deployer automatically and should be renounced as well. */ constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) { // self administration _grantRole(DEFAULT_ADMIN_ROLE, address(this)); // optional admin if (admin != address(0)) { _grantRole(DEFAULT_ADMIN_ROLE, admin); } // register proposers and cancellers for (uint256 i = 0; i < proposers.length; ++i) { _grantRole(PROPOSER_ROLE, proposers[i]); _grantRole(CANCELLER_ROLE, proposers[i]); } // register executors for (uint256 i = 0; i < executors.length; ++i) { _grantRole(EXECUTOR_ROLE, executors[i]); } _minDelay = minDelay; emit MinDelayChange(0, minDelay); } /** * @dev Modifier to make a function callable only by a certain role. In * addition to checking the sender's role, `address(0)` 's role is also * considered. Granting a role to `address(0)` is equivalent to enabling * this role for everyone. */ modifier onlyRoleOrOpenRole(bytes32 role) { if (!hasRole(role, address(0))) { _checkRole(role, _msgSender()); } _; } /** * @dev Contract might receive/hold ETH as part of the maintenance process. */ receive() external payable {} /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(AccessControl, ERC1155Holder) returns (bool) { return super.supportsInterface(interfaceId); } /** * @dev Returns whether an id corresponds to a registered operation. This * includes both Waiting, Ready, and Done operations. */ function isOperation(bytes32 id) public view returns (bool) { return getOperationState(id) != OperationState.Unset; } /** * @dev Returns whether an operation is pending or not. Note that a "pending" operation may also be "ready". */ function isOperationPending(bytes32 id) public view returns (bool) { OperationState state = getOperationState(id); return state == OperationState.Waiting || state == OperationState.Ready; } /** * @dev Returns whether an operation is ready for execution. Note that a "ready" operation is also "pending". */ function isOperationReady(bytes32 id) public view returns (bool) { return getOperationState(id) == OperationState.Ready; } /** * @dev Returns whether an operation is done or not. */ function isOperationDone(bytes32 id) public view returns (bool) { return getOperationState(id) == OperationState.Done; } /** * @dev Returns the timestamp at which an operation becomes ready (0 for * unset operations, 1 for done operations). */ function getTimestamp(bytes32 id) public view virtual returns (uint256) { return _timestamps[id]; } /** * @dev Returns operation state. */ function getOperationState(bytes32 id) public view virtual returns (OperationState) { uint256 timestamp = getTimestamp(id); if (timestamp == 0) { return OperationState.Unset; } else if (timestamp == _DONE_TIMESTAMP) { return OperationState.Done; } else if (timestamp > block.timestamp) { return OperationState.Waiting; } else { return OperationState.Ready; } } /** * @dev Returns the minimum delay in seconds for an operation to become valid. * * This value can be changed by executing an operation that calls `updateDelay`. */ function getMinDelay() public view virtual returns (uint256) { return _minDelay; } /** * @dev Returns the identifier of an operation containing a single * transaction. */ function hashOperation( address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt ) public pure virtual returns (bytes32) { return keccak256(abi.encode(target, value, data, predecessor, salt)); } /** * @dev Returns the identifier of an operation containing a batch of * transactions. */ function hashOperationBatch( address[] calldata targets, uint256[] calldata values, bytes[] calldata payloads, bytes32 predecessor, bytes32 salt ) public pure virtual returns (bytes32) { return keccak256(abi.encode(targets, values, payloads, predecessor, salt)); } /** * @dev Schedule an operation containing a single transaction. * * Emits {CallSalt} if salt is nonzero, and {CallScheduled}. * * Requirements: * * - the caller must have the 'proposer' role. */ function schedule( address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt, uint256 delay ) public virtual onlyRole(PROPOSER_ROLE) { bytes32 id = hashOperation(target, value, data, predecessor, salt); _schedule(id, delay); emit CallScheduled(id, 0, target, value, data, predecessor, delay); if (salt != bytes32(0)) { emit CallSalt(id, salt); } } /** * @dev Schedule an operation containing a batch of transactions. * * Emits {CallSalt} if salt is nonzero, and one {CallScheduled} event per transaction in the batch. * * Requirements: * * - the caller must have the 'proposer' role. */ function scheduleBatch( address[] calldata targets, uint256[] calldata values, bytes[] calldata payloads, bytes32 predecessor, bytes32 salt, uint256 delay ) public virtual onlyRole(PROPOSER_ROLE) { if (targets.length != values.length || targets.length != payloads.length) { revert TimelockInvalidOperationLength(targets.length, payloads.length, values.length); } bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); _schedule(id, delay); for (uint256 i = 0; i < targets.length; ++i) { emit CallScheduled(id, i, targets[i], values[i], payloads[i], predecessor, delay); } if (salt != bytes32(0)) { emit CallSalt(id, salt); } } /** * @dev Schedule an operation that is to become valid after a given delay. */ function _schedule(bytes32 id, uint256 delay) private { if (isOperation(id)) { revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Unset)); } uint256 minDelay = getMinDelay(); if (delay < minDelay) { revert TimelockInsufficientDelay(delay, minDelay); } _timestamps[id] = block.timestamp + delay; } /** * @dev Cancel an operation. * * Requirements: * * - the caller must have the 'canceller' role. */ function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) { if (!isOperationPending(id)) { revert TimelockUnexpectedOperationState( id, _encodeStateBitmap(OperationState.Waiting) | _encodeStateBitmap(OperationState.Ready) ); } delete _timestamps[id]; emit Cancelled(id); } /** * @dev Execute an (ready) operation containing a single transaction. * * Emits a {CallExecuted} event. * * Requirements: * * - the caller must have the 'executor' role. */ // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, // thus any modifications to the operation during reentrancy should be caught. // slither-disable-next-line reentrancy-eth function execute( address target, uint256 value, bytes calldata payload, bytes32 predecessor, bytes32 salt ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { bytes32 id = hashOperation(target, value, payload, predecessor, salt); _beforeCall(id, predecessor); _execute(target, value, payload); emit CallExecuted(id, 0, target, value, payload); _afterCall(id); } /** * @dev Execute an (ready) operation containing a batch of transactions. * * Emits one {CallExecuted} event per transaction in the batch. * * Requirements: * * - the caller must have the 'executor' role. */ // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, // thus any modifications to the operation during reentrancy should be caught. // slither-disable-next-line reentrancy-eth function executeBatch( address[] calldata targets, uint256[] calldata values, bytes[] calldata payloads, bytes32 predecessor, bytes32 salt ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { if (targets.length != values.length || targets.length != payloads.length) { revert TimelockInvalidOperationLength(targets.length, payloads.length, values.length); } bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); _beforeCall(id, predecessor); for (uint256 i = 0; i < targets.length; ++i) { address target = targets[i]; uint256 value = values[i]; bytes calldata payload = payloads[i]; _execute(target, value, payload); emit CallExecuted(id, i, target, value, payload); } _afterCall(id); } /** * @dev Execute an operation's call. */ function _execute(address target, uint256 value, bytes calldata data) internal virtual { (bool success, bytes memory returndata) = target.call{value: value}(data); Address.verifyCallResult(success, returndata); } /** * @dev Checks before execution of an operation's calls. */ function _beforeCall(bytes32 id, bytes32 predecessor) private view { if (!isOperationReady(id)) { revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready)); } if (predecessor != bytes32(0) && !isOperationDone(predecessor)) { revert TimelockUnexecutedPredecessor(predecessor); } } /** * @dev Checks after execution of an operation's calls. */ function _afterCall(bytes32 id) private { if (!isOperationReady(id)) { revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready)); } _timestamps[id] = _DONE_TIMESTAMP; } /** * @dev Changes the minimum timelock duration for future operations. * * Emits a {MinDelayChange} event. * * Requirements: * * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing * an operation where the timelock is the target and the data is the ABI-encoded call to this function. */ function updateDelay(uint256 newDelay) external virtual { address sender = _msgSender(); if (sender != address(this)) { revert TimelockUnauthorizedCaller(sender); } emit MinDelayChange(_minDelay, newDelay); _minDelay = newDelay; } /** * @dev Encodes a `OperationState` into a `bytes32` representation where each bit enabled corresponds to * the underlying position in the `OperationState` enum. For example: * * 0x000...1000 * ^^^^^^----- ... * ^---- Done * ^--- Ready * ^-- Waiting * ^- Unset */ function _encodeStateBitmap(OperationState operationState) internal pure returns (bytes32) { return bytes32(1 << uint8(operationState)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol) pragma solidity ^0.8.20; /** * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. */ interface IVotes { /** * @dev The signature used has expired. */ error VotesExpiredSignature(uint256 expiry); /** * @dev Emitted when an account changes their delegate. */ event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /** * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units. */ event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes); /** * @dev Returns the current amount of votes that `account` has. */ function getVotes(address account) external view returns (uint256); /** * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is * configured to use block numbers, this will return the value at the end of the corresponding block. */ function getPastVotes(address account, uint256 timepoint) external view returns (uint256); /** * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is * configured to use block numbers, this will return the value at the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a * vote. */ function getPastTotalSupply(uint256 timepoint) external view returns (uint256); /** * @dev Returns the delegate that `account` has chosen. */ function delegates(address account) external view returns (address); /** * @dev Delegates votes from the sender to `delegatee`. */ function delegate(address delegatee) external; /** * @dev Delegates votes from signer to `delegatee`. */ function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/Votes.sol) pragma solidity ^0.8.20; import {IERC5805} from "../../interfaces/IERC5805.sol"; import {Context} from "../../utils/Context.sol"; import {Nonces} from "../../utils/Nonces.sol"; import {EIP712} from "../../utils/cryptography/EIP712.sol"; import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; import {SafeCast} from "../../utils/math/SafeCast.sol"; import {ECDSA} from "../../utils/cryptography/ECDSA.sol"; import {Time} from "../../utils/types/Time.sol"; /** * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of * "representative" that will pool delegated voting units from different accounts and can then use it to vote in * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative. * * This contract is often combined with a token contract such that voting units correspond to token units. For an * example, see {ERC721Votes}. * * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the * cost of this history tracking optional. * * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the * previous example, it would be included in {ERC721-_update}). */ abstract contract Votes is Context, EIP712, Nonces, IERC5805 { using Checkpoints for Checkpoints.Trace208; bytes32 private constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); mapping(address account => address) private _delegatee; mapping(address delegatee => Checkpoints.Trace208) private _delegateCheckpoints; Checkpoints.Trace208 private _totalCheckpoints; /** * @dev The clock was incorrectly modified. */ error ERC6372InconsistentClock(); /** * @dev Lookup to future votes is not available. */ error ERC5805FutureLookup(uint256 timepoint, uint48 clock); /** * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based * checkpoints (and voting), in which case {CLOCK_MODE} should be overridden as well to match. */ function clock() public view virtual returns (uint48) { return Time.blockNumber(); } /** * @dev Machine-readable description of the clock as specified in ERC-6372. */ // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() public view virtual returns (string memory) { // Check that the clock was not modified if (clock() != Time.blockNumber()) { revert ERC6372InconsistentClock(); } return "mode=blocknumber&from=default"; } /** * @dev Returns the current amount of votes that `account` has. */ function getVotes(address account) public view virtual returns (uint256) { return _delegateCheckpoints[account].latest(); } /** * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is * configured to use block numbers, this will return the value at the end of the corresponding block. * * Requirements: * * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. */ function getPastVotes(address account, uint256 timepoint) public view virtual returns (uint256) { uint48 currentTimepoint = clock(); if (timepoint >= currentTimepoint) { revert ERC5805FutureLookup(timepoint, currentTimepoint); } return _delegateCheckpoints[account].upperLookupRecent(SafeCast.toUint48(timepoint)); } /** * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is * configured to use block numbers, this will return the value at the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a * vote. * * Requirements: * * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. */ function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) { uint48 currentTimepoint = clock(); if (timepoint >= currentTimepoint) { revert ERC5805FutureLookup(timepoint, currentTimepoint); } return _totalCheckpoints.upperLookupRecent(SafeCast.toUint48(timepoint)); } /** * @dev Returns the current total supply of votes. */ function _getTotalSupply() internal view virtual returns (uint256) { return _totalCheckpoints.latest(); } /** * @dev Returns the delegate that `account` has chosen. */ function delegates(address account) public view virtual returns (address) { return _delegatee[account]; } /** * @dev Delegates votes from the sender to `delegatee`. */ function delegate(address delegatee) public virtual { address account = _msgSender(); _delegate(account, delegatee); } /** * @dev Delegates votes from signer to `delegatee`. */ function delegateBySig( address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) public virtual { if (block.timestamp > expiry) { revert VotesExpiredSignature(expiry); } address signer = ECDSA.recover( _hashTypedDataV4(keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))), v, r, s ); _useCheckedNonce(signer, nonce); _delegate(signer, delegatee); } /** * @dev Delegate all of `account`'s voting units to `delegatee`. * * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. */ function _delegate(address account, address delegatee) internal virtual { address oldDelegate = delegates(account); _delegatee[account] = delegatee; emit DelegateChanged(account, oldDelegate, delegatee); _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account)); } /** * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to` * should be zero. Total supply of voting units will be adjusted with mints and burns. */ function _transferVotingUnits(address from, address to, uint256 amount) internal virtual { if (from == address(0)) { _push(_totalCheckpoints, _add, SafeCast.toUint208(amount)); } if (to == address(0)) { _push(_totalCheckpoints, _subtract, SafeCast.toUint208(amount)); } _moveDelegateVotes(delegates(from), delegates(to), amount); } /** * @dev Moves delegated votes from one delegate to another. */ function _moveDelegateVotes(address from, address to, uint256 amount) internal virtual { if (from != to && amount > 0) { if (from != address(0)) { (uint256 oldValue, uint256 newValue) = _push( _delegateCheckpoints[from], _subtract, SafeCast.toUint208(amount) ); emit DelegateVotesChanged(from, oldValue, newValue); } if (to != address(0)) { (uint256 oldValue, uint256 newValue) = _push( _delegateCheckpoints[to], _add, SafeCast.toUint208(amount) ); emit DelegateVotesChanged(to, oldValue, newValue); } } } /** * @dev Get number of checkpoints for `account`. */ function _numCheckpoints(address account) internal view virtual returns (uint32) { return SafeCast.toUint32(_delegateCheckpoints[account].length()); } /** * @dev Get the `pos`-th checkpoint for `account`. */ function _checkpoints( address account, uint32 pos ) internal view virtual returns (Checkpoints.Checkpoint208 memory) { return _delegateCheckpoints[account].at(pos); } function _push( Checkpoints.Trace208 storage store, function(uint208, uint208) view returns (uint208) op, uint208 delta ) private returns (uint208 oldValue, uint208 newValue) { return store.push(clock(), op(store.latest(), delta)); } function _add(uint208 a, uint208 b) private pure returns (uint208) { return a + b; } function _subtract(uint208 a, uint208 b) private pure returns (uint208) { return a - b; } /** * @dev Must return the voting units held by an account. */ function _getVotingUnits(address) internal view virtual returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC-20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC-721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC-1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.20; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol) pragma solidity ^0.8.20; import {IVotes} from "../governance/utils/IVotes.sol"; import {IERC6372} from "./IERC6372.sol"; interface IERC5805 is IERC6372, IVotes {}
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol) pragma solidity ^0.8.20; interface IERC6372 { /** * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting). */ function clock() external view returns (uint48); /** * @dev Description of the clock */ // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Interface that must be implemented by smart contracts in order to receive * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC-1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC-1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.20; import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; import {IERC1155Receiver} from "../IERC1155Receiver.sol"; /** * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. */ abstract contract ERC1155Holder is ERC165, IERC1155Receiver { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; import {Context} from "../../utils/Context.sol"; import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC-20 * applications. */ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { mapping(address account => uint256) private _balances; mapping(address account => mapping(address spender => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); return true; } /** * @dev See {IERC20-transferFrom}. * * Skips emitting an {Approval} event indicating an allowance update. This is not * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve]. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `value`. * - the caller must have allowance for ``from``'s tokens of at least * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @dev Moves a `value` amount of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(from, to, value); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { if (from == address(0)) { // Overflow check required: The rest of the code assumes that totalSupply never overflows _totalSupply += value; } else { uint256 fromBalance = _balances[from]; if (fromBalance < value) { revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { // Overflow not possible: value <= fromBalance <= totalSupply. _balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. _totalSupply -= value; } } else { unchecked { // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. _balances[to] += value; } } emit Transfer(from, to, value); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } _update(account, address(0), value); } /** * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { _approve(owner, spender, value, true); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * * ```solidity * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } _allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Context} from "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys a `value` amount of tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 value) public virtual { _burn(_msgSender(), value); } /** * @dev Destroys a `value` amount of tokens from `account`, deducting from * the caller's allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `value`. */ function burnFrom(address account, uint256 value) public virtual { _spendAllowance(account, _msgSender(), value); _burn(account, value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; /** * @dev Extension of {ERC20} that adds a cap to the supply of tokens. */ abstract contract ERC20Capped is ERC20 { uint256 private immutable _cap; /** * @dev Total supply cap has been exceeded. */ error ERC20ExceededCap(uint256 increasedSupply, uint256 cap); /** * @dev The supplied cap is not a valid cap. */ error ERC20InvalidCap(uint256 cap); /** * @dev Sets the value of the `cap`. This value is immutable, it can only be * set once during construction. */ constructor(uint256 cap_) { if (cap_ == 0) { revert ERC20InvalidCap(0); } _cap = cap_; } /** * @dev Returns the cap on the token's total supply. */ function cap() public view virtual returns (uint256) { return _cap; } /** * @dev See {ERC20-_update}. */ function _update(address from, address to, uint256 value) internal virtual override { super._update(from, to, value); if (from == address(0)) { uint256 maxSupply = cap(); uint256 supply = totalSupply(); if (supply > maxSupply) { revert ERC20ExceededCap(supply, maxSupply); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol) pragma solidity ^0.8.20; import {IERC20Permit} from "./IERC20Permit.sol"; import {ERC20} from "../ERC20.sol"; import {ECDSA} from "../../../utils/cryptography/ECDSA.sol"; import {EIP712} from "../../../utils/cryptography/EIP712.sol"; import {Nonces} from "../../../utils/Nonces.sol"; /** * @dev Implementation of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. * * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces { bytes32 private constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev Permit deadline has expired. */ error ERC2612ExpiredSignature(uint256 deadline); /** * @dev Mismatched signature. */ error ERC2612InvalidSigner(address signer, address owner); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC-20 token name. */ constructor(string memory name) EIP712(name, "1") {} /** * @inheritdoc IERC20Permit */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { if (block.timestamp > deadline) { revert ERC2612ExpiredSignature(deadline); } bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); if (signer != owner) { revert ERC2612InvalidSigner(signer, owner); } _approve(owner, spender, value); } /** * @inheritdoc IERC20Permit */ function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) { return super.nonces(owner); } /** * @inheritdoc IERC20Permit */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view virtual returns (bytes32) { return _domainSeparatorV4(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Votes.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Votes} from "../../../governance/utils/Votes.sol"; import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; /** * @dev Extension of ERC-20 to support Compound-like voting and delegation. This version is more generic than Compound's, * and supports token supply up to 2^208^ - 1, while COMP is limited to 2^96^ - 1. * * NOTE: This contract does not provide interface compatibility with Compound's COMP token. * * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either * by calling the {Votes-delegate} function directly, or by providing a signature to be used with {Votes-delegateBySig}. Voting * power can be queried through the public accessors {Votes-getVotes} and {Votes-getPastVotes}. * * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. */ abstract contract ERC20Votes is ERC20, Votes { /** * @dev Total supply cap has been exceeded, introducing a risk of votes overflowing. */ error ERC20ExceededSafeSupply(uint256 increasedSupply, uint256 cap); /** * @dev Maximum token supply. Defaults to `type(uint208).max` (2^208^ - 1). * * This maximum is enforced in {_update}. It limits the total supply of the token, which is otherwise a uint256, * so that checkpoints can be stored in the Trace208 structure used by {Votes}. Increasing this value will not * remove the underlying limitation, and will cause {_update} to fail because of a math overflow in * {Votes-_transferVotingUnits}. An override could be used to further restrict the total supply (to a lower value) if * additional logic requires it. When resolving override conflicts on this function, the minimum should be * returned. */ function _maxSupply() internal view virtual returns (uint256) { return type(uint208).max; } /** * @dev Move voting power when tokens are transferred. * * Emits a {IVotes-DelegateVotesChanged} event. */ function _update(address from, address to, uint256 value) internal virtual override { super._update(from, to, value); if (from == address(0)) { uint256 supply = totalSupply(); uint256 cap = _maxSupply(); if (supply > cap) { revert ERC20ExceededSafeSupply(supply, cap); } } _transferVotingUnits(from, to, value); } /** * @dev Returns the voting units of an `account`. * * WARNING: Overriding this function may compromise the internal vote accounting. * `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change. */ function _getVotingUnits(address account) internal view virtual override returns (uint256) { return balanceOf(account); } /** * @dev Get number of checkpoints for `account`. */ function numCheckpoints(address account) public view virtual returns (uint32) { return _numCheckpoints(account); } /** * @dev Get the `pos`-th checkpoint for `account`. */ function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoints.Checkpoint208 memory) { return _checkpoints(account, pos); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Wrapper.sol) pragma solidity ^0.8.20; import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol"; import {SafeERC20} from "../utils/SafeERC20.sol"; /** * @dev Extension of the ERC-20 token contract to support token wrapping. * * Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC20Votes} will allow the * wrapping of an existing "basic" ERC-20 into a governance token. * * WARNING: Any mechanism in which the underlying token changes the {balanceOf} of an account without an explicit transfer * may desynchronize this contract's supply and its underlying balance. Please exercise caution when wrapping tokens that * may undercollateralize the wrapper (i.e. wrapper's total supply is higher than its underlying balance). See {_recover} * for recovering value accrued to the wrapper. */ abstract contract ERC20Wrapper is ERC20 { IERC20 private immutable _underlying; /** * @dev The underlying token couldn't be wrapped. */ error ERC20InvalidUnderlying(address token); constructor(IERC20 underlyingToken) { if (underlyingToken == this) { revert ERC20InvalidUnderlying(address(this)); } _underlying = underlyingToken; } /** * @dev See {ERC20-decimals}. */ function decimals() public view virtual override returns (uint8) { try IERC20Metadata(address(_underlying)).decimals() returns (uint8 value) { return value; } catch { return super.decimals(); } } /** * @dev Returns the address of the underlying ERC-20 token that is being wrapped. */ function underlying() public view returns (IERC20) { return _underlying; } /** * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens. */ function depositFor(address account, uint256 value) public virtual returns (bool) { address sender = _msgSender(); if (sender == address(this)) { revert ERC20InvalidSender(address(this)); } if (account == address(this)) { revert ERC20InvalidReceiver(account); } SafeERC20.safeTransferFrom(_underlying, sender, address(this), value); _mint(account, value); return true; } /** * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens. */ function withdrawTo(address account, uint256 value) public virtual returns (bool) { if (account == address(this)) { revert ERC20InvalidReceiver(account); } _burn(_msgSender(), value); SafeERC20.safeTransfer(_underlying, account, value); return true; } /** * @dev Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake or acquired from * rebasing mechanisms. Internal function that can be exposed with access control if desired. */ function _recover(address account) internal virtual returns (uint256) { uint256 value = _underlying.balanceOf(address(this)) - totalSupply(); _mint(account, value); return value; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC-20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. * * Adds the {permit} method, which can be used to change an account's ERC-20 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 ERC-20 standard as defined in the ERC. */ 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 {IERC1363} from "../../../interfaces/IERC1363.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 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 { /** * @dev An operation with an ERC-20 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 Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { 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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { 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 silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC-721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC-721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.20; import {IERC721Receiver} from "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or * {IERC721-setApprovalForAll}. */ abstract contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @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 Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @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 * {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value); } (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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}. */ 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 assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover( bytes32 hash, bytes memory signature ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly ("memory-safe") { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures] */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.20; import {MessageHashUtils} from "./MessageHashUtils.sol"; import {ShortStrings, ShortString} from "../ShortStrings.sol"; import {IERC5267} from "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data. * * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * @custom:oz-upgrades-unsafe-allow state-variable-immutable */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {IERC-5267}. */ function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: By default this function reads _name which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Name() internal view returns (string memory) { return _name.toStringWithFallback(_nameFallback); } /** * @dev The version parameter for the EIP712 domain. * * NOTE: By default this function reads _version which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Version() internal view returns (string memory) { return _version.toStringWithFallback(_versionFallback); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { assembly ("memory-safe") { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { assembly ("memory-safe") { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol) pragma solidity ^0.8.20; import {ECDSA} from "./ECDSA.sol"; import {IERC1271} from "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC-1271 signatures from smart contract wallets like * Argent and Safe Wallet (previously Gnosis Safe). */ library SignatureChecker { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC-1271, otherwise it's validated using `ECDSA.recover`. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { if (signer.code.length == 0) { (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecover(hash, signature); return err == ECDSA.RecoverError.NoError && recovered == signer; } else { return isValidERC1271SignatureNow(signer, hash, signature); } } /** * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated * against the signer smart contract using ERC-1271. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidERC1271SignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (bool success, bytes memory result) = signer.staticcall( abi.encodeCall(IERC1271.isValidSignature, (hash, signature)) ); return (success && result.length >= 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). */ function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). */ function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * SafeCast.toUint(condition)); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a < b, a, b); } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. Panic.panic(Panic.DIVISION_BY_ZERO); } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); } } /** * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2²⁵⁶ + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. if (denominator <= prod1) { Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW)); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv ≡ 1 mod 2⁴. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2⁸ inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ inverse *= 2 - denominator * inverse; // inverse mod 2³² inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); } /** * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. * * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. * * If the input value is not inversible, 0 is returned. * * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. */ function invMod(uint256 a, uint256 n) internal pure returns (uint256) { unchecked { if (n == 0) return 0; // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) // Used to compute integers x and y such that: ax + ny = gcd(a, n). // When the gcd is 1, then the inverse of a modulo n exists and it's x. // ax + ny = 1 // ax = 1 + (-y)n // ax ≡ 1 (mod n) # x is the inverse of a modulo n // If the remainder is 0 the gcd is n right away. uint256 remainder = a % n; uint256 gcd = n; // Therefore the initial coefficients are: // ax + ny = gcd(a, n) = n // 0a + 1n = n int256 x = 0; int256 y = 1; while (remainder != 0) { uint256 quotient = gcd / remainder; (gcd, remainder) = ( // The old remainder is the next gcd to try. remainder, // Compute the next remainder. // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd // where gcd is at most n (capped to type(uint256).max) gcd - remainder * quotient ); (x, y) = ( // Increment the coefficient of a. y, // Decrement the coefficient of n. // Can overflow, but the result is casted to uint256 so that the // next value of y is "wrapped around" to a value between 0 and n - 1. x - y * int256(quotient) ); } if (gcd != 1) return 0; // No inverse exists. return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. } } /** * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. * * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that * `a**(p-2)` is the modular multiplicative inverse of a in Fp. * * NOTE: this function does NOT check that `p` is a prime greater than `2`. */ function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { unchecked { return Math.modExp(a, p - 2, p); } } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) * * Requirements: * - modulus can't be zero * - underlying staticcall to precompile must succeed * * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make * sure the chain you're using it on supports the precompiled contract for modular exponentiation * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, * the underlying function will succeed given the lack of a revert, but the result may be incorrectly * interpreted as 0. */ function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { (bool success, uint256 result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying * to operate modulo 0 or if the underlying precompile reverted. * * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack * of a revert, but the result may be incorrectly interpreted as 0. */ function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { if (m == 0) return (false, 0); assembly ("memory-safe") { let ptr := mload(0x40) // | Offset | Content | Content (Hex) | // |-----------|------------|--------------------------------------------------------------------| // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x60:0x7f | value of b | 0x<.............................................................b> | // | 0x80:0x9f | value of e | 0x<.............................................................e> | // | 0xa0:0xbf | value of m | 0x<.............................................................m> | mstore(ptr, 0x20) mstore(add(ptr, 0x20), 0x20) mstore(add(ptr, 0x40), 0x20) mstore(add(ptr, 0x60), b) mstore(add(ptr, 0x80), e) mstore(add(ptr, 0xa0), m) // Given the result < m, it's guaranteed to fit in 32 bytes, // so we can use the memory scratch space located at offset 0. success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) result := mload(0x00) } } /** * @dev Variant of {modExp} that supports inputs of arbitrary length. */ function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { (bool success, bytes memory result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Variant of {tryModExp} that supports inputs of arbitrary length. */ function tryModExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bool success, bytes memory result) { if (_zeroBytes(m)) return (false, new bytes(0)); uint256 mLen = m.length; // Encode call args in result and move the free memory pointer result = abi.encodePacked(b.length, e.length, mLen, b, e, m); assembly ("memory-safe") { let dataPtr := add(result, 0x20) // Write result on top of args to avoid allocating extra memory. success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) // Overwrite the length. // result.length > returndatasize() is guaranteed because returndatasize() == m.length mstore(result, mLen) // Set the memory pointer after the returned data. mstore(0x40, add(dataPtr, mLen)) } } /** * @dev Returns whether the provided byte array is zero. */ function _zeroBytes(bytes memory byteArray) private pure returns (bool) { for (uint256 i = 0; i < byteArray.length; ++i) { if (byteArray[i] != 0) { return false; } } return true; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * This method is based on Newton's method for computing square roots; the algorithm is restricted to only * using integer operations. */ function sqrt(uint256 a) internal pure returns (uint256) { unchecked { // Take care of easy edge cases when a == 0 or a == 1 if (a <= 1) { return a; } // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between // the current value as `ε_n = | x_n - sqrt(a) |`. // // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is // bigger than any uint256. // // By noticing that // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar // to the msb function. uint256 aa = a; uint256 xn = 1; if (aa >= (1 << 128)) { aa >>= 128; xn <<= 64; } if (aa >= (1 << 64)) { aa >>= 64; xn <<= 32; } if (aa >= (1 << 32)) { aa >>= 32; xn <<= 16; } if (aa >= (1 << 16)) { aa >>= 16; xn <<= 8; } if (aa >= (1 << 8)) { aa >>= 8; xn <<= 4; } if (aa >= (1 << 4)) { aa >>= 4; xn <<= 2; } if (aa >= (1 << 2)) { xn <<= 1; } // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). // // We can refine our estimation by noticing that the middle of that interval minimizes the error. // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). // This is going to be our x_0 (and ε_0) xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) // From here, Newton's method give us: // x_{n+1} = (x_n + a / x_n) / 2 // // One should note that: // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a // = ((x_n² + a) / (2 * x_n))² - a // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) // = (x_n² - a)² / (2 * x_n)² // = ((x_n² - a) / (2 * x_n))² // ≥ 0 // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n // // This gives us the proof of quadratic convergence of the sequence: // ε_{n+1} = | x_{n+1} - sqrt(a) | // = | (x_n + a / x_n) / 2 - sqrt(a) | // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | // = | (x_n - sqrt(a))² / (2 * x_n) | // = | ε_n² / (2 * x_n) | // = ε_n² / | (2 * x_n) | // // For the first iteration, we have a special case where x_0 is known: // ε_1 = ε_0² / | (2 * x_0) | // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) // ≤ 2**(2*e-4) / (3 * 2**(e-1)) // ≤ 2**(e-3) / 3 // ≤ 2**(e-3-log2(3)) // ≤ 2**(e-4.5) // // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: // ε_{n+1} = ε_n² / | (2 * x_n) | // ≤ (2**(e-k))² / (2 * 2**(e-1)) // ≤ 2**(2*e-2*k) / 2**e // ≤ 2**(e-2*k) xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either // sqrt(a) or sqrt(a) + 1. return xn - SafeCast.toUint(xn > a / xn); } } /** * @dev Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 exp; unchecked { exp = 128 * SafeCast.toUint(value > (1 << 128) - 1); value >>= exp; result += exp; exp = 64 * SafeCast.toUint(value > (1 << 64) - 1); value >>= exp; result += exp; exp = 32 * SafeCast.toUint(value > (1 << 32) - 1); value >>= exp; result += exp; exp = 16 * SafeCast.toUint(value > (1 << 16) - 1); value >>= exp; result += exp; exp = 8 * SafeCast.toUint(value > (1 << 8) - 1); value >>= exp; result += exp; exp = 4 * SafeCast.toUint(value > (1 << 4) - 1); value >>= exp; result += exp; exp = 2 * SafeCast.toUint(value > (1 << 2) - 1); value >>= exp; result += exp; result += SafeCast.toUint(value > 1); } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 isGt; unchecked { isGt = SafeCast.toUint(value > (1 << 128) - 1); value >>= isGt * 128; result += isGt * 16; isGt = SafeCast.toUint(value > (1 << 64) - 1); value >>= isGt * 64; result += isGt * 8; isGt = SafeCast.toUint(value > (1 << 32) - 1); value >>= isGt * 32; result += isGt * 4; isGt = SafeCast.toUint(value > (1 << 16) - 1); value >>= isGt * 16; result += isGt * 2; result += SafeCast.toUint(value > (1 << 8) - 1); } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { assembly ("memory-safe") { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * int256(SafeCast.toUint(condition))); } } /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return ternary(a < b, a, b); } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, // taking advantage of the most significant (or "sign" bit) in two's complement representation. // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative). int256 mask = n >> 255; // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. return uint256((n + mask) ^ mask); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) pragma solidity ^0.8.20; /** * @dev Provides tracking nonces for addresses. Nonces will only increment. */ abstract contract Nonces { /** * @dev The nonce used for an `account` is not the expected current nonce. */ error InvalidAccountNonce(address account, uint256 currentNonce); mapping(address account => uint256) private _nonces; /** * @dev Returns the next unused nonce for an address. */ function nonces(address owner) public view virtual returns (uint256) { return _nonces[owner]; } /** * @dev Consumes a nonce. * * Returns the current value and increments nonce. */ function _useNonce(address owner) internal virtual returns (uint256) { // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be // decremented or reset. This guarantees that the nonce never overflows. unchecked { // It is important to do x++ and not ++x here. return _nonces[owner]++; } } /** * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. */ function _useCheckedNonce(address owner, uint256 nonce) internal virtual { uint256 current = _useNonce(owner); if (nonce != current) { revert InvalidAccountNonce(owner, current); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @dev Helper library for emitting standardized panic codes. * * ```solidity * contract Example { * using Panic for uint256; * * // Use any of the declared internal constants * function foo() { Panic.GENERIC.panic(); } * * // Alternatively * function foo() { Panic.panic(Panic.GENERIC); } * } * ``` * * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. * * _Available since v5.1._ */ // slither-disable-next-line unused-state library Panic { /// @dev generic / unspecified error uint256 internal constant GENERIC = 0x00; /// @dev used by the assert() builtin uint256 internal constant ASSERT = 0x01; /// @dev arithmetic underflow or overflow uint256 internal constant UNDER_OVERFLOW = 0x11; /// @dev division or modulo by zero uint256 internal constant DIVISION_BY_ZERO = 0x12; /// @dev enum conversion error uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; /// @dev invalid encoding in storage uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; /// @dev empty array pop uint256 internal constant EMPTY_ARRAY_POP = 0x31; /// @dev array out of bounds access uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; /// @dev resource error (too large allocation or too large array) uint256 internal constant RESOURCE_ERROR = 0x41; /// @dev calling invalid internal function uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; /// @dev Reverts with a panic code. Recommended to use with /// the internal constants with predefined codes. function panic(uint256 code) internal pure { assembly ("memory-safe") { mstore(0x00, 0x4e487b71) mstore(0x20, code) revert(0x1c, 0x24) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol) pragma solidity ^0.8.20; import {StorageSlot} from "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); assembly ("memory-safe") { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using * {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.24; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * Since version 5.1, this library also support writing and reading value types to and from transient storage. * * * Example using transient storage: * ```solidity * contract Lock { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; * * modifier locked() { * require(!_LOCK_SLOT.asBoolean().tload()); * * _LOCK_SLOT.asBoolean().tstore(true); * _; * _LOCK_SLOT.asBoolean().tstore(false); * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev UDVT that represent a slot holding a address. */ type AddressSlotType is bytes32; /** * @dev Cast an arbitrary slot to a AddressSlotType. */ function asAddress(bytes32 slot) internal pure returns (AddressSlotType) { return AddressSlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a bool. */ type BooleanSlotType is bytes32; /** * @dev Cast an arbitrary slot to a BooleanSlotType. */ function asBoolean(bytes32 slot) internal pure returns (BooleanSlotType) { return BooleanSlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a bytes32. */ type Bytes32SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Bytes32SlotType. */ function asBytes32(bytes32 slot) internal pure returns (Bytes32SlotType) { return Bytes32SlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a uint256. */ type Uint256SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Uint256SlotType. */ function asUint256(bytes32 slot) internal pure returns (Uint256SlotType) { return Uint256SlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a int256. */ type Int256SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Int256SlotType. */ function asInt256(bytes32 slot) internal pure returns (Int256SlotType) { return Int256SlotType.wrap(slot); } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(AddressSlotType slot) internal view returns (address value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(AddressSlotType slot, address value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(BooleanSlotType slot) internal view returns (bool value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(BooleanSlotType slot, bool value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Bytes32SlotType slot) internal view returns (bytes32 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Bytes32SlotType slot, bytes32 value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Uint256SlotType slot) internal view returns (uint256 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Uint256SlotType slot, uint256 value) internal { assembly ("memory-safe") { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Int256SlotType slot) internal view returns (int256 value) { assembly ("memory-safe") { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Int256SlotType slot, int256 value) internal { assembly ("memory-safe") { tstore(slot, value) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; assembly ("memory-safe") { ptr := add(buffer, add(32, length)) } while (true) { ptr--; assembly ("memory-safe") { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal * representation, according to EIP-55. */ function toChecksumHexString(address addr) internal pure returns (string memory) { bytes memory buffer = bytes(toHexString(addr)); // hash the hex part of buffer (skip length + 2 bytes, length 40) uint256 hashValue; assembly ("memory-safe") { hashValue := shr(96, keccak256(add(buffer, 0x22), 40)) } for (uint256 i = 41; i > 1; --i) { // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f) if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) { // case shift by xoring with 0x20 buffer[i] ^= 0x20; } hashValue >>= 4; } return string(buffer); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol) // This file was procedurally generated from scripts/generate/templates/Checkpoints.js. pragma solidity ^0.8.20; import {Math} from "../math/Math.sol"; /** * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in * time, and later looking up past values by block number. See {Votes} as an example. * * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new * checkpoint for the current transaction block using the {push} function. */ library Checkpoints { /** * @dev A value was attempted to be inserted on a past checkpoint. */ error CheckpointUnorderedInsertion(); struct Trace224 { Checkpoint224[] _checkpoints; } struct Checkpoint224 { uint32 _key; uint224 _value; } /** * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. * * Returns previous value and new value. * * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the * library. */ function push( Trace224 storage self, uint32 key, uint224 value ) internal returns (uint224 oldValue, uint224 newValue) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if * there is none. */ function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. */ function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high * keys). */ function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(Trace224 storage self) internal view returns (uint224) { uint256 pos = self._checkpoints.length; return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, 0); } else { Checkpoint224 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(Trace224 storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Returns checkpoint at given position. */ function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) { return self._checkpoints[pos]; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert( Checkpoint224[] storage self, uint32 key, uint224 value ) private returns (uint224 oldValue, uint224 newValue) { uint256 pos = self.length; if (pos > 0) { Checkpoint224 storage last = _unsafeAccess(self, pos - 1); uint32 lastKey = last._key; uint224 lastValue = last._value; // Checkpoint keys must be non-decreasing. if (lastKey > key) { revert CheckpointUnorderedInsertion(); } // Update or push new checkpoint if (lastKey == key) { last._value = value; } else { self.push(Checkpoint224({_key: key, _value: value})); } return (lastValue, value); } else { self.push(Checkpoint224({_key: key, _value: value})); return (0, value); } } /** * @dev Return the index of the first (oldest) checkpoint with key strictly bigger than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( Checkpoint224[] storage self, uint32 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key greater or equal than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( Checkpoint224[] storage self, uint32 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess( Checkpoint224[] storage self, uint256 pos ) private pure returns (Checkpoint224 storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } struct Trace208 { Checkpoint208[] _checkpoints; } struct Checkpoint208 { uint48 _key; uint208 _value; } /** * @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint. * * Returns previous value and new value. * * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the * library. */ function push( Trace208 storage self, uint48 key, uint208 value ) internal returns (uint208 oldValue, uint208 newValue) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if * there is none. */ function lowerLookup(Trace208 storage self, uint48 key) internal view returns (uint208) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. */ function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high * keys). */ function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(Trace208 storage self) internal view returns (uint208) { uint256 pos = self._checkpoints.length; return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, 0); } else { Checkpoint208 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(Trace208 storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Returns checkpoint at given position. */ function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) { return self._checkpoints[pos]; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert( Checkpoint208[] storage self, uint48 key, uint208 value ) private returns (uint208 oldValue, uint208 newValue) { uint256 pos = self.length; if (pos > 0) { Checkpoint208 storage last = _unsafeAccess(self, pos - 1); uint48 lastKey = last._key; uint208 lastValue = last._value; // Checkpoint keys must be non-decreasing. if (lastKey > key) { revert CheckpointUnorderedInsertion(); } // Update or push new checkpoint if (lastKey == key) { last._value = value; } else { self.push(Checkpoint208({_key: key, _value: value})); } return (lastValue, value); } else { self.push(Checkpoint208({_key: key, _value: value})); return (0, value); } } /** * @dev Return the index of the first (oldest) checkpoint with key strictly bigger than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( Checkpoint208[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key greater or equal than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( Checkpoint208[] storage self, uint48 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess( Checkpoint208[] storage self, uint256 pos ) private pure returns (Checkpoint208 storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } struct Trace160 { Checkpoint160[] _checkpoints; } struct Checkpoint160 { uint96 _key; uint160 _value; } /** * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. * * Returns previous value and new value. * * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the * library. */ function push( Trace160 storage self, uint96 key, uint160 value ) internal returns (uint160 oldValue, uint160 newValue) { return _insert(self._checkpoints, key, value); } /** * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if * there is none. */ function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. */ function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero * if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high * keys). */ function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; uint256 low = 0; uint256 high = len; if (len > 5) { uint256 mid = len - Math.sqrt(len); if (key < _unsafeAccess(self._checkpoints, mid)._key) { high = mid; } else { low = mid + 1; } } uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ function latest(Trace160 storage self) internal view returns (uint160) { uint256 pos = self._checkpoints.length; return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } /** * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value * in the most recent checkpoint. */ function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) { uint256 pos = self._checkpoints.length; if (pos == 0) { return (false, 0, 0); } else { Checkpoint160 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1); return (true, ckpt._key, ckpt._value); } } /** * @dev Returns the number of checkpoint. */ function length(Trace160 storage self) internal view returns (uint256) { return self._checkpoints.length; } /** * @dev Returns checkpoint at given position. */ function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) { return self._checkpoints[pos]; } /** * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, * or by updating the last one. */ function _insert( Checkpoint160[] storage self, uint96 key, uint160 value ) private returns (uint160 oldValue, uint160 newValue) { uint256 pos = self.length; if (pos > 0) { Checkpoint160 storage last = _unsafeAccess(self, pos - 1); uint96 lastKey = last._key; uint160 lastValue = last._value; // Checkpoint keys must be non-decreasing. if (lastKey > key) { revert CheckpointUnorderedInsertion(); } // Update or push new checkpoint if (lastKey == key) { last._value = value; } else { self.push(Checkpoint160({_key: key, _value: value})); } return (lastValue, value); } else { self.push(Checkpoint160({_key: key, _value: value})); return (0, value); } } /** * @dev Return the index of the first (oldest) checkpoint with key strictly bigger than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _upperBinaryLookup( Checkpoint160[] storage self, uint96 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key > key) { high = mid; } else { low = mid + 1; } } return high; } /** * @dev Return the index of the first (oldest) checkpoint with key greater or equal than the search key, or `high` * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive * `high`. * * WARNING: `high` should not be greater than the array's length. */ function _lowerBinaryLookup( Checkpoint160[] storage self, uint96 key, uint256 low, uint256 high ) private view returns (uint256) { while (low < high) { uint256 mid = Math.average(low, high); if (_unsafeAccess(self, mid)._key < key) { low = mid + 1; } else { high = mid; } } return high; } /** * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. */ function _unsafeAccess( Checkpoint160[] storage self, uint256 pos ) private pure returns (Checkpoint160 storage result) { assembly { mstore(0, self.slot) result.slot := add(keccak256(0, 0x20), pos) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; /** * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that * the existing queue contents are left in storage. * * The struct is called `Bytes32Deque`. Other types can be cast to and from `bytes32`. This data structure can only be * used in storage, and not in memory. * ```solidity * DoubleEndedQueue.Bytes32Deque queue; * ``` */ library DoubleEndedQueue { /** * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access. * * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and * lead to unexpected behavior. * * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around. */ struct Bytes32Deque { uint128 _begin; uint128 _end; mapping(uint128 index => bytes32) _data; } /** * @dev Inserts an item at the end of the queue. * * Reverts with {Panic-RESOURCE_ERROR} if the queue is full. */ function pushBack(Bytes32Deque storage deque, bytes32 value) internal { unchecked { uint128 backIndex = deque._end; if (backIndex + 1 == deque._begin) Panic.panic(Panic.RESOURCE_ERROR); deque._data[backIndex] = value; deque._end = backIndex + 1; } } /** * @dev Removes the item at the end of the queue and returns it. * * Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty. */ function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) { unchecked { uint128 backIndex = deque._end; if (backIndex == deque._begin) Panic.panic(Panic.EMPTY_ARRAY_POP); --backIndex; value = deque._data[backIndex]; delete deque._data[backIndex]; deque._end = backIndex; } } /** * @dev Inserts an item at the beginning of the queue. * * Reverts with {Panic-RESOURCE_ERROR} if the queue is full. */ function pushFront(Bytes32Deque storage deque, bytes32 value) internal { unchecked { uint128 frontIndex = deque._begin - 1; if (frontIndex == deque._end) Panic.panic(Panic.RESOURCE_ERROR); deque._data[frontIndex] = value; deque._begin = frontIndex; } } /** * @dev Removes the item at the beginning of the queue and returns it. * * Reverts with {Panic-EMPTY_ARRAY_POP} if the queue is empty. */ function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) { unchecked { uint128 frontIndex = deque._begin; if (frontIndex == deque._end) Panic.panic(Panic.EMPTY_ARRAY_POP); value = deque._data[frontIndex]; delete deque._data[frontIndex]; deque._begin = frontIndex + 1; } } /** * @dev Returns the item at the beginning of the queue. * * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty. */ function front(Bytes32Deque storage deque) internal view returns (bytes32 value) { if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); return deque._data[deque._begin]; } /** * @dev Returns the item at the end of the queue. * * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the queue is empty. */ function back(Bytes32Deque storage deque) internal view returns (bytes32 value) { if (empty(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); unchecked { return deque._data[deque._end - 1]; } } /** * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at * `length(deque) - 1`. * * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if the index is out of bounds. */ function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) { if (index >= length(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS); // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128 unchecked { return deque._data[deque._begin + uint128(index)]; } } /** * @dev Resets the queue back to being empty. * * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses * out on potential gas refunds. */ function clear(Bytes32Deque storage deque) internal { deque._begin = 0; deque._end = 0; } /** * @dev Returns the number of items in the queue. */ function length(Bytes32Deque storage deque) internal view returns (uint256) { unchecked { return uint256(deque._end - deque._begin); } } /** * @dev Returns true if the queue is empty. */ function empty(Bytes32Deque storage deque) internal view returns (bool) { return deque._end == deque._begin; } }
// 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; assembly ("memory-safe") { 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; assembly ("memory-safe") { 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; assembly ("memory-safe") { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol) pragma solidity ^0.8.20; import {Math} from "../math/Math.sol"; import {SafeCast} from "../math/SafeCast.sol"; /** * @dev This library provides helpers for manipulating time-related objects. * * It uses the following types: * - `uint48` for timepoints * - `uint32` for durations * * While the library doesn't provide specific types for timepoints and duration, it does provide: * - a `Delay` type to represent duration that can be programmed to change value automatically at a given point * - additional helper functions */ library Time { using Time for *; /** * @dev Get the block timestamp as a Timepoint. */ function timestamp() internal view returns (uint48) { return SafeCast.toUint48(block.timestamp); } /** * @dev Get the block number as a Timepoint. */ function blockNumber() internal view returns (uint48) { return SafeCast.toUint48(block.number); } // ==================================================== Delay ===================================================== /** * @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the * future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value. * This allows updating the delay applied to some operation while keeping some guarantees. * * In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for * some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set * the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should * still apply for some time. * * * The `Delay` type is 112 bits long, and packs the following: * * ``` * | [uint48]: effect date (timepoint) * | | [uint32]: value before (duration) * ↓ ↓ ↓ [uint32]: value after (duration) * 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC * ``` * * NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently * supported. */ type Delay is uint112; /** * @dev Wrap a duration into a Delay to add the one-step "update in the future" feature */ function toDelay(uint32 duration) internal pure returns (Delay) { return Delay.wrap(duration); } /** * @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled * change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered. */ function _getFullAt( Delay self, uint48 timepoint ) private pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) { (valueBefore, valueAfter, effect) = self.unpack(); return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect); } /** * @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the * effect timepoint is 0, then the pending value should not be considered. */ function getFull(Delay self) internal view returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) { return _getFullAt(self, timestamp()); } /** * @dev Get the current value. */ function get(Delay self) internal view returns (uint32) { (uint32 delay, , ) = self.getFull(); return delay; } /** * @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to * enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the * new delay becomes effective. */ function withUpdate( Delay self, uint32 newValue, uint32 minSetback ) internal view returns (Delay updatedDelay, uint48 effect) { uint32 value = self.get(); uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0)); effect = timestamp() + setback; return (pack(value, newValue, effect), effect); } /** * @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint). */ function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) { uint112 raw = Delay.unwrap(self); valueAfter = uint32(raw); valueBefore = uint32(raw >> 32); effect = uint48(raw >> 64); return (valueBefore, valueAfter, effect); } /** * @dev pack the components into a Delay object. */ function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) { return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; // Common.sol // // Common mathematical functions used in both SD59x18 and UD60x18. Note that these global functions do not // always operate with SD59x18 and UD60x18 numbers. /*////////////////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when the resultant value in {mulDiv} overflows uint256. error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator); /// @notice Thrown when the resultant value in {mulDiv18} overflows uint256. error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y); /// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`. error PRBMath_MulDivSigned_InputTooSmall(); /// @notice Thrown when the resultant value in {mulDivSigned} overflows int256. error PRBMath_MulDivSigned_Overflow(int256 x, int256 y); /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ /// @dev The maximum value a uint128 number can have. uint128 constant MAX_UINT128 = type(uint128).max; /// @dev The maximum value a uint40 number can have. uint40 constant MAX_UINT40 = type(uint40).max; /// @dev The maximum value a uint64 number can have. uint64 constant MAX_UINT64 = type(uint64).max; /// @dev The unit number, which the decimal precision of the fixed-point types. uint256 constant UNIT = 1e18; /// @dev The unit number inverted mod 2^256. uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant /// bit in the binary representation of `UNIT`. uint256 constant UNIT_LPOTD = 262144; /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. /// @custom:smtchecker abstract-function-nondet function exp2(uint256 x) pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // The following logic multiplies the result by $\sqrt{2^{-i}}$ when the bit at position i is 1. Key points: // // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65. // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1, // we know that `x & 0xFF` is also 1. if (x & 0xFF00000000000000 > 0) { if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } } if (x & 0xFF000000000000 > 0) { if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } } if (x & 0xFF0000000000 > 0) { if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } } if (x & 0xFF00000000 > 0) { if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } } if (x & 0xFF000000 > 0) { if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } } if (x & 0xFF0000 > 0) { if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } } if (x & 0xFF00 > 0) { if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } } if (x & 0xFF > 0) { if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } } // In the code snippet below, two operations are executed simultaneously: // // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1 // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192. // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format. // // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the, // integer part, $2^n$. result *= UNIT; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first 1 in the binary representation of x. /// /// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set /// /// Each step in this implementation is equivalent to this high-level code: /// /// ```solidity /// if (x >= 2 ** 128) { /// x >>= 128; /// result += 128; /// } /// ``` /// /// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here: /// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948 /// /// The Yul instructions used below are: /// /// - "gt" is "greater than" /// - "or" is the OR bitwise operator /// - "shl" is "shift left" /// - "shr" is "shift right" /// /// @param x The uint256 number for which to find the index of the most significant bit. /// @return result The index of the most significant bit as a uint256. /// @custom:smtchecker abstract-function-nondet function msb(uint256 x) pure returns (uint256 result) { // 2^128 assembly ("memory-safe") { let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^64 assembly ("memory-safe") { let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^32 assembly ("memory-safe") { let factor := shl(5, gt(x, 0xFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^16 assembly ("memory-safe") { let factor := shl(4, gt(x, 0xFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^8 assembly ("memory-safe") { let factor := shl(3, gt(x, 0xFF)) x := shr(factor, x) result := or(result, factor) } // 2^4 assembly ("memory-safe") { let factor := shl(2, gt(x, 0xF)) x := shr(factor, x) result := or(result, factor) } // 2^2 assembly ("memory-safe") { let factor := shl(1, gt(x, 0x3)) x := shr(factor, x) result := or(result, factor) } // 2^1 // No need to shift x any more. assembly ("memory-safe") { let factor := gt(x, 0x1) result := or(result, factor) } } /// @notice Calculates x*y÷denominator with 512-bit precision. /// /// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - The denominator must not be zero. /// - The result must fit in uint256. /// /// @param x The multiplicand as a uint256. /// @param y The multiplier as a uint256. /// @param denominator The divisor as a uint256. /// @return result The result as a uint256. /// @custom:smtchecker abstract-function-nondet function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly ("memory-safe") { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { unchecked { return prod0 / denominator; } } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath_MulDiv_Overflow(x, y, denominator); } //////////////////////////////////////////////////////////////////////////// // 512 by 256 division //////////////////////////////////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly ("memory-safe") { // Compute remainder using the mulmod Yul instruction. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512-bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } unchecked { // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow // because the denominator cannot be zero at this point in the function execution. The result is always >= 1. // For more detail, see https://cs.stackexchange.com/q/138556/92363. uint256 lpotdod = denominator & (~denominator + 1); uint256 flippedLpotdod; assembly ("memory-safe") { // Factor powers of two out of denominator. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one. // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits. // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693 flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * flippedLpotdod; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; } } /// @notice Calculates x*y÷1e18 with 512-bit precision. /// /// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18. /// /// Notes: /// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}. /// - The result is rounded toward zero. /// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations: /// /// $$ /// \begin{cases} /// x * y = MAX\_UINT256 * UNIT \\ /// (x * y) \% UNIT \geq \frac{UNIT}{2} /// \end{cases} /// $$ /// /// Requirements: /// - Refer to the requirements in {mulDiv}. /// - The result must fit in uint256. /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. /// @custom:smtchecker abstract-function-nondet function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly ("memory-safe") { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 == 0) { unchecked { return prod0 / UNIT; } } if (prod1 >= UNIT) { revert PRBMath_MulDiv18_Overflow(x, y); } uint256 remainder; assembly ("memory-safe") { remainder := mulmod(x, y, UNIT) result := mul( or( div(sub(prod0, remainder), UNIT_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1)) ), UNIT_INVERSE ) } } /// @notice Calculates x*y÷denominator with 512-bit precision. /// /// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately. /// /// Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - Refer to the requirements in {mulDiv}. /// - None of the inputs can be `type(int256).min`. /// - The result must fit in int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. /// @custom:smtchecker abstract-function-nondet function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath_MulDivSigned_InputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 xAbs; uint256 yAbs; uint256 dAbs; unchecked { xAbs = x < 0 ? uint256(-x) : uint256(x); yAbs = y < 0 ? uint256(-y) : uint256(y); dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of x*y÷denominator. The result must fit in int256. uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs); if (resultAbs > uint256(type(int256).max)) { revert PRBMath_MulDivSigned_Overflow(x, y); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly ("memory-safe") { // "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement. sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs. // If there are, the result should be negative. Otherwise, it should be positive. unchecked { result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs); } } /// @notice Calculates the square root of x using the Babylonian method. /// /// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Notes: /// - If x is not a perfect square, the result is rounded down. /// - Credits to OpenZeppelin for the explanations in comments below. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as a uint256. /// @custom:smtchecker abstract-function-nondet function sqrt(uint256 x) pure returns (uint256 result) { if (x == 0) { return 0; } // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x. // // We know that the "msb" (most significant bit) of x is a power of 2 such that we have: // // $$ // msb(x) <= x <= 2*msb(x)$ // $$ // // We write $msb(x)$ as $2^k$, and we get: // // $$ // k = log_2(x) // $$ // // Thus, we can write the initial inequality as: // // $$ // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\ // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\ // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1} // $$ // // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit. uint256 xAux = uint256(x); result = 1; if (xAux >= 2 ** 128) { xAux >>= 128; result <<= 64; } if (xAux >= 2 ** 64) { xAux >>= 64; result <<= 32; } if (xAux >= 2 ** 32) { xAux >>= 32; result <<= 16; } if (xAux >= 2 ** 16) { xAux >>= 16; result <<= 8; } if (xAux >= 2 ** 8) { xAux >>= 8; result <<= 4; } if (xAux >= 2 ** 4) { xAux >>= 4; result <<= 2; } if (xAux >= 2 ** 2) { result <<= 1; } // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of // precision into the expected uint128 result. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // If x is not a perfect square, round the result toward zero. uint256 roundedResult = x / result; if (result >= roundedResult) { result = roundedResult; } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "../Common.sol" as Common; import "./Errors.sol" as CastingErrors; import { SD59x18 } from "../sd59x18/ValueType.sol"; import { UD60x18 } from "../ud60x18/ValueType.sol"; import { SD1x18 } from "./ValueType.sol"; /// @notice Casts an SD1x18 number into SD59x18. /// @dev There is no overflow check because SD1x18 ⊆ SD59x18. function intoSD59x18(SD1x18 x) pure returns (SD59x18 result) { result = SD59x18.wrap(int256(SD1x18.unwrap(x))); } /// @notice Casts an SD1x18 number into UD60x18. /// @dev Requirements: /// - x ≥ 0 function intoUD60x18(SD1x18 x) pure returns (UD60x18 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD1x18_ToUD60x18_Underflow(x); } result = UD60x18.wrap(uint64(xInt)); } /// @notice Casts an SD1x18 number into uint128. /// @dev Requirements: /// - x ≥ 0 function intoUint128(SD1x18 x) pure returns (uint128 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD1x18_ToUint128_Underflow(x); } result = uint128(uint64(xInt)); } /// @notice Casts an SD1x18 number into uint256. /// @dev Requirements: /// - x ≥ 0 function intoUint256(SD1x18 x) pure returns (uint256 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD1x18_ToUint256_Underflow(x); } result = uint256(uint64(xInt)); } /// @notice Casts an SD1x18 number into uint40. /// @dev Requirements: /// - x ≥ 0 /// - x ≤ MAX_UINT40 function intoUint40(SD1x18 x) pure returns (uint40 result) { int64 xInt = SD1x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD1x18_ToUint40_Underflow(x); } if (xInt > int64(uint64(Common.MAX_UINT40))) { revert CastingErrors.PRBMath_SD1x18_ToUint40_Overflow(x); } result = uint40(uint64(xInt)); } /// @notice Alias for {wrap}. function sd1x18(int64 x) pure returns (SD1x18 result) { result = SD1x18.wrap(x); } /// @notice Unwraps an SD1x18 number into int64. function unwrap(SD1x18 x) pure returns (int64 result) { result = SD1x18.unwrap(x); } /// @notice Wraps an int64 number into SD1x18. function wrap(int64 x) pure returns (SD1x18 result) { result = SD1x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { SD1x18 } from "./ValueType.sol"; /// @dev Euler's number as an SD1x18 number. SD1x18 constant E = SD1x18.wrap(2_718281828459045235); /// @dev The maximum value an SD1x18 number can have. int64 constant uMAX_SD1x18 = 9_223372036854775807; SD1x18 constant MAX_SD1x18 = SD1x18.wrap(uMAX_SD1x18); /// @dev The minimum value an SD1x18 number can have. int64 constant uMIN_SD1x18 = -9_223372036854775808; SD1x18 constant MIN_SD1x18 = SD1x18.wrap(uMIN_SD1x18); /// @dev PI as an SD1x18 number. SD1x18 constant PI = SD1x18.wrap(3_141592653589793238); /// @dev The unit number, which gives the decimal precision of SD1x18. SD1x18 constant UNIT = SD1x18.wrap(1e18); int64 constant uUNIT = 1e18;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { SD1x18 } from "./ValueType.sol"; /// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in UD60x18. error PRBMath_SD1x18_ToUD60x18_Underflow(SD1x18 x); /// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint128. error PRBMath_SD1x18_ToUint128_Underflow(SD1x18 x); /// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint256. error PRBMath_SD1x18_ToUint256_Underflow(SD1x18 x); /// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint40. error PRBMath_SD1x18_ToUint40_Overflow(SD1x18 x); /// @notice Thrown when trying to cast an SD1x18 number that doesn't fit in uint40. error PRBMath_SD1x18_ToUint40_Underflow(SD1x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "./Casting.sol" as Casting; /// @notice The signed 1.18-decimal fixed-point number representation, which can have up to 1 digit and up to 18 /// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity /// type int64. This is useful when end users want to use int64 to save gas, e.g. with tight variable packing in contract /// storage. type SD1x18 is int64; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { Casting.intoSD59x18, Casting.intoUD60x18, Casting.intoUint128, Casting.intoUint256, Casting.intoUint40, Casting.unwrap } for SD1x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "../Common.sol" as Common; import "./Errors.sol" as CastingErrors; import { SD59x18 } from "../sd59x18/ValueType.sol"; import { UD60x18 } from "../ud60x18/ValueType.sol"; import { SD21x18 } from "./ValueType.sol"; /// @notice Casts an SD21x18 number into SD59x18. /// @dev There is no overflow check because SD21x18 ⊆ SD59x18. function intoSD59x18(SD21x18 x) pure returns (SD59x18 result) { result = SD59x18.wrap(int256(SD21x18.unwrap(x))); } /// @notice Casts an SD21x18 number into UD60x18. /// @dev Requirements: /// - x ≥ 0 function intoUD60x18(SD21x18 x) pure returns (UD60x18 result) { int128 xInt = SD21x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD21x18_ToUD60x18_Underflow(x); } result = UD60x18.wrap(uint128(xInt)); } /// @notice Casts an SD21x18 number into uint128. /// @dev Requirements: /// - x ≥ 0 function intoUint128(SD21x18 x) pure returns (uint128 result) { int128 xInt = SD21x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD21x18_ToUint128_Underflow(x); } result = uint128(xInt); } /// @notice Casts an SD21x18 number into uint256. /// @dev Requirements: /// - x ≥ 0 function intoUint256(SD21x18 x) pure returns (uint256 result) { int128 xInt = SD21x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD21x18_ToUint256_Underflow(x); } result = uint256(uint128(xInt)); } /// @notice Casts an SD21x18 number into uint40. /// @dev Requirements: /// - x ≥ 0 /// - x ≤ MAX_UINT40 function intoUint40(SD21x18 x) pure returns (uint40 result) { int128 xInt = SD21x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD21x18_ToUint40_Underflow(x); } if (xInt > int128(uint128(Common.MAX_UINT40))) { revert CastingErrors.PRBMath_SD21x18_ToUint40_Overflow(x); } result = uint40(uint128(xInt)); } /// @notice Alias for {wrap}. function sd21x18(int128 x) pure returns (SD21x18 result) { result = SD21x18.wrap(x); } /// @notice Unwraps an SD21x18 number into int128. function unwrap(SD21x18 x) pure returns (int128 result) { result = SD21x18.unwrap(x); } /// @notice Wraps an int128 number into SD21x18. function wrap(int128 x) pure returns (SD21x18 result) { result = SD21x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { SD21x18 } from "./ValueType.sol"; /// @dev Euler's number as an SD21x18 number. SD21x18 constant E = SD21x18.wrap(2_718281828459045235); /// @dev The maximum value an SD21x18 number can have. int128 constant uMAX_SD21x18 = 170141183460469231731_687303715884105727; SD21x18 constant MAX_SD21x18 = SD21x18.wrap(uMAX_SD21x18); /// @dev The minimum value an SD21x18 number can have. int128 constant uMIN_SD21x18 = -170141183460469231731_687303715884105728; SD21x18 constant MIN_SD21x18 = SD21x18.wrap(uMIN_SD21x18); /// @dev PI as an SD21x18 number. SD21x18 constant PI = SD21x18.wrap(3_141592653589793238); /// @dev The unit number, which gives the decimal precision of SD21x18. SD21x18 constant UNIT = SD21x18.wrap(1e18); int128 constant uUNIT = 1e18;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { SD21x18 } from "./ValueType.sol"; /// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint128. error PRBMath_SD21x18_ToUint128_Underflow(SD21x18 x); /// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in UD60x18. error PRBMath_SD21x18_ToUD60x18_Underflow(SD21x18 x); /// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint256. error PRBMath_SD21x18_ToUint256_Underflow(SD21x18 x); /// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint40. error PRBMath_SD21x18_ToUint40_Overflow(SD21x18 x); /// @notice Thrown when trying to cast an SD21x18 number that doesn't fit in uint40. error PRBMath_SD21x18_ToUint40_Underflow(SD21x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "./Casting.sol" as Casting; /// @notice The signed 21.18-decimal fixed-point number representation, which can have up to 21 digits and up to 18 /// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity /// type int128. This is useful when end users want to use int128 to save gas, e.g. with tight variable packing in contract /// storage. type SD21x18 is int128; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { Casting.intoSD59x18, Casting.intoUD60x18, Casting.intoUint128, Casting.intoUint256, Casting.intoUint40, Casting.unwrap } for SD21x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "./Errors.sol" as CastingErrors; import { MAX_UINT128, MAX_UINT40 } from "../Common.sol"; import { uMAX_SD1x18, uMIN_SD1x18 } from "../sd1x18/Constants.sol"; import { SD1x18 } from "../sd1x18/ValueType.sol"; import { uMAX_SD21x18, uMIN_SD21x18 } from "../sd21x18/Constants.sol"; import { SD21x18 } from "../sd21x18/ValueType.sol"; import { uMAX_UD2x18 } from "../ud2x18/Constants.sol"; import { UD2x18 } from "../ud2x18/ValueType.sol"; import { uMAX_UD21x18 } from "../ud21x18/Constants.sol"; import { UD21x18 } from "../ud21x18/ValueType.sol"; import { UD60x18 } from "../ud60x18/ValueType.sol"; import { SD59x18 } from "./ValueType.sol"; /// @notice Casts an SD59x18 number into int256. /// @dev This is basically a functional alias for {unwrap}. function intoInt256(SD59x18 x) pure returns (int256 result) { result = SD59x18.unwrap(x); } /// @notice Casts an SD59x18 number into SD1x18. /// @dev Requirements: /// - x ≥ uMIN_SD1x18 /// - x ≤ uMAX_SD1x18 function intoSD1x18(SD59x18 x) pure returns (SD1x18 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < uMIN_SD1x18) { revert CastingErrors.PRBMath_SD59x18_IntoSD1x18_Underflow(x); } if (xInt > uMAX_SD1x18) { revert CastingErrors.PRBMath_SD59x18_IntoSD1x18_Overflow(x); } result = SD1x18.wrap(int64(xInt)); } /// @notice Casts an SD59x18 number into SD21x18. /// @dev Requirements: /// - x ≥ uMIN_SD21x18 /// - x ≤ uMAX_SD21x18 function intoSD21x18(SD59x18 x) pure returns (SD21x18 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < uMIN_SD21x18) { revert CastingErrors.PRBMath_SD59x18_IntoSD21x18_Underflow(x); } if (xInt > uMAX_SD21x18) { revert CastingErrors.PRBMath_SD59x18_IntoSD21x18_Overflow(x); } result = SD21x18.wrap(int128(xInt)); } /// @notice Casts an SD59x18 number into UD2x18. /// @dev Requirements: /// - x ≥ 0 /// - x ≤ uMAX_UD2x18 function intoUD2x18(SD59x18 x) pure returns (UD2x18 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD59x18_IntoUD2x18_Underflow(x); } if (xInt > int256(uint256(uMAX_UD2x18))) { revert CastingErrors.PRBMath_SD59x18_IntoUD2x18_Overflow(x); } result = UD2x18.wrap(uint64(uint256(xInt))); } /// @notice Casts an SD59x18 number into UD21x18. /// @dev Requirements: /// - x ≥ 0 /// - x ≤ uMAX_UD21x18 function intoUD21x18(SD59x18 x) pure returns (UD21x18 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD59x18_IntoUD21x18_Underflow(x); } if (xInt > int256(uint256(uMAX_UD21x18))) { revert CastingErrors.PRBMath_SD59x18_IntoUD21x18_Overflow(x); } result = UD21x18.wrap(uint128(uint256(xInt))); } /// @notice Casts an SD59x18 number into UD60x18. /// @dev Requirements: /// - x ≥ 0 function intoUD60x18(SD59x18 x) pure returns (UD60x18 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD59x18_IntoUD60x18_Underflow(x); } result = UD60x18.wrap(uint256(xInt)); } /// @notice Casts an SD59x18 number into uint256. /// @dev Requirements: /// - x ≥ 0 function intoUint256(SD59x18 x) pure returns (uint256 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD59x18_IntoUint256_Underflow(x); } result = uint256(xInt); } /// @notice Casts an SD59x18 number into uint128. /// @dev Requirements: /// - x ≥ 0 /// - x ≤ uMAX_UINT128 function intoUint128(SD59x18 x) pure returns (uint128 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD59x18_IntoUint128_Underflow(x); } if (xInt > int256(uint256(MAX_UINT128))) { revert CastingErrors.PRBMath_SD59x18_IntoUint128_Overflow(x); } result = uint128(uint256(xInt)); } /// @notice Casts an SD59x18 number into uint40. /// @dev Requirements: /// - x ≥ 0 /// - x ≤ MAX_UINT40 function intoUint40(SD59x18 x) pure returns (uint40 result) { int256 xInt = SD59x18.unwrap(x); if (xInt < 0) { revert CastingErrors.PRBMath_SD59x18_IntoUint40_Underflow(x); } if (xInt > int256(uint256(MAX_UINT40))) { revert CastingErrors.PRBMath_SD59x18_IntoUint40_Overflow(x); } result = uint40(uint256(xInt)); } /// @notice Alias for {wrap}. function sd(int256 x) pure returns (SD59x18 result) { result = SD59x18.wrap(x); } /// @notice Alias for {wrap}. function sd59x18(int256 x) pure returns (SD59x18 result) { result = SD59x18.wrap(x); } /// @notice Unwraps an SD59x18 number into int256. function unwrap(SD59x18 x) pure returns (int256 result) { result = SD59x18.unwrap(x); } /// @notice Wraps an int256 number into SD59x18. function wrap(int256 x) pure returns (SD59x18 result) { result = SD59x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { SD59x18 } from "./ValueType.sol"; // NOTICE: the "u" prefix stands for "unwrapped". /// @dev Euler's number as an SD59x18 number. SD59x18 constant E = SD59x18.wrap(2_718281828459045235); /// @dev The maximum input permitted in {exp}. int256 constant uEXP_MAX_INPUT = 133_084258667509499440; SD59x18 constant EXP_MAX_INPUT = SD59x18.wrap(uEXP_MAX_INPUT); /// @dev Any value less than this returns 0 in {exp}. int256 constant uEXP_MIN_THRESHOLD = -41_446531673892822322; SD59x18 constant EXP_MIN_THRESHOLD = SD59x18.wrap(uEXP_MIN_THRESHOLD); /// @dev The maximum input permitted in {exp2}. int256 constant uEXP2_MAX_INPUT = 192e18 - 1; SD59x18 constant EXP2_MAX_INPUT = SD59x18.wrap(uEXP2_MAX_INPUT); /// @dev Any value less than this returns 0 in {exp2}. int256 constant uEXP2_MIN_THRESHOLD = -59_794705707972522261; SD59x18 constant EXP2_MIN_THRESHOLD = SD59x18.wrap(uEXP2_MIN_THRESHOLD); /// @dev Half the UNIT number. int256 constant uHALF_UNIT = 0.5e18; SD59x18 constant HALF_UNIT = SD59x18.wrap(uHALF_UNIT); /// @dev $log_2(10)$ as an SD59x18 number. int256 constant uLOG2_10 = 3_321928094887362347; SD59x18 constant LOG2_10 = SD59x18.wrap(uLOG2_10); /// @dev $log_2(e)$ as an SD59x18 number. int256 constant uLOG2_E = 1_442695040888963407; SD59x18 constant LOG2_E = SD59x18.wrap(uLOG2_E); /// @dev The maximum value an SD59x18 number can have. int256 constant uMAX_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_792003956564819967; SD59x18 constant MAX_SD59x18 = SD59x18.wrap(uMAX_SD59x18); /// @dev The maximum whole value an SD59x18 number can have. int256 constant uMAX_WHOLE_SD59x18 = 57896044618658097711785492504343953926634992332820282019728_000000000000000000; SD59x18 constant MAX_WHOLE_SD59x18 = SD59x18.wrap(uMAX_WHOLE_SD59x18); /// @dev The minimum value an SD59x18 number can have. int256 constant uMIN_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_792003956564819968; SD59x18 constant MIN_SD59x18 = SD59x18.wrap(uMIN_SD59x18); /// @dev The minimum whole value an SD59x18 number can have. int256 constant uMIN_WHOLE_SD59x18 = -57896044618658097711785492504343953926634992332820282019728_000000000000000000; SD59x18 constant MIN_WHOLE_SD59x18 = SD59x18.wrap(uMIN_WHOLE_SD59x18); /// @dev PI as an SD59x18 number. SD59x18 constant PI = SD59x18.wrap(3_141592653589793238); /// @dev The unit number, which gives the decimal precision of SD59x18. int256 constant uUNIT = 1e18; SD59x18 constant UNIT = SD59x18.wrap(1e18); /// @dev The unit number squared. int256 constant uUNIT_SQUARED = 1e36; SD59x18 constant UNIT_SQUARED = SD59x18.wrap(uUNIT_SQUARED); /// @dev Zero as an SD59x18 number. SD59x18 constant ZERO = SD59x18.wrap(0);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { SD59x18 } from "./ValueType.sol"; /// @notice Thrown when taking the absolute value of `MIN_SD59x18`. error PRBMath_SD59x18_Abs_MinSD59x18(); /// @notice Thrown when ceiling a number overflows SD59x18. error PRBMath_SD59x18_Ceil_Overflow(SD59x18 x); /// @notice Thrown when converting a basic integer to the fixed-point format overflows SD59x18. error PRBMath_SD59x18_Convert_Overflow(int256 x); /// @notice Thrown when converting a basic integer to the fixed-point format underflows SD59x18. error PRBMath_SD59x18_Convert_Underflow(int256 x); /// @notice Thrown when dividing two numbers and one of them is `MIN_SD59x18`. error PRBMath_SD59x18_Div_InputTooSmall(); /// @notice Thrown when dividing two numbers and one of the intermediary unsigned results overflows SD59x18. error PRBMath_SD59x18_Div_Overflow(SD59x18 x, SD59x18 y); /// @notice Thrown when taking the natural exponent of a base greater than 133_084258667509499441. error PRBMath_SD59x18_Exp_InputTooBig(SD59x18 x); /// @notice Thrown when taking the binary exponent of a base greater than 192e18. error PRBMath_SD59x18_Exp2_InputTooBig(SD59x18 x); /// @notice Thrown when flooring a number underflows SD59x18. error PRBMath_SD59x18_Floor_Underflow(SD59x18 x); /// @notice Thrown when taking the geometric mean of two numbers and their product is negative. error PRBMath_SD59x18_Gm_NegativeProduct(SD59x18 x, SD59x18 y); /// @notice Thrown when taking the geometric mean of two numbers and multiplying them overflows SD59x18. error PRBMath_SD59x18_Gm_Overflow(SD59x18 x, SD59x18 y); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD1x18. error PRBMath_SD59x18_IntoSD1x18_Overflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD1x18. error PRBMath_SD59x18_IntoSD1x18_Underflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD21x18. error PRBMath_SD59x18_IntoSD21x18_Overflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in SD21x18. error PRBMath_SD59x18_IntoSD21x18_Underflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD2x18. error PRBMath_SD59x18_IntoUD2x18_Overflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD2x18. error PRBMath_SD59x18_IntoUD2x18_Underflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD21x18. error PRBMath_SD59x18_IntoUD21x18_Overflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD21x18. error PRBMath_SD59x18_IntoUD21x18_Underflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in UD60x18. error PRBMath_SD59x18_IntoUD60x18_Underflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint128. error PRBMath_SD59x18_IntoUint128_Overflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint128. error PRBMath_SD59x18_IntoUint128_Underflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint256. error PRBMath_SD59x18_IntoUint256_Underflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint40. error PRBMath_SD59x18_IntoUint40_Overflow(SD59x18 x); /// @notice Thrown when trying to cast an SD59x18 number that doesn't fit in uint40. error PRBMath_SD59x18_IntoUint40_Underflow(SD59x18 x); /// @notice Thrown when taking the logarithm of a number less than or equal to zero. error PRBMath_SD59x18_Log_InputTooSmall(SD59x18 x); /// @notice Thrown when multiplying two numbers and one of the inputs is `MIN_SD59x18`. error PRBMath_SD59x18_Mul_InputTooSmall(); /// @notice Thrown when multiplying two numbers and the intermediary absolute result overflows SD59x18. error PRBMath_SD59x18_Mul_Overflow(SD59x18 x, SD59x18 y); /// @notice Thrown when raising a number to a power and the intermediary absolute result overflows SD59x18. error PRBMath_SD59x18_Powu_Overflow(SD59x18 x, uint256 y); /// @notice Thrown when taking the square root of a negative number. error PRBMath_SD59x18_Sqrt_NegativeInput(SD59x18 x); /// @notice Thrown when the calculating the square root overflows SD59x18. error PRBMath_SD59x18_Sqrt_Overflow(SD59x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { wrap } from "./Casting.sol"; import { SD59x18 } from "./ValueType.sol"; /// @notice Implements the checked addition operation (+) in the SD59x18 type. function add(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { return wrap(x.unwrap() + y.unwrap()); } /// @notice Implements the AND (&) bitwise operation in the SD59x18 type. function and(SD59x18 x, int256 bits) pure returns (SD59x18 result) { return wrap(x.unwrap() & bits); } /// @notice Implements the AND (&) bitwise operation in the SD59x18 type. function and2(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { return wrap(x.unwrap() & y.unwrap()); } /// @notice Implements the equal (=) operation in the SD59x18 type. function eq(SD59x18 x, SD59x18 y) pure returns (bool result) { result = x.unwrap() == y.unwrap(); } /// @notice Implements the greater than operation (>) in the SD59x18 type. function gt(SD59x18 x, SD59x18 y) pure returns (bool result) { result = x.unwrap() > y.unwrap(); } /// @notice Implements the greater than or equal to operation (>=) in the SD59x18 type. function gte(SD59x18 x, SD59x18 y) pure returns (bool result) { result = x.unwrap() >= y.unwrap(); } /// @notice Implements a zero comparison check function in the SD59x18 type. function isZero(SD59x18 x) pure returns (bool result) { result = x.unwrap() == 0; } /// @notice Implements the left shift operation (<<) in the SD59x18 type. function lshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) { result = wrap(x.unwrap() << bits); } /// @notice Implements the lower than operation (<) in the SD59x18 type. function lt(SD59x18 x, SD59x18 y) pure returns (bool result) { result = x.unwrap() < y.unwrap(); } /// @notice Implements the lower than or equal to operation (<=) in the SD59x18 type. function lte(SD59x18 x, SD59x18 y) pure returns (bool result) { result = x.unwrap() <= y.unwrap(); } /// @notice Implements the unchecked modulo operation (%) in the SD59x18 type. function mod(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { result = wrap(x.unwrap() % y.unwrap()); } /// @notice Implements the not equal operation (!=) in the SD59x18 type. function neq(SD59x18 x, SD59x18 y) pure returns (bool result) { result = x.unwrap() != y.unwrap(); } /// @notice Implements the NOT (~) bitwise operation in the SD59x18 type. function not(SD59x18 x) pure returns (SD59x18 result) { result = wrap(~x.unwrap()); } /// @notice Implements the OR (|) bitwise operation in the SD59x18 type. function or(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { result = wrap(x.unwrap() | y.unwrap()); } /// @notice Implements the right shift operation (>>) in the SD59x18 type. function rshift(SD59x18 x, uint256 bits) pure returns (SD59x18 result) { result = wrap(x.unwrap() >> bits); } /// @notice Implements the checked subtraction operation (-) in the SD59x18 type. function sub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { result = wrap(x.unwrap() - y.unwrap()); } /// @notice Implements the checked unary minus operation (-) in the SD59x18 type. function unary(SD59x18 x) pure returns (SD59x18 result) { result = wrap(-x.unwrap()); } /// @notice Implements the unchecked addition operation (+) in the SD59x18 type. function uncheckedAdd(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { unchecked { result = wrap(x.unwrap() + y.unwrap()); } } /// @notice Implements the unchecked subtraction operation (-) in the SD59x18 type. function uncheckedSub(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { unchecked { result = wrap(x.unwrap() - y.unwrap()); } } /// @notice Implements the unchecked unary minus operation (-) in the SD59x18 type. function uncheckedUnary(SD59x18 x) pure returns (SD59x18 result) { unchecked { result = wrap(-x.unwrap()); } } /// @notice Implements the XOR (^) bitwise operation in the SD59x18 type. function xor(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { result = wrap(x.unwrap() ^ y.unwrap()); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "../Common.sol" as Common; import "./Errors.sol" as Errors; import { uEXP_MAX_INPUT, uEXP2_MAX_INPUT, uEXP_MIN_THRESHOLD, uEXP2_MIN_THRESHOLD, uHALF_UNIT, uLOG2_10, uLOG2_E, uMAX_SD59x18, uMAX_WHOLE_SD59x18, uMIN_SD59x18, uMIN_WHOLE_SD59x18, UNIT, uUNIT, uUNIT_SQUARED, ZERO } from "./Constants.sol"; import { wrap } from "./Helpers.sol"; import { SD59x18 } from "./ValueType.sol"; /// @notice Calculates the absolute value of x. /// /// @dev Requirements: /// - x > MIN_SD59x18. /// /// @param x The SD59x18 number for which to calculate the absolute value. /// @return result The absolute value of x as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function abs(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); if (xInt == uMIN_SD59x18) { revert Errors.PRBMath_SD59x18_Abs_MinSD59x18(); } result = xInt < 0 ? wrap(-xInt) : x; } /// @notice Calculates the arithmetic average of x and y. /// /// @dev Notes: /// - The result is rounded toward zero. /// /// @param x The first operand as an SD59x18 number. /// @param y The second operand as an SD59x18 number. /// @return result The arithmetic average as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function avg(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); int256 yInt = y.unwrap(); unchecked { // This operation is equivalent to `x / 2 + y / 2`, and it can never overflow. int256 sum = (xInt >> 1) + (yInt >> 1); if (sum < 0) { // If at least one of x and y is odd, add 1 to the result, because shifting negative numbers to the right // rounds toward negative infinity. The right part is equivalent to `sum + (x % 2 == 1 || y % 2 == 1)`. assembly ("memory-safe") { result := add(sum, and(or(xInt, yInt), 1)) } } else { // Add 1 if both x and y are odd to account for the double 0.5 remainder truncated after shifting. result = wrap(sum + (xInt & yInt & 1)); } } } /// @notice Yields the smallest whole number greater than or equal to x. /// /// @dev Optimized for fractional value inputs, because every whole value has (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x ≤ MAX_WHOLE_SD59x18 /// /// @param x The SD59x18 number to ceil. /// @return result The smallest whole number greater than or equal to x, as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function ceil(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); if (xInt > uMAX_WHOLE_SD59x18) { revert Errors.PRBMath_SD59x18_Ceil_Overflow(x); } int256 remainder = xInt % uUNIT; if (remainder == 0) { result = x; } else { unchecked { // Solidity uses C fmod style, which returns a modulus with the same sign as x. int256 resultInt = xInt - remainder; if (xInt > 0) { resultInt += uUNIT; } result = wrap(resultInt); } } } /// @notice Divides two SD59x18 numbers, returning a new SD59x18 number. /// /// @dev This is an extension of {Common.mulDiv} for signed numbers, which works by computing the signs and the absolute /// values separately. /// /// Notes: /// - Refer to the notes in {Common.mulDiv}. /// - The result is rounded toward zero. /// /// Requirements: /// - Refer to the requirements in {Common.mulDiv}. /// - None of the inputs can be `MIN_SD59x18`. /// - The denominator must not be zero. /// - The result must fit in SD59x18. /// /// @param x The numerator as an SD59x18 number. /// @param y The denominator as an SD59x18 number. /// @return result The quotient as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function div(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); int256 yInt = y.unwrap(); if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) { revert Errors.PRBMath_SD59x18_Div_InputTooSmall(); } // Get hold of the absolute values of x and y. uint256 xAbs; uint256 yAbs; unchecked { xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt); yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt); } // Compute the absolute value (x*UNIT÷y). The resulting value must fit in SD59x18. uint256 resultAbs = Common.mulDiv(xAbs, uint256(uUNIT), yAbs); if (resultAbs > uint256(uMAX_SD59x18)) { revert Errors.PRBMath_SD59x18_Div_Overflow(x, y); } // Check if x and y have the same sign using two's complement representation. The left-most bit represents the sign (1 for // negative, 0 for positive or zero). bool sameSign = (xInt ^ yInt) > -1; // If the inputs have the same sign, the result should be positive. Otherwise, it should be negative. unchecked { result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs)); } } /// @notice Calculates the natural exponent of x using the following formula: /// /// $$ /// e^x = 2^{x * log_2{e}} /// $$ /// /// @dev Notes: /// - Refer to the notes in {exp2}. /// /// Requirements: /// - Refer to the requirements in {exp2}. /// - x < 133_084258667509499441. /// /// @param x The exponent as an SD59x18 number. /// @return result The result as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function exp(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); // Any input less than the threshold returns zero. // This check also prevents an overflow for very small numbers. if (xInt < uEXP_MIN_THRESHOLD) { return ZERO; } // This check prevents values greater than 192e18 from being passed to {exp2}. if (xInt > uEXP_MAX_INPUT) { revert Errors.PRBMath_SD59x18_Exp_InputTooBig(x); } unchecked { // Inline the fixed-point multiplication to save gas. int256 doubleUnitProduct = xInt * uLOG2_E; result = exp2(wrap(doubleUnitProduct / uUNIT)); } } /// @notice Calculates the binary exponent of x using the binary fraction method using the following formula: /// /// $$ /// 2^{-x} = \frac{1}{2^x} /// $$ /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Notes: /// - If x < -59_794705707972522261, the result is zero. /// /// Requirements: /// - x < 192e18. /// - The result must fit in SD59x18. /// /// @param x The exponent as an SD59x18 number. /// @return result The result as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function exp2(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); if (xInt < 0) { // The inverse of any number less than the threshold is truncated to zero. if (xInt < uEXP2_MIN_THRESHOLD) { return ZERO; } unchecked { // Inline the fixed-point inversion to save gas. result = wrap(uUNIT_SQUARED / exp2(wrap(-xInt)).unwrap()); } } else { // Numbers greater than or equal to 192e18 don't fit in the 192.64-bit format. if (xInt > uEXP2_MAX_INPUT) { revert Errors.PRBMath_SD59x18_Exp2_InputTooBig(x); } unchecked { // Convert x to the 192.64-bit fixed-point format. uint256 x_192x64 = uint256((xInt << 64) / uUNIT); // It is safe to cast the result to int256 due to the checks above. result = wrap(int256(Common.exp2(x_192x64))); } } } /// @notice Yields the greatest whole number less than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional /// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x ≥ MIN_WHOLE_SD59x18 /// /// @param x The SD59x18 number to floor. /// @return result The greatest whole number less than or equal to x, as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function floor(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); if (xInt < uMIN_WHOLE_SD59x18) { revert Errors.PRBMath_SD59x18_Floor_Underflow(x); } int256 remainder = xInt % uUNIT; if (remainder == 0) { result = x; } else { unchecked { // Solidity uses C fmod style, which returns a modulus with the same sign as x. int256 resultInt = xInt - remainder; if (xInt < 0) { resultInt -= uUNIT; } result = wrap(resultInt); } } } /// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right. /// of the radix point for negative numbers. /// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part /// @param x The SD59x18 number to get the fractional part of. /// @return result The fractional part of x as an SD59x18 number. function frac(SD59x18 x) pure returns (SD59x18 result) { result = wrap(x.unwrap() % uUNIT); } /// @notice Calculates the geometric mean of x and y, i.e. $\sqrt{x * y}$. /// /// @dev Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - x * y must fit in SD59x18. /// - x * y must not be negative, since complex numbers are not supported. /// /// @param x The first operand as an SD59x18 number. /// @param y The second operand as an SD59x18 number. /// @return result The result as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function gm(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); int256 yInt = y.unwrap(); if (xInt == 0 || yInt == 0) { return ZERO; } unchecked { // Equivalent to `xy / x != y`. Checking for overflow this way is faster than letting Solidity do it. int256 xyInt = xInt * yInt; if (xyInt / xInt != yInt) { revert Errors.PRBMath_SD59x18_Gm_Overflow(x, y); } // The product must not be negative, since complex numbers are not supported. if (xyInt < 0) { revert Errors.PRBMath_SD59x18_Gm_NegativeProduct(x, y); } // We don't need to multiply the result by `UNIT` here because the x*y product picked up a factor of `UNIT` // during multiplication. See the comments in {Common.sqrt}. uint256 resultUint = Common.sqrt(uint256(xyInt)); result = wrap(int256(resultUint)); } } /// @notice Calculates the inverse of x. /// /// @dev Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - x must not be zero. /// /// @param x The SD59x18 number for which to calculate the inverse. /// @return result The inverse as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function inv(SD59x18 x) pure returns (SD59x18 result) { result = wrap(uUNIT_SQUARED / x.unwrap()); } /// @notice Calculates the natural logarithm of x using the following formula: /// /// $$ /// ln{x} = log_2{x} / log_2{e} /// $$ /// /// @dev Notes: /// - Refer to the notes in {log2}. /// - The precision isn't sufficiently fine-grained to return exactly `UNIT` when the input is `E`. /// /// Requirements: /// - Refer to the requirements in {log2}. /// /// @param x The SD59x18 number for which to calculate the natural logarithm. /// @return result The natural logarithm as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function ln(SD59x18 x) pure returns (SD59x18 result) { // Inline the fixed-point multiplication to save gas. This is overflow-safe because the maximum value that // {log2} can return is ~195_205294292027477728. result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E); } /// @notice Calculates the common logarithm of x using the following formula: /// /// $$ /// log_{10}{x} = log_2{x} / log_2{10} /// $$ /// /// However, if x is an exact power of ten, a hard coded value is returned. /// /// @dev Notes: /// - Refer to the notes in {log2}. /// /// Requirements: /// - Refer to the requirements in {log2}. /// /// @param x The SD59x18 number for which to calculate the common logarithm. /// @return result The common logarithm as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function log10(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); if (xInt < 0) { revert Errors.PRBMath_SD59x18_Log_InputTooSmall(x); } // Note that the `mul` in this block is the standard multiplication operation, not {SD59x18.mul}. // prettier-ignore assembly ("memory-safe") { switch x case 1 { result := mul(uUNIT, sub(0, 18)) } case 10 { result := mul(uUNIT, sub(1, 18)) } case 100 { result := mul(uUNIT, sub(2, 18)) } case 1000 { result := mul(uUNIT, sub(3, 18)) } case 10000 { result := mul(uUNIT, sub(4, 18)) } case 100000 { result := mul(uUNIT, sub(5, 18)) } case 1000000 { result := mul(uUNIT, sub(6, 18)) } case 10000000 { result := mul(uUNIT, sub(7, 18)) } case 100000000 { result := mul(uUNIT, sub(8, 18)) } case 1000000000 { result := mul(uUNIT, sub(9, 18)) } case 10000000000 { result := mul(uUNIT, sub(10, 18)) } case 100000000000 { result := mul(uUNIT, sub(11, 18)) } case 1000000000000 { result := mul(uUNIT, sub(12, 18)) } case 10000000000000 { result := mul(uUNIT, sub(13, 18)) } case 100000000000000 { result := mul(uUNIT, sub(14, 18)) } case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) } case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) } case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := uUNIT } case 100000000000000000000 { result := mul(uUNIT, 2) } case 1000000000000000000000 { result := mul(uUNIT, 3) } case 10000000000000000000000 { result := mul(uUNIT, 4) } case 100000000000000000000000 { result := mul(uUNIT, 5) } case 1000000000000000000000000 { result := mul(uUNIT, 6) } case 10000000000000000000000000 { result := mul(uUNIT, 7) } case 100000000000000000000000000 { result := mul(uUNIT, 8) } case 1000000000000000000000000000 { result := mul(uUNIT, 9) } case 10000000000000000000000000000 { result := mul(uUNIT, 10) } case 100000000000000000000000000000 { result := mul(uUNIT, 11) } case 1000000000000000000000000000000 { result := mul(uUNIT, 12) } case 10000000000000000000000000000000 { result := mul(uUNIT, 13) } case 100000000000000000000000000000000 { result := mul(uUNIT, 14) } case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) } case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) } case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) } case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) } case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) } case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) } case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) } case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) } case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) } case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) } case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) } case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) } default { result := uMAX_SD59x18 } } if (result.unwrap() == uMAX_SD59x18) { unchecked { // Inline the fixed-point division to save gas. result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10); } } } /// @notice Calculates the binary logarithm of x using the iterative approximation algorithm: /// /// $$ /// log_2{x} = n + log_2{y}, \text{ where } y = x*2^{-n}, \ y \in [1, 2) /// $$ /// /// For $0 \leq x \lt 1$, the input is inverted: /// /// $$ /// log_2{x} = -log_2{\frac{1}{x}} /// $$ /// /// @dev See https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation. /// /// Notes: /// - Due to the lossy precision of the iterative approximation, the results are not perfectly accurate to the last decimal. /// /// Requirements: /// - x > 0 /// /// @param x The SD59x18 number for which to calculate the binary logarithm. /// @return result The binary logarithm as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function log2(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); if (xInt <= 0) { revert Errors.PRBMath_SD59x18_Log_InputTooSmall(x); } unchecked { int256 sign; if (xInt >= uUNIT) { sign = 1; } else { sign = -1; // Inline the fixed-point inversion to save gas. xInt = uUNIT_SQUARED / xInt; } // Calculate the integer part of the logarithm. uint256 n = Common.msb(uint256(xInt / uUNIT)); // This is the integer part of the logarithm as an SD59x18 number. The operation can't overflow // because n is at most 255, `UNIT` is 1e18, and the sign is either 1 or -1. int256 resultInt = int256(n) * uUNIT; // Calculate $y = x * 2^{-n}$. int256 y = xInt >> n; // If y is the unit number, the fractional part is zero. if (y == uUNIT) { return wrap(resultInt * sign); } // Calculate the fractional part via the iterative approximation. // The `delta >>= 1` part is equivalent to `delta /= 2`, but shifting bits is more gas efficient. int256 DOUBLE_UNIT = 2e18; for (int256 delta = uHALF_UNIT; delta > 0; delta >>= 1) { y = (y * y) / uUNIT; // Is y^2 >= 2e18 and so in the range [2e18, 4e18)? if (y >= DOUBLE_UNIT) { // Add the 2^{-m} factor to the logarithm. resultInt = resultInt + delta; // Halve y, which corresponds to z/2 in the Wikipedia article. y >>= 1; } } resultInt *= sign; result = wrap(resultInt); } } /// @notice Multiplies two SD59x18 numbers together, returning a new SD59x18 number. /// /// @dev Notes: /// - Refer to the notes in {Common.mulDiv18}. /// /// Requirements: /// - Refer to the requirements in {Common.mulDiv18}. /// - None of the inputs can be `MIN_SD59x18`. /// - The result must fit in SD59x18. /// /// @param x The multiplicand as an SD59x18 number. /// @param y The multiplier as an SD59x18 number. /// @return result The product as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function mul(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); int256 yInt = y.unwrap(); if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) { revert Errors.PRBMath_SD59x18_Mul_InputTooSmall(); } // Get hold of the absolute values of x and y. uint256 xAbs; uint256 yAbs; unchecked { xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt); yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt); } // Compute the absolute value (x*y÷UNIT). The resulting value must fit in SD59x18. uint256 resultAbs = Common.mulDiv18(xAbs, yAbs); if (resultAbs > uint256(uMAX_SD59x18)) { revert Errors.PRBMath_SD59x18_Mul_Overflow(x, y); } // Check if x and y have the same sign using two's complement representation. The left-most bit represents the sign (1 for // negative, 0 for positive or zero). bool sameSign = (xInt ^ yInt) > -1; // If the inputs have the same sign, the result should be positive. Otherwise, it should be negative. unchecked { result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs)); } } /// @notice Raises x to the power of y using the following formula: /// /// $$ /// x^y = 2^{log_2{x} * y} /// $$ /// /// @dev Notes: /// - Refer to the notes in {exp2}, {log2}, and {mul}. /// - Returns `UNIT` for 0^0. /// /// Requirements: /// - Refer to the requirements in {exp2}, {log2}, and {mul}. /// /// @param x The base as an SD59x18 number. /// @param y Exponent to raise x to, as an SD59x18 number /// @return result x raised to power y, as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); int256 yInt = y.unwrap(); // If both x and y are zero, the result is `UNIT`. If just x is zero, the result is always zero. if (xInt == 0) { return yInt == 0 ? UNIT : ZERO; } // If x is `UNIT`, the result is always `UNIT`. else if (xInt == uUNIT) { return UNIT; } // If y is zero, the result is always `UNIT`. if (yInt == 0) { return UNIT; } // If y is `UNIT`, the result is always x. else if (yInt == uUNIT) { return x; } // Calculate the result using the formula. result = exp2(mul(log2(x), y)); } /// @notice Raises x (an SD59x18 number) to the power y (an unsigned basic integer) using the well-known /// algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring. /// /// Notes: /// - Refer to the notes in {Common.mulDiv18}. /// - Returns `UNIT` for 0^0. /// /// Requirements: /// - Refer to the requirements in {abs} and {Common.mulDiv18}. /// - The result must fit in SD59x18. /// /// @param x The base as an SD59x18 number. /// @param y The exponent as a uint256. /// @return result The result as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function powu(SD59x18 x, uint256 y) pure returns (SD59x18 result) { uint256 xAbs = uint256(abs(x).unwrap()); // Calculate the first iteration of the loop in advance. uint256 resultAbs = y & 1 > 0 ? xAbs : uint256(uUNIT); // Equivalent to `for(y /= 2; y > 0; y /= 2)`. uint256 yAux = y; for (yAux >>= 1; yAux > 0; yAux >>= 1) { xAbs = Common.mulDiv18(xAbs, xAbs); // Equivalent to `y % 2 == 1`. if (yAux & 1 > 0) { resultAbs = Common.mulDiv18(resultAbs, xAbs); } } // The result must fit in SD59x18. if (resultAbs > uint256(uMAX_SD59x18)) { revert Errors.PRBMath_SD59x18_Powu_Overflow(x, y); } unchecked { // Is the base negative and the exponent odd? If yes, the result should be negative. int256 resultInt = int256(resultAbs); bool isNegative = x.unwrap() < 0 && y & 1 == 1; if (isNegative) { resultInt = -resultInt; } result = wrap(resultInt); } } /// @notice Calculates the square root of x using the Babylonian method. /// /// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Notes: /// - Only the positive root is returned. /// - The result is rounded toward zero. /// /// Requirements: /// - x ≥ 0, since complex numbers are not supported. /// - x ≤ MAX_SD59x18 / UNIT /// /// @param x The SD59x18 number for which to calculate the square root. /// @return result The result as an SD59x18 number. /// @custom:smtchecker abstract-function-nondet function sqrt(SD59x18 x) pure returns (SD59x18 result) { int256 xInt = x.unwrap(); if (xInt < 0) { revert Errors.PRBMath_SD59x18_Sqrt_NegativeInput(x); } if (xInt > uMAX_SD59x18 / uUNIT) { revert Errors.PRBMath_SD59x18_Sqrt_Overflow(x); } unchecked { // Multiply x by `UNIT` to account for the factor of `UNIT` picked up when multiplying two SD59x18 numbers. // In this case, the two numbers are both the square root. uint256 resultUint = Common.sqrt(uint256(xInt * uUNIT)); result = wrap(int256(resultUint)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "./Casting.sol" as Casting; import "./Helpers.sol" as Helpers; import "./Math.sol" as Math; /// @notice The signed 59.18-decimal fixed-point number representation, which can have up to 59 digits and up to 18 /// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity /// type int256. type SD59x18 is int256; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { Casting.intoInt256, Casting.intoSD1x18, Casting.intoSD21x18, Casting.intoUD2x18, Casting.intoUD21x18, Casting.intoUD60x18, Casting.intoUint256, Casting.intoUint128, Casting.intoUint40, Casting.unwrap } for SD59x18 global; /*////////////////////////////////////////////////////////////////////////// MATHEMATICAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ using { Math.abs, Math.avg, Math.ceil, Math.div, Math.exp, Math.exp2, Math.floor, Math.frac, Math.gm, Math.inv, Math.log10, Math.log2, Math.ln, Math.mul, Math.pow, Math.powu, Math.sqrt } for SD59x18 global; /*////////////////////////////////////////////////////////////////////////// HELPER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ using { Helpers.add, Helpers.and, Helpers.eq, Helpers.gt, Helpers.gte, Helpers.isZero, Helpers.lshift, Helpers.lt, Helpers.lte, Helpers.mod, Helpers.neq, Helpers.not, Helpers.or, Helpers.rshift, Helpers.sub, Helpers.uncheckedAdd, Helpers.uncheckedSub, Helpers.uncheckedUnary, Helpers.xor } for SD59x18 global; /*////////////////////////////////////////////////////////////////////////// OPERATORS //////////////////////////////////////////////////////////////////////////*/ // The global "using for" directive makes it possible to use these operators on the SD59x18 type. using { Helpers.add as +, Helpers.and2 as &, Math.div as /, Helpers.eq as ==, Helpers.gt as >, Helpers.gte as >=, Helpers.lt as <, Helpers.lte as <=, Helpers.mod as %, Math.mul as *, Helpers.neq as !=, Helpers.not as ~, Helpers.or as |, Helpers.sub as -, Helpers.unary as -, Helpers.xor as ^ } for SD59x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "../Common.sol" as Common; import "./Errors.sol" as Errors; import { SD59x18 } from "../sd59x18/ValueType.sol"; import { UD60x18 } from "../ud60x18/ValueType.sol"; import { UD21x18 } from "./ValueType.sol"; /// @notice Casts a UD21x18 number into SD59x18. /// @dev There is no overflow check because UD21x18 ⊆ SD59x18. function intoSD59x18(UD21x18 x) pure returns (SD59x18 result) { result = SD59x18.wrap(int256(uint256(UD21x18.unwrap(x)))); } /// @notice Casts a UD21x18 number into UD60x18. /// @dev There is no overflow check because UD21x18 ⊆ UD60x18. function intoUD60x18(UD21x18 x) pure returns (UD60x18 result) { result = UD60x18.wrap(UD21x18.unwrap(x)); } /// @notice Casts a UD21x18 number into uint128. /// @dev This is basically an alias for {unwrap}. function intoUint128(UD21x18 x) pure returns (uint128 result) { result = UD21x18.unwrap(x); } /// @notice Casts a UD21x18 number into uint256. /// @dev There is no overflow check because UD21x18 ⊆ uint256. function intoUint256(UD21x18 x) pure returns (uint256 result) { result = uint256(UD21x18.unwrap(x)); } /// @notice Casts a UD21x18 number into uint40. /// @dev Requirements: /// - x ≤ MAX_UINT40 function intoUint40(UD21x18 x) pure returns (uint40 result) { uint128 xUint = UD21x18.unwrap(x); if (xUint > uint128(Common.MAX_UINT40)) { revert Errors.PRBMath_UD21x18_IntoUint40_Overflow(x); } result = uint40(xUint); } /// @notice Alias for {wrap}. function ud21x18(uint128 x) pure returns (UD21x18 result) { result = UD21x18.wrap(x); } /// @notice Unwrap a UD21x18 number into uint128. function unwrap(UD21x18 x) pure returns (uint128 result) { result = UD21x18.unwrap(x); } /// @notice Wraps a uint128 number into UD21x18. function wrap(uint128 x) pure returns (UD21x18 result) { result = UD21x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { UD21x18 } from "./ValueType.sol"; /// @dev Euler's number as a UD21x18 number. UD21x18 constant E = UD21x18.wrap(2_718281828459045235); /// @dev The maximum value a UD21x18 number can have. uint128 constant uMAX_UD21x18 = 340282366920938463463_374607431768211455; UD21x18 constant MAX_UD21x18 = UD21x18.wrap(uMAX_UD21x18); /// @dev PI as a UD21x18 number. UD21x18 constant PI = UD21x18.wrap(3_141592653589793238); /// @dev The unit number, which gives the decimal precision of UD21x18. uint256 constant uUNIT = 1e18; UD21x18 constant UNIT = UD21x18.wrap(1e18);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { UD21x18 } from "./ValueType.sol"; /// @notice Thrown when trying to cast a UD21x18 number that doesn't fit in uint40. error PRBMath_UD21x18_IntoUint40_Overflow(UD21x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "./Casting.sol" as Casting; /// @notice The unsigned 21.18-decimal fixed-point number representation, which can have up to 21 digits and up to 18 /// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity /// type uint128. This is useful when end users want to use uint128 to save gas, e.g. with tight variable packing in contract /// storage. type UD21x18 is uint128; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { Casting.intoSD59x18, Casting.intoUD60x18, Casting.intoUint128, Casting.intoUint256, Casting.intoUint40, Casting.unwrap } for UD21x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "../Common.sol" as Common; import "./Errors.sol" as Errors; import { SD59x18 } from "../sd59x18/ValueType.sol"; import { UD60x18 } from "../ud60x18/ValueType.sol"; import { UD2x18 } from "./ValueType.sol"; /// @notice Casts a UD2x18 number into SD59x18. /// @dev There is no overflow check because UD2x18 ⊆ SD59x18. function intoSD59x18(UD2x18 x) pure returns (SD59x18 result) { result = SD59x18.wrap(int256(uint256(UD2x18.unwrap(x)))); } /// @notice Casts a UD2x18 number into UD60x18. /// @dev There is no overflow check because UD2x18 ⊆ UD60x18. function intoUD60x18(UD2x18 x) pure returns (UD60x18 result) { result = UD60x18.wrap(UD2x18.unwrap(x)); } /// @notice Casts a UD2x18 number into uint128. /// @dev There is no overflow check because UD2x18 ⊆ uint128. function intoUint128(UD2x18 x) pure returns (uint128 result) { result = uint128(UD2x18.unwrap(x)); } /// @notice Casts a UD2x18 number into uint256. /// @dev There is no overflow check because UD2x18 ⊆ uint256. function intoUint256(UD2x18 x) pure returns (uint256 result) { result = uint256(UD2x18.unwrap(x)); } /// @notice Casts a UD2x18 number into uint40. /// @dev Requirements: /// - x ≤ MAX_UINT40 function intoUint40(UD2x18 x) pure returns (uint40 result) { uint64 xUint = UD2x18.unwrap(x); if (xUint > uint64(Common.MAX_UINT40)) { revert Errors.PRBMath_UD2x18_IntoUint40_Overflow(x); } result = uint40(xUint); } /// @notice Alias for {wrap}. function ud2x18(uint64 x) pure returns (UD2x18 result) { result = UD2x18.wrap(x); } /// @notice Unwrap a UD2x18 number into uint64. function unwrap(UD2x18 x) pure returns (uint64 result) { result = UD2x18.unwrap(x); } /// @notice Wraps a uint64 number into UD2x18. function wrap(uint64 x) pure returns (UD2x18 result) { result = UD2x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { UD2x18 } from "./ValueType.sol"; /// @dev Euler's number as a UD2x18 number. UD2x18 constant E = UD2x18.wrap(2_718281828459045235); /// @dev The maximum value a UD2x18 number can have. uint64 constant uMAX_UD2x18 = 18_446744073709551615; UD2x18 constant MAX_UD2x18 = UD2x18.wrap(uMAX_UD2x18); /// @dev PI as a UD2x18 number. UD2x18 constant PI = UD2x18.wrap(3_141592653589793238); /// @dev The unit number, which gives the decimal precision of UD2x18. UD2x18 constant UNIT = UD2x18.wrap(1e18); uint64 constant uUNIT = 1e18;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { UD2x18 } from "./ValueType.sol"; /// @notice Thrown when trying to cast a UD2x18 number that doesn't fit in uint40. error PRBMath_UD2x18_IntoUint40_Overflow(UD2x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "./Casting.sol" as Casting; /// @notice The unsigned 2.18-decimal fixed-point number representation, which can have up to 2 digits and up to 18 /// decimals. The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity /// type uint64. This is useful when end users want to use uint64 to save gas, e.g. with tight variable packing in contract /// storage. type UD2x18 is uint64; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { Casting.intoSD59x18, Casting.intoUD60x18, Casting.intoUint128, Casting.intoUint256, Casting.intoUint40, Casting.unwrap } for UD2x18 global;
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; /* ██████╗ ██████╗ ██████╗ ███╗ ███╗ █████╗ ████████╗██╗ ██╗ ██╔══██╗██╔══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝██║ ██║ ██████╔╝██████╔╝██████╔╝██╔████╔██║███████║ ██║ ███████║ ██╔═══╝ ██╔══██╗██╔══██╗██║╚██╔╝██║██╔══██║ ██║ ██╔══██║ ██║ ██║ ██║██████╔╝██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║ ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ██╗ ██╗██████╗ ██████╗ ██████╗ ██╗ ██╗ ██╗ █████╗ ██║ ██║██╔══██╗██╔════╝ ██╔═████╗╚██╗██╔╝███║██╔══██╗ ██║ ██║██║ ██║███████╗ ██║██╔██║ ╚███╔╝ ╚██║╚█████╔╝ ██║ ██║██║ ██║██╔═══██╗████╔╝██║ ██╔██╗ ██║██╔══██╗ ╚██████╔╝██████╔╝╚██████╔╝╚██████╔╝██╔╝ ██╗ ██║╚█████╔╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚════╝ */ import "./ud60x18/Casting.sol"; import "./ud60x18/Constants.sol"; import "./ud60x18/Conversions.sol"; import "./ud60x18/Errors.sol"; import "./ud60x18/Helpers.sol"; import "./ud60x18/Math.sol"; import "./ud60x18/ValueType.sol";
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "./Errors.sol" as CastingErrors; import { MAX_UINT128, MAX_UINT40 } from "../Common.sol"; import { uMAX_SD1x18 } from "../sd1x18/Constants.sol"; import { SD1x18 } from "../sd1x18/ValueType.sol"; import { uMAX_SD21x18 } from "../sd21x18/Constants.sol"; import { SD21x18 } from "../sd21x18/ValueType.sol"; import { uMAX_SD59x18 } from "../sd59x18/Constants.sol"; import { SD59x18 } from "../sd59x18/ValueType.sol"; import { uMAX_UD2x18 } from "../ud2x18/Constants.sol"; import { uMAX_UD21x18 } from "../ud21x18/Constants.sol"; import { UD2x18 } from "../ud2x18/ValueType.sol"; import { UD21x18 } from "../ud21x18/ValueType.sol"; import { UD60x18 } from "./ValueType.sol"; /// @notice Casts a UD60x18 number into SD1x18. /// @dev Requirements: /// - x ≤ uMAX_SD1x18 function intoSD1x18(UD60x18 x) pure returns (SD1x18 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > uint256(int256(uMAX_SD1x18))) { revert CastingErrors.PRBMath_UD60x18_IntoSD1x18_Overflow(x); } result = SD1x18.wrap(int64(uint64(xUint))); } /// @notice Casts a UD60x18 number into SD21x18. /// @dev Requirements: /// - x ≤ uMAX_SD21x18 function intoSD21x18(UD60x18 x) pure returns (SD21x18 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > uint256(int256(uMAX_SD21x18))) { revert CastingErrors.PRBMath_UD60x18_IntoSD21x18_Overflow(x); } result = SD21x18.wrap(int128(uint128(xUint))); } /// @notice Casts a UD60x18 number into UD2x18. /// @dev Requirements: /// - x ≤ uMAX_UD2x18 function intoUD2x18(UD60x18 x) pure returns (UD2x18 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > uMAX_UD2x18) { revert CastingErrors.PRBMath_UD60x18_IntoUD2x18_Overflow(x); } result = UD2x18.wrap(uint64(xUint)); } /// @notice Casts a UD60x18 number into UD21x18. /// @dev Requirements: /// - x ≤ uMAX_UD21x18 function intoUD21x18(UD60x18 x) pure returns (UD21x18 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > uMAX_UD21x18) { revert CastingErrors.PRBMath_UD60x18_IntoUD21x18_Overflow(x); } result = UD21x18.wrap(uint128(xUint)); } /// @notice Casts a UD60x18 number into SD59x18. /// @dev Requirements: /// - x ≤ uMAX_SD59x18 function intoSD59x18(UD60x18 x) pure returns (SD59x18 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > uint256(uMAX_SD59x18)) { revert CastingErrors.PRBMath_UD60x18_IntoSD59x18_Overflow(x); } result = SD59x18.wrap(int256(xUint)); } /// @notice Casts a UD60x18 number into uint128. /// @dev This is basically an alias for {unwrap}. function intoUint256(UD60x18 x) pure returns (uint256 result) { result = UD60x18.unwrap(x); } /// @notice Casts a UD60x18 number into uint128. /// @dev Requirements: /// - x ≤ MAX_UINT128 function intoUint128(UD60x18 x) pure returns (uint128 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > MAX_UINT128) { revert CastingErrors.PRBMath_UD60x18_IntoUint128_Overflow(x); } result = uint128(xUint); } /// @notice Casts a UD60x18 number into uint40. /// @dev Requirements: /// - x ≤ MAX_UINT40 function intoUint40(UD60x18 x) pure returns (uint40 result) { uint256 xUint = UD60x18.unwrap(x); if (xUint > MAX_UINT40) { revert CastingErrors.PRBMath_UD60x18_IntoUint40_Overflow(x); } result = uint40(xUint); } /// @notice Alias for {wrap}. function ud(uint256 x) pure returns (UD60x18 result) { result = UD60x18.wrap(x); } /// @notice Alias for {wrap}. function ud60x18(uint256 x) pure returns (UD60x18 result) { result = UD60x18.wrap(x); } /// @notice Unwraps a UD60x18 number into uint256. function unwrap(UD60x18 x) pure returns (uint256 result) { result = UD60x18.unwrap(x); } /// @notice Wraps a uint256 number into the UD60x18 value type. function wrap(uint256 x) pure returns (UD60x18 result) { result = UD60x18.wrap(x); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { UD60x18 } from "./ValueType.sol"; // NOTICE: the "u" prefix stands for "unwrapped". /// @dev Euler's number as a UD60x18 number. UD60x18 constant E = UD60x18.wrap(2_718281828459045235); /// @dev The maximum input permitted in {exp}. uint256 constant uEXP_MAX_INPUT = 133_084258667509499440; UD60x18 constant EXP_MAX_INPUT = UD60x18.wrap(uEXP_MAX_INPUT); /// @dev The maximum input permitted in {exp2}. uint256 constant uEXP2_MAX_INPUT = 192e18 - 1; UD60x18 constant EXP2_MAX_INPUT = UD60x18.wrap(uEXP2_MAX_INPUT); /// @dev Half the UNIT number. uint256 constant uHALF_UNIT = 0.5e18; UD60x18 constant HALF_UNIT = UD60x18.wrap(uHALF_UNIT); /// @dev $log_2(10)$ as a UD60x18 number. uint256 constant uLOG2_10 = 3_321928094887362347; UD60x18 constant LOG2_10 = UD60x18.wrap(uLOG2_10); /// @dev $log_2(e)$ as a UD60x18 number. uint256 constant uLOG2_E = 1_442695040888963407; UD60x18 constant LOG2_E = UD60x18.wrap(uLOG2_E); /// @dev The maximum value a UD60x18 number can have. uint256 constant uMAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935; UD60x18 constant MAX_UD60x18 = UD60x18.wrap(uMAX_UD60x18); /// @dev The maximum whole value a UD60x18 number can have. uint256 constant uMAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000; UD60x18 constant MAX_WHOLE_UD60x18 = UD60x18.wrap(uMAX_WHOLE_UD60x18); /// @dev PI as a UD60x18 number. UD60x18 constant PI = UD60x18.wrap(3_141592653589793238); /// @dev The unit number, which gives the decimal precision of UD60x18. uint256 constant uUNIT = 1e18; UD60x18 constant UNIT = UD60x18.wrap(uUNIT); /// @dev The unit number squared. uint256 constant uUNIT_SQUARED = 1e36; UD60x18 constant UNIT_SQUARED = UD60x18.wrap(uUNIT_SQUARED); /// @dev Zero as a UD60x18 number. UD60x18 constant ZERO = UD60x18.wrap(0);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { uMAX_UD60x18, uUNIT } from "./Constants.sol"; import { PRBMath_UD60x18_Convert_Overflow } from "./Errors.sol"; import { UD60x18 } from "./ValueType.sol"; /// @notice Converts a UD60x18 number to a simple integer by dividing it by `UNIT`. /// @dev The result is rounded toward zero. /// @param x The UD60x18 number to convert. /// @return result The same number in basic integer form. function convert(UD60x18 x) pure returns (uint256 result) { result = UD60x18.unwrap(x) / uUNIT; } /// @notice Converts a simple integer to UD60x18 by multiplying it by `UNIT`. /// /// @dev Requirements: /// - x ≤ MAX_UD60x18 / UNIT /// /// @param x The basic integer to convert. /// @return result The same number converted to UD60x18. function convert(uint256 x) pure returns (UD60x18 result) { if (x > uMAX_UD60x18 / uUNIT) { revert PRBMath_UD60x18_Convert_Overflow(x); } unchecked { result = UD60x18.wrap(x * uUNIT); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { UD60x18 } from "./ValueType.sol"; /// @notice Thrown when ceiling a number overflows UD60x18. error PRBMath_UD60x18_Ceil_Overflow(UD60x18 x); /// @notice Thrown when converting a basic integer to the fixed-point format overflows UD60x18. error PRBMath_UD60x18_Convert_Overflow(uint256 x); /// @notice Thrown when taking the natural exponent of a base greater than 133_084258667509499441. error PRBMath_UD60x18_Exp_InputTooBig(UD60x18 x); /// @notice Thrown when taking the binary exponent of a base greater than 192e18. error PRBMath_UD60x18_Exp2_InputTooBig(UD60x18 x); /// @notice Thrown when taking the geometric mean of two numbers and multiplying them overflows UD60x18. error PRBMath_UD60x18_Gm_Overflow(UD60x18 x, UD60x18 y); /// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD1x18. error PRBMath_UD60x18_IntoSD1x18_Overflow(UD60x18 x); /// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD21x18. error PRBMath_UD60x18_IntoSD21x18_Overflow(UD60x18 x); /// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in SD59x18. error PRBMath_UD60x18_IntoSD59x18_Overflow(UD60x18 x); /// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD2x18. error PRBMath_UD60x18_IntoUD2x18_Overflow(UD60x18 x); /// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in UD21x18. error PRBMath_UD60x18_IntoUD21x18_Overflow(UD60x18 x); /// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint128. error PRBMath_UD60x18_IntoUint128_Overflow(UD60x18 x); /// @notice Thrown when trying to cast a UD60x18 number that doesn't fit in uint40. error PRBMath_UD60x18_IntoUint40_Overflow(UD60x18 x); /// @notice Thrown when taking the logarithm of a number less than UNIT. error PRBMath_UD60x18_Log_InputTooSmall(UD60x18 x); /// @notice Thrown when calculating the square root overflows UD60x18. error PRBMath_UD60x18_Sqrt_Overflow(UD60x18 x);
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import { wrap } from "./Casting.sol"; import { UD60x18 } from "./ValueType.sol"; /// @notice Implements the checked addition operation (+) in the UD60x18 type. function add(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(x.unwrap() + y.unwrap()); } /// @notice Implements the AND (&) bitwise operation in the UD60x18 type. function and(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(x.unwrap() & bits); } /// @notice Implements the AND (&) bitwise operation in the UD60x18 type. function and2(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(x.unwrap() & y.unwrap()); } /// @notice Implements the equal operation (==) in the UD60x18 type. function eq(UD60x18 x, UD60x18 y) pure returns (bool result) { result = x.unwrap() == y.unwrap(); } /// @notice Implements the greater than operation (>) in the UD60x18 type. function gt(UD60x18 x, UD60x18 y) pure returns (bool result) { result = x.unwrap() > y.unwrap(); } /// @notice Implements the greater than or equal to operation (>=) in the UD60x18 type. function gte(UD60x18 x, UD60x18 y) pure returns (bool result) { result = x.unwrap() >= y.unwrap(); } /// @notice Implements a zero comparison check function in the UD60x18 type. function isZero(UD60x18 x) pure returns (bool result) { // This wouldn't work if x could be negative. result = x.unwrap() == 0; } /// @notice Implements the left shift operation (<<) in the UD60x18 type. function lshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(x.unwrap() << bits); } /// @notice Implements the lower than operation (<) in the UD60x18 type. function lt(UD60x18 x, UD60x18 y) pure returns (bool result) { result = x.unwrap() < y.unwrap(); } /// @notice Implements the lower than or equal to operation (<=) in the UD60x18 type. function lte(UD60x18 x, UD60x18 y) pure returns (bool result) { result = x.unwrap() <= y.unwrap(); } /// @notice Implements the checked modulo operation (%) in the UD60x18 type. function mod(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(x.unwrap() % y.unwrap()); } /// @notice Implements the not equal operation (!=) in the UD60x18 type. function neq(UD60x18 x, UD60x18 y) pure returns (bool result) { result = x.unwrap() != y.unwrap(); } /// @notice Implements the NOT (~) bitwise operation in the UD60x18 type. function not(UD60x18 x) pure returns (UD60x18 result) { result = wrap(~x.unwrap()); } /// @notice Implements the OR (|) bitwise operation in the UD60x18 type. function or(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(x.unwrap() | y.unwrap()); } /// @notice Implements the right shift operation (>>) in the UD60x18 type. function rshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) { result = wrap(x.unwrap() >> bits); } /// @notice Implements the checked subtraction operation (-) in the UD60x18 type. function sub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(x.unwrap() - y.unwrap()); } /// @notice Implements the unchecked addition operation (+) in the UD60x18 type. function uncheckedAdd(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { unchecked { result = wrap(x.unwrap() + y.unwrap()); } } /// @notice Implements the unchecked subtraction operation (-) in the UD60x18 type. function uncheckedSub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { unchecked { result = wrap(x.unwrap() - y.unwrap()); } } /// @notice Implements the XOR (^) bitwise operation in the UD60x18 type. function xor(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(x.unwrap() ^ y.unwrap()); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "../Common.sol" as Common; import "./Errors.sol" as Errors; import { wrap } from "./Casting.sol"; import { uEXP_MAX_INPUT, uEXP2_MAX_INPUT, uHALF_UNIT, uLOG2_10, uLOG2_E, uMAX_UD60x18, uMAX_WHOLE_UD60x18, UNIT, uUNIT, uUNIT_SQUARED, ZERO } from "./Constants.sol"; import { UD60x18 } from "./ValueType.sol"; /*////////////////////////////////////////////////////////////////////////// MATHEMATICAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @notice Calculates the arithmetic average of x and y using the following formula: /// /// $$ /// avg(x, y) = (x & y) + ((xUint ^ yUint) / 2) /// $$ /// /// In English, this is what this formula does: /// /// 1. AND x and y. /// 2. Calculate half of XOR x and y. /// 3. Add the two results together. /// /// This technique is known as SWAR, which stands for "SIMD within a register". You can read more about it here: /// https://devblogs.microsoft.com/oldnewthing/20220207-00/?p=106223 /// /// @dev Notes: /// - The result is rounded toward zero. /// /// @param x The first operand as a UD60x18 number. /// @param y The second operand as a UD60x18 number. /// @return result The arithmetic average as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function avg(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); uint256 yUint = y.unwrap(); unchecked { result = wrap((xUint & yUint) + ((xUint ^ yUint) >> 1)); } } /// @notice Yields the smallest whole number greater than or equal to x. /// /// @dev This is optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional /// counterparts. See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x ≤ MAX_WHOLE_UD60x18 /// /// @param x The UD60x18 number to ceil. /// @return result The smallest whole number greater than or equal to x, as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function ceil(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); if (xUint > uMAX_WHOLE_UD60x18) { revert Errors.PRBMath_UD60x18_Ceil_Overflow(x); } assembly ("memory-safe") { // Equivalent to `x % UNIT`. let remainder := mod(x, uUNIT) // Equivalent to `UNIT - remainder`. let delta := sub(uUNIT, remainder) // Equivalent to `x + remainder > 0 ? delta : 0`. result := add(x, mul(delta, gt(remainder, 0))) } } /// @notice Divides two UD60x18 numbers, returning a new UD60x18 number. /// /// @dev Uses {Common.mulDiv} to enable overflow-safe multiplication and division. /// /// Notes: /// - Refer to the notes in {Common.mulDiv}. /// /// Requirements: /// - Refer to the requirements in {Common.mulDiv}. /// /// @param x The numerator as a UD60x18 number. /// @param y The denominator as a UD60x18 number. /// @return result The quotient as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function div(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(Common.mulDiv(x.unwrap(), uUNIT, y.unwrap())); } /// @notice Calculates the natural exponent of x using the following formula: /// /// $$ /// e^x = 2^{x * log_2{e}} /// $$ /// /// @dev Requirements: /// - x ≤ 133_084258667509499440 /// /// @param x The exponent as a UD60x18 number. /// @return result The result as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function exp(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); // This check prevents values greater than 192e18 from being passed to {exp2}. if (xUint > uEXP_MAX_INPUT) { revert Errors.PRBMath_UD60x18_Exp_InputTooBig(x); } unchecked { // Inline the fixed-point multiplication to save gas. uint256 doubleUnitProduct = xUint * uLOG2_E; result = exp2(wrap(doubleUnitProduct / uUNIT)); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693 /// /// Requirements: /// - x < 192e18 /// - The result must fit in UD60x18. /// /// @param x The exponent as a UD60x18 number. /// @return result The result as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function exp2(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); // Numbers greater than or equal to 192e18 don't fit in the 192.64-bit format. if (xUint > uEXP2_MAX_INPUT) { revert Errors.PRBMath_UD60x18_Exp2_InputTooBig(x); } // Convert x to the 192.64-bit fixed-point format. uint256 x_192x64 = (xUint << 64) / uUNIT; // Pass x to the {Common.exp2} function, which uses the 192.64-bit fixed-point number representation. result = wrap(Common.exp2(x_192x64)); } /// @notice Yields the greatest whole number less than or equal to x. /// @dev Optimized for fractional value inputs, because every whole value has (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// @param x The UD60x18 number to floor. /// @return result The greatest whole number less than or equal to x, as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function floor(UD60x18 x) pure returns (UD60x18 result) { assembly ("memory-safe") { // Equivalent to `x % UNIT`. let remainder := mod(x, uUNIT) // Equivalent to `x - remainder > 0 ? remainder : 0)`. result := sub(x, mul(remainder, gt(remainder, 0))) } } /// @notice Yields the excess beyond the floor of x using the odd function definition. /// @dev See https://en.wikipedia.org/wiki/Fractional_part. /// @param x The UD60x18 number to get the fractional part of. /// @return result The fractional part of x as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function frac(UD60x18 x) pure returns (UD60x18 result) { assembly ("memory-safe") { result := mod(x, uUNIT) } } /// @notice Calculates the geometric mean of x and y, i.e. $\sqrt{x * y}$, rounding down. /// /// @dev Requirements: /// - x * y must fit in UD60x18. /// /// @param x The first operand as a UD60x18 number. /// @param y The second operand as a UD60x18 number. /// @return result The result as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function gm(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); uint256 yUint = y.unwrap(); if (xUint == 0 || yUint == 0) { return ZERO; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. uint256 xyUint = xUint * yUint; if (xyUint / xUint != yUint) { revert Errors.PRBMath_UD60x18_Gm_Overflow(x, y); } // We don't need to multiply the result by `UNIT` here because the x*y product picked up a factor of `UNIT` // during multiplication. See the comments in {Common.sqrt}. result = wrap(Common.sqrt(xyUint)); } } /// @notice Calculates the inverse of x. /// /// @dev Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - x must not be zero. /// /// @param x The UD60x18 number for which to calculate the inverse. /// @return result The inverse as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function inv(UD60x18 x) pure returns (UD60x18 result) { unchecked { result = wrap(uUNIT_SQUARED / x.unwrap()); } } /// @notice Calculates the natural logarithm of x using the following formula: /// /// $$ /// ln{x} = log_2{x} / log_2{e} /// $$ /// /// @dev Notes: /// - Refer to the notes in {log2}. /// - The precision isn't sufficiently fine-grained to return exactly `UNIT` when the input is `E`. /// /// Requirements: /// - Refer to the requirements in {log2}. /// /// @param x The UD60x18 number for which to calculate the natural logarithm. /// @return result The natural logarithm as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function ln(UD60x18 x) pure returns (UD60x18 result) { unchecked { // Inline the fixed-point multiplication to save gas. This is overflow-safe because the maximum value that // {log2} can return is ~196_205294292027477728. result = wrap(log2(x).unwrap() * uUNIT / uLOG2_E); } } /// @notice Calculates the common logarithm of x using the following formula: /// /// $$ /// log_{10}{x} = log_2{x} / log_2{10} /// $$ /// /// However, if x is an exact power of ten, a hard coded value is returned. /// /// @dev Notes: /// - Refer to the notes in {log2}. /// /// Requirements: /// - Refer to the requirements in {log2}. /// /// @param x The UD60x18 number for which to calculate the common logarithm. /// @return result The common logarithm as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function log10(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); if (xUint < uUNIT) { revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x); } // Note that the `mul` in this assembly block is the standard multiplication operation, not {UD60x18.mul}. // prettier-ignore assembly ("memory-safe") { switch x case 1 { result := mul(uUNIT, sub(0, 18)) } case 10 { result := mul(uUNIT, sub(1, 18)) } case 100 { result := mul(uUNIT, sub(2, 18)) } case 1000 { result := mul(uUNIT, sub(3, 18)) } case 10000 { result := mul(uUNIT, sub(4, 18)) } case 100000 { result := mul(uUNIT, sub(5, 18)) } case 1000000 { result := mul(uUNIT, sub(6, 18)) } case 10000000 { result := mul(uUNIT, sub(7, 18)) } case 100000000 { result := mul(uUNIT, sub(8, 18)) } case 1000000000 { result := mul(uUNIT, sub(9, 18)) } case 10000000000 { result := mul(uUNIT, sub(10, 18)) } case 100000000000 { result := mul(uUNIT, sub(11, 18)) } case 1000000000000 { result := mul(uUNIT, sub(12, 18)) } case 10000000000000 { result := mul(uUNIT, sub(13, 18)) } case 100000000000000 { result := mul(uUNIT, sub(14, 18)) } case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) } case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) } case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := uUNIT } case 100000000000000000000 { result := mul(uUNIT, 2) } case 1000000000000000000000 { result := mul(uUNIT, 3) } case 10000000000000000000000 { result := mul(uUNIT, 4) } case 100000000000000000000000 { result := mul(uUNIT, 5) } case 1000000000000000000000000 { result := mul(uUNIT, 6) } case 10000000000000000000000000 { result := mul(uUNIT, 7) } case 100000000000000000000000000 { result := mul(uUNIT, 8) } case 1000000000000000000000000000 { result := mul(uUNIT, 9) } case 10000000000000000000000000000 { result := mul(uUNIT, 10) } case 100000000000000000000000000000 { result := mul(uUNIT, 11) } case 1000000000000000000000000000000 { result := mul(uUNIT, 12) } case 10000000000000000000000000000000 { result := mul(uUNIT, 13) } case 100000000000000000000000000000000 { result := mul(uUNIT, 14) } case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) } case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) } case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) } case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) } case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) } case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) } case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) } case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) } case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) } case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) } case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) } case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) } case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 59) } default { result := uMAX_UD60x18 } } if (result.unwrap() == uMAX_UD60x18) { unchecked { // Inline the fixed-point division to save gas. result = wrap(log2(x).unwrap() * uUNIT / uLOG2_10); } } } /// @notice Calculates the binary logarithm of x using the iterative approximation algorithm: /// /// $$ /// log_2{x} = n + log_2{y}, \text{ where } y = x*2^{-n}, \ y \in [1, 2) /// $$ /// /// For $0 \leq x \lt 1$, the input is inverted: /// /// $$ /// log_2{x} = -log_2{\frac{1}{x}} /// $$ /// /// @dev See https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Notes: /// - Due to the lossy precision of the iterative approximation, the results are not perfectly accurate to the last decimal. /// /// Requirements: /// - x ≥ UNIT /// /// @param x The UD60x18 number for which to calculate the binary logarithm. /// @return result The binary logarithm as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function log2(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); if (xUint < uUNIT) { revert Errors.PRBMath_UD60x18_Log_InputTooSmall(x); } unchecked { // Calculate the integer part of the logarithm. uint256 n = Common.msb(xUint / uUNIT); // This is the integer part of the logarithm as a UD60x18 number. The operation can't overflow because n // n is at most 255 and UNIT is 1e18. uint256 resultUint = n * uUNIT; // Calculate $y = x * 2^{-n}$. uint256 y = xUint >> n; // If y is the unit number, the fractional part is zero. if (y == uUNIT) { return wrap(resultUint); } // Calculate the fractional part via the iterative approximation. // The `delta >>= 1` part is equivalent to `delta /= 2`, but shifting bits is more gas efficient. uint256 DOUBLE_UNIT = 2e18; for (uint256 delta = uHALF_UNIT; delta > 0; delta >>= 1) { y = (y * y) / uUNIT; // Is y^2 >= 2e18 and so in the range [2e18, 4e18)? if (y >= DOUBLE_UNIT) { // Add the 2^{-m} factor to the logarithm. resultUint += delta; // Halve y, which corresponds to z/2 in the Wikipedia article. y >>= 1; } } result = wrap(resultUint); } } /// @notice Multiplies two UD60x18 numbers together, returning a new UD60x18 number. /// /// @dev Uses {Common.mulDiv} to enable overflow-safe multiplication and division. /// /// Notes: /// - Refer to the notes in {Common.mulDiv}. /// /// Requirements: /// - Refer to the requirements in {Common.mulDiv}. /// /// @dev See the documentation in {Common.mulDiv18}. /// @param x The multiplicand as a UD60x18 number. /// @param y The multiplier as a UD60x18 number. /// @return result The product as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function mul(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { result = wrap(Common.mulDiv18(x.unwrap(), y.unwrap())); } /// @notice Raises x to the power of y. /// /// For $1 \leq x \leq \infty$, the following standard formula is used: /// /// $$ /// x^y = 2^{log_2{x} * y} /// $$ /// /// For $0 \leq x \lt 1$, since the unsigned {log2} is undefined, an equivalent formula is used: /// /// $$ /// i = \frac{1}{x} /// w = 2^{log_2{i} * y} /// x^y = \frac{1}{w} /// $$ /// /// @dev Notes: /// - Refer to the notes in {log2} and {mul}. /// - Returns `UNIT` for 0^0. /// - It may not perform well with very small values of x. Consider using SD59x18 as an alternative. /// /// Requirements: /// - Refer to the requirements in {exp2}, {log2}, and {mul}. /// /// @param x The base as a UD60x18 number. /// @param y The exponent as a UD60x18 number. /// @return result The result as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function pow(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); uint256 yUint = y.unwrap(); // If both x and y are zero, the result is `UNIT`. If just x is zero, the result is always zero. if (xUint == 0) { return yUint == 0 ? UNIT : ZERO; } // If x is `UNIT`, the result is always `UNIT`. else if (xUint == uUNIT) { return UNIT; } // If y is zero, the result is always `UNIT`. if (yUint == 0) { return UNIT; } // If y is `UNIT`, the result is always x. else if (yUint == uUNIT) { return x; } // If x is > UNIT, use the standard formula. if (xUint > uUNIT) { result = exp2(mul(log2(x), y)); } // Conversely, if x < UNIT, use the equivalent formula. else { UD60x18 i = wrap(uUNIT_SQUARED / xUint); UD60x18 w = exp2(mul(log2(i), y)); result = wrap(uUNIT_SQUARED / w.unwrap()); } } /// @notice Raises x (a UD60x18 number) to the power y (an unsigned basic integer) using the well-known /// algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring. /// /// Notes: /// - Refer to the notes in {Common.mulDiv18}. /// - Returns `UNIT` for 0^0. /// /// Requirements: /// - The result must fit in UD60x18. /// /// @param x The base as a UD60x18 number. /// @param y The exponent as a uint256. /// @return result The result as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function powu(UD60x18 x, uint256 y) pure returns (UD60x18 result) { // Calculate the first iteration of the loop in advance. uint256 xUint = x.unwrap(); uint256 resultUint = y & 1 > 0 ? xUint : uUNIT; // Equivalent to `for(y /= 2; y > 0; y /= 2)`. for (y >>= 1; y > 0; y >>= 1) { xUint = Common.mulDiv18(xUint, xUint); // Equivalent to `y % 2 == 1`. if (y & 1 > 0) { resultUint = Common.mulDiv18(resultUint, xUint); } } result = wrap(resultUint); } /// @notice Calculates the square root of x using the Babylonian method. /// /// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - x ≤ MAX_UD60x18 / UNIT /// /// @param x The UD60x18 number for which to calculate the square root. /// @return result The result as a UD60x18 number. /// @custom:smtchecker abstract-function-nondet function sqrt(UD60x18 x) pure returns (UD60x18 result) { uint256 xUint = x.unwrap(); unchecked { if (xUint > uMAX_UD60x18 / uUNIT) { revert Errors.PRBMath_UD60x18_Sqrt_Overflow(x); } // Multiply x by `UNIT` to account for the factor of `UNIT` picked up when multiplying two UD60x18 numbers. // In this case, the two numbers are both the square root. result = wrap(Common.sqrt(xUint * uUNIT)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; import "./Casting.sol" as Casting; import "./Helpers.sol" as Helpers; import "./Math.sol" as Math; /// @notice The unsigned 60.18-decimal fixed-point number representation, which can have up to 60 digits and up to 18 /// decimals. The values of this are bound by the minimum and the maximum values permitted by the Solidity type uint256. /// @dev The value type is defined here so it can be imported in all other files. type UD60x18 is uint256; /*////////////////////////////////////////////////////////////////////////// CASTING //////////////////////////////////////////////////////////////////////////*/ using { Casting.intoSD1x18, Casting.intoSD21x18, Casting.intoSD59x18, Casting.intoUD2x18, Casting.intoUD21x18, Casting.intoUint128, Casting.intoUint256, Casting.intoUint40, Casting.unwrap } for UD60x18 global; /*////////////////////////////////////////////////////////////////////////// MATHEMATICAL FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ // The global "using for" directive makes the functions in this library callable on the UD60x18 type. using { Math.avg, Math.ceil, Math.div, Math.exp, Math.exp2, Math.floor, Math.frac, Math.gm, Math.inv, Math.ln, Math.log10, Math.log2, Math.mul, Math.pow, Math.powu, Math.sqrt } for UD60x18 global; /*////////////////////////////////////////////////////////////////////////// HELPER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ // The global "using for" directive makes the functions in this library callable on the UD60x18 type. using { Helpers.add, Helpers.and, Helpers.eq, Helpers.gt, Helpers.gte, Helpers.isZero, Helpers.lshift, Helpers.lt, Helpers.lte, Helpers.mod, Helpers.neq, Helpers.not, Helpers.or, Helpers.rshift, Helpers.sub, Helpers.uncheckedAdd, Helpers.uncheckedSub, Helpers.xor } for UD60x18 global; /*////////////////////////////////////////////////////////////////////////// OPERATORS //////////////////////////////////////////////////////////////////////////*/ // The global "using for" directive makes it possible to use these operators on the UD60x18 type. using { Helpers.add as +, Helpers.and2 as &, Math.div as /, Helpers.eq as ==, Helpers.gt as >, Helpers.gte as >=, Helpers.lt as <, Helpers.lte as <=, Helpers.or as |, Helpers.mod as %, Math.mul as *, Helpers.neq as !=, Helpers.not as ~, Helpers.sub as -, Helpers.xor as ^ } for UD60x18 global;
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {IAccessControlErrors} from "../interfaces/IAccessControlErrors.sol"; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; /** * @title LimitedAccessControl * @dev This contract extends OpenZeppelin's AccessControl, disabling direct role granting and revoking. * It's designed to be used as a base contract for more specific access control implementations. * @dev This contract overrides the grantRole and revokeRole functions from AccessControl to disable direct role * granting and revoking. * @dev It doesn't override the renounceRole function, so it can be used to renounce roles for compromised accounts. */ abstract contract LimitedAccessControl is AccessControl, IAccessControlErrors { /** * @dev Overrides the grantRole function from AccessControl to disable direct role granting. * @notice This function always reverts with a DirectGrantIsDisabled error. */ function grantRole(bytes32, address) public view override { revert DirectGrantIsDisabled(msg.sender); } /** * @dev Overrides the revokeRole function from AccessControl to disable direct role revoking. * @notice This function always reverts with a DirectRevokeIsDisabled error. */ function revokeRole(bytes32, address) public view override { revert DirectRevokeIsDisabled(msg.sender); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {IAccessControlErrors} from "../interfaces/IAccessControlErrors.sol"; import {ContractSpecificRoles, IProtocolAccessManager} from "../interfaces/IProtocolAccessManager.sol"; import {ProtocolAccessManager} from "./ProtocolAccessManager.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @title ProtocolAccessManaged * @notice This contract provides role-based access control functionality for protocol contracts * by interfacing with a central ProtocolAccessManager. * * @dev This contract is meant to be inherited by other protocol contracts that need * role-based access control. It provides modifiers and utilities to check various roles. * * The contract supports several key roles through modifiers: * 1. GOVERNOR_ROLE: System-wide administrators * 2. KEEPER_ROLE: Routine maintenance operators (contract-specific) * 3. SUPER_KEEPER_ROLE: Advanced maintenance operators (global) * 4. CURATOR_ROLE: Fleet-specific managers * 5. GUARDIAN_ROLE: Emergency response operators * 6. DECAY_CONTROLLER_ROLE: Specific role for decay management * 7. ADMIRALS_QUARTERS_ROLE: Specific role for admirals quarters bundler contract * * Usage: * - Inherit from this contract to gain access to role-checking modifiers * - Use modifiers like onlyGovernor, onlyKeeper, etc. to protect functions * - Access the internal _accessManager to perform custom role checks * * Security Considerations: * - The contract validates the access manager address during construction * - All role checks are performed against the immutable access manager instance * - Contract-specific roles are generated using the contract's address to prevent conflicts */ contract ProtocolAccessManaged is IAccessControlErrors, Context { /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /// @notice Role identifier for protocol governors - highest privilege level with admin capabilities bytes32 public constant GOVERNOR_ROLE = keccak256("GOVERNOR_ROLE"); /// @notice Role identifier for super keepers who can globally perform fleet maintanence roles bytes32 public constant SUPER_KEEPER_ROLE = keccak256("SUPER_KEEPER_ROLE"); /** * @notice Role identifier for protocol guardians * @dev Guardians have emergency powers across multiple protocol components: * - Can pause/unpause Fleet operations for security * - Can pause/unpause TipJar operations * - Can cancel governance proposals on SummerGovernor even if they don't meet normal cancellation requirements * - Can cancel TipJar proposals * * The guardian role serves as an emergency backstop to protect the protocol, but with less * privilege than governors. */ bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE"); /** * @notice Role identifier for decay controller * @dev This role allows the decay controller to manage the decay of user voting power */ bytes32 public constant DECAY_CONTROLLER_ROLE = keccak256("DECAY_CONTROLLER_ROLE"); /** * @notice Role identifier for admirals quarters bundler contract * @dev This role allows Admirals Quarters to unstake and withdraw assets from fleets, on behalf of users * @dev Withdrawn tokens go straight to users wallet, lowering the risk of manipulation if the role is compromised */ bytes32 public constant ADMIRALS_QUARTERS_ROLE = keccak256("ADMIRALS_QUARTERS_ROLE"); /*////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////*/ /// @notice The ProtocolAccessManager instance used for access control ProtocolAccessManager internal immutable _accessManager; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /** * @notice Initializes the ProtocolAccessManaged contract * @param accessManager Address of the ProtocolAccessManager contract * @dev Validates the provided accessManager address and initializes the _accessManager */ constructor(address accessManager) { if (accessManager == address(0)) { revert InvalidAccessManagerAddress(address(0)); } if ( !IERC165(accessManager).supportsInterface( type(IProtocolAccessManager).interfaceId ) ) { revert InvalidAccessManagerAddress(accessManager); } _accessManager = ProtocolAccessManager(accessManager); } /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ /** * @notice Modifier to restrict access to governors only * * @dev Modifier to check that the caller has the Governor role * @custom:internal-logic * - Checks if the caller has the GOVERNOR_ROLE in the access manager * @custom:effects * - Reverts if the caller doesn't have the GOVERNOR_ROLE * - Allows the function to proceed if the caller has the role * @custom:security-considerations * - Ensures that only authorized governors can access critical functions * - Relies on the correct setup of the access manager */ modifier onlyGovernor() { if (!_accessManager.hasRole(GOVERNOR_ROLE, msg.sender)) { revert CallerIsNotGovernor(msg.sender); } _; } /** * @notice Modifier to restrict access to keepers only * @dev Modifier to check that the caller has the Keeper role * @custom:internal-logic * - Checks if the caller has either the contract-specific KEEPER_ROLE or the SUPER_KEEPER_ROLE * @custom:effects * - Reverts if the caller doesn't have either of the required roles * - Allows the function to proceed if the caller has one of the roles * @custom:security-considerations * - Ensures that only authorized keepers can access maintenance functions * - Allows for both contract-specific and super keepers * @custom:gas-considerations * - Performs two role checks, which may impact gas usage */ modifier onlyKeeper() { if ( !_accessManager.hasRole( generateRole(ContractSpecificRoles.KEEPER_ROLE, address(this)), msg.sender ) && !_accessManager.hasRole(SUPER_KEEPER_ROLE, msg.sender) ) { revert CallerIsNotKeeper(msg.sender); } _; } /** * @notice Modifier to restrict access to super keepers only * @dev Modifier to check that the caller has the Super Keeper role * @custom:internal-logic * - Checks if the caller has the SUPER_KEEPER_ROLE in the access manager * @custom:effects * - Reverts if the caller doesn't have the SUPER_KEEPER_ROLE * - Allows the function to proceed if the caller has the role * @custom:security-considerations * - Ensures that only authorized super keepers can access advanced maintenance functions * - Relies on the correct setup of the access manager */ modifier onlySuperKeeper() { if (!_accessManager.hasRole(SUPER_KEEPER_ROLE, msg.sender)) { revert CallerIsNotSuperKeeper(msg.sender); } _; } /** * @notice Modifier to restrict access to curators only * @param fleetAddress The address of the fleet to check the curator role for * @dev Checks if the caller has the contract-specific CURATOR_ROLE */ modifier onlyCurator(address fleetAddress) { if ( fleetAddress == address(0) || !_accessManager.hasRole( generateRole(ContractSpecificRoles.CURATOR_ROLE, fleetAddress), msg.sender ) ) { revert CallerIsNotCurator(msg.sender); } _; } /** * @notice Modifier to restrict access to guardians only * @dev Modifier to check that the caller has the Guardian role * @custom:internal-logic * - Checks if the caller has the GUARDIAN_ROLE in the access manager * @custom:effects * - Reverts if the caller doesn't have the GUARDIAN_ROLE * - Allows the function to proceed if the caller has the role * @custom:security-considerations * - Ensures that only authorized guardians can access emergency functions * - Relies on the correct setup of the access manager */ modifier onlyGuardian() { if (!_accessManager.hasRole(GUARDIAN_ROLE, msg.sender)) { revert CallerIsNotGuardian(msg.sender); } _; } /** * @notice Modifier to restrict access to either guardians or governors * @dev Modifier to check that the caller has either the Guardian or Governor role * @custom:internal-logic * - Checks if the caller has either the GUARDIAN_ROLE or the GOVERNOR_ROLE * @custom:effects * - Reverts if the caller doesn't have either of the required roles * - Allows the function to proceed if the caller has one of the roles * @custom:security-considerations * - Ensures that only authorized guardians or governors can access certain functions * - Provides flexibility for functions that can be accessed by either role * @custom:gas-considerations * - Performs two role checks, which may impact gas usage */ modifier onlyGuardianOrGovernor() { if ( !_accessManager.hasRole(GUARDIAN_ROLE, msg.sender) && !_accessManager.hasRole(GOVERNOR_ROLE, msg.sender) ) { revert CallerIsNotGuardianOrGovernor(msg.sender); } _; } /** * @notice Modifier to restrict access to decay controllers only */ modifier onlyDecayController() { if (!_accessManager.hasRole(DECAY_CONTROLLER_ROLE, msg.sender)) { revert CallerIsNotDecayController(msg.sender); } _; } /** * @notice Modifier to restrict access to foundation only * @dev Modifier to check that the caller has the Foundation role * @custom:security-considerations * - Ensures that only the Foundation can access vesting and related functions * - Relies on the correct setup of the access manager */ modifier onlyFoundation() { if ( !_accessManager.hasRole( _accessManager.FOUNDATION_ROLE(), msg.sender ) ) { revert CallerIsNotFoundation(msg.sender); } _; } /*////////////////////////////////////////////////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Generates a role identifier for a specific contract and role * @param roleName The name of the role * @param roleTargetContract The address of the contract the role is for * @return The generated role identifier * @dev This function is used to create unique role identifiers for contract-specific roles */ function generateRole( ContractSpecificRoles roleName, address roleTargetContract ) public pure returns (bytes32) { return keccak256(abi.encodePacked(roleName, roleTargetContract)); } /** * @notice Checks if an account has the Admirals Quarters role * @param account The address to check * @return bool True if the account has the Admirals Quarters role */ function hasAdmiralsQuartersRole( address account ) public view returns (bool) { return _accessManager.hasRole(ADMIRALS_QUARTERS_ROLE, account); } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Helper function to check if an address has the Governor role * @param account The address to check * @return bool True if the address has the Governor role */ function _isGovernor(address account) internal view returns (bool) { return _accessManager.hasRole(GOVERNOR_ROLE, account); } function _isDecayController(address account) internal view returns (bool) { return _accessManager.hasRole(DECAY_CONTROLLER_ROLE, account); } /** * @notice Helper function to check if an address has the Foundation role * @param account The address to check * @return bool True if the address has the Foundation role */ function _isFoundation(address account) internal view returns (bool) { return _accessManager.hasRole(_accessManager.FOUNDATION_ROLE(), account); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ContractSpecificRoles, IProtocolAccessManager} from "../interfaces/IProtocolAccessManager.sol"; import {LimitedAccessControl} from "./LimitedAccessControl.sol"; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; /** * @title ProtocolAccessManager * @notice This contract is the central authority for access control within the protocol. * It defines and manages various roles that govern different aspects of the system. * * @dev This contract extends LimitedAccessControl, which restricts direct role management. * Roles are typically assigned during deployment or through governance proposals. * * The contract defines four main roles: * 1. GOVERNOR_ROLE: System-wide administrators * 2. KEEPER_ROLE: Routine maintenance operators * 3. SUPER_KEEPER_ROLE: Advanced maintenance operators * 4. COMMANDER_ROLE: Managers of specific protocol components (Arks) * 5. ADMIRALS_QUARTERS_ROLE: Specific role for admirals quarters bundler contract * Role Hierarchy and Management: * - The GOVERNOR_ROLE is at the top of the hierarchy and can manage all other roles. * - Other roles cannot manage roles directly due to LimitedAccessControl restrictions. * - Role assignments are typically done through governance proposals or during initial setup. * * Usage in the System: * - Other contracts in the system inherit from ProtocolAccessManaged, which checks permissions * against this ProtocolAccessManager. * - Critical functions in various contracts are protected by role-based modifiers * (e.g., onlyGovernor, onlyKeeper, etc.) which query this contract for permissions. * * Security Considerations: * - The GOVERNOR_ROLE has significant power and should be managed carefully, potentially * through a multi-sig wallet or governance contract. * - The SUPER_KEEPER_ROLE has elevated privileges and should be assigned judiciously. * - The COMMANDER_ROLE is not directly manageable through this contract but is used * in other parts of the system for specific access control. */ contract ProtocolAccessManager is IProtocolAccessManager, LimitedAccessControl { /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /// @notice Role identifier for protocol governors - highest privilege level with admin capabilities bytes32 public constant GOVERNOR_ROLE = keccak256("GOVERNOR_ROLE"); /// @notice Role identifier for super keepers who can globally perform fleet maintanence roles bytes32 public constant SUPER_KEEPER_ROLE = keccak256("SUPER_KEEPER_ROLE"); /** * @notice Role identifier for protocol guardians * @dev Guardians have emergency powers across multiple protocol components: * - Can pause/unpause Fleet operations for security * - Can pause/unpause TipJar operations * - Can cancel governance proposals on SummerGovernor even if they don't meet normal cancellation requirements * - Can cancel TipJar proposals * * The guardian role serves as an emergency backstop to protect the protocol, but with less * privilege than governors. */ bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE"); /** * @notice Role identifier for decay controller * @dev This role allows the decay controller to manage the decay of user voting power */ bytes32 public constant DECAY_CONTROLLER_ROLE = keccak256("DECAY_CONTROLLER_ROLE"); /** * @notice Role identifier for admirals quarters bundler contract * @dev This role allows Admirals Quarters to unstake and withdraw assets from fleets, on behalf of users * @dev Withdrawn tokens go straight to users wallet, lowering the risk of manipulation if the role is compromised */ bytes32 public constant ADMIRALS_QUARTERS_ROLE = keccak256("ADMIRALS_QUARTERS_ROLE"); /// @notice Minimum allowed guardian expiration period (7 days) uint256 public constant MIN_GUARDIAN_EXPIRY = 7 days; /// @notice Maximum allowed guardian expiration period (180 days) uint256 public constant MAX_GUARDIAN_EXPIRY = 180 days; /// @notice Role identifier for the Foundation which manages vesting wallets and related operations bytes32 public constant FOUNDATION_ROLE = keccak256("FOUNDATION_ROLE"); /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /** * @notice Initializes the ProtocolAccessManager contract * @param governor Address of the initial governor * @dev Grants the governor address the GOVERNOR_ROLE */ constructor(address governor) { _grantRole(GOVERNOR_ROLE, governor); } /** * @dev Modifier to check that the caller has the Governor role */ modifier onlyGovernor() { if (!hasRole(GOVERNOR_ROLE, msg.sender)) { revert CallerIsNotGovernor(msg.sender); } _; } /*////////////////////////////////////////////////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Checks if the contract supports a given interface * @dev Overrides the supportsInterface function from AccessControl * @param interfaceId The interface identifier, as specified in ERC-165 * @return bool True if the contract supports the interface, false otherwise * * This function supports: * - IProtocolAccessManager interface * - All interfaces supported by the parent AccessControl contract */ function supportsInterface( bytes4 interfaceId ) public view override returns (bool) { return interfaceId == type(IProtocolAccessManager).interfaceId || super.supportsInterface(interfaceId); } /// @inheritdoc IProtocolAccessManager function grantGovernorRole(address account) external onlyGovernor { _grantRole(GOVERNOR_ROLE, account); } /// @inheritdoc IProtocolAccessManager function revokeGovernorRole(address account) external onlyGovernor { _revokeRole(GOVERNOR_ROLE, account); } /*////////////////////////////////////////////////////////////// EXTERNAL GOVERNOR FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IProtocolAccessManager function grantSuperKeeperRole(address account) external onlyGovernor { _grantRole(SUPER_KEEPER_ROLE, account); } /// @inheritdoc IProtocolAccessManager function grantGuardianRole(address account) external onlyGovernor { _grantRole(GUARDIAN_ROLE, account); } /// @inheritdoc IProtocolAccessManager function revokeGuardianRole(address account) external onlyGovernor { _revokeRole(GUARDIAN_ROLE, account); } /// @inheritdoc IProtocolAccessManager function revokeSuperKeeperRole(address account) external onlyGovernor { _revokeRole(SUPER_KEEPER_ROLE, account); } /// @inheritdoc IProtocolAccessManager function grantContractSpecificRole( ContractSpecificRoles roleName, address roleTargetContract, address roleOwner ) public onlyGovernor { bytes32 role = generateRole(roleName, roleTargetContract); _grantRole(role, roleOwner); } /// @inheritdoc IProtocolAccessManager function revokeContractSpecificRole( ContractSpecificRoles roleName, address roleTargetContract, address roleOwner ) public onlyGovernor { bytes32 role = generateRole(roleName, roleTargetContract); _revokeRole(role, roleOwner); } /// @inheritdoc IProtocolAccessManager function grantCuratorRole( address fleetCommanderAddress, address account ) public onlyGovernor { grantContractSpecificRole( ContractSpecificRoles.CURATOR_ROLE, fleetCommanderAddress, account ); } /// @inheritdoc IProtocolAccessManager function revokeCuratorRole( address fleetCommanderAddress, address account ) public onlyGovernor { revokeContractSpecificRole( ContractSpecificRoles.CURATOR_ROLE, fleetCommanderAddress, account ); } /// @inheritdoc IProtocolAccessManager function grantKeeperRole( address fleetCommanderAddress, address account ) public onlyGovernor { grantContractSpecificRole( ContractSpecificRoles.KEEPER_ROLE, fleetCommanderAddress, account ); } /// @inheritdoc IProtocolAccessManager function revokeKeeperRole( address fleetCommanderAddress, address account ) public onlyGovernor { revokeContractSpecificRole( ContractSpecificRoles.KEEPER_ROLE, fleetCommanderAddress, account ); } /// @inheritdoc IProtocolAccessManager function grantCommanderRole( address arkAddress, address account ) public onlyGovernor { grantContractSpecificRole( ContractSpecificRoles.COMMANDER_ROLE, arkAddress, account ); } /// @inheritdoc IProtocolAccessManager function revokeCommanderRole( address arkAddress, address account ) public onlyGovernor { revokeContractSpecificRole( ContractSpecificRoles.COMMANDER_ROLE, arkAddress, account ); } /// @inheritdoc IProtocolAccessManager function grantDecayControllerRole(address account) public onlyGovernor { _grantRole(DECAY_CONTROLLER_ROLE, account); } /// @inheritdoc IProtocolAccessManager function revokeDecayControllerRole(address account) public onlyGovernor { _revokeRole(DECAY_CONTROLLER_ROLE, account); } /*////////////////////////////////////////////////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IProtocolAccessManager function selfRevokeContractSpecificRole( ContractSpecificRoles roleName, address roleTargetContract ) public { bytes32 role = generateRole(roleName, roleTargetContract); if (!hasRole(role, msg.sender)) { revert CallerIsNotContractSpecificRole(msg.sender, role); } _revokeRole(role, msg.sender); } /// @inheritdoc IProtocolAccessManager function generateRole( ContractSpecificRoles roleName, address roleTargetContract ) public pure returns (bytes32) { return keccak256(abi.encodePacked(roleName, roleTargetContract)); } /// @inheritdoc IProtocolAccessManager function grantAdmiralsQuartersRole( address account ) external onlyRole(GOVERNOR_ROLE) { _grantRole(ADMIRALS_QUARTERS_ROLE, account); } /// @inheritdoc IProtocolAccessManager function revokeAdmiralsQuartersRole( address account ) external onlyRole(GOVERNOR_ROLE) { _revokeRole(ADMIRALS_QUARTERS_ROLE, account); } mapping(address guardian => uint256 expirationTimestamp) public guardianExpirations; /** * @notice Checks if an account is an active guardian (has role and not expired) * @param account Address to check * @return bool True if account is an active guardian */ function isActiveGuardian(address account) public view returns (bool) { return hasRole(GUARDIAN_ROLE, account) && guardianExpirations[account] > block.timestamp; } /** * @notice Sets the expiration timestamp for a guardian * @param account Guardian address * @param expiration Timestamp when guardian powers expire * @dev The expiration period (time from now until expiration) must be between MIN_GUARDIAN_EXPIRY and MAX_GUARDIAN_EXPIRY * This ensures guardians can't be immediately removed (protecting against malicious proposals) while still * allowing for their eventual phase-out (protecting against malicious guardians) */ function setGuardianExpiration( address account, uint256 expiration ) external onlyRole(GOVERNOR_ROLE) { if (!hasRole(GUARDIAN_ROLE, account)) { revert CallerIsNotGuardian(account); } uint256 expiryPeriod = expiration - block.timestamp; if ( expiryPeriod < MIN_GUARDIAN_EXPIRY || expiryPeriod > MAX_GUARDIAN_EXPIRY ) { revert InvalidGuardianExpiryPeriod( expiryPeriod, MIN_GUARDIAN_EXPIRY, MAX_GUARDIAN_EXPIRY ); } guardianExpirations[account] = expiration; emit GuardianExpirationSet(account, expiration); } /** * @inheritdoc IProtocolAccessManager */ function hasRole( bytes32 role, address account ) public view virtual override(IProtocolAccessManager, AccessControl) returns (bool) { return super.hasRole(role, account); } /// @inheritdoc IProtocolAccessManager function getGuardianExpiration( address account ) external view returns (uint256 expiration) { if (!hasRole(GUARDIAN_ROLE, account)) { revert CallerIsNotGuardian(account); } return guardianExpirations[account]; } /// @inheritdoc IProtocolAccessManager function grantFoundationRole(address account) external onlyGovernor { _grantRole(FOUNDATION_ROLE, account); } /// @inheritdoc IProtocolAccessManager function revokeFoundationRole(address account) external onlyGovernor { _revokeRole(FOUNDATION_ROLE, account); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; /** * @title IAccessControlErrors * @dev This file contains custom error definitions for access control in the system. * @notice These custom errors provide more gas-efficient and informative error handling * compared to traditional require statements with string messages. */ interface IAccessControlErrors { /** * @notice Thrown when a caller does not have the required role. */ error CallerIsNotContractSpecificRole(address caller, bytes32 role); /** * @notice Thrown when a caller is not the curator. */ error CallerIsNotCurator(address caller); /** * @notice Thrown when a caller is not the governor. */ error CallerIsNotGovernor(address caller); /** * @notice Thrown when a caller is not a keeper. */ error CallerIsNotKeeper(address caller); /** * @notice Thrown when a caller is not a super keeper. */ error CallerIsNotSuperKeeper(address caller); /** * @notice Thrown when a caller is not the commander. */ error CallerIsNotCommander(address caller); /** * @notice Thrown when a caller is neither the Raft nor the commander. */ error CallerIsNotRaftOrCommander(address caller); /** * @notice Thrown when a caller is not the Raft. */ error CallerIsNotRaft(address caller); /** * @notice Thrown when a caller is not an admin. */ error CallerIsNotAdmin(address caller); /** * @notice Thrown when a caller is not the guardian. */ error CallerIsNotGuardian(address caller); /** * @notice Thrown when a caller is not the guardian or governor. */ error CallerIsNotGuardianOrGovernor(address caller); /** * @notice Thrown when a caller is not the decay controller. */ error CallerIsNotDecayController(address caller); /** * @notice Thrown when a caller is not authorized to board. */ error CallerIsNotAuthorizedToBoard(address caller); /** * @notice Thrown when direct grant is disabled. */ error DirectGrantIsDisabled(address caller); /** * @notice Thrown when direct revoke is disabled. */ error DirectRevokeIsDisabled(address caller); /** * @notice Thrown when an invalid access manager address is provided. */ error InvalidAccessManagerAddress(address invalidAddress); /** * @notice Error thrown when a caller is not the Foundation * @param caller The address that attempted the operation */ error CallerIsNotFoundation(address caller); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; /** * @dev Dynamic roles are roles that are not hardcoded in the contract but are defined by the protocol * Members of this enum are treated as prefixes to the role generated using prefix and target contract address * e.g generateRole(ContractSpecificRoles.CURATOR_ROLE, address(this)) for FleetCommander, to generate the CURATOR_ROLE * for the curator of the FleetCommander contract */ enum ContractSpecificRoles { CURATOR_ROLE, KEEPER_ROLE, COMMANDER_ROLE } /** * @title IProtocolAccessManager * @notice Defines system roles and provides role based remote-access control for * contracts that inherit from ProtocolAccessManaged contract */ interface IProtocolAccessManager { /** * @notice Grants the Governor role to a given account * * @param account The account to which the Governor role will be granted */ function grantGovernorRole(address account) external; /** * @notice Revokes the Governor role from a given account * * @param account The account from which the Governor role will be revoked */ function revokeGovernorRole(address account) external; /** * @notice Grants the Super Keeper role to a given account * * @param account The account to which the Super Keeper role will be granted */ function grantSuperKeeperRole(address account) external; /** * @notice Revokes the Super Keeper role from a given account * * @param account The account from which the Super Keeper role will be revoked */ function revokeSuperKeeperRole(address account) external; /** * @dev Generates a unique role identifier based on the role name and target contract address * @param roleName The name of the role (from ContractSpecificRoles enum) * @param roleTargetContract The address of the contract the role is for * @return bytes32 The generated role identifier * @custom:internal-logic * - Combines the roleName and roleTargetContract using abi.encodePacked * - Applies keccak256 hash function to generate a unique bytes32 identifier * @custom:effects * - Does not modify any state, pure function * @custom:security-considerations * - Ensures unique role identifiers for different contracts * - Relies on the uniqueness of contract addresses and role names */ function generateRole( ContractSpecificRoles roleName, address roleTargetContract ) external pure returns (bytes32); /** * @notice Grants a contract specific role to a given account * @param roleName The name of the role to grant * @param roleTargetContract The address of the contract to grant the role for * @param account The account to which the role will be granted */ function grantContractSpecificRole( ContractSpecificRoles roleName, address roleTargetContract, address account ) external; /** * @notice Revokes a contract specific role from a given account * @param roleName The name of the role to revoke * @param roleTargetContract The address of the contract to revoke the role for * @param account The account from which the role will be revoked */ function revokeContractSpecificRole( ContractSpecificRoles roleName, address roleTargetContract, address account ) external; /** * @notice Grants the Curator role to a given account * @param fleetCommanderAddress The address of the fleet commander to grant the role for * @param account The account to which the role will be granted */ function grantCuratorRole( address fleetCommanderAddress, address account ) external; /** * @notice Revokes the Curator role from a given account * @param fleetCommanderAddress The address of the fleet commander to revoke the role for * @param account The account from which the role will be revoked */ function revokeCuratorRole( address fleetCommanderAddress, address account ) external; /** * @notice Grants the Keeper role to a given account * @param fleetCommanderAddress The address of the fleet commander to grant the role for * @param account The account to which the role will be granted */ function grantKeeperRole( address fleetCommanderAddress, address account ) external; /** * @notice Revokes the Keeper role from a given account * @param fleetCommanderAddress The address of the fleet commander to revoke the role for * @param account The account from which the role will be revoked */ function revokeKeeperRole( address fleetCommanderAddress, address account ) external; /** * @notice Grants the Commander role for a specific Ark * @param arkAddress Address of the Ark contract * @param account Address to grant the Commander role to */ function grantCommanderRole(address arkAddress, address account) external; /** * @notice Revokes the Commander role for a specific Ark * @param arkAddress Address of the Ark contract * @param account Address to revoke the Commander role from */ function revokeCommanderRole(address arkAddress, address account) external; /** * @notice Revokes a contract specific role from the caller * @param roleName The name of the role to revoke * @param roleTargetContract The address of the contract to revoke the role for */ function selfRevokeContractSpecificRole( ContractSpecificRoles roleName, address roleTargetContract ) external; /** * @notice Grants the Guardian role to a given account * * @param account The account to which the Guardian role will be granted */ function grantGuardianRole(address account) external; /** * @notice Revokes the Guardian role from a given account * * @param account The account from which the Guardian role will be revoked */ function revokeGuardianRole(address account) external; /** * @notice Grants the Decay Controller role to a given account * @param account The account to which the Decay Controller role will be granted */ function grantDecayControllerRole(address account) external; /** * @notice Revokes the Decay Controller role from a given account * @param account The account from which the Decay Controller role will be revoked */ function revokeDecayControllerRole(address account) external; /** * @notice Grants the ADMIRALS_QUARTERS_ROLE to an address * @param account The address to grant the role to */ function grantAdmiralsQuartersRole(address account) external; /** * @notice Revokes the ADMIRALS_QUARTERS_ROLE from an address * @param account The address to revoke the role from */ function revokeAdmiralsQuartersRole(address account) external; /*////////////////////////////////////////////////////////////// ROLE CONSTANTS //////////////////////////////////////////////////////////////*/ /// @notice Role identifier for the Governor role function GOVERNOR_ROLE() external pure returns (bytes32); /// @notice Role identifier for the Guardian role function GUARDIAN_ROLE() external pure returns (bytes32); /// @notice Role identifier for the Super Keeper role function SUPER_KEEPER_ROLE() external pure returns (bytes32); /// @notice Role identifier for the Decay Controller role function DECAY_CONTROLLER_ROLE() external pure returns (bytes32); /// @notice Role identifier for the Admirals Quarters role function ADMIRALS_QUARTERS_ROLE() external pure returns (bytes32); /// @notice Role identifier for the Foundation, responsible for managing vesting wallets and related operations function FOUNDATION_ROLE() external pure returns (bytes32); /** * @notice Checks if an account has a specific role * @param role The role identifier to check * @param account The account to check the role for * @return bool True if the account has the role, false otherwise */ function hasRole( bytes32 role, address account ) external view returns (bool); /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /** * @notice Emitted when a guardian's expiration is set * @param account The address of the guardian * @param expiration The timestamp until which the guardian powers are valid */ event GuardianExpirationSet(address indexed account, uint256 expiration); /*////////////////////////////////////////////////////////////// GUARDIAN FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Checks if an account is an active guardian (has role and not expired) * @param account Address to check * @return bool True if account is an active guardian */ function isActiveGuardian(address account) external view returns (bool); /** * @notice Sets the expiration timestamp for a guardian * @param account Guardian address * @param expiration Timestamp when guardian powers expire */ function setGuardianExpiration( address account, uint256 expiration ) external; /** * @notice Gets the expiration timestamp for a guardian * @param account Guardian address * @return uint256 Timestamp when guardian powers expire */ function guardianExpirations( address account ) external view returns (uint256); /** * @notice Gets the expiration timestamp for a guardian * @param account Guardian address * @return expiration Timestamp when guardian powers expire */ function getGuardianExpiration( address account ) external view returns (uint256 expiration); /** * @notice Emitted when an invalid guardian expiry period is set * @param expiryPeriod The expiry period that was set * @param minExpiryPeriod The minimum allowed expiry period * @param maxExpiryPeriod The maximum allowed expiry period */ error InvalidGuardianExpiryPeriod( uint256 expiryPeriod, uint256 minExpiryPeriod, uint256 maxExpiryPeriod ); /** * @notice Grants the Foundation role to a given account. The Foundation is responsible for * managing vesting wallets and related operations. * @param account The account to which the Foundation role will be granted */ function grantFoundationRole(address account) external; /** * @notice Revokes the Foundation role from a given account * @param account The account from which the Foundation role will be revoked */ function revokeFoundationRole(address account) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; library Constants { // WAD: Common unit, stands for "18 decimals" uint256 public constant WAD = 1e18; // RAY: Higher precision unit, "27 decimals" uint256 public constant RAY = 1e27; // Conversion factor from WAD to RAY uint256 public constant WAD_TO_RAY = 1e9; // Number of seconds in a day uint256 public constant SECONDS_PER_DAY = 1 days; // Number of seconds in a year (assuming 365 days) uint256 public constant SECONDS_PER_YEAR = 365 days; // Maximum value for uint256 uint256 public constant MAX_UINT256 = type(uint256).max; // AAVE V3 POOL CONFIG DATA MASK uint256 internal constant ACTIVE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF; uint256 internal constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF; uint256 internal constant PAUSED_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFF; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {StorageSlot} from "./StorageSlot.sol"; /** * @dev Variant of {ReentrancyGuard} that uses transient storage. * * NOTE: This variant only works on networks where EIP-1153 is available. */ abstract contract ReentrancyGuardTransient { using StorageSlot for *; // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant REENTRANCY_GUARD_STORAGE = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_reentrancyGuardEntered()) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true); } function _nonReentrantAfter() private { REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false); } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return REENTRANCY_GUARD_STORAGE.asBoolean().tload(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.24; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * Since version 5.1, this library also support writing and reading value types to and from transient storage. * * * Example using transient storage: * ```solidity * contract Lock { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542; * * modifier locked() { * require(!_LOCK_SLOT.asBoolean().tload()); * * _LOCK_SLOT.asBoolean().tstore(true); * _; * _LOCK_SLOT.asBoolean().tstore(false); * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot( bytes32 slot ) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot( bytes32 slot ) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot( bytes32 slot ) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot( bytes32 slot ) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot( bytes32 slot ) internal pure returns (Int256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot( bytes32 slot ) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot( string storage store ) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot( bytes32 slot ) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot( bytes storage store ) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev UDVT that represent a slot holding a address. */ type AddressSlotType is bytes32; /** * @dev Cast an arbitrary slot to a AddressSlotType. */ function asAddress(bytes32 slot) internal pure returns (AddressSlotType) { return AddressSlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a bool. */ type BooleanSlotType is bytes32; /** * @dev Cast an arbitrary slot to a BooleanSlotType. */ function asBoolean(bytes32 slot) internal pure returns (BooleanSlotType) { return BooleanSlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a bytes32. */ type Bytes32SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Bytes32SlotType. */ function asBytes32(bytes32 slot) internal pure returns (Bytes32SlotType) { return Bytes32SlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a uint256. */ type Uint256SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Uint256SlotType. */ function asUint256(bytes32 slot) internal pure returns (Uint256SlotType) { return Uint256SlotType.wrap(slot); } /** * @dev UDVT that represent a slot holding a int256. */ type Int256SlotType is bytes32; /** * @dev Cast an arbitrary slot to a Int256SlotType. */ function asInt256(bytes32 slot) internal pure returns (Int256SlotType) { return Int256SlotType.wrap(slot); } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(AddressSlotType slot) internal view returns (address value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(AddressSlotType slot, address value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(BooleanSlotType slot) internal view returns (bool value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(BooleanSlotType slot, bool value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Bytes32SlotType slot) internal view returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Bytes32SlotType slot, bytes32 value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Uint256SlotType slot) internal view returns (uint256 value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Uint256SlotType slot, uint256 value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } /** * @dev Load the value held at location `slot` in transient storage. */ function tload(Int256SlotType slot) internal view returns (int256 value) { /// @solidity memory-safe-assembly assembly { value := tload(slot) } } /** * @dev Store `value` at location `slot` in transient storage. */ function tstore(Int256SlotType slot, int256 value) internal { /// @solidity memory-safe-assembly assembly { tstore(slot, value) } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; /** * @title Percentage * @author Roberto Cano * @notice Custom type for Percentage values with associated utility functions * @dev This contract defines a custom Percentage type and overloaded operators * to perform arithmetic and comparison operations on Percentage values. */ /** * @dev Custom percentage type as uint256 * @notice This type is used to represent percentage values with high precision */ type Percentage is uint256; /** * @dev Overridden operators declaration for Percentage * @notice These operators allow for intuitive arithmetic and comparison operations * on Percentage values */ using { add as +, subtract as -, multiply as *, divide as /, lessOrEqualThan as <=, lessThan as <, greaterOrEqualThan as >=, greaterThan as >, equalTo as == } for Percentage global; /** * @dev The number of decimals used for the percentage * This constant defines the precision of the Percentage type */ uint256 constant PERCENTAGE_DECIMALS = 18; /** * @dev The factor used to scale the percentage * This constant is used to convert between human-readable percentages * and the internal representation */ uint256 constant PERCENTAGE_FACTOR = 10 ** PERCENTAGE_DECIMALS; /** * @dev Percentage of 100% with the given `PERCENTAGE_DECIMALS` * This constant represents 100% in the Percentage type */ Percentage constant PERCENTAGE_100 = Percentage.wrap(100 * PERCENTAGE_FACTOR); /** * OPERATOR FUNCTIONS */ /** * @dev Adds two Percentage values * @param a The first Percentage value * @param b The second Percentage value * @return The sum of a and b as a Percentage */ function add(Percentage a, Percentage b) pure returns (Percentage) { return Percentage.wrap(Percentage.unwrap(a) + Percentage.unwrap(b)); } /** * @dev Subtracts one Percentage value from another * @param a The Percentage value to subtract from * @param b The Percentage value to subtract * @return The difference between a and b as a Percentage */ function subtract(Percentage a, Percentage b) pure returns (Percentage) { return Percentage.wrap(Percentage.unwrap(a) - Percentage.unwrap(b)); } /** * @dev Multiplies two Percentage values * @param a The first Percentage value * @param b The second Percentage value * @return The product of a and b as a Percentage, scaled appropriately */ function multiply(Percentage a, Percentage b) pure returns (Percentage) { return Percentage.wrap( (Percentage.unwrap(a) * Percentage.unwrap(b)) / Percentage.unwrap(PERCENTAGE_100) ); } /** * @dev Divides one Percentage value by another * @param a The Percentage value to divide * @param b The Percentage value to divide by * @return The quotient of a divided by b as a Percentage, scaled appropriately */ function divide(Percentage a, Percentage b) pure returns (Percentage) { return Percentage.wrap( (Percentage.unwrap(a) * Percentage.unwrap(PERCENTAGE_100)) / Percentage.unwrap(b) ); } /** * @dev Checks if one Percentage value is less than or equal to another * @param a The first Percentage value * @param b The second Percentage value * @return True if a is less than or equal to b, false otherwise */ function lessOrEqualThan(Percentage a, Percentage b) pure returns (bool) { return Percentage.unwrap(a) <= Percentage.unwrap(b); } /** * @dev Checks if one Percentage value is less than another * @param a The first Percentage value * @param b The second Percentage value * @return True if a is less than b, false otherwise */ function lessThan(Percentage a, Percentage b) pure returns (bool) { return Percentage.unwrap(a) < Percentage.unwrap(b); } /** * @dev Checks if one Percentage value is greater than or equal to another * @param a The first Percentage value * @param b The second Percentage value * @return True if a is greater than or equal to b, false otherwise */ function greaterOrEqualThan(Percentage a, Percentage b) pure returns (bool) { return Percentage.unwrap(a) >= Percentage.unwrap(b); } /** * @dev Checks if one Percentage value is greater than another * @param a The first Percentage value * @param b The second Percentage value * @return True if a is greater than b, false otherwise */ function greaterThan(Percentage a, Percentage b) pure returns (bool) { return Percentage.unwrap(a) > Percentage.unwrap(b); } /** * @dev Checks if two Percentage values are equal * @param a The first Percentage value * @param b The second Percentage value * @return True if a is equal to b, false otherwise */ function equalTo(Percentage a, Percentage b) pure returns (bool) { return Percentage.unwrap(a) == Percentage.unwrap(b); } /** * @dev Alias for equalTo function * @param a The first Percentage value * @param b The second Percentage value * @return True if a is equal to b, false otherwise */ function equals(Percentage a, Percentage b) pure returns (bool) { return Percentage.unwrap(a) == Percentage.unwrap(b); } /** * @dev Converts a uint256 value to a Percentage * @param value The uint256 value to convert * @return The input value as a Percentage */ function toPercentage(uint256 value) pure returns (Percentage) { return Percentage.wrap(value * PERCENTAGE_FACTOR); } /** * @dev Converts a Percentage value to a uint256 * @param value The Percentage value to convert * @return The Percentage value as a uint256 */ function fromPercentage(Percentage value) pure returns (uint256) { return Percentage.unwrap(value) / PERCENTAGE_FACTOR; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; /** * @title StakingRewardsManager * @notice Contract for managing staking rewards with multiple reward tokens in the Summer protocol * @dev Implements IStakingRewards interface and inherits from ReentrancyGuardTransient and ProtocolAccessManaged * @dev Inspired by Synthetix's StakingRewards contract: * https://github.com/Synthetixio/synthetix/blob/v2.101.3/contracts/StakingRewards.sol */ import {IStakingRewardsManagerBase} from "../interfaces/IStakingRewardsManagerBase.sol"; import {ProtocolAccessManaged} from "@summerfi/access-contracts/contracts/ProtocolAccessManaged.sol"; import {ReentrancyGuardTransient} from "@summerfi/dependencies/openzeppelin-next/ReentrancyGuardTransient.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {Constants} from "@summerfi/constants/Constants.sol"; import {ERC20Wrapper} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol"; /** * @title StakingRewards * @notice Contract for managing staking rewards with multiple reward tokens in the Summer protocol * @dev Implements IStakingRewards interface and inherits from ReentrancyGuardTransient and ProtocolAccessManaged */ abstract contract StakingRewardsManagerBase is IStakingRewardsManagerBase, ReentrancyGuardTransient, ProtocolAccessManaged { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; struct RewardData { uint256 periodFinish; uint256 rewardRate; uint256 rewardsDuration; uint256 lastUpdateTime; uint256 rewardPerTokenStored; } /*////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////*/ /* @notice List of all reward tokens supported by this contract */ EnumerableSet.AddressSet internal _rewardTokensList; /* @notice The token that users stake to earn rewards */ address public immutable stakingToken; /* @notice Mapping of reward token to its reward distribution data */ mapping(address rewardToken => RewardData data) public rewardData; /* @notice Tracks the last reward per token paid to each user for each reward token */ mapping(address rewardToken => mapping(address account => uint256 rewardPerTokenPaid)) public userRewardPerTokenPaid; /* @notice Tracks the unclaimed rewards for each user for each reward token */ mapping(address rewardToken => mapping(address account => uint256 rewardAmount)) public rewards; /* @notice Total amount of tokens staked in the contract */ uint256 public totalSupply; mapping(address account => uint256 balance) internal _balances; uint256 private constant MAX_REWARD_DURATION = 360 days; // 1 year /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ modifier updateReward(address account) virtual { _updateReward(account); _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /** * @notice Initializes the StakingRewards contract * @param accessManager The address of the access manager */ constructor(address accessManager) ProtocolAccessManaged(accessManager) {} /*////////////////////////////////////////////////////////////// VIEWS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IStakingRewardsManagerBase function rewardTokens( uint256 index ) external view override returns (address) { if (index >= _rewardTokensList.length()) revert IndexOutOfBounds(); address rewardTokenAddress = _rewardTokensList.at(index); return rewardTokenAddress; } /// @inheritdoc IStakingRewardsManagerBase function rewardTokensLength() external view returns (uint256) { return _rewardTokensList.length(); } /// @inheritdoc IStakingRewardsManagerBase function balanceOf(address account) public view virtual returns (uint256) { return _balances[account]; } /// @inheritdoc IStakingRewardsManagerBase function lastTimeRewardApplicable( address rewardToken ) public view returns (uint256) { return block.timestamp < rewardData[rewardToken].periodFinish ? block.timestamp : rewardData[rewardToken].periodFinish; } /// @inheritdoc IStakingRewardsManagerBase function rewardPerToken(address rewardToken) public view returns (uint256) { if (totalSupply == 0) { return rewardData[rewardToken].rewardPerTokenStored; } return rewardData[rewardToken].rewardPerTokenStored + ((lastTimeRewardApplicable(rewardToken) - rewardData[rewardToken].lastUpdateTime) * rewardData[rewardToken].rewardRate) / totalSupply; } /// @inheritdoc IStakingRewardsManagerBase function earned( address account, address rewardToken ) public view virtual returns (uint256) { return _earned(account, rewardToken); } /// @inheritdoc IStakingRewardsManagerBase function getRewardForDuration( address rewardToken ) external view returns (uint256) { RewardData storage data = rewardData[rewardToken]; if (block.timestamp >= data.periodFinish) { return (data.rewardRate * data.rewardsDuration) / Constants.WAD; } // For active periods, calculate remaining rewards plus any new rewards uint256 remaining = data.periodFinish - block.timestamp; return (data.rewardRate * remaining) / Constants.WAD; } /// @inheritdoc IStakingRewardsManagerBase function isRewardToken(address rewardToken) external view returns (bool) { return _isRewardToken(rewardToken); } /*////////////////////////////////////////////////////////////// MUTATIVE FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IStakingRewardsManagerBase function stake(uint256 amount) external virtual updateReward(_msgSender()) { _stake(_msgSender(), _msgSender(), amount); } /// @inheritdoc IStakingRewardsManagerBase function unstake( uint256 amount ) external virtual updateReward(_msgSender()) { _unstake(_msgSender(), _msgSender(), amount); } /// @inheritdoc IStakingRewardsManagerBase function getReward() public virtual nonReentrant { uint256 rewardTokenCount = _rewardTokensList.length(); for (uint256 i = 0; i < rewardTokenCount; i++) { address rewardTokenAddress = _rewardTokensList.at(i); _getReward(_msgSender(), rewardTokenAddress); } } /// @inheritdoc IStakingRewardsManagerBase function getReward(address rewardToken) public virtual nonReentrant { if (!_isRewardToken(rewardToken)) revert RewardTokenDoesNotExist(); _getReward(_msgSender(), rewardToken); } /// @inheritdoc IStakingRewardsManagerBase function exit() external virtual { getReward(); _unstake(_msgSender(), _msgSender(), _balances[_msgSender()]); } /// @notice Claims rewards for a specific account /// @param account The address to claim rewards for function getRewardFor(address account) public virtual nonReentrant { uint256 rewardTokenCount = _rewardTokensList.length(); for (uint256 i = 0; i < rewardTokenCount; i++) { address rewardTokenAddress = _rewardTokensList.at(i); _getReward(account, rewardTokenAddress); } } /// @notice Claims rewards for a specific account and specific reward token /// @param account The address to claim rewards for /// @param rewardToken The address of the reward token to claim function getRewardFor( address account, address rewardToken ) public virtual nonReentrant { if (!_isRewardToken(rewardToken)) revert RewardTokenDoesNotExist(); _getReward(account, rewardToken); } /*////////////////////////////////////////////////////////////// RESTRICTED FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IStakingRewardsManagerBase function notifyRewardAmount( address rewardToken, uint256 reward, uint256 newRewardsDuration ) external virtual onlyGovernor updateReward(address(0)) { _notifyRewardAmount(rewardToken, reward, newRewardsDuration); } /// @inheritdoc IStakingRewardsManagerBase function setRewardsDuration( address rewardToken, uint256 _rewardsDuration ) external onlyGovernor { if (!_isRewardToken(rewardToken)) { revert RewardTokenDoesNotExist(); } if (_rewardsDuration == 0) { revert RewardsDurationCannotBeZero(); } if (_rewardsDuration > MAX_REWARD_DURATION) { revert RewardsDurationTooLong(); } RewardData storage data = rewardData[rewardToken]; if (block.timestamp <= data.periodFinish) { revert RewardPeriodNotComplete(); } data.rewardsDuration = _rewardsDuration; emit RewardsDurationUpdated(address(rewardToken), _rewardsDuration); } /// @notice Removes a reward token from the list of reward tokens /// @param rewardToken The address of the reward token to remove function removeRewardToken(address rewardToken) external onlyGovernor { if (!_isRewardToken(rewardToken)) { revert RewardTokenDoesNotExist(); } if (block.timestamp <= rewardData[rewardToken].periodFinish) { revert RewardPeriodNotComplete(); } // Check if all tokens have been claimed, allowing a small dust balance uint256 remainingBalance = IERC20(rewardToken).balanceOf(address(this)); uint256 dustThreshold; try IERC20Metadata(address(rewardToken)).decimals() returns ( uint8 decimals ) { // For tokens with 4 or fewer decimals, use a minimum threshold of 1 // For tokens with more decimals, use 0.01% of 1 token if (decimals <= 4) { dustThreshold = 1; } else { dustThreshold = 10 ** (decimals - 4); // 0.01% of 1 token } } catch { dustThreshold = 1e14; // Default threshold for tokens without decimals } if (remainingBalance > dustThreshold) { revert RewardTokenStillHasBalance(remainingBalance); } // Remove the token from the rewardTokens map bool success = _rewardTokensList.remove(address(rewardToken)); if (!success) revert RewardTokenDoesNotExist(); emit RewardTokenRemoved(address(rewardToken)); } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ function _isRewardToken(address rewardToken) internal view returns (bool) { return _rewardTokensList.contains(rewardToken); } function _stake( address staker, address receiver, uint256 amount ) internal virtual { if (receiver == address(0)) revert CannotStakeToZeroAddress(); if (amount == 0) revert CannotStakeZero(); if (address(stakingToken) == address(0)) { revert StakingTokenNotInitialized(); } totalSupply += amount; _balances[receiver] += amount; IERC20(stakingToken).safeTransferFrom(staker, address(this), amount); emit Staked(staker, receiver, amount); } function _unstake( address staker, address receiver, uint256 amount ) internal virtual { if (amount == 0) revert CannotUnstakeZero(); totalSupply -= amount; _balances[staker] -= amount; IERC20(stakingToken).safeTransfer(receiver, amount); emit Unstaked(staker, receiver, amount); } /* * @notice Internal function to calculate earned rewards for an account * @param account The address to calculate earnings for * @param rewardToken The reward token to calculate earnings for * @return The amount of reward tokens earned */ function _earned( address account, address rewardToken ) internal view returns (uint256) { return (_balances[account] * (rewardPerToken(rewardToken) - userRewardPerTokenPaid[rewardToken][account])) / Constants.WAD + rewards[rewardToken][account]; } function _updateReward(address account) internal { uint256 rewardTokenCount = _rewardTokensList.length(); for (uint256 i = 0; i < rewardTokenCount; i++) { address rewardTokenAddress = _rewardTokensList.at(i); RewardData storage rewardTokenData = rewardData[rewardTokenAddress]; rewardTokenData.rewardPerTokenStored = rewardPerToken( rewardTokenAddress ); rewardTokenData.lastUpdateTime = lastTimeRewardApplicable( rewardTokenAddress ); if (account != address(0)) { rewards[rewardTokenAddress][account] = earned( account, rewardTokenAddress ); userRewardPerTokenPaid[rewardTokenAddress][ account ] = rewardTokenData.rewardPerTokenStored; } } } /** * @notice Internal function to claim rewards for an account for a specific token * @param account The address to claim rewards for * @param rewardTokenAddress The address of the reward token to claim * @dev rewards go straight to the user's wallet */ function _getReward( address account, address rewardTokenAddress ) internal virtual updateReward(account) { uint256 reward = rewards[rewardTokenAddress][account]; if (reward > 0) { rewards[rewardTokenAddress][account] = 0; IERC20(rewardTokenAddress).safeTransfer(account, reward); emit RewardPaid(account, rewardTokenAddress, reward); } } /** * @dev Internal implementation of notifyRewardAmount * @param rewardToken The token to distribute as rewards * @param reward The amount of reward tokens to distribute * @param newRewardsDuration The duration for new reward tokens (only used for first time) */ function _notifyRewardAmount( address rewardToken, uint256 reward, uint256 newRewardsDuration ) internal { RewardData storage rewardTokenData = rewardData[rewardToken]; if (newRewardsDuration == 0) { revert RewardsDurationCannotBeZero(); } if (newRewardsDuration > MAX_REWARD_DURATION) { revert RewardsDurationTooLong(); } // For existing reward tokens, check if current period is complete if (_isRewardToken(rewardToken)) { if (newRewardsDuration != rewardTokenData.rewardsDuration) { revert CannotChangeRewardsDuration(); } } else { // First time setup for new reward token bool success = _rewardTokensList.add(rewardToken); if (!success) revert RewardTokenAlreadyExists(); rewardTokenData.rewardsDuration = newRewardsDuration; emit RewardTokenAdded(rewardToken, rewardTokenData.rewardsDuration); } // Transfer exact amount needed for new rewards IERC20(rewardToken).safeTransferFrom(msg.sender, address(this), reward); // Calculate new reward rate rewardTokenData.rewardRate = (reward * Constants.WAD) / rewardTokenData.rewardsDuration; rewardTokenData.lastUpdateTime = block.timestamp; rewardTokenData.periodFinish = block.timestamp + rewardTokenData.rewardsDuration; emit RewardAdded(address(rewardToken), reward); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IStakingRewardsManagerBaseErrors} from "./IStakingRewardsManagerBaseErrors.sol"; /* @title IStakingRewardsManagerBase * @notice Interface for the Staking Rewards Manager contract * @dev Manages staking and distribution of multiple reward tokens */ interface IStakingRewardsManagerBase is IStakingRewardsManagerBaseErrors { // Views /* @notice Get the total amount of staked tokens * @return The total supply of staked tokens */ function totalSupply() external view returns (uint256); /* @notice Get the staked balance of a specific account * @param account The address of the account to check * @return The staked balance of the account */ function balanceOf(address account) external view returns (uint256); /* @notice Get the last time the reward was applicable for a specific reward token * @param rewardToken The address of the reward token * @return The timestamp of the last applicable reward time */ function lastTimeRewardApplicable( address rewardToken ) external view returns (uint256); /* @notice Get the reward per token for a specific reward token * @param rewardToken The address of the reward token * @return The reward amount per staked token (WAD-scaled) * @dev Returns a WAD-scaled value (1e18) to maintain precision in calculations * @dev This value represents: (rewardRate * timeElapsed * WAD) / totalSupply */ function rewardPerToken( address rewardToken ) external view returns (uint256); /* @notice Calculate the earned reward for an account and a specific reward token * @param account The address of the account * @param rewardToken The address of the reward token * @return The amount of reward tokens earned (not WAD-scaled) * @dev Calculated as: (balance * (rewardPerToken - userRewardPerTokenPaid)) / WAD + rewards */ function earned( address account, address rewardToken ) external view returns (uint256); /* @notice Get the reward for the entire duration for a specific reward token * @param rewardToken The address of the reward token * @return The total reward amount for the duration (not WAD-scaled) * @dev Calculated as: (rewardRate * rewardsDuration) / WAD */ function getRewardForDuration( address rewardToken ) external view returns (uint256); /* @notice Get the address of the staking token * @return The address of the staking token */ function stakingToken() external view returns (address); /* @notice Get the reward token at a specific index * @param index The index of the reward token * @return The address of the reward token * @dev Reverts with IndexOutOfBounds if index >= rewardTokensLength() */ function rewardTokens(uint256 index) external view returns (address); /* @notice Get the total number of reward tokens * @return The length of the reward tokens list */ function rewardTokensLength() external view returns (uint256); /* @notice Check if a token is in the list of reward tokens * @param rewardToken The address to check * @return bool True if the token is a reward token, false otherwise */ function isRewardToken(address rewardToken) external view returns (bool); // Mutative functions /* @notice Stake tokens for an account * @param amount The amount of tokens to stake */ function stake(uint256 amount) external; /* @notice Stake tokens for an account on behalf of another account * @param receiver The address of the account to stake for * @param amount The amount of tokens to stake */ function stakeOnBehalfOf(address receiver, uint256 amount) external; /* @notice Unstake staked tokens on behalf of another account * @param owner The address of the account to unstake from * @param amount The amount of tokens to unstake * @param claimRewards Whether to claim rewards before unstaking */ function unstakeAndWithdrawOnBehalfOf( address owner, uint256 amount, bool claimRewards ) external; /* @notice Unstake staked tokens * @param amount The amount of tokens to unstake */ function unstake(uint256 amount) external; /* @notice Claim accumulated rewards for all reward tokens */ function getReward() external; /* @notice Claim accumulated rewards for a specific reward token * @param rewardToken The address of the reward token to claim */ function getReward(address rewardToken) external; /* @notice Withdraw all staked tokens and claim rewards */ function exit() external; // Admin functions /* @notice Notify the contract about new reward amount * @param rewardToken The address of the reward token * @param reward The amount of new reward (not WAD-scaled) * @param newRewardsDuration The duration for rewards distribution (only used when adding a new reward token) * @dev Internally sets rewardRate as (reward * WAD) / duration to maintain precision */ function notifyRewardAmount( address rewardToken, uint256 reward, uint256 newRewardsDuration ) external; /* @notice Set the duration for rewards distribution * @param rewardToken The address of the reward token * @param _rewardsDuration The new duration for rewards */ function setRewardsDuration( address rewardToken, uint256 _rewardsDuration ) external; /* @notice Removes a reward token from the list of reward tokens * @dev Can only be called by governor * @dev Can only be called after reward period is complete * @dev Can only be called if remaining balance is below dust threshold * @param rewardToken The address of the reward token to remove */ function removeRewardToken(address rewardToken) external; // Events /* @notice Emitted when a new reward is added * @param rewardToken The address of the reward token * @param reward The amount of reward added */ event RewardAdded(address indexed rewardToken, uint256 reward); /* @notice Emitted when tokens are staked * @param staker The address that provided the tokens for staking * @param receiver The address whose staking balance was updated * @param amount The amount of tokens added to the staking position */ event Staked( address indexed staker, address indexed receiver, uint256 amount ); /* @notice Emitted when tokens are unstaked * @param staker The address whose tokens were unstaked * @param receiver The address receiving the unstaked tokens * @param amount The amount of tokens unstaked */ event Unstaked( address indexed staker, address indexed receiver, uint256 amount ); /* @notice Emitted when tokens are withdrawn * @param user The address of the user that withdrew * @param amount The amount of tokens withdrawn */ event Withdrawn(address indexed user, uint256 amount); /* @notice Emitted when rewards are paid out * @param user The address of the user receiving the reward * @param rewardToken The address of the reward token * @param reward The amount of reward paid */ event RewardPaid( address indexed user, address indexed rewardToken, uint256 reward ); /* @notice Emitted when the rewards duration is updated * @param rewardToken The address of the reward token * @param newDuration The new duration for rewards */ event RewardsDurationUpdated( address indexed rewardToken, uint256 newDuration ); /* @notice Emitted when a new reward token is added * @param rewardToken The address of the new reward token * @param rewardsDuration The duration for the new reward token */ event RewardTokenAdded(address rewardToken, uint256 rewardsDuration); /* @notice Emitted when a reward token is removed * @param rewardToken The address of the reward token */ event RewardTokenRemoved(address rewardToken); /* @notice Claims rewards for a specific account * @param account The address to claim rewards for */ function getRewardFor(address account) external; /* @notice Claims rewards for a specific account and specific reward token * @param account The address to claim rewards for * @param rewardToken The address of the reward token to claim */ function getRewardFor(address account, address rewardToken) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; /* @title IStakingRewardsManagerBaseErrors * @notice Interface defining custom errors for the Staking Rewards Manager */ interface IStakingRewardsManagerBaseErrors { /* @notice Thrown when attempting to stake zero tokens */ error CannotStakeZero(); /* @notice Thrown when attempting to withdraw zero tokens */ error CannotWithdrawZero(); /* @notice Thrown when the provided reward amount is too high */ error ProvidedRewardTooHigh(); /* @notice Thrown when trying to set rewards before the current period is complete */ error RewardPeriodNotComplete(); /* @notice Thrown when there are no reward tokens set */ error NoRewardTokens(); /* @notice Thrown when trying to add a reward token that already exists */ error RewardTokenAlreadyExists(); /* @notice Thrown when setting an invalid rewards duration */ error InvalidRewardsDuration(); /* @notice Thrown when trying to interact with a reward token that hasn't been initialized */ error RewardTokenNotInitialized(); /* @notice Thrown when the reward amount is invalid for the given duration * @param rewardToken The address of the reward token * @param rewardsDuration The duration for which the reward is invalid */ error InvalidRewardAmount(address rewardToken, uint256 rewardsDuration); /* @notice Thrown when trying to interact with the staking token before it's initialized */ error StakingTokenNotInitialized(); /* @notice Thrown when trying to remove a reward token that doesn't exist */ error RewardTokenDoesNotExist(); /* @notice Thrown when trying to change the rewards duration of a reward token */ error CannotChangeRewardsDuration(); /* @notice Thrown when a reward token still has a balance */ error RewardTokenStillHasBalance(uint256 balance); /* @notice Thrown when the index is out of bounds */ error IndexOutOfBounds(); /* @notice Thrown when the rewards duration is zero */ error RewardsDurationCannotBeZero(); /* @notice Thrown when attempting to unstake zero tokens */ error CannotUnstakeZero(); /* @notice Thrown when the rewards duration is too long */ error RewardsDurationTooLong(); /** * @notice Thrown when the receiver is the zero address */ error CannotStakeToZeroAddress(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {VotingDecayMath} from "./VotingDecayMath.sol"; import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol"; /* * @title VotingDecayLibrary * @notice A library for managing voting power decay in governance systems * @dev Utilizes VotingDecayMath for decay calculations */ library VotingDecayLibrary { using VotingDecayMath for uint256; using Checkpoints for Checkpoints.Trace224; /* @notice Constant representing 1 in the system's fixed-point arithmetic (18 decimal places) */ uint256 private constant WAD = 1e18; /* @notice Number of seconds in a year, used for annualized rate calculations */ uint256 private constant SECONDS_PER_YEAR = 365 days; /* @notice Enumeration of supported decay function types */ enum DecayFunction { Linear, Exponential } /* * @notice Structure to store decay information for an account * @param decayFactor The current decay factor of the account's voting power * @param lastUpdateTimestamp The timestamp of the last update to the account's decay info */ struct DecayInfo { uint256 decayFactor; uint40 lastUpdateTimestamp; } struct DecayState { mapping(address => DecayInfo) decayInfoByAccount; uint40 decayFreeWindow; uint256 decayRatePerSecond; DecayFunction decayFunction; uint40 originTimestamp; mapping(address => Checkpoints.Trace224) decayFactorCheckpoints; } /** * @notice Thrown when the decay type is invalid */ error InvalidDecayType(); // Events event DecayRateSet(uint256 newRate); event DecayFreeWindowSet(uint40 newWindow); event DecayFunctionSet(uint8 newFunction); event AccountInitialized(address account); event DecayUpdated(address account, uint256 newDecayFactor); event DecayReset(address account); // Errors error AccountNotInitialized(); error InvalidDecayRate(); /** * @notice Maximum allowed depth for delegation chains to prevent recursion attacks * @dev When this depth is exceeded, voting power decays to 0 to maintain EIP-5805 invariants * Example chain at max depth (2): * User A -> delegates to B -> delegates to C (ok) * User A -> delegates to B -> delegates to C -> delegates to D (returns 0) */ uint256 public constant MAX_DELEGATION_DEPTH = 2; /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ function initializeAccount( DecayState storage self, address accountAddress ) internal { _initializeAccount(self, accountAddress); } /** * @notice Gets the current decay factor for an account, considering delegation * @param self The DecayState storage * @param accountAddress The address of the account to check * @param getDelegateTo Function to retrieve delegation information * @return The current decay factor for the account */ function getDecayFactor( DecayState storage self, address accountAddress, function(address) view returns (address) getDelegateTo ) internal view returns (uint256) { return _getDecayFactorWithDepth( self, accountAddress, 0, accountAddress, getDelegateTo ); } /** * @notice Retrieves the decay info for a specific account * @param self The DecayState storage * @param accountAddress The address of the account * @return DecayInfo struct containing the account's decay information */ function getDecayInfo( DecayState storage self, address accountAddress ) internal view returns (DecayInfo memory) { return self.decayInfoByAccount[accountAddress]; } /** * @notice Sets the decay rate per second * @param self The DecayState storage * @param newRatePerSecond The new decay rate to set */ function setDecayRatePerSecond( DecayState storage self, uint256 newRatePerSecond ) internal { if (!isValidDecayRate(newRatePerSecond)) { revert InvalidDecayRate(); } self.decayRatePerSecond = newRatePerSecond; emit DecayRateSet(newRatePerSecond); } /** * @notice Sets the decay-free window period during which no decay occurs * @param self The DecayState storage * @param newWindow The new decay-free window duration in seconds */ function setDecayFreeWindow( DecayState storage self, uint40 newWindow ) internal { self.decayFreeWindow = newWindow; emit DecayFreeWindowSet(newWindow); } /** * @notice Sets the decay function type (Linear or Exponential) * @param self The DecayState storage * @param newFunction The new decay function to use */ function setDecayFunction( DecayState storage self, DecayFunction newFunction ) internal { self.decayFunction = newFunction; emit DecayFunctionSet(uint8(newFunction)); } /** * @notice Updates the decay factor for an account and creates a checkpoint * @param self The DecayState storage * @param accountAddress The address of the account to update * @param getDelegateTo Function to retrieve delegation information */ function updateDecayFactor( DecayState storage self, address accountAddress, function(address) view returns (address) getDelegateTo ) internal { _initializeAccount(self, accountAddress); DecayInfo storage account = self.decayInfoByAccount[accountAddress]; uint256 decayPeriod = block.timestamp - account.lastUpdateTimestamp; uint256 newDecayFactor = account.decayFactor; if (decayPeriod > self.decayFreeWindow) { newDecayFactor = getDecayFactor( self, accountAddress, getDelegateTo ); } // Create checkpoint with current timestamp and new decay factor self.decayFactorCheckpoints[accountAddress].push( uint32(block.timestamp), uint224(newDecayFactor) ); account.decayFactor = newDecayFactor; account.lastUpdateTimestamp = uint40(block.timestamp); emit DecayUpdated(accountAddress, newDecayFactor); } /** * @notice Resets the decay factor for an account back to WAD (1e18) * @param self The DecayState storage * @param accountAddress The address of the account to reset */ function resetDecay( DecayState storage self, address accountAddress ) internal { _initializeAccount(self, accountAddress); DecayInfo storage account = self.decayInfoByAccount[accountAddress]; account.lastUpdateTimestamp = uint40(block.timestamp); account.decayFactor = WAD; emit DecayReset(accountAddress); } /** * @notice Initializes the decay state with initial parameters * @param self The DecayState storage * @param decayFreeWindow_ The initial decay-free window duration in seconds * @param decayRatePerSecond_ The initial decay rate per second * @param decayFunction_ The initial decay function type */ function initialize( DecayState storage self, uint40 decayFreeWindow_, uint256 decayRatePerSecond_, DecayFunction decayFunction_ ) internal { self.decayFreeWindow = decayFreeWindow_; self.decayRatePerSecond = decayRatePerSecond_; self.decayFunction = decayFunction_; self.originTimestamp = uint40(block.timestamp); } /** * @notice Calculates the current voting power by applying decay to the original value * @param self The DecayState storage * @param accountAddress The address of the account * @param originalValue The original voting power value before decay * @param getDelegateTo Function to retrieve delegation information * @return The current voting power after applying decay */ function getVotingPower( DecayState storage self, address accountAddress, uint256 originalValue, function(address) view returns (address) getDelegateTo ) internal view returns (uint256) { uint256 decayFactor = getDecayFactor( self, accountAddress, getDelegateTo ); return applyDecay(originalValue, decayFactor); } /* * @notice Applies the decay to the original voting power value * @param originalValue The original voting power value * @param retentionFactor The current retention factor * @return The decayed voting power value */ function applyDecay( uint256 originalValue, uint256 retentionFactor ) internal pure returns (uint256) { return VotingDecayMath.mulDiv(originalValue, retentionFactor, WAD); } /* * @notice Checks if a given decay rate is valid * @param rate The decay rate to check * @return A boolean indicating whether the rate is valid (less than or equal to WAD) */ function isValidDecayRate(uint256 rate) internal pure returns (bool) { return rate <= WAD; } /*////////////////////////////////////////////////////////////// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Initializes decay information for an account if it hasn't been initialized before * @dev Sets initial decay factor to WAD (1e18) and lastUpdateTimestamp to current block timestamp * @param self The DecayState storage * @param accountAddress The address of the account to initialize * @custom:emits AccountInitialized when a new account is initialized */ function _initializeAccount( DecayState storage self, address accountAddress ) private { if (self.decayInfoByAccount[accountAddress].lastUpdateTimestamp == 0) { self.decayInfoByAccount[accountAddress] = DecayInfo({ decayFactor: WAD, lastUpdateTimestamp: uint40(block.timestamp) }); self.decayFactorCheckpoints[accountAddress].push( uint32(block.timestamp), uint224(WAD) ); emit AccountInitialized(accountAddress); } } /** * @notice Recursively calculates decay factor considering delegation depth * @dev Returns 0 in the following cases: * 1. When accountAddress is address(0) * 2. When delegation depth exceeds MAX_DELEGATION_DEPTH * 3. When the account or its delegate has no decay info * @param self The DecayState storage * @param accountAddress Current account being checked * @param depth Current delegation depth * @param originalAccount The initial account that started the calculation * @param getDelegateTo Function to retrieve delegation information * @return The calculated decay factor, or 0 if max depth exceeded */ function _getDecayFactorWithDepth( DecayState storage self, address accountAddress, uint256 depth, address originalAccount, function(address) view returns (address) getDelegateTo ) private view returns (uint256) { if (accountAddress == address(0)) { return 0; } if (depth >= MAX_DELEGATION_DEPTH) { return 0; } address delegateTo = getDelegateTo(accountAddress); // Detect cycles - if we're back to original account and within depth limit, // return the original account's decay factor if (delegateTo == originalAccount && depth > 0) { return _calculateAccountDecayFactor(self, originalAccount); } // Has Delegate + Delegate has Decay Info if ( delegateTo != address(0) && delegateTo != accountAddress && hasDecayInfo(self, delegateTo) ) { return _getDecayFactorWithDepth( self, delegateTo, depth + 1, originalAccount, getDelegateTo ); } // For uninitialized accounts, calculate decay from contract origin if (!hasDecayInfo(self, accountAddress)) { return _calculateDecayFactor( WAD, block.timestamp - self.originTimestamp, self.decayRatePerSecond, self.decayFreeWindow, self.decayFunction ); } // No Delegate + Has Decay Info return _calculateAccountDecayFactor(self, accountAddress); } /** * @notice Calculates the current decay factor for an account * @param self The DecayState storage * @param accountAddress The address of the account * @return The calculated decay factor */ function _calculateAccountDecayFactor( DecayState storage self, address accountAddress ) private view returns (uint256) { DecayInfo storage account = self.decayInfoByAccount[accountAddress]; uint256 decayPeriod = block.timestamp - account.lastUpdateTimestamp; return _calculateDecayFactor( account.decayFactor, decayPeriod, self.decayRatePerSecond, self.decayFreeWindow, self.decayFunction ); } /** * @notice Checks if an account has decay information initialized * @param self The DecayState storage * @param accountAddress The address to check * @return bool True if the account has decay info, false otherwise */ function hasDecayInfo( DecayState storage self, address accountAddress ) internal view returns (bool) { return self.decayInfoByAccount[accountAddress].lastUpdateTimestamp != 0; } /* * @notice Calculates the new decay factor based on elapsed time and decay parameters * @param currentDecayFactor The current retention factor * @param elapsedSeconds The number of seconds elapsed since the last update * @param decayRatePerSecond The decay rate per second * @param decayFreeWindow The duration (in seconds) during which no decay occurs * @param decayFunction The type of decay function to use (Linear or Exponential) * @return The newly calculated retention factor */ function _calculateDecayFactor( uint256 currentDecayFactor, uint256 elapsedSeconds, uint256 decayRatePerSecond, uint256 decayFreeWindow, DecayFunction decayFunction ) private pure returns (uint256) { if (elapsedSeconds <= decayFreeWindow) return currentDecayFactor; uint256 decayTime = elapsedSeconds - decayFreeWindow; if (decayFunction == DecayFunction.Linear) { return currentDecayFactor.linearDecay(decayRatePerSecond, decayTime); } else if (decayFunction == DecayFunction.Exponential) { return currentDecayFactor.exponentialDecay( decayRatePerSecond, decayTime ); } else { revert InvalidDecayType(); } } /** * @notice Gets the length of a delegation chain for an account * @dev Counts the number of steps in the delegation chain until: * 1. A self-delegation is found * 2. An address(0) delegation is found * 3. MAX_DELEGATION_DEPTH is reached * @param self The DecayState storage * @param accountAddress The address to check delegation chain for * @param getDelegateTo Function to retrieve delegation information * @return uint256 The length of the delegation chain */ function getDelegationChainLength( DecayState storage self, address accountAddress, function(address) view returns (address) getDelegateTo ) internal view returns (uint256) { return _getDelegationChainLengthWithDepth( self, accountAddress, 0, accountAddress, getDelegateTo ); } /** * @notice Internal recursive function to calculate delegation chain length * @param self The DecayState storage * @param accountAddress Current account being checked * @param depth Current depth in the delegation chain * @param originalAccount The initial account that started the calculation * @param getDelegateTo Function to retrieve delegation information * @return uint256 The length of the delegation chain */ function _getDelegationChainLengthWithDepth( DecayState storage self, address accountAddress, uint256 depth, address originalAccount, function(address) view returns (address) getDelegateTo ) private view returns (uint256) { if (accountAddress == address(0)) { return 0; } address delegateTo = getDelegateTo(accountAddress); // Detect cycles by checking if we're back to the original account if (delegateTo == originalAccount) { return depth; } // Self-delegation or no delegation if (delegateTo == address(0) || delegateTo == accountAddress) { return depth; } // Continue counting if there's a valid delegation return _getDelegationChainLengthWithDepth( self, delegateTo, depth + 1, originalAccount, getDelegateTo ); } /** * @notice Gets the historical decay factor for an account at a specific timestamp * @param self The DecayState storage * @param accountAddress The address to check * @param timestamp The timestamp to check at * @return The decay factor at that timestamp */ function getHistoricalDecayFactor( DecayState storage self, address accountAddress, uint256 timestamp ) internal view returns (uint256) { if (timestamp < self.originTimestamp) { return 0; } uint224 checkpointValue = self .decayFactorCheckpoints[accountAddress] .upperLookup(uint32(timestamp)); // No checkpoint found - calculate from origin if (checkpointValue == 0) { uint256 decayPeriod = timestamp - self.originTimestamp; if (decayPeriod <= self.decayFreeWindow) { return WAD; } // Apply decay from origin with WAD as base if (self.decayFunction == DecayFunction.Linear) { return VotingDecayMath.linearDecay( WAD, self.decayRatePerSecond, decayPeriod - self.decayFreeWindow ); } else if (self.decayFunction == DecayFunction.Exponential) { return VotingDecayMath.exponentialDecay( WAD, self.decayRatePerSecond, decayPeriod - self.decayFreeWindow ); } else { revert InvalidDecayType(); } } // Checkpoint found - use it as base else { return uint256(checkpointValue); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {UD60x18, ud, unwrap} from "@prb/math/src/UD60x18.sol"; /* * @title VotingDecayMath * @notice A library for advanced mathematical operations used in voting decay calculations * @dev Utilizes PRBMath for precise calculations */ library VotingDecayMath { /* @notice Constant representing the scale factor for calculations (18 decimal places) */ uint256 private constant WAD = 1e18; /** * @dev Multiplies two numbers and divides the result by a third number, using PRBMath for precision. * @param a The first number to multiply * @param b The second number to multiply * @param denominator The number to divide by * @return The result of (a * b) / denominator, using PRBMath's UD60x18 type */ function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256) { UD60x18 result = ud(a).mul(ud(b)).div(ud(denominator)); return unwrap(result); } /** * @dev Calculates the exponential decay using PRBMath's UD60x18 type. * @param initialValue The initial value * @param decayRatePerSecond The decay rate per second * @param decayTimeInSeconds The time elapsed in seconds * @return The decayed value */ function exponentialDecay( uint256 initialValue, uint256 decayRatePerSecond, uint256 decayTimeInSeconds ) internal pure returns (uint256) { // Early returns if (decayTimeInSeconds == 0 || decayRatePerSecond == 0) { return initialValue; } if (decayRatePerSecond >= WAD) { return 0; } if (initialValue == 0) { return 0; } // Safe conversion to UD60x18 UD60x18 retentionRatePerSecond; unchecked { // WAD - decayRatePerSecond is safe because we checked decayRatePerSecond < WAD retentionRatePerSecond = ud(WAD - decayRatePerSecond); } // If retention rate is 0 or time is too large, return 0 if ( unwrap(retentionRatePerSecond) == 0 || decayTimeInSeconds > type(uint32).max ) { return 0; } UD60x18 retentionFactor = retentionRatePerSecond.powu( decayTimeInSeconds ); // If retention factor became 0 during calculation if (unwrap(retentionFactor) == 0) { return 0; } UD60x18 result = ud(initialValue).mul(retentionFactor); return unwrap(result.gt(ud(0)) ? result.div(ud(WAD)) : ud(0)); } /** * @dev Calculates the linear decay. * @param initialValue The initial value * @param decayRatePerSecond The decay rate per second * @param decayTimeInSeconds The time elapsed in seconds * @return The decayed value */ function linearDecay( uint256 initialValue, uint256 decayRatePerSecond, uint256 decayTimeInSeconds ) internal pure returns (uint256) { // Early returns if (decayTimeInSeconds == 0 || decayRatePerSecond == 0) { return initialValue; } if (decayRatePerSecond >= WAD) { return 0; } if (initialValue == 0) { return 0; } // Check for overflow in multiplication if ( decayRatePerSecond > 0 && decayTimeInSeconds > WAD / decayRatePerSecond ) { return 0; } uint256 totalDecayFactor; unchecked { // Safe because of the check above totalDecayFactor = decayRatePerSecond * decayTimeInSeconds; } // Check if total decay exceeds 100% if (totalDecayFactor >= WAD) { return 0; } uint256 retentionFactor; unchecked { // Safe because we checked totalDecayFactor < WAD retentionFactor = WAD - totalDecayFactor; } // Final multiplication and division return (initialValue * retentionFactor) / WAD; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ISummerToken} from "../interfaces/ISummerToken.sol"; import {IDecayController} from "../interfaces/IDecayController.sol"; import {IGovernanceRewardsManager} from "../interfaces/IGovernanceRewardsManager.sol"; /** * @title DecayController * @notice Manages decay updates for governance rewards and voting power */ abstract contract DecayController is IDecayController { ISummerToken private immutable _summerToken; IGovernanceRewardsManager private _rewardsManager; constructor(address summerToken_) { if (summerToken_ == address(0)) { revert DecayController__ZeroAddress(); } _summerToken = ISummerToken(summerToken_); } /** * @notice Internal function to set the rewards manager address * @dev This function must be called by the inheriting contract after deployment * to avoid circular dependencies, as both DecayController and GovernanceRewardsManager * need to reference each other. The pattern used is: * 1. Deploy DecayController (with rewardsManager unset) * 2. Deploy GovernanceRewardsManager (which can reference DecayController) * 3. Call this function to set rewardsManager address * @param rewardsManager_ Address of the GovernanceRewardsManager contract */ function _setRewardsManager(address rewardsManager_) internal { if (rewardsManager_ == address(0)) { revert DecayController__ZeroAddress(); } if (address(_rewardsManager) != address(0)) { revert DecayController__RewardsManagerAlreadySet(); } _rewardsManager = IGovernanceRewardsManager(rewardsManager_); } function _updateDecay(address account) internal { if (account != address(0)) { _summerToken.updateDecayFactor(account); _rewardsManager.updateSmoothedDecayFactor(account); } } /** * @notice Modifier to update decay before executing a function * @param account Address to update decay for * @dev Updates both base decay and smoothed decay factors */ modifier updateDecay(address account) { _updateDecay(account); _; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ReentrancyGuardTransient} from "@summerfi/dependencies/openzeppelin-next/ReentrancyGuardTransient.sol"; import {StakingRewardsManagerBase} from "@summerfi/rewards-contracts/contracts/StakingRewardsManagerBase.sol"; import {IStakingRewardsManagerBase} from "@summerfi/rewards-contracts/interfaces/IStakingRewardsManagerBase.sol"; import {ProtocolAccessManaged} from "@summerfi/access-contracts/contracts/ProtocolAccessManaged.sol"; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IGovernanceRewardsManager} from "../interfaces/IGovernanceRewardsManager.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {Constants} from "@summerfi/constants/Constants.sol"; import {ISummerToken} from "../interfaces/ISummerToken.sol"; import {DecayController} from "./DecayController.sol"; import {WrappedStakingToken} from "./WrappedStakingToken.sol"; /** * @title GovernanceRewardsManager * @notice Contract for managing governance rewards with multiple reward tokens in the Summer protocol * @dev Implements IGovernanceRewardsManager interface and inherits from StakingRewardsManagerBase */ contract GovernanceRewardsManager is IGovernanceRewardsManager, StakingRewardsManagerBase, DecayController { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; /*////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////*/ /** * @notice Smoothing factor base for decay calculations (1e18) */ uint256 public constant DECAY_SMOOTHING_FACTOR_BASE = Constants.WAD; /** * @notice Smoothing factor for decay calculations (0.2 * 1e18) */ uint256 public constant DECAY_SMOOTHING_FACTOR = DECAY_SMOOTHING_FACTOR_BASE / 5; // represents 0.2 /** * @notice Mapping of user addresses to their smoothed decay factors */ mapping(address account => uint256 smoothedDecayFactor) public userSmoothedDecayFactor; /** * @notice Wrapped version of staking token for rewards */ address public immutable wrappedStakingToken; /** * @notice Updates rewards for an account before executing a function * @param account The address of the account to update rewards for * @dev Updates reward data for all reward tokens */ modifier updateReward(address account) override { _updateReward(account); _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /** * @notice Initializes the contract with the protocol access manager * @param _stakingToken Address of the staking token * @param accessManager Address of the ProtocolAccessManager contract */ constructor( address _stakingToken, address accessManager ) StakingRewardsManagerBase(accessManager) DecayController(_stakingToken) { stakingToken = _stakingToken; wrappedStakingToken = address(new WrappedStakingToken(stakingToken)); _setRewardsManager(address(this)); } /*////////////////////////////////////////////////////////////// MUTATIVE FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IStakingRewardsManagerBase function stakeOnBehalfOf(address, uint256) external pure override { revert StakeOnBehalfOfNotSupported(); } /** * @notice No op function to satisfy interface requirements. Emits an event but performs no state changes. * @dev This operation is not supported and will only emit an event */ function unstakeAndWithdrawOnBehalfOf( address, uint256, bool ) external pure override { revert UnstakeOnBehalfOfNotSupported(); } /// @inheritdoc IStakingRewardsManagerBase function stake( uint256 amount ) external override(IStakingRewardsManagerBase, StakingRewardsManagerBase) updateDecay(_msgSender()) updateReward(_msgSender()) { _stake(_msgSender(), _msgSender(), amount); } /// @inheritdoc IStakingRewardsManagerBase function unstake( uint256 amount ) external override(IStakingRewardsManagerBase, StakingRewardsManagerBase) updateReward(_msgSender()) updateDecay(_msgSender()) { _unstake(_msgSender(), _msgSender(), amount); } /** * @notice External function to update smoothed decay factor * @param account The address to update * @dev Only callable by the SummerToken or this contract */ function updateSmoothedDecayFactor( address account ) external onlyDecayController { _updateSmoothedDecayFactor(account); } /*////////////////////////////////////////////////////////////// VIEWS //////////////////////////////////////////////////////////////*/ /// @inheritdoc IGovernanceRewardsManager function balanceOf( address account ) public view override(IGovernanceRewardsManager, StakingRewardsManagerBase) returns (uint256) { return super.balanceOf(account); } /// @inheritdoc IStakingRewardsManagerBase function earned( address account, address rewardToken ) public view override(IStakingRewardsManagerBase, StakingRewardsManagerBase) returns (uint256) { uint256 rawEarned = _earned(account, rewardToken); uint256 latestSmoothedDecayFactor = _calculateSmoothedDecayFactor( account ); return (rawEarned * latestSmoothedDecayFactor) / Constants.WAD; } /// @inheritdoc IGovernanceRewardsManager function calculateSmoothedDecayFactor( address account ) external view returns (uint256) { return _calculateSmoothedDecayFactor(account); } /*////////////////////////////////////////////////////////////// INTERNAL //////////////////////////////////////////////////////////////*/ /** * @notice Updates the smoothed decay factor for a given account * @param account The address of the account to update */ function _updateSmoothedDecayFactor(address account) internal { if (account != address(0)) { userSmoothedDecayFactor[account] = _calculateSmoothedDecayFactor( account ); } } /** * @notice Calculates the smoothed decay factor for a given account without modifying state * @param account The address of the account to calculate for * @return The calculated smoothed decay factor */ function _calculateSmoothedDecayFactor( address account ) internal view returns (uint256) { uint256 currentDecayFactor = ISummerToken(address(stakingToken)) .getDecayFactor(account); // If there's no existing smoothed factor, return the current factor if (userSmoothedDecayFactor[account] == 0) { return currentDecayFactor; } // Apply exponential moving average (EMA) smoothing // Formula: EMA = α * currentValue + (1 - α) * previousEMA // Where α is the smoothing factor (DECAY_SMOOTHING_FACTOR / DECAY_SMOOTHING_FACTOR_BASE) return ((currentDecayFactor * DECAY_SMOOTHING_FACTOR) + (userSmoothedDecayFactor[account] * (DECAY_SMOOTHING_FACTOR_BASE - DECAY_SMOOTHING_FACTOR))) / DECAY_SMOOTHING_FACTOR_BASE; } /** * @notice Override _stake to wrap tokens * @param from The address to transfer tokens from * @param receiver The address to receive tokens * @param amount The amount of tokens to transfer */ function _stake( address from, address receiver, uint256 amount ) internal override { if (receiver == address(0)) revert CannotStakeToZeroAddress(); if (amount == 0) revert CannotStakeZero(); if (address(stakingToken) == address(0)) { revert StakingTokenNotInitialized(); } address delegate = ISummerToken(address(stakingToken)).delegates( receiver ); if (delegate == address(0)) { revert NotDelegated(); } totalSupply += amount; _balances[receiver] += amount; IERC20(stakingToken).safeTransferFrom(from, address(this), amount); IERC20(stakingToken).forceApprove(wrappedStakingToken, amount); WrappedStakingToken(wrappedStakingToken).depositFor( address(this), amount ); emit Staked(from, receiver, amount); } /** * @notice Override _unstake to unwrap tokens * @param from The address to transfer tokens from * @param receiver The address to receive tokens * @param amount The amount of tokens to transfer */ function _unstake( address from, address receiver, uint256 amount ) internal virtual override { if (amount == 0) revert CannotUnstakeZero(); address delegate = ISummerToken(address(stakingToken)).delegates( receiver ); if (delegate == address(0)) { revert NotDelegated(); } totalSupply -= amount; _balances[from] -= amount; // Send direct to receiver to avoid any interim state where voting units might be incorrectly calculated WrappedStakingToken(wrappedStakingToken).withdrawTo(receiver, amount); emit Unstaked(from, receiver, amount); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ISummerGovernor} from "../interfaces/ISummerGovernor.sol"; import {ISummerToken} from "../interfaces/ISummerToken.sol"; import {IProtocolAccessManager} from "@summerfi/access-contracts/interfaces/IProtocolAccessManager.sol"; import {IGovernor} from "@openzeppelin/contracts/governance/IGovernor.sol"; import {IERC6372} from "@openzeppelin/contracts/interfaces/IERC6372.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {MessagingFee, OApp, Origin} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; import {Governor, GovernorVotes, IVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; import {GovernorCountingSimple} from "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol"; import {GovernorSettings} from "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol"; import {GovernorTimelockControl, TimelockController} from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; import {GovernorVotesQuorumFraction} from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {DecayController} from "./DecayController.sol"; /* * @title SummerGovernor * @dev This contract implements the governance mechanism for the Summer protocol. * It extends various OpenZeppelin governance modules and includes custom functionality * such as whitelisting and voting decay. */ contract SummerGovernor is ISummerGovernor, GovernorTimelockControl, GovernorSettings, GovernorCountingSimple, GovernorVotesQuorumFraction, DecayController, OApp { /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ uint256 public constant MIN_PROPOSAL_THRESHOLD = 1000e18; // 1,000 Tokens uint256 public constant MAX_PROPOSAL_THRESHOLD = 100000e18; // 100,000 Tokens uint32 public immutable hubChainId; /*////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////*/ address public immutable accessManager; /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ /** * @dev Modifier to restrict certain functions to only be called on the hub chain. * This ensures that governance actions like proposing, executing, and canceling can only happen * on the designated hub chain, while other chains act as spokes that can only receive and execute * proposals that have been approved on the hub. */ modifier onlyHubChain() { if (block.chainid != hubChainId) { revert SummerGovernorNotHubChain(block.chainid, hubChainId); } _; } /** * @dev Modifier to restrict certain functions to only be called on satellite chains (non-hub chains). * This ensures that certain operations can only happen on spoke chains that receive and execute * proposals from the hub chain. */ modifier onlySatelliteChain() { if (block.chainid == hubChainId) { revert SummerGovernorCannotExecuteOnHubChain(); } _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( GovernorParams memory params ) Governor("SummerGovernor") GovernorSettings( params.votingDelay, params.votingPeriod, params.proposalThreshold ) GovernorVotes(params.token) GovernorVotesQuorumFraction(params.quorumFraction) GovernorTimelockControl(params.timelock) OApp(params.endpoint, address(params.timelock)) DecayController(address(params.token)) Ownable(address(params.initialOwner)) { accessManager = params.accessManager; _setRewardsManager( address(ISummerToken(params.token).rewardsManager()) ); _validateProposalThreshold(params.proposalThreshold); hubChainId = params.hubChainId; } /*////////////////////////////////////////////////////////////// CROSS-CHAIN MESSAGING FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISummerGovernor function sendProposalToTargetChain( uint32 _dstEid, address[] memory _dstTargets, uint256[] memory _dstValues, bytes[] memory _dstCalldatas, bytes32 _dstDescriptionHash, bytes calldata _options ) external onlyGovernance onlyHubChain { _sendProposalToTargetChain( _dstEid, _dstTargets, _dstValues, _dstCalldatas, _dstDescriptionHash, _options ); } /** * @dev Internal function to send a proposal to another chain. * @param _dstEid The destination endpoint ID. * @param _dstTargets The target addresses for the proposal. * @param _dstValues The values for the proposal. * @param _dstCalldatas The calldata for the proposal. * @param _dstDescriptionHash The description hash for the proposal. * @param _options Message execution options. */ function _sendProposalToTargetChain( uint32 _dstEid, address[] memory _dstTargets, uint256[] memory _dstValues, bytes[] memory _dstCalldatas, bytes32 _dstDescriptionHash, bytes calldata _options ) internal { uint256 dstProposalId = hashProposal( _dstTargets, _dstValues, _dstCalldatas, _dstDescriptionHash ); bytes memory payload = abi.encode( dstProposalId, _dstTargets, _dstValues, _dstCalldatas, _dstDescriptionHash ); MessagingFee memory fee = _quote(_dstEid, payload, _options, false); _lzSend( _dstEid, payload, _options, MessagingFee(fee.nativeFee + 100000, 0), payable(address(this)) ); emit ProposalSentCrossChain(dstProposalId, _dstEid); } // Receive function to allow the contract to receive ETH from LayerZero receive() external payable override { // Allow deposits from LayerZero endpoint or timelock if (msg.sender != address(endpoint) && msg.sender != timelock()) { revert GovernorDisabledDeposit(); } } /** * @dev Internal function to queue a proposal received from another chain. * @param proposalId The ID of the proposal to queue. * @param targets The target addresses for the proposal. * @param values The values for the proposal. * @param calldatas The calldata for the proposal. * @param descriptionHash The description hash for the proposal. */ function _queueCrossChainProposal( uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal onlySatelliteChain returns (uint256) { uint48 eta = _queueOperations( proposalId, targets, values, calldatas, descriptionHash ); emit ProposalQueued(proposalId, uint256(eta)); return proposalId; } /** * @dev Receives a proposal from another chain and executes it. * @param _origin The origin of the message. * @param // _guid The global packet identifier. * @param payload The encoded message payload. * @param // executor_ The Executor address. * @param // _extraData Arbitrary data appended by the Executor. */ function _lzReceive( Origin calldata _origin, bytes32, bytes calldata payload, address, bytes calldata ) internal override { ( uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) = abi.decode( payload, (uint256, address[], uint256[], bytes[], bytes32) ); emit ProposalReceivedCrossChain(proposalId, _origin.srcEid); _queueCrossChainProposal( proposalId, targets, values, calldatas, descriptionHash ); } /*////////////////////////////////////////////////////////////// GOVERNANCE FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISummerGovernor function castVote( uint256 proposalId, uint8 support ) public override(ISummerGovernor, Governor) updateDecay(_msgSender()) onlyHubChain returns (uint256) { address voter = _msgSender(); return _castVote(proposalId, voter, support, ""); } /// @inheritdoc ISummerGovernor function propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description ) public override(Governor, ISummerGovernor) updateDecay(_msgSender()) onlyHubChain returns (uint256) { address proposer = _msgSender(); uint256 proposerVotes = getVotes(proposer, block.timestamp - 1); if ( proposerVotes < proposalThreshold() && !isActiveGuardian(proposer) ) { revert SummerGovernorProposerBelowThresholdAndNotGuardian( proposer, proposerVotes, proposalThreshold() ); } return _propose(targets, values, calldatas, description, proposer); } /// @inheritdoc ISummerGovernor function execute( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public payable override(Governor, ISummerGovernor) updateDecay(_msgSender()) onlyHubChain returns (uint256) { return super.execute(targets, values, calldatas, descriptionHash); } /// @inheritdoc ISummerGovernor function cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) public override(Governor, ISummerGovernor) updateDecay(_msgSender()) onlyHubChain returns (uint256) { uint256 proposalId = hashProposal( targets, values, calldatas, descriptionHash ); address proposer = proposalProposer(proposalId); if ( _msgSender() != proposer && getVotes(proposer, block.timestamp - 1) >= proposalThreshold() && !isActiveGuardian(_msgSender()) ) { revert SummerGovernorUnauthorizedCancellation( _msgSender(), proposer, getVotes(proposer, block.timestamp - 1), proposalThreshold() ); } return _cancel(targets, values, calldatas, descriptionHash); } /*////////////////////////////////////////////////////////////// WHITELIST MANAGEMENT FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc ISummerGovernor function isActiveGuardian(address account) public view returns (bool) { return IProtocolAccessManager(accessManager).isActiveGuardian(account); } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @dev Internal function to pay the native fee for LayerZero messaging. * @param _nativeFee The amount of native tokens to pay for the fee. * @return nativeFee The amount of native tokens to pay for the fee. */ function _payNative( uint256 _nativeFee ) internal view override returns (uint256 nativeFee) { if (address(this).balance < _nativeFee) { revert NotEnoughNative(address(this).balance); } return _nativeFee; } /** * @dev Internal function to validate the proposal threshold * @param thresholdToValidate The threshold value to validate against min/max bounds */ function _validateProposalThreshold( uint256 thresholdToValidate ) internal pure { if ( thresholdToValidate < MIN_PROPOSAL_THRESHOLD || thresholdToValidate > MAX_PROPOSAL_THRESHOLD ) { revert SummerGovernorInvalidProposalThreshold( thresholdToValidate, MIN_PROPOSAL_THRESHOLD, MAX_PROPOSAL_THRESHOLD ); } } /*////////////////////////////////////////////////////////////// OVERRIDE FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @dev Override of GovernorCountingSimple._countVote to use decayed voting power */ function _countVote( uint256 proposalId, address account, uint8 support, uint256, bytes memory params ) internal virtual override(Governor, GovernorCountingSimple) returns (uint256) { uint256 decayedWeight = ISummerToken(address(token())).getVotes( account ); return super._countVote( proposalId, account, support, decayedWeight, params ); } /* * @dev Overrides the internal cancellation function to use the timelocked version * @param targets The addresses of the contracts to call * @param values The ETH values to send with the calls * @param calldatas The call data for each contract call * @param descriptionHash The hash of the proposal description * @return The ID of the cancelled proposal */ function _cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal override(Governor, GovernorTimelockControl) returns (uint256) { return GovernorTimelockControl._cancel( targets, values, calldatas, descriptionHash ); } /** * @dev Returns the address of the executor (timelock). * @return The address of the executor. */ function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { return GovernorTimelockControl._executor(); } /** * @dev Returns the current proposal threshold. * @return The current proposal threshold. */ function proposalThreshold() public view override(Governor, GovernorSettings, IGovernor) returns (uint256) { return GovernorSettings.proposalThreshold(); } /** * @dev Returns the state of a proposal. * @param proposalId The ID of the proposal. * @return The current state of the proposal. */ function state( uint256 proposalId ) public view override(Governor, GovernorTimelockControl, IGovernor) returns (ProposalState) { return GovernorTimelockControl.state(proposalId); } /** * @dev Checks if the contract supports an interface. * @param interfaceId The interface identifier. * @return True if the contract supports the interface, false otherwise. */ function supportsInterface( bytes4 interfaceId ) public view override(Governor, IERC165) returns (bool) { return super.supportsInterface(interfaceId); } /** * @dev Internal function to execute proposal operations. * @param proposalId The ID of the proposal. * @param targets The addresses of the contracts to call. * @param values The ETH values to send with the calls. * @param calldatas The call data for each contract call. * @param descriptionHash The hash of the proposal description. */ function _executeOperations( uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal override(Governor, GovernorTimelockControl) { GovernorTimelockControl._executeOperations( proposalId, targets, values, calldatas, descriptionHash ); } /** * @dev Internal function to queue proposal operations. * @param proposalId The ID of the proposal. * @param targets The addresses of the contracts to call. * @param values The ETH values to send with the calls. * @param calldatas The call data for each contract call. * @param descriptionHash The hash of the proposal description. * @return The timestamp at which the proposal will be executable. */ function _queueOperations( uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) internal override(Governor, GovernorTimelockControl) returns (uint48) { return GovernorTimelockControl._queueOperations( proposalId, targets, values, calldatas, descriptionHash ); } /** * @dev Checks if a proposal needs queuing. * @param proposalId The ID of the proposal. * @return True if the proposal needs queuing, false otherwise. */ function proposalNeedsQueuing( uint256 proposalId ) public view override(Governor, GovernorTimelockControl, IGovernor) returns (bool) { return super.proposalNeedsQueuing(proposalId); } /** * @dev Returns the clock mode used by the contract. * @return A string describing the clock mode. */ function CLOCK_MODE() public view override(Governor, GovernorVotes, IERC6372) returns (string memory) { return super.CLOCK_MODE(); } /** * @dev Returns the current clock value used by the contract. * @return The current clock value. */ function clock() public view override(Governor, GovernorVotes, IERC6372) returns (uint48) { return super.clock(); } /** * @dev Calculates the quorum for a specific timepoint. * @param timepoint The timepoint to calculate the quorum for. * @return The quorum value. */ function quorum( uint256 timepoint ) public view override(Governor, GovernorVotesQuorumFraction, IGovernor) returns (uint256) { return super.quorum(timepoint); } /** * @dev Returns the current voting delay. * @return The current voting delay */ function votingDelay() public view override(Governor, GovernorSettings, IGovernor) returns (uint256) { return super.votingDelay(); } /** * @dev Returns the current voting period. * @return The current voting period */ function votingPeriod() public view override(Governor, GovernorSettings, IGovernor) returns (uint256) { return super.votingPeriod(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol"; import {IProtocolAccessManager} from "@summerfi/access-contracts/interfaces/IProtocolAccessManager.sol"; contract SummerTimelockController is TimelockController { IProtocolAccessManager public immutable accessManager; // Add mapping to track guardian expiry operations mapping(bytes32 => bool) private _guardianExpiryOperations; constructor( uint256 minDelay, address[] memory proposers, address[] memory executors, address admin, address _accessManager ) TimelockController(minDelay, proposers, executors, admin) { accessManager = IProtocolAccessManager(_accessManager); } /** * @dev Override of the TimelockController's cancel function to support guardian-based cancellation * with special handling for guardian expiry proposals. * * Cancellation rules: * 1. Guardian expiry proposals can ONLY be cancelled by governors * 2. Governors with cancel role can cancel any other proposal * 3. Active guardians with cancel role can cancel any non-expiry proposal * * @param id The identifier of the operation to cancel */ function cancel(bytes32 id) public virtual override { if (_isGuardianExpiryProposal(id)) { require( accessManager.hasRole( accessManager.GOVERNOR_ROLE(), msg.sender ), "Only governors can cancel guardian expiry proposals" ); super.cancel(id); return; } if (_isGovernorWithCancelRole(msg.sender)) { super.cancel(id); return; } if (!_isActiveGuardianWithCancelRole(msg.sender)) { revert TimelockUnauthorizedCaller(msg.sender); } super.cancel(id); } /** * @dev Checks if the provided operation data corresponds to a guardian expiry proposal. * * Guardian expiry proposals are special operations that set the expiration time for guardians. * These proposals have additional restrictions on who can cancel them to prevent guardians * from blocking their own expiry mechanisms. * * @return bool True if the operation is a guardian expiry proposal */ function _isGuardianExpiryProposal( bytes32 id ) internal view returns (bool) { return _guardianExpiryOperations[id]; } /** * @dev Checks if an account is a governor with cancellation privileges. * * To have governor cancellation rights, an account must: * 1. Have the CANCELLER_ROLE in this contract * 2. Have the GOVERNOR_ROLE in the access manager * * Governors with cancel rights can cancel any proposal except guardian expiry proposals, * which have special handling. * * @param account The address to check * @return bool True if the account is a governor with cancel rights */ function _isGovernorWithCancelRole( address account ) internal view returns (bool) { return hasRole(CANCELLER_ROLE, account) && accessManager.hasRole(accessManager.GOVERNOR_ROLE(), account); } /** * @dev Checks if an account is an active guardian with cancellation privileges. * * To have guardian cancellation rights, an account must: * 1. Have the CANCELLER_ROLE in this contract * 2. Be an active guardian in the access manager * * Active guardians with cancel rights can cancel any proposal EXCEPT guardian * expiry proposals, which can only be cancelled by governors. * * @param account The address to check * @return bool True if the account is an active guardian with cancel rights */ function _isActiveGuardianWithCancelRole( address account ) internal view returns (bool) { return hasRole(CANCELLER_ROLE, account) && accessManager.isActiveGuardian(account); } // Override schedule to track guardian expiry operations function schedule( address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt, uint256 delay ) public virtual override onlyRole(PROPOSER_ROLE) { bytes32 id = hashOperation(target, value, data, predecessor, salt); // Check if this is a guardian expiry operation before scheduling if ( bytes4(data) == IProtocolAccessManager.setGuardianExpiration.selector ) { _guardianExpiryOperations[id] = true; } super.schedule(target, value, data, predecessor, salt, delay); } // Override scheduleBatch to track guardian expiry operations function scheduleBatch( address[] calldata targets, uint256[] calldata values, bytes[] calldata payloads, bytes32 predecessor, bytes32 salt, uint256 delay ) public virtual override onlyRole(PROPOSER_ROLE) { bytes32 id = hashOperationBatch( targets, values, payloads, predecessor, salt ); for (uint256 i = 0; i < payloads.length; i++) { if ( bytes4(payloads[i]) == IProtocolAccessManager.setGuardianExpiration.selector ) { _guardianExpiryOperations[id] = true; } } super.scheduleBatch( targets, values, payloads, predecessor, salt, delay ); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ISummerVestingWallet} from "../interfaces/ISummerVestingWallet.sol"; import {VestingWallet} from "@openzeppelin/contracts/finance/VestingWallet.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ProtocolAccessManaged} from "@summerfi/access-contracts/contracts/ProtocolAccessManaged.sol"; /** * @title SummerVestingWallet * @dev Implementation of ISummerVestingWallet */ contract SummerVestingWallet is ISummerVestingWallet, VestingWallet, ProtocolAccessManaged { using SafeERC20 for IERC20; ////////////////////////////////////////////// /// CONSTANTS /// ////////////////////////////////////////////// /// @dev Duration of a month in seconds uint256 private constant MONTH = 30 days; /// @dev Duration of the cliff period in seconds uint256 private constant CLIFF = 180 days; /// @dev Duration of the vesting period in seconds uint64 private constant DURATION_SECONDS = 730 days; // 2 years for both vesting types ////////////////////////////////////////////// /// STATE VARIABLES /// ////////////////////////////////////////////// /// @dev The type of vesting schedule for this wallet VestingType private immutable _vestingType; /// @inheritdoc ISummerVestingWallet address public immutable token; // Performance-based vesting amounts uint256[] public goalAmounts; // Performance milestone flags bool[] public goalsReached; // Time-based vesting amount uint256 public immutable timeBasedVestingAmount; ////////////////////////////////////////////// /// CONSTRUCTOR /// ////////////////////////////////////////////// /** * @dev Constructor that sets up the vesting wallet with a specific vesting type * @param _token The address of the token to be vested * @param beneficiaryAddress Address of the beneficiary to whom vested tokens are transferred * @param startTimestamp Unix timestamp marking the start of the vesting period * @param vestingType Type of vesting schedule (0 for TeamVesting, 1 for InvestorExTeamVesting) * @param _timeBasedVestingAmount Amount of tokens to be vested time-based * @param _goalAmounts Array of goal amounts for performance-based vesting * @param _accessManager The address of the ProtocolAccessManager contract */ constructor( address _token, address beneficiaryAddress, uint64 startTimestamp, VestingType vestingType, uint256 _timeBasedVestingAmount, uint256[] memory _goalAmounts, address _accessManager ) VestingWallet(beneficiaryAddress, startTimestamp, DURATION_SECONDS) ProtocolAccessManaged(_accessManager) { _vestingType = vestingType; timeBasedVestingAmount = _timeBasedVestingAmount; if (_vestingType == VestingType.TeamVesting) { for (uint256 i = 0; i < _goalAmounts.length; i++) { _addNewGoal(_goalAmounts[i]); } } else if (_goalAmounts.length > 0) { revert OnlyTeamVesting(); } token = _token; if (token == address(0)) { revert InvalidToken(_token); } } ////////////////////////////////////////////// /// PUBLIC FUNCTIONS /// ////////////////////////////////////////////// /// @inheritdoc ISummerVestingWallet function getVestingType() public view returns (VestingType) { return _vestingType; } ////////////////////////////////////////////// /// EXTERNAL FUNCTIONS /// ////////////////////////////////////////////// /// @inheritdoc ISummerVestingWallet function addNewGoal(uint256 goalAmount) external onlyFoundation { if (_vestingType != VestingType.TeamVesting) { revert OnlyTeamVesting(); } _addNewGoal(goalAmount); SafeERC20.safeTransferFrom( IERC20(token), msg.sender, address(this), goalAmount ); } function _addNewGoal(uint256 goalAmount) internal { goalAmounts.push(goalAmount); goalsReached.push(false); emit NewGoalAdded(goalAmount, goalAmounts.length); } /// @inheritdoc ISummerVestingWallet function markGoalReached(uint256 goalNumber) external onlyFoundation { if (goalNumber < 1 || goalNumber > goalAmounts.length) { revert InvalidGoalNumber(); } goalsReached[goalNumber - 1] = true; emit GoalReached(goalNumber); } /// @inheritdoc ISummerVestingWallet function recallUnvestedTokens() external onlyFoundation { if (_vestingType != VestingType.TeamVesting) { revert OnlyTeamVesting(); } uint256 unvestedPerformanceTokens = _calculateUnvestedPerformanceTokens(); for (uint256 i = 0; i < goalAmounts.length; i++) { if (!goalsReached[i]) { goalAmounts[i] = 0; } } IERC20(token).transfer(msg.sender, unvestedPerformanceTokens); emit UnvestedTokensRecalled(unvestedPerformanceTokens); } ////////////////////////////////////////////// /// INTERNAL FUNCTIONS /// ////////////////////////////////////////////// /** * @dev Calculates the amount of tokens that has vested at a specific time * @param timestamp The timestamp to check for vested tokens * @return uint256 The amount of tokens already vested * @custom:override Overrides the _vestingSchedule function from VestingWallet * @custom:internal-logic * - Checks if the timestamp is before the start of vesting * - Combines time-based vesting (capped at timeBasedVestingAmount) and performance-based vesting (only for reached goals) * - Performance goals must be explicitly marked as reached to vest, regardless of time elapsed * @custom:effects * - Does not modify any state, view function only * @custom:security-considerations * - Ensure that the totalAllocation parameter accurately reflects the total vesting amount * - The function assumes that start() is correctly set * - Performance-based tokens never vest unless their goals are explicitly reached * @custom:gas-considerations * - This function calls two other internal functions, which may impact gas usage * - Consider gas costs when frequently querying vested amounts */ function _vestingSchedule( uint256, uint64 timestamp ) internal view override returns (uint256) { if (timestamp < start() + CLIFF) { return 0; } uint256 timeBasedVested = _calculateTimeBasedVesting(timestamp); uint256 performanceBasedVested = _calculatePerformanceBasedVesting(); return timeBasedVested + performanceBasedVested; } ////////////////////////////////////////////// /// PRIVATE FUNCTIONS /// ////////////////////////////////////////////// /** * @dev Calculates the time-based vesting amount based on the vesting type and timestamp * @param timestamp The timestamp to check for vested tokens * @return uint256 The amount of tokens already vested based on time * @custom:internal-logic * - Checks if the timestamp is before the cliff period * - Calculates the number of quarters that have passed, including the cliff period * - Determines the vested amount based on elapsed quarters * - Caps the vested amount at the timeBasedVestingAmount * @custom:effects * - Does not modify any state, view function only * @custom:security-considerations * - Ensure that the CLIFF and MONTH constants are correctly set * - The function assumes that start() is correctly set * @custom:gas-considerations * - This function performs several mathematical operations, which may impact gas usage * - Consider caching results if called frequently within the same transaction */ function _calculateTimeBasedVesting( uint64 timestamp ) private view returns (uint256) { uint256 elapsedMonths = (timestamp - start()) / MONTH; uint256 _vestedAmount = (timeBasedVestingAmount * elapsedMonths) / 24; return _vestedAmount < timeBasedVestingAmount ? _vestedAmount : timeBasedVestingAmount; } /** * @dev Calculates the amount of unvested performance-based tokens * @return The total amount of unvested performance-based tokens * @custom:internal-logic * - Calculates the total amount of tokens allocated for all performance goals * - Subtracts the amount of tokens vested based on reached performance goals * @custom:performance-considerations * - The gas cost of this function increases linearly with the number of goals * - Consider gas limitations when adding a large number of goals */ function _calculateUnvestedPerformanceTokens() private view returns (uint256) { uint256 unvestedAmount = 0; uint256 _goalLen = goalAmounts.length; for (uint256 i = 0; i < _goalLen; i++) { if (!goalsReached[i]) { unvestedAmount += goalAmounts[i]; } } return unvestedAmount; } /** * @dev Calculates the performance-based vesting amount * @return The total amount of tokens vested based on reached performance goals * @custom:internal-logic * - Checks if the vesting type is TeamVesting * - Iterates through all goals, summing up the amounts for reached goals * @custom:performance-considerations * - The gas cost of this function increases linearly with the number of goals * - Consider gas limitations when adding a large number of goals */ function _calculatePerformanceBasedVesting() private view returns (uint256) { if (_vestingType != VestingType.TeamVesting) { return 0; } uint256 vested = 0; uint256 _goalLen = goalAmounts.length; for (uint256 i = 0; i < _goalLen; i++) { if (goalsReached[i]) vested += goalAmounts[i]; } return vested; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ISummerVestingWalletFactory} from "../interfaces/ISummerVestingWalletFactory.sol"; import {SummerVestingWallet} from "../contracts/SummerVestingWallet.sol"; import {ProtocolAccessManaged} from "@summerfi/access-contracts/contracts/ProtocolAccessManaged.sol"; /** * @title SummerVestingWalletFactory * @notice Factory contract for creating new SummerVestingWallet instances * @dev Creates and tracks vesting wallets for beneficiaries with both time-based and goal-based vesting */ contract SummerVestingWalletFactory is ISummerVestingWalletFactory, ProtocolAccessManaged { using SafeERC20 for IERC20; /** @notice The ERC20 token that will be vested */ address public immutable token; /** @notice Mapping from beneficiary address to their vesting wallet address */ mapping(address beneficiary => address vestingWallet) public vestingWallets; /** @notice Mapping from vesting wallet address to its beneficiary address */ mapping(address vestingWallet => address beneficiary) public vestingWalletOwners; /** * @notice Initializes the factory with the token to be vested * @param _token The address of the ERC20 token that will be vested * @param _accessManager The address of the ProtocolAccessManager contract */ constructor( address _token, address _accessManager ) ProtocolAccessManaged(_accessManager) { if (_token == address(0)) revert ZeroTokenAddress(); token = _token; } /** * @notice Creates a new vesting wallet for a beneficiary * @dev Only callable by the Foundation */ function createVestingWallet( address beneficiary, uint256 timeBasedAmount, uint256[] memory goalAmounts, SummerVestingWallet.VestingType vestingType ) external onlyFoundation returns (address newVestingWallet) { if (vestingWallets[beneficiary] != address(0)) { revert VestingWalletAlreadyExists(beneficiary); } uint64 startTimestamp = uint64(block.timestamp); uint256 totalAmount = timeBasedAmount; for (uint256 i = 0; i < goalAmounts.length; i++) { totalAmount += goalAmounts[i]; } IERC20 tokenContract = IERC20(token); uint256 allowance = tokenContract.allowance(msg.sender, address(this)); if (allowance < totalAmount) { revert InsufficientAllowance(totalAmount, allowance); } uint256 senderBalance = tokenContract.balanceOf(msg.sender); if (senderBalance < totalAmount) { revert InsufficientBalance(totalAmount, senderBalance); } newVestingWallet = address( new SummerVestingWallet( token, beneficiary, startTimestamp, vestingType, timeBasedAmount, goalAmounts, address(_accessManager) // Pass access manager instead of admin ) ); vestingWallets[beneficiary] = newVestingWallet; vestingWalletOwners[newVestingWallet] = beneficiary; uint256 preBalance = tokenContract.balanceOf(newVestingWallet); tokenContract.safeTransferFrom( msg.sender, newVestingWallet, totalAmount ); uint256 postBalance = tokenContract.balanceOf(newVestingWallet); if (postBalance != preBalance + totalAmount) { revert TransferAmountMismatch( preBalance + totalAmount, postBalance ); } emit VestingWalletCreated( beneficiary, newVestingWallet, timeBasedAmount, goalAmounts, vestingType ); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ERC20Wrapper} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; /** * @title WrappedStakingToken * @notice A simple wrapper for the staking token that inherits from ERC20Wrapper * @dev This contract is used by GovernanceRewardsManager to wrap staking tokens when they are used as rewards */ contract WrappedStakingToken is ERC20Wrapper { constructor( address underlyingToken ) ERC20(string.concat("Wrapped ", "Summer"), string.concat("w", "SUMR")) ERC20Wrapper(IERC20(underlyingToken)) {} }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; /** * @title IGovernanceRewardsManagerErrors * @notice Interface defining custom errors for the Governance Rewards Manager */ interface IGovernanceRewardsManagerErrors { /** * @notice Thrown when the caller is not the staking token * @dev Used to restrict certain functions to only be callable by the staking token contract */ error InvalidCaller(); /** * @notice Thrown when the stakeOnBehalfOf function is called (operation not supported) */ error StakeOnBehalfOfNotSupported(); /** * @notice Thrown when the UnstakeOnBehalfOfNotSupported function is called (operation not supported) */ error UnstakeOnBehalfOfNotSupported(); /** * @notice Thrown when the caller is not delegated */ error NotDelegated(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /* @title ISummerGovernorErrors * @notice Interface defining custom errors for the SummerGovernor contract */ interface ISummerGovernorErrors { /* @notice Error thrown when the proposal threshold is invalid * @param proposalThreshold The invalid proposal threshold * @param minThreshold The minimum allowed threshold * @param maxThreshold The maximum allowed threshold */ error SummerGovernorInvalidProposalThreshold( uint256 proposalThreshold, uint256 minThreshold, uint256 maxThreshold ); /* @notice Error thrown when a proposer is below the threshold and not a guardian * @param proposer The address of the proposer * @param votes The number of votes the proposer has * @param threshold The required threshold for proposing */ error SummerGovernorProposerBelowThresholdAndNotGuardian( address proposer, uint256 votes, uint256 threshold ); /* @notice Error thrown when an unauthorized cancellation is attempted * @param caller The address attempting to cancel the proposal * @param proposer The address of the original proposer * @param votes The number of votes the proposer has * @param threshold The required threshold for proposing */ error SummerGovernorUnauthorizedCancellation( address caller, address proposer, uint256 votes, uint256 threshold ); /* @notice Error thrown when the trusted remote is invalid * @param trustedRemote The invalid trusted remote */ error SummerGovernorInvalidTrustedRemote(address trustedRemote); /* @notice Error thrown when the chain id is invalid * @param chainId The invalid chain id * @param hubChainId The valid chain id */ error SummerGovernorNotHubChain(uint256 chainId, uint256 hubChainId); /* @notice Error thrown when an attempt is made to execute on the hub chain */ error SummerGovernorCannotExecuteOnHubChain(); /* @notice Error thrown when the governor is not set */ error GovernorNotSet(); /* @notice Error thrown when the caller is not the rewards manager */ error SummerGovernorInvalidCaller(); /* @notice Error thrown when the peer arrays are invalid */ error SummerGovernorInvalidPeerArrays(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ISummerVestingWallet} from "../interfaces/ISummerVestingWallet.sol"; /** * @title ISummerTokenErrors * @notice Interface defining custom errors for the SummerToken contract */ interface ISummerTokenErrors { /** * @dev Error thrown when an invalid vesting type is provided * @param invalidType The invalid vesting type that was provided */ error InvalidVestingType(ISummerVestingWallet.VestingType invalidType); /** * @dev Error thrown when the caller is not the decay manager or governor * @param caller The address of the caller */ error CallerIsNotAuthorized(address caller); /** * @dev Error thrown when the caller is not the decay manager * @param caller The address of the caller */ error CallerIsNotDecayManager(address caller); /** * @dev Error thrown when the decay rate is too high */ error DecayRateTooHigh(uint256 rate); /** * @dev Error thrown when the decay free window is invalid (less than 30 days or more than 365.25 days) * @param window The invalid window duration that was provided */ error InvalidDecayFreeWindow(uint40 window); /** * @dev Error thrown when attempting to initialize the contract after it has already been initialized */ error AlreadyInitialized(); /** * @dev Error thrown when attempting to undelegate while staked */ error CannotUndelegateWhileStaked(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; /** * @title IDecayController * @notice Interface for the DecayController contract that manages decay updates */ interface IDecayController { /** * @notice Error thrown when a zero address is provided for the summer token */ error DecayController__ZeroAddress(); /** * @notice Error thrown when the rewards manager is already set */ error DecayController__RewardsManagerAlreadySet(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IGovernanceRewardsManagerErrors} from "../errors/IGovernanceRewardsManagerErrors.sol"; import {IStakingRewardsManagerBase} from "@summerfi/rewards-contracts/interfaces/IStakingRewardsManagerBase.sol"; /** * @title IGovernanceRewardsManager * @notice Interface for the GovernanceRewardsManager contract * @dev Manages staking and distribution of multiple reward tokens */ interface IGovernanceRewardsManager is IStakingRewardsManagerBase, IGovernanceRewardsManagerErrors { /** * @notice Returns the wrapped staking token * @return The wrapped staking token */ function wrappedStakingToken() external view returns (address); /** * @notice Emitted when unstakeAndWithdrawOnBehalfOf is called (operation not supported) * @param owner The address that owns the staked tokens * @param receiver The address that would have received the unstaked tokens * @param amount The amount of tokens that was attempted to be unstaked */ event UnstakeOnBehalfOfIgnored( address indexed owner, address indexed receiver, uint256 amount ); /** * @notice Returns the balance of staked tokens for an account * @param account The address of the staker * @return The amount of tokens staked by the account */ function balanceOf(address account) external view returns (uint256); /** * @notice Updates the smoothed decay factor for an account * @param account The address to update the smoothed decay factor for */ function updateSmoothedDecayFactor(address account) external; /** * @notice Calculates the smoothed decay factor for a given account without modifying state * @param account The address of the account to calculate for * @return The calculated smoothed decay factor */ function calculateSmoothedDecayFactor( address account ) external view returns (uint256); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ISummerGovernorErrors} from "../errors/ISummerGovernorErrors.sol"; import {IGovernor} from "@openzeppelin/contracts/governance/IGovernor.sol"; import {VotingDecayLibrary} from "@summerfi/voting-decay/VotingDecayLibrary.sol"; import {SummerTimelockController} from "../contracts/SummerTimelockController.sol"; import {ISummerToken} from "./ISummerToken.sol"; import {IProtocolAccessManager} from "@summerfi/access-contracts/interfaces/IProtocolAccessManager.sol"; /** * @title ISummerGovernor Interface * @notice Interface for the SummerGovernor contract, extending OpenZeppelin's IGovernor */ interface ISummerGovernor is IGovernor, ISummerGovernorErrors { /* * @dev Struct for the governor parameters * @param token The token contract address * @param timelock The timelock controller contract address * @param accessManager The access manager contract address * @param votingDelay The voting delay in seconds * @param votingPeriod The voting period in seconds * @param proposalThreshold The proposal threshold in tokens * @param quorumFraction The quorum fraction in tokens * @param endpoint The LayerZero endpoint address * @param hubChainId The hub chain ID * @param initialOwner The initial owner of the contract */ struct GovernorParams { ISummerToken token; SummerTimelockController timelock; address accessManager; uint48 votingDelay; uint32 votingPeriod; uint256 proposalThreshold; uint256 quorumFraction; address endpoint; uint32 hubChainId; address initialOwner; } /** * @notice Emitted when a proposal is sent cross-chain * @param proposalId The ID of the proposal * @param dstEid The destination endpoint ID */ event ProposalSentCrossChain( uint256 indexed proposalId, uint32 indexed dstEid ); /** * @notice Emitted when a proposal is received cross-chain * @param proposalId The ID of the proposal * @param srcEid The source endpoint ID */ event ProposalReceivedCrossChain( uint256 indexed proposalId, uint32 indexed srcEid ); /** * @notice Casts a vote for a proposal * @param proposalId The ID of the proposal to vote on * @param support The support for the proposal (0 = against, 1 = for, 2 = abstain) * @return The proposal ID */ function castVote( uint256 proposalId, uint8 support ) external returns (uint256); /** * @notice Proposes a new governance action * @param targets The addresses of the contracts to call * @param values The ETH values to send with the calls * @param calldatas The call data for each contract call * @param description A description of the proposal * @return proposalId The ID of the newly created proposal */ function propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description ) external override(IGovernor) returns (uint256 proposalId); /** * @notice Executes a proposal. Only callable on the proposal chain * @dev Crosschain proposals are executed using LayerZero. Check _lzReceive for the execution logic * @param targets The addresses of the contracts to call * @param values The ETH values to send with the calls * @param calldatas The call data for each contract call * @param descriptionHash The hash of the proposal description * @return proposalId The ID of the executed proposal */ function execute( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external payable override(IGovernor) returns (uint256 proposalId); /** * @notice Cancels an existing proposal * @param targets The addresses of the contracts to call * @param values The ETH values to send with the calls * @param calldatas The call data for each contract call * @param descriptionHash The hash of the proposal description * @return proposalId The ID of the cancelled proposal */ function cancel( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) external override(IGovernor) returns (uint256 proposalId); /** * @notice Sends a proposal to another chain for execution * @param _dstEid The destination Endpoint ID * @param _dstTargets The target addresses for the proposal * @param _dstValues The values for the proposal * @param _dstCalldatas The calldata for the proposal * @param _dstDescriptionHash The description hash for the proposal * @param _options Message execution options */ function sendProposalToTargetChain( uint32 _dstEid, address[] memory _dstTargets, uint256[] memory _dstValues, bytes[] memory _dstCalldatas, bytes32 _dstDescriptionHash, bytes calldata _options ) external; /** * @notice Checks if an account is an active guardian for governance purposes * @dev Delegates check to ProtocolAccessManager * @param account The address to check * @return bool True if the account is an active guardian, false otherwise */ function isActiveGuardian(address account) external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {ISummerTokenErrors} from "../errors/ISummerTokenErrors.sol"; import {VotingDecayLibrary} from "@summerfi/voting-decay/VotingDecayLibrary.sol"; import {IGovernanceRewardsManager} from "./IGovernanceRewardsManager.sol"; import {IVotes} from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; import {Percentage} from "@summerfi/percentage-solidity/contracts/Percentage.sol"; import {IOFT} from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol"; /** * @title ISummerToken * @dev Interface for the Summer governance token, combining ERC20, permit functionality, * and voting decay mechanisms */ interface ISummerToken is IOFT, IERC20, IERC20Permit, ISummerTokenErrors, IVotes { /*////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ /** * @dev Parameters required for contract construction * @param name The name of the token * @param symbol The symbol of the token * @param lzEndpoint The LayerZero endpoint address * @param initialOwner The initial owner of the contract * @param accessManager The access manager contract address * @param maxSupply The maximum token supply * @param transferEnableDate The timestamp when transfers can be enabled * @param hubChainId The chain ID of the hub chain */ struct ConstructorParams { string name; string symbol; address lzEndpoint; address initialOwner; address accessManager; uint256 maxSupply; uint256 transferEnableDate; uint32 hubChainId; } /** * @dev Parameters required for contract initialization * @param initialSupply The initial token supply to mint * @param initialDecayFreeWindow The initial decay-free window duration in seconds * @param initialYearlyDecayRate The initial yearly decay rate as a percentage * @param initialDecayFunction The initial decay function type * @param vestingWalletFactory The address of the vesting wallet factory contract */ struct InitializeParams { uint256 initialSupply; uint40 initialDecayFreeWindow; Percentage initialYearlyDecayRate; VotingDecayLibrary.DecayFunction initialDecayFunction; address vestingWalletFactory; } /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ /* * @dev Error thrown when the chain is not the hub chain * @param chainId The chain ID * @param hubChainId The hub chain ID */ error NotHubChain(uint256 chainId, uint256 hubChainId); /** * @notice Error thrown when transfers are not allowed */ error TransferNotAllowed(); /** * @notice Error thrown when transfers cannot be enabled yet */ error TransfersCannotBeEnabledYet(); /** * @notice Error thrown when transfers are already enabled */ error TransfersAlreadyEnabled(); /** * @notice Error thrown when the address length is invalid */ error InvalidAddressLength(); /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /** * @notice Emitted when transfers are enabled */ event TransfersEnabled(); /** * @notice Error thrown when invalid peer arrays are provided */ error SummerTokenInvalidPeerArrays(); /** * @notice Emitted when an address is whitelisted * @param account The address of the whitelisted account */ event AddressWhitelisted(address indexed account); /** * @notice Emitted when an address is removed from the whitelist * @param account The address of the removed account */ event AddressRemovedFromWhitelist(address indexed account); /*////////////////////////////////////////////////////////////// EXTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Returns the decay free window * @return The decay free window in seconds */ function getDecayFreeWindow() external view returns (uint40); /** * @notice Returns the yearly decay rate as a percentage * @return The yearly decay rate as a Percentage type * @dev This returns the annualized rate using simple multiplication rather than * compound interest calculation for clarity and predictability */ function getDecayRatePerYear() external view returns (Percentage); /** * @notice Returns the decay factor for an account * @param account The address to get the decay factor for * @return The decay factor for the account */ function getDecayFactor(address account) external view returns (uint256); /** * @notice Returns the decay factor for an account at a specific timepoint * @param account The address to get the decay factor for * @param timepoint The timestamp to get the decay factor at * @return The decay factor for the account at the specified timepoint */ function getPastDecayFactor( address account, uint256 timepoint ) external view returns (uint256); /** * @notice Returns the current votes for an account with decay factor applied * @param account The address to get votes for * @return The current voting power after applying the decay factor * @dev This function: * 1. Gets the raw votes using ERC20Votes' _getVotes * 2. Applies the decay factor from VotingDecayManager * @custom:relationship-to-votingdecay * - Uses VotingDecayManager.getVotingPower() to apply decay * - Decay factor is determined by: * - Time since last update * - Delegation chain (up to MAX_DELEGATION_DEPTH) * - Current decayRatePerSecond and decayFreeWindow */ function getVotes(address account) external view returns (uint256); /** * @notice Updates the decay factor for a specific account * @param account The address of the account to update * @dev Can only be called by the governor */ function updateDecayFactor(address account) external; /** * @notice Sets the yearly decay rate for voting power decay * @param newYearlyRate The new decay rate per year as a Percentage * @dev Can only be called by the governor * @dev The rate is converted internally to a per-second rate using simple division */ function setDecayRatePerYear(Percentage newYearlyRate) external; /** * @notice Sets the decay-free window duration * @param newWindow The new decay-free window duration in seconds * @dev Can only be called by the governor */ function setDecayFreeWindow(uint40 newWindow) external; /** * @notice Sets the decay function type * @param newFunction The new decay function to use * @dev Can only be called by the governor */ function setDecayFunction( VotingDecayLibrary.DecayFunction newFunction ) external; /** * @notice Enables transfers */ function enableTransfers() external; /** * @notice Adds an address to the whitelist * @param account The address to add to the whitelist */ function addToWhitelist(address account) external; /** * @notice Removes an address from the whitelist * @param account The address to remove from the whitelist */ function removeFromWhitelist(address account) external; /** * @notice Returns the address of the rewards manager contract * @return The address of the rewards manager */ function rewardsManager() external view returns (address); /** * @notice Gets the length of the delegation chain for an account * @param account The address to check delegation chain for * @return The length of the delegation chain (0 for self-delegated or invalid chains) */ function getDelegationChainLength( address account ) external view returns (uint256); /** * @notice Returns the raw votes (before decay) for an account at a specific timepoint * @param account The address to get raw votes for * @param timestamp The timestamp to get raw votes at * @return The current voting power before applying any decay factor * @dev This returns the total voting units including direct balance, staked tokens, * and vesting wallet balances, but without applying the decay factor */ function getRawVotesAt( address account, uint256 timestamp ) external view returns (uint256); /** * @notice Returns the votes for an account at a specific past block, with decay factor applied * @param account The address to get votes for * @param timepoint The block number to get votes at * @return The historical voting power after applying the decay factor * @dev This function: * 1. Gets the historical raw votes using ERC20Votes' _getPastVotes * 2. Applies the current decay factor from VotingDecayManager * @custom:relationship-to-votingdecay * - Uses VotingDecayManager.getVotingPower() to apply decay * - Note: The decay factor is current, not historical * - This means voting power can decrease over time even for past checkpoints */ function getPastVotes( address account, uint256 timepoint ) external view returns (uint256); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title ISummerVestingWallet * @dev Interface for SummerVestingWallet, an extension of OpenZeppelin's VestingWallet with custom vesting schedules * and separate admin role. * Supports two types of vesting: Team vesting and Investor/Ex-Team vesting, both with a 6-month cliff. * * Vesting Schedules: * 1. Team Vesting: * - Time-based: Monthly releases over 2 years, starting after the 6-month cliff. * - Performance-based: arbitrary amount of additional milestone-based releases, triggered by the guardian. * 2. Investor/Ex-Team Vesting: * - Time-based only: Monthly releases over 2 years, starting after the 6-month cliff. * * The guardian role can mark performance goals as reached for team vesting and recall unvested * performance-based tokens if necessary. */ interface ISummerVestingWallet { /// @dev Enum representing the types of vesting schedules enum VestingType { TeamVesting, InvestorExTeamVesting } ////////////////////////////////////////////// /// VIEW FUNCTIONS /// ////////////////////////////////////////////// /// @dev The token being vested function token() external view returns (address); /// @dev Performance-based vesting amounts function goalAmounts(uint256 index) external view returns (uint256); /// @dev Performance milestone flags function goalsReached(uint256 index) external view returns (bool); /// @dev Time-based vesting amount function timeBasedVestingAmount() external view returns (uint256); /** * @dev Returns the vesting type of this wallet * @return The VestingType enum value representing the vesting type (TeamVesting or InvestorExTeamVesting) */ function getVestingType() external view returns (VestingType); ////////////////////////////////////////////// /// MUTATIVE FUNCTIONS /// ////////////////////////////////////////////// /** * @notice Adds a new performance-based vesting goal to the contract * @dev This function can only be called by an address with the GUARDIAN_ROLE * @dev The new goal is appended to the existing goalAmounts array * @dev A corresponding false value is added to the goalsReached array * @dev This function allows for dynamic expansion of performance-based vesting goals * @dev The caller must transfer the goalAmount of tokens to this contract after calling this function * @param goalAmount The amount of tokens associated with the new performance goal */ function addNewGoal(uint256 goalAmount) external; /** * @notice Marks a specific performance goal as reached * @dev This function can only be called by an address with the GUARDIAN_ROLE * @param goalNumber The number of the goal to mark as reached (1-indexed) */ function markGoalReached(uint256 goalNumber) external; /** * @notice Recalls unvested performance-based tokens * @dev This function can only be called by an address with the GUARDIAN_ROLE * @dev It's only applicable for TeamVesting type */ function recallUnvestedTokens() external; ////////////////////////////////////////////// /// ERRORS /// ////////////////////////////////////////////// /// @dev Thrown when an invalid goal number is provided error InvalidGoalNumber(); /// @dev Thrown when a function is called that's only applicable to TeamVesting error OnlyTeamVesting(); /// @dev Thrown when the goal array length is invalid error InvalidGoalArrayLength(); /// @dev Thrown when the token address is invalid error InvalidToken(address token); /// @dev Emitted when a new goal is added event NewGoalAdded(uint256 goalAmount, uint256 goalNumber); /// @dev Emitted when a goal is reached event GoalReached(uint256 goalNumber); /// @dev Emitted when unvested tokens are recalled event UnvestedTokensRecalled(uint256 unvestedTokens); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; import {ISummerVestingWallet} from "./ISummerVestingWallet.sol"; interface ISummerVestingWalletFactory { /** @notice Custom errors */ error ZeroTokenAddress(); error InsufficientAllowance(uint256 required, uint256 actual); error InsufficientBalance(uint256 required, uint256 actual); error TransferAmountMismatch(uint256 expected, uint256 actual); error VestingWalletAlreadyExists(address beneficiary); /** * @notice Emitted when a new vesting wallet is created * @param beneficiary The address of the beneficiary * @param vestingWallet The address of the created vesting wallet * @param timeBasedAmount The amount of tokens to be vested based on time * @param goalAmounts The amounts of tokens to be vested based on goals * @param vestingType The type of vesting schedule */ event VestingWalletCreated( address indexed beneficiary, address indexed vestingWallet, uint256 timeBasedAmount, uint256[] goalAmounts, ISummerVestingWallet.VestingType vestingType ); /** * @notice Creates a new vesting wallet for a beneficiary * @param beneficiary Address of the beneficiary to whom vested tokens are transferred * @param timeBasedAmount Amount of tokens to be vested based on time * @param goalAmounts Array of token amounts to be vested based on performance goals * @param vestingType Type of vesting schedule * @return newVestingWallet The address of the created vesting wallet */ function createVestingWallet( address beneficiary, uint256 timeBasedAmount, uint256[] memory goalAmounts, ISummerVestingWallet.VestingType vestingType ) external returns (address newVestingWallet); /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Gets the vesting wallet address for a given account * @param owner The address of the account * @return The address of the vesting wallet */ function vestingWallets(address owner) external view returns (address); /** * @notice Gets the owner of a vesting wallet for a given account * @param beneficiary The address of the vesting wallet * @return The address of the owner */ function vestingWalletOwners( address beneficiary ) external view returns (address); }
{ "optimizer": { "enabled": true, "runs": 50 }, "evmVersion": "cancun", "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"lzEndpoint","type":"address"},{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"accessManager","type":"address"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"transferEnableDate","type":"uint256"},{"internalType":"uint32","name":"hubChainId","type":"uint32"}],"internalType":"struct ISummerToken.ConstructorParams","name":"params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotAdmin","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotAuthorized","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotAuthorizedToBoard","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotCommander","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"CallerIsNotContractSpecificRole","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotCurator","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotDecayController","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotDecayManager","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotFoundation","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotGovernor","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotGuardian","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotGuardianOrGovernor","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotKeeper","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotRaft","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotRaftOrCommander","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotSuperKeeper","type":"error"},{"inputs":[],"name":"CannotUndelegateWhileStaked","type":"error"},{"inputs":[],"name":"CheckpointUnorderedInsertion","type":"error"},{"inputs":[],"name":"DecayController__RewardsManagerAlreadySet","type":"error"},{"inputs":[],"name":"DecayController__ZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"DecayRateTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"DirectGrantIsDisabled","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"DirectRevokeIsDisabled","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"uint256","name":"increasedSupply","type":"uint256"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"ERC20ExceededCap","type":"error"},{"inputs":[{"internalType":"uint256","name":"increasedSupply","type":"uint256"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"ERC20ExceededSafeSupply","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"ERC20InvalidCap","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[{"internalType":"uint256","name":"timepoint","type":"uint256"},{"internalType":"uint48","name":"clock","type":"uint48"}],"name":"ERC5805FutureLookup","type":"error"},{"inputs":[],"name":"ERC6372InconsistentClock","type":"error"},{"inputs":[{"internalType":"address","name":"invalidAddress","type":"address"}],"name":"InvalidAccessManagerAddress","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentNonce","type":"uint256"}],"name":"InvalidAccountNonce","type":"error"},{"inputs":[],"name":"InvalidAddressLength","type":"error"},{"inputs":[{"internalType":"uint40","name":"window","type":"uint40"}],"name":"InvalidDecayFreeWindow","type":"error"},{"inputs":[],"name":"InvalidDecayRate","type":"error"},{"inputs":[],"name":"InvalidDecayType","type":"error"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[],"name":"InvalidLocalDecimals","type":"error"},{"inputs":[{"internalType":"bytes","name":"options","type":"bytes"}],"name":"InvalidOptions","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"enum ISummerVestingWallet.VestingType","name":"invalidType","type":"uint8"}],"name":"InvalidVestingType","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"NoPeer","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"NotEnoughNative","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"hubChainId","type":"uint256"}],"name":"NotHubChain","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","type":"error"},{"inputs":[],"name":"OnlySelf","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":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"PRBMath_MulDiv18_Overflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath_MulDiv_Overflow","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"name":"SimulationResult","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"}],"name":"SlippageExceeded","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"SummerTokenInvalidPeerArrays","type":"error"},{"inputs":[],"name":"TransferNotAllowed","type":"error"},{"inputs":[],"name":"TransfersAlreadyEnabled","type":"error"},{"inputs":[],"name":"TransfersCannotBeEnabledYet","type":"error"},{"inputs":[{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"VotesExpiredSignature","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"AccountInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddressRemovedFromWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddressWhitelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"newWindow","type":"uint40"}],"name":"DecayFreeWindowSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"newFunction","type":"uint8"}],"name":"DecayFunctionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"DecayRateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newDecayFactor","type":"uint256"}],"name":"DecayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousVotes","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVotes","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"},{"internalType":"bytes","name":"options","type":"bytes"}],"indexed":false,"internalType":"struct EnforcedOptionParam[]","name":"_enforcedOptions","type":"tuple[]"}],"name":"EnforcedOptionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"inspector","type":"address"}],"name":"MsgInspectorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"srcEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"dstEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTSent","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":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"preCrimeAddress","type":"address"}],"name":"PreCrimeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[],"name":"TransfersEnabled","type":"event"},{"inputs":[],"name":"ADMIRALS_QUARTERS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CLOCK_MODE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"DECAY_CONTROLLER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEND","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEND_AND_CALL","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUPER_KEEPER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"}],"name":"allowInitializePath","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"approvalRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"pos","type":"uint32"}],"name":"checkpoints","outputs":[{"components":[{"internalType":"uint48","name":"_key","type":"uint48"},{"internalType":"uint208","name":"_value","type":"uint208"}],"internalType":"struct Checkpoints.Checkpoint208","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clock","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"uint16","name":"_msgType","type":"uint16"},{"internalType":"bytes","name":"_extraOptions","type":"bytes"}],"name":"combineOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimalConversionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableTransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"}],"name":"enforcedOptions","outputs":[{"internalType":"bytes","name":"enforcedOption","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum ContractSpecificRoles","name":"roleName","type":"uint8"},{"internalType":"address","name":"roleTargetContract","type":"address"}],"name":"generateRole","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getDecayFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDecayFreeWindow","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDecayRatePerYear","outputs":[{"internalType":"Percentage","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getDelegationChainLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timepoint","type":"uint256"}],"name":"getPastDecayFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timepoint","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timepoint","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"getRawVotesAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"hasAdmiralsQuartersRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hubChainId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint40","name":"initialDecayFreeWindow","type":"uint40"},{"internalType":"Percentage","name":"initialYearlyDecayRate","type":"uint256"},{"internalType":"enum VotingDecayLibrary.DecayFunction","name":"initialDecayFunction","type":"uint8"},{"internalType":"address","name":"vestingWalletFactory","type":"address"}],"internalType":"struct ISummerToken.InitializeParams","name":"params","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"isComposeMsgSender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"isPeer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct InboundPacket[]","name":"_packets","type":"tuple[]"}],"name":"lzReceiveAndRevert","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceiveSimulate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"msgInspector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nextNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oApp","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"oftVersion","outputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"},{"internalType":"uint64","name":"version","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"peer","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"preCrime","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"}],"name":"quoteOFT","outputs":[{"components":[{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"uint256","name":"maxAmountLD","type":"uint256"}],"internalType":"struct OFTLimit","name":"oftLimit","type":"tuple"},{"components":[{"internalType":"int256","name":"feeAmountLD","type":"int256"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct OFTFeeDetail[]","name":"oftFeeDetails","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"internalType":"bool","name":"_payInLzToken","type":"bool"}],"name":"quoteSend","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"msgFee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"_fee","type":"tuple"},{"internalType":"address","name":"_refundAddress","type":"address"}],"name":"send","outputs":[{"components":[{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"internalType":"struct MessagingReceipt","name":"msgReceipt","type":"tuple"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint40","name":"newWindow","type":"uint40"}],"name":"setDecayFreeWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum VotingDecayLibrary.DecayFunction","name":"newFunction","type":"uint8"}],"name":"setDecayFunction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"Percentage","name":"newYearlyRate","type":"uint256"}],"name":"setDecayRatePerYear","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"},{"internalType":"bytes","name":"options","type":"bytes"}],"internalType":"struct EnforcedOptionParam[]","name":"_enforcedOptions","type":"tuple[]"}],"name":"setEnforcedOptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_msgInspector","type":"address"}],"name":"setMsgInspector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_preCrime","type":"address"}],"name":"setPreCrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sharedDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferEnableDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transfersEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"updateDecayFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vestingWalletFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"whitelistedAddresses","outputs":[{"internalType":"bool","name":"isWhitelisted","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6102408060405234610808575f90619aff803803809161001f8285610833565b8339810190602081830312610808578051906001600160401b038211610808570161010081830312610808576040519161010083016001600160401b0381118482101761081f5760405281516001600160401b0381116108085781610085918401610856565b83526020820151906001600160401b038211610808576100a6918301610856565b918260208201526100b9604083016108ab565b908160408201526100cc606084016108ab565b908160608201526100df608085016108ab565b92608082019284845260a0860151918260a085015260e060c08801519760c0860198895201519563ffffffff871687036108085760e0850196875293516040805190996001600160a01b039687169691948216939091166101408b86610833565b600185526020850193603160f81b8552801561080c575f80546001600160a01b03198116831782558d51939183916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a380608052803b15610808576024835f8193819563ca5eb5e160e01b845260048401525af180156107fe576107e9575b5064e8d4a5100060a05281516001600160401b0381116106f657600854600181811c911680156107df575b60208210146106d857601f8111610777575b508060208d601f8311600114610715579161070a575b508160011b915f199060031b1c1916176008555b8051906001600160401b0382116106f657600954600181811c911680156106ec575b60208210146106d8579081601f849311610667575b506020908d601f841160011461060357926105f8575b50508160011b915f199060031b1c1916176009555b61029d816108bf565b610160526102aa83610a5a565b610180526020815191012091826101205251902080610140524660e05287519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f84528983015260608201524660808201523060a082015260a0815261031660c082610833565b51902060c052306101005280156105e4576101a05280156105d05784516301ffc9a760e01b815263261c910560e21b6004820152602081602481855afa9081156105c6578791610587575b5015610575576101c052301561054557306101e05251835190612f80808301916001600160a01b0316906001600160401b03831184841017610561579183918793616b7f8439308252602082015203019085f0801561055457601280546001600160a01b0319166001600160a01b039290921691821790558015610545576010546001600160a01b038116610536576001600160a01b031916176010555163ffffffff1661020052516102205251615fec9081610b938239608051818181610a0a01528181610b2a01528181610fa00152818161147301528181612837015281816147ae01526152c0015260a051818181610ef001528181611e350152818161383501528181613dd4015281816146b501526148d4015260c05181613ac8015260e05181613b8501526101005181613a9201526101205181613b1701526101405181613b3d015261016051816118d4015261018051816118fd01526101a051818181610ded015261418d01526101c05181818161174f01528181611a1f01528181611ca801528181611fb5015281816120d701528181612b4801528181612bf90152612cf001526101e0518161137e015261020051818181611c150152612fcb0152610220518181816108ee01526134120152f35b6336f62bb160e01b8652600486fd5b6334566e4b60e21b8552600485fd5b50505051903d90823e3d90fd5b634e487b7160e01b88526041600452602488fd5b6347bd7c1d60e01b8652600452602485fd5b90506020813d6020116105be575b816105a260209383610833565b810103126105ba575180151581036105ba575f610361565b8680fd5b3d9150610595565b86513d89823e3d90fd5b6347bd7c1d60e01b86526004869052602486fd5b63392e1e2760e01b87526004879052602487fd5b015190505f8061027f565b600981528281209350601f198516905b81811061064f5750908460019594939210610637575b505050811b01600955610294565b01515f1960f88460031b161c191690555f8080610629565b92936020600181928786015181550195019301610613565b60098e529091507f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af601f840160051c810191602085106106ce575b849392918f91601f0160051c0191905b8282106106c0575050610269565b81558493506001018e6106b2565b90915081906106a2565b634e487b7160e01b8d52602260045260248dfd5b90607f1690610254565b634e487b7160e01b8c52604160045260248cfd5b90508301515f61021e565b600881528181209250601f198416905b81811061075f57509083600194939210610747575b5050811b01600855610232565b8501515f1960f88460031b161c191690555f8061073a565b9192602060018192868a015181550194019201610725565b60088d527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3601f830160051c810191602084106107d5575b601f0160051c01908d905b8281106107c8575050610208565b6001918155018d906107ba565b90915081906107af565b90607f16906101f6565b6107f6919b505f90610833565b5f995f6101cb565b8b513d5f823e3d90fd5b5f80fd5b631e4fbdf760e01b5f525f60045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b601f909101601f19168101906001600160401b0382119082101761081f57604052565b81601f82011215610808578051906001600160401b03821161081f576040519261088a601f8401601f191660200185610833565b8284526020838301011161080857815f9260208093018386015e8301015290565b51906001600160a01b038216820361080857565b908151602081105f14610939575090601f8151116108f95760208151910151602082106108ea571790565b5f198260200360031b1b161790565b604460209160405192839163305a27a960e01b83528160048401528051918291826024860152018484015e5f828201840152601f01601f19168101030190fd5b6001600160401b03811161081f57600a54600181811c91168015610a50575b6020821014610a3c57601f8111610a09575b50602092601f82116001146109a857928192935f9261099d575b50508160011b915f199060031b1c191617600a5560ff90565b015190505f80610984565b601f19821693600a5f52805f20915f5b8681106109f157508360019596106109d9575b505050811b01600a5560ff90565b01515f1960f88460031b161c191690555f80806109cb565b919260206001819286850151815501940192016109b8565b600a5f52601f60205f20910160051c810190601f830160051c015b818110610a31575061096a565b5f8155600101610a24565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610958565b908151602081105f14610a85575090601f8151116108f95760208151910151602082106108ea571790565b6001600160401b03811161081f57600b54600181811c91168015610b88575b6020821014610a3c57601f8111610b55575b50602092601f8211600114610af457928192935f92610ae9575b50508160011b915f199060031b1c191617600b5560ff90565b015190505f80610ad0565b601f19821693600b5f52805f20915f5b868110610b3d5750836001959610610b25575b505050811b01600b5560ff90565b01515f1960f88460031b161c191690555f8080610b17565b91926020600181928685015181550194019201610b04565b600b5f52601f60205f20910160051c810190601f830160051c015b818110610b7d5750610ab6565b5f8155600101610b70565b90607f1690610aa456fe60806040526004361015610011575f80fd5b5f3560e01c806306c933d81461056f57806306fdde031461056a578063095ea7b3146105655780630d35b415146105605780630dce88f41461055b578063111ecdad1461055657806313137d6514610551578063134d4f251461054c578063156a0d0f1461054757806317442b701461054257806318160ddd1461053d5780631f5e13341461053857806323b872dd1461053357806324ea54f41461052e578063313ce567146105295780633400288b14610524578063355274ea1461051f5780633644e5151461051a5780633a46b1a8146105155780633b6f743b14610510578063412290811461050b57806342966c68146105065780634bf5d7e91461050157806352ae2879146103d05780635535d461146104fc578063587cde1e146104f75780635a0dfe4d146104f25780635c19a95c146104ed5780635e280f11146104e857806366e943f1146104e357806369b3054b146104de5780636fc1b31e146104d95780636fcfff45146104d457806370a08231146104cf578063715018a6146104ca57806379cc6790146104c55780637c930dde146104c05780637d25a05e146104bb5780637ecebe00146104b657806382413eac146104b157806382c4e4ca146104ac57806384b0196e146104a7578063857749b0146104a25780638ab1d6811461049d5780638da5cb5b146104985780638e539e8c1461049357806391ddadf41461048e578063929f58401461048957806392a525d514610484578063934cc3101461047f57806395d89b411461047a578063963efcaa146104755780639ab24eb0146104705780639db6468c1461046b5780639de048dc146104665780639f68b96414610461578063a89f38a31461045c578063a9059cbb14610457578063af35c6c714610452578063b5e86d4f1461044d578063b731ea0a14610448578063b98bd07014610443578063bb0b6a531461043e578063bc70b35414610439578063bd815db014610434578063bef97c871461042f578063c0b534c21461042a578063c3cda52014610425578063c7c7f5b314610420578063ca5eb5e11461041b578063ccc5749014610416578063d045a0dc14610411578063d42438851461040c578063d505accf14610407578063dd62ed3e14610402578063defe2053146103fd578063e0cf01ae146103f8578063e43252d7146103f3578063ea4ebdca146103ee578063ebc136d0146103e9578063f1127ed8146103e4578063f2fde38b146103df578063f3cc0393146103da578063f56a47a5146103d5578063fc0c546a146103d05763ff7bd03d146103cb575f80fd5b612ee6565b6110d6565b612eb9565b612e8e565b612e05565b612d55565b612c83565b612c5f565b612bae565b612b01565b612ad9565b612a87565b612974565b612904565b6128d3565b6128ac565b61280f565b61267a565b61252d565b6124d3565b6124b1565b61235d565b612309565b6122d0565b6121ed565b612173565b61213c565b612099565b61206f565b612035565b61201b565b611f73565b611efe565b611e58565b611e1e565b611d79565b611d0e565b611c61565b611bf9565b611bd7565b611abf565b611a98565b6119d4565b6119b9565b6118bc565b61188f565b611831565b6117f6565b6117d0565b6116e9565b6116b5565b61165e565b611623565b6115bb565b61154b565b6114dc565b6114a2565b61145e565b611350565b61130a565b6112c7565b61124c565b611086565b611067565b61103f565b610e8c565b610e32565b610e10565b610dd6565b610d51565b610d28565b610cee565b610cae565b610c93565b610c76565b610c55565b610c2f565b610c14565b6109f7565b610924565b6108d7565b6107f6565b610713565b610639565b6105b7565b6001600160a01b0381160361058557565b5f80fd5b6001600160a01b03165f90815260056020526040902090565b9060018060a01b03165f5260205260405f2090565b34610585576020366003190112610585576004356105d481610574565b60018060a01b03165f526019602052602060ff60405f2054166040519015158152f35b5f91031261058557565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b906020610636928181520190610601565b90565b34610585575f366003190112610585576040515f60085461065981611123565b80845290600181169081156106ef5750600114610691575b61068d836106818185038261122b565b60405191829182610625565b0390f35b60085f9081527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3939250905b8082106106d557509091508101602001610681610671565b9192600181602092548385880101520191019092916106bd565b60ff191660208086019190915291151560051b840190910191506106819050610671565b346105855760403660031901126105855761073d60043561073381610574565b6024359033614843565b602060405160018152f35b908160e09103126105855790565b939291906107728560a081019260208091805184520151910152565b60a06040860152815180915260c0850190602060c08260051b8801019301915f905b8282106107ba57505050509060606107b89294019060208091805184520151910152565b565b909192936020806107e860019360bf198c82030186526040838a518051845201519181858201520190610601565b960192019201909291610794565b34610585576020366003190112610585576004356001600160401b03811161058557610826903690600401610748565b61082e612f2b565b50610837612f2b565b50604051610844816111f0565b5f81526001600160401b036020820152602060405192610864828561122b565b5f8452601f1982015f5b8181106108b45750509061089861068d926040810135610892606083013592612f5a565b5061382c565b90916108a2611ec2565b92835282015260405193849384610756565b83906040516108c2816111f0565b5f81526060838201528282890101520161086e565b34610585575f3660031901126105855760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b6001600160a01b03909116815260200190565b34610585575f366003190112610585576004546040516001600160a01b039091168152602090f35b606090600319011261058557600490565b9181601f84011215610585578235916001600160401b038311610585576020838186019501011161058557565b90600319820160e081126105855760601361058557600491606435916084356001600160401b03811161058557826109c49160040161095d565b9290929160a4356109d481610574565b9160c435906001600160401b038211610585576109f39160040161095d565b9091565b610a003661098a565b50919492915050337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610c01578135610a4281610d43565b610a4b8161387e565b906020840135809203610bdc575050610a73610a6785836148a8565b6001600160a01b031690565b93610a99610a89610a8483856148b4565b6148c6565b610a9285612f5a565b50866148fa565b91610aa48260281090565b610afc575b5050610ad57fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c92612f5a565b6040805163ffffffff92909216825260208201929092526001600160a01b039490941693a3005b9082610b2792610b21610b11604088016138ae565b93610b1b88612f5a565b9261491e565b9261493a565b917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561058557604051633e5ac80960e11b8152935f918591829084908290610b80908b8d600485016138b8565b03925af1908115610bd7577fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c93610ad592610bbd575b5092610aa9565b80610bcb5f610bd19361122b565b806105f7565b5f610bb6565b6130fe565b80610beb63ffffffff92610d43565b63309afaf360e21b5f521660045260245260445ffd5b6391ac5e4f60e01b5f523360045260245ffd5b34610585575f36600319011261058557602060405160028152f35b34610585575f366003190112610585576040805162b9270b60e21b815260016020820152f35b34610585575f36600319011261058557604080516001815260026020820152f35b34610585575f366003190112610585576020600754604051908152f35b34610585575f36600319011261058557602060405160018152f35b346105855760603660031901126105855761073d600435610cce81610574565b602435610cda81610574565b60443591610ce98333836138e2565b61399a565b34610585575f3660031901126105855760206040517f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50418152f35b34610585575f36600319011261058557602060405160128152f35b63ffffffff81160361058557565b34610585576040366003190112610585577f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b600435610d8f81610d43565b60243590610d9b613a69565b63ffffffff81165f5260016020528160405f2055610dd1604051928392836020909392919363ffffffff60408201951681520152565b0390a1005b34610585575f3660031901126105855760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610585575f366003190112610585576020610e2a613a8f565b604051908152f35b34610585576040366003190112610585576020670de0b6b3a7640000610e79600435610e5d81610574565b610e73602435610e6d8184613bab565b92613caa565b90612f78565b04604051908152f35b8015150361058557565b34610585576040366003190112610585576004356001600160401b03811161058557610ebc903690600401610748565b602435610ec881610e82565b610ed0612f2b565b50813591606081013590610f1b6040820135610eeb86610d43565b610f167f00000000000000000000000000000000000000000000000000000000000000008092612f8b565b612f78565b9180831061102957610f9c604086610f8187610f378888613dbd565b90610f4185610d43565b610f49612f2b565b50610f538561387e565b610f6a610f5e611ed1565b63ffffffff9097168752565b602086015285850152606084015215156080830152565b815180938192631bb8518b60e31b8352309060048401613ef8565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015610bd75761068d915f91610ffa575b5060405191829182815181526020918201519181019190915260400190565b61101c915060403d604011611022575b611014818361122b565b810190613ee4565b82610fdb565b503d61100a565b826371c4efed60e01b5f5260045260245260445ffd5b34610585575f366003190112610585576011546040516001600160a01b039091168152602090f35b346105855760203660031901126105855761108460043533613f66565b005b34610585575f3660031901126105855761068d6040516110a760408261122b565b600e81526d06d6f64653d74696d657374616d760941b6020820152604051918291602083526020830190610601565b34610585575f366003190112610585576020604051308152f35b6024359061ffff8216820361058557565b359061ffff8216820361058557565b634e487b7160e01b5f525f60045260245ffd5b90600182811c92168015611151575b602083101461113d57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691611132565b5f929181549161116a83611123565b80835292600181169081156111bf575060011461118657505050565b5f9081526020812093945091925b8383106111a5575060209250010190565b600181602092949394548385870101520191019190611194565b915050602093945060ff929192191683830152151560051b010190565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761120b57604052565b6111dc565b606081019081106001600160401b0382111761120b57604052565b90601f801991011681019081106001600160401b0382111761120b57604052565b346105855760403660031901126105855761068d6112ac6112b36112a060043561127581610d43565b63ffffffff6112826110f0565b91165f52600360205260405f209061ffff165f5260205260405f2090565b6040519283809261115b565b038261122b565b604051918291602083526020830190610601565b34610585576020366003190112610585576004356112e481610574565b60018060a01b03165f52600d602052602060018060a01b0360405f205416604051908152f35b3461058557604036600319011261058557602061134660043561132c81610d43565b6024359063ffffffff165f52600160205260405f20541490565b6040519015158152f35b346105855760203660031901126105855760043561136d81610574565b3361137c575b61108490612fc4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610585575f6040518092633e4986ef60e11b82528183816113cd3360048301610911565b03925af18015610bd75761144a575b506010546113f2906001600160a01b0316610a67565b90813b15610585575f604051809363dae21dab60e01b825281838161141a3360048301610911565b03925af1918215610bd75761108492611436575b509050611373565b80610bcb5f6114449361122b565b5f61142e565b80610bcb5f6114589361122b565b5f6113dc565b34610585575f366003190112610585576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610585575f3660031901126105855760206040517f0d186688925976bbe6755ae984501c8e3e2b103a7af59fd803ab9c6d891ae7e08152f35b346105855760403660031901126105855760043560038110156105855761068d9060243561150981610574565b60405190602082019260f81b835260018060601b03199060601b1660218201526015815261153860358261122b565b5190206040519081529081906020820190565b34610585576020366003190112610585577ff0be4f1e87349231d80c36b33f9e8639658eeaf474014dee15a3e6a4d4414197602060043561158b81610574565b611593613a69565b600480546001600160a01b0319166001600160a01b03929092169182179055604051908152a1005b34610585576020366003190112610585576004356115d881610574565b6001600160a01b03165f908152600e602052604090205463ffffffff811161160c5760405163ffffffff9091168152602090f35b6306dfcc6560e41b5f52602060045260245260445ffd5b346105855760203660031901126105855760043561164081610574565b60018060a01b03165f526005602052602060405f2054604051908152f35b34610585575f36600319011261058557611676613a69565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610585576040366003190112610585576110846004356116d581610574565b602435906116e48233836138e2565b613f66565b346105855760203660031901126105855760043561170681610574565b604051632474521560e21b81527f025d8bbf3268be680d2605ebf6da15063b9915615bf1087dab336efc1bf970cb60048201523360248201526020816044816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa908115610bd7575f916117a1575b501561178e5761108490613132565b630a4510f960e31b5f523360045260245ffd5b6117c3915060203d6020116117c9575b6117bb818361122b565b81019061311d565b5f61177f565b503d6117b1565b34610585576040366003190112610585576117ec600435610d43565b60206040515f8152f35b346105855760203660031901126105855760043561181381610574565b60018060a01b03165f52600c602052602060405f2054604051908152f35b346105855760a03660031901126105855761184b3661094c565b506064356001600160401b0381116105855761186b90369060040161095d565b5050602060843561187b81610574565b6040516001600160a01b0390911630148152f35b34610585576020366003190112610585576020610e2a60036004356118b381610574565b5f816013614d6c565b34610585575f366003190112610585576119606118f87f0000000000000000000000000000000000000000000000000000000000000000614deb565b6119217f0000000000000000000000000000000000000000000000000000000000000000614e44565b6020604051611930828261122b565b5f81528161196e81830194601f198301368737604051978897600f60f81b895260e0858a015260e0890190610601565b908782036040890152610601565b914660608701523060808701525f60a087015285830360c087015251918281520192915f5b8281106119a257505050500390f35b835185528695509381019392810192600101611993565b34610585575f36600319011261058557602060405160068152f35b34610585576020366003190112610585576004356119f181610574565b604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610bd7575f91611a79575b5015611a66576110849061324b565b630ea7d7ed60e21b5f523360045260245ffd5b611a92915060203d6020116117c9576117bb818361122b565b5f611a57565b34610585575f366003190112610585575f546040516001600160a01b039091168152602090f35b34610585576020366003190112610585574265ffffffffffff1660043581811015611bc257611aed9061401a565b600f54905f829160058411611b69575b611b099350600f614fd9565b80611b2e575061068d5f5b6040516001600160d01b0390911681529081906020820190565b611b3a61068d91613c8f565b600f5f527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802015460301c611b14565b9192611b7481614e7b565b8103908111611bbd57611b0993600f5f5265ffffffffffff8260205f2001541665ffffffffffff8516105f14611bab575091611afd565b929150611bb790614049565b90611afd565b612f64565b637669fc0f60e11b5f5260045260245260445ffd5b34610585575f36600319011261058557602060405165ffffffffffff42168152f35b34610585575f36600319011261058557602060405163ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b6004359064ffffffffff8216820361058557565b6024359064ffffffffff8216820361058557565b3461058557602036600319011261058557611c7a611c39565b604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610bd7575f91611cef575b5015611a66576110849061328f565b611d08915060203d6020116117c9576117bb818361122b565b5f611ce0565b3461058557604036600319011261058557600435611d2b81610574565b60243580611d6857506001600160a01b03165f908152600e602090815260409091206001600160d01b0390611d5f90615035565b16604051908152f35b611d7490602092613bab565b610e2a565b34610585575f366003190112610585576040515f600954611d9981611123565b80845290600181169081156106ef5750600114611dc05761068d836106818185038261122b565b60095f9081527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af939250905b808210611e0457509091508101602001610681610671565b919260018160209254838588010152019101909291611dec565b34610585575f3660031901126105855760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610585576020366003190112610585576020610e2a611ebd600435611e7d81610574565b611eb76003611ea4611e9f8460018060a01b03165f52600e60205260405f2090565b615035565b6001600160d01b0316925f8160136153c3565b9061597d565b615a12565b604051906107b860408361122b565b604051906107b860a08361122b565b60643590600282101561058557565b60043590600282101561058557565b346105855760a03660031901126105855760405160a08101908082106001600160401b0383111761120b5761108491604052611f3960043590565b8152611f43611c4d565b60208201526044356040820152611f58611ee0565b6060820152608435611f6981610574565b60808201526132dc565b3461058557602036600319011261058557600435604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610bd7575f91611ffc575b5015611a6657611084906133a6565b612015915060203d6020116117c9576117bb818361122b565b5f611fed565b34610585575f3660031901126105855760206040515f8152f35b34610585575f3660031901126105855760206040517fb00be3d6a5434b97b328543d1486d56adcb7e74080170d1cdd7e0306c3d9ba3d8152f35b346105855760403660031901126105855761073d60043561208f81610574565b602435903361399a565b34610585575f36600319011261058557604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610bd7575f9161211d575b5015611a6657611084613405565b612136915060203d6020116117c9576117bb818361122b565b5f61210f565b34610585575f366003190112610585576015546301e187e08102908082046301e187e01490151715611bbd57602090604051908152f35b34610585575f366003190112610585576002546040516001600160a01b039091168152602090f35b906020600319830112610585576004356001600160401b0381116105855760040182601f82011215610585578035926001600160401b038411610585576020808301928560051b010111610585579190565b34610585576121fb3661219b565b90612204613a69565b61220d82612f43565b9061221b604051928361122b565b828252602082019260051b8101903682116105855780935b8285106122435761108484614398565b84356001600160401b03811161058557820190606082360312610585576040519161226d83611210565b803561227881610d43565b835261228660208201611101565b60208401526040810135906001600160401b03821161058557019036601f83011215610585576020926122c0849336908581359101613485565b6040820152815201940193612233565b346105855760203660031901126105855763ffffffff6004356122f281610d43565b165f526001602052602060405f2054604051908152f35b346105855760603660031901126105855760043561232681610d43565b61232e6110f0565b604435906001600160401b0382116105855761068d926123556112b393369060040161095d565b92909161354a565b6123663661219b565b5f5b8181106123d557604051638e9e709960e01b81525f81600481335afa8015610bd7576123af915f916123b3575b50604051638351eea760e01b815291829160048301610625565b0390fd5b6123cf91503d805f833e6123c7818361122b565b8101906136ef565b82612395565b6123e0818385613600565b9061241061240c6123f084612f5a565b60208501359063ffffffff165f52600160205260405f20541490565b1590565b6124a85760c08201359160a081013561242d610100830183613628565b94909161243c60e0850161365a565b9361244b610120820182613628565b959095303b15610585575f96612478926040519a8b9889978897633411683760e21b895260048901613675565b0391305af1918215610bd757600192612494575b505b01612368565b80610bcb5f6124a29361122b565b5f61248c565b6001915061248e565b34610585575f36600319011261058557602060ff601854166040519015158152f35b34610585575f3660031901126105855760206040517f025d8bbf3268be680d2605ebf6da15063b9915615bf1087dab336efc1bf970cb8152f35b6064359060ff8216820361058557565b6084359060ff8216820361058557565b346105855760c03660031901126105855760043561254a81610574565b6024359060443561255961250d565b6084359060a4359280421161261757916125de93916125d06125d59460405160208101917fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf835260018060a01b038a1660408301528a60608301526080820152608081526125c860a08261122b565b51902061448d565b61505f565b909291926150e1565b6125e781614821565b8093036125f85761108492506144c2565b90506301d4b62360e61b5f5260018060a01b031660045260245260445ffd5b632341d78760e11b5f5260045260245ffd5b9160806107b8929493612669604060c0830197805184526001600160401b0360208201511660208501520151604083019060208091805184520151910152565b019060208091805184520151910152565b6080366003190112610585576004356001600160401b038111610585576126a5903690600401610748565b604036602319011261058557606435906126be82610574565b6126c6613751565b506126cf612f2b565b506126e66001600160a01b03602083013516610a67565b6126f561240c60185460ff1690565b90816127e0575b816127cc575b506127bd5761274e916127286040830135606084013561272185612f5a565b91336146a8565b9390916127358585613dbd565b61273e86612f5a565b9161274836613777565b92614731565b917f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a612778611ec2565b9483865280602087015261278d855193612f5a565b6040805163ffffffff9290921682526020820195909552938401523392606090a361068d60405192839283612629565b638cd22d1960e01b5f5260045ffd5b6001600160a01b031633141590505f612702565b905061280961240c6128028360018060a01b03165f52601960205260405f2090565b5460ff1690565b906126fc565b34610585575f60203660031901126105855760043561282d81610574565b612835613a69565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b156105855760405163ca5eb5e160e01b81526001600160a01b039091166004820152905f908290602490829084905af18015610bd7576128a0575080f35b61108491505f9061122b565b34610585575f3660031901126105855760206040515f516020615f775f395f51905f528152f35b6128dc3661098a565b50505092903033036128f557610a73610a6785836148a8565b63029a949d60e31b5f5260045ffd5b34610585576020366003190112610585577fd48d879cef83a1c0bdda516f27b13ddb1b3f8bbac1c9e1511bb2a659c2427760602060043561294481610574565b61294c613a69565b600280546001600160a01b0319166001600160a01b03929092169182179055604051908152a1005b346105855760e03660031901126105855760043561299181610574565b60243561299d81610574565b60443590606435926129ad61251d565b60a43560c43590864211612a7457612a3992612a346129cb86614821565b9860405160208101917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9835260018060a01b0389169b8c604084015260018060a01b038b1660608401528b608084015260a083015260c082015260c081526125c860e08261122b565b6144b3565b936001600160a01b03851603612a53576110849350614843565b6325c0072360e11b5f526001600160a01b038085166004521660245260445ffd5b8663313c898160e11b5f5260045260245ffd5b34610585576040366003190112610585576020612ad0600435612aa981610574565b60243590612ab682610574565b6001600160a01b03165f90815260068452604090206105a2565b54604051908152f35b34610585575f366003190112610585576012546040516001600160a01b039091168152602090f35b3461058557602036600319011261058557612b1a611eef565b604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610bd7575f91612b8f575b5015611a66576110849061379f565b612ba8915060203d6020116117c9576117bb818361122b565b5f612b80565b3461058557602036600319011261058557600435612bcb81610574565b604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610bd7575f91612c40575b5015611a6657611084906137e5565b612c59915060203d6020116117c9576117bb818361122b565b5f612c31565b34610585575f36600319011261058557602064ffffffffff60145416604051908152f35b3461058557602036600319011261058557600435612ca081610574565b604051632474521560e21b81527fb00be3d6a5434b97b328543d1486d56adcb7e74080170d1cdd7e0306c3d9ba3d60048201526001600160a01b03918216602482015290602090829060449082907f0000000000000000000000000000000000000000000000000000000000000000165afa8015610bd75761068d915f91612d36575b5060405190151581529081906020820190565b612d4f915060203d6020116117c9576117bb818361122b565b5f612d23565b346105855760403660031901126105855761068d612dbb600435612d7881610574565b60243590612d8582610d43565b612d8d612f2b565b50612d96612f2b565b506001600160a01b03165f908152600e60205260409020612db5612f2b565b506153ae565b5060405190612dc9826111f0565b5465ffffffffffff811680835260309190911c60209283019081526040805192835290516001600160d01b031692820192909252918291820190565b3461058557602036600319011261058557600435612e2281610574565b612e2a613a69565b6001600160a01b03168015612e7b575f80546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b631e4fbdf760e01b5f525f60045260245ffd5b34610585576040366003190112610585576020610e2a600435612eb081610574565b60243590613caa565b34610585576020366003190112610585576020610e2a6003600435612edd81610574565b5f8160136153c3565b34610585576060366003190112610585576020612f023661094c565b63ffffffff8135612f1281610d43565b165f52600182528160405f205491013560405191148152f35b60405190612f38826111f0565b5f6020838281520152565b6001600160401b03811161120b5760051b60200190565b3561063681610d43565b634e487b7160e01b5f52601160045260245ffd5b81810292918115918404141715611bbd57565b8115612f95570490565b634e487b7160e01b5f52601260045260245ffd5b6001600160401b03811161120b57601f01601f191660200190565b63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168046036130d957506001600160a01b03811615908161304c575b6107b8911580613023575b156140105761301e81614c9f565b614010565b506001600160a01b0381165f9081526013602052604090206001015464ffffffffff1615613010565b60125461306390610a67906001600160a01b031681565b602060405180926370a0823160e01b825281806130833360048301610911565b03915afa908115610bd7575f916130aa575b501561300557630e7ae57960e01b5f5260045ffd5b6130cc915060203d6020116130d2575b6130c4818361122b565b8101906130ef565b5f613095565b503d6130ba565b6322a45b8960e21b5f524660045260245260445ffd5b90816020910312610585575190565b6040513d5f823e3d90fd5b634e487b7160e01b5f52602160045260245ffd5b90816020910312610585575161063681610e82565b7f7d4f30fa682bd557f547a1f7245a280525fd183bdb54917c56ec7ef22e5b532a9061315d81614c9f565b6001600160a01b0381165f90815260136020526040902060018101805491929161318e9064ffffffffff1642613c9d565b928054936131af6131a560145464ffffffffff1690565b64ffffffffff1690565b1061322d575b6001600160a01b0383165f908152601760205260409020613209929185916131ef906001600160e01b038416904263ffffffff16906156ea565b505055805464ffffffffff19164264ffffffffff16179055565b604080516001600160a01b039092168252602082019290925290819081015b0390a1565b9250613209906132426003845f8160136153c3565b939091506131b5565b6001600160a01b03165f818152601960205260408120805460ff191690557f535611fb62fa2a833988f283b779e417e996813e44046f521d76c17b5943b08c9080a2565b602064ffffffffff7f9ec539ec1ff2fdcda111a25f0c7d902ff0205d74dfaa05f434eecc8cdea9e8b1926132c281614064565b168064ffffffffff196014541617601455604051908152a1565b6132e4613a69565b60ff601a5416613389578061337060406133779301613303815161409e565b61335b61334f602085019261331f64ffffffffff855116614064565b6080860151601180546001600160a01b0319166001600160a01b0392909216919091179055516301e187e0900490565b915164ffffffffff1690565b9060608401519161336b83613397565b6140c2565b513361410c565b6107b8600160ff19601a541617601a55565b62dc149f60e41b5f5260045ffd5b600211156133a157565b613109565b6301e187e0906133b58161409e565b04670de0b6b3a764000081116133f6576020817f179ae38251712f92ada204166c624f1fd16102c85f82e13348393a898b04e9d292601555604051908152a1565b630678582160e51b5f5260045ffd5b60185460ff8116613476577f000000000000000000000000000000000000000000000000000000000000000042106134675760ff19166001176018557feadb24812ab3c9a55c774958184293ebdb6c7f6a2dbab11f397d80c86feb65d35f80a1565b63be5fb0cb60e01b5f5260045ffd5b6385e1a58160e01b5f5260045ffd5b92919261349182612fa9565b9161349f604051938461122b565b829481845281830111610585578281602093845f960137010152565b909291928360021161058557831161058557600201916001190190565b805191908290602001825e015f815290565b61350493926107b8928160405196879460208601906134d8565b918237015f815203601f19810184528361122b565b908060209392818452848401375f828201840152601f01601f1916010190565b916020610636938181520191613519565b6112a06112ac9263ffffffff61357b9397959697165f52600360205260405f209061ffff165f5260205260405f2090565b8051156135de5783156135d85760028410156135af5750506123af604051928392639a6d49cd60e01b845260048401613539565b9092806135d291610636946135cd6135c8368484613485565b614455565b6134bb565b916134ea565b92509050565b509190610636913691613485565b634e487b7160e01b5f52603260045260245ffd5b91908110156136235760051b8101359061013e1981360301821215610585570190565b6135ec565b903590601e198136030182121561058557018035906001600160401b0382116105855760200191813603831361058557565b3561063681610574565b6001600160401b0381160361058557565b9290936136d1926001600160401b0360406106369a98999763ffffffff813561369d81610d43565b1688526020810135602089015201356136b581613664565b166040860152606085015260e0608085015260e0840191613519565b6001600160a01b0390941660a082015280840360c090910152613519565b602081830312610585578051906001600160401b038211610585570181601f820112156105855780519061372282612fa9565b92613730604051948561122b565b8284526020838301011161058557815f9260208093018386015e8301015290565b6040519061375e82611210565b815f81525f60208201526040613772612f2b565b910152565b60409060231901126105855760405190613790826111f0565b60243582526044356020830152565b60028110156133a15760207f7b7c2a74bf19219346c0b038bc25beb1372ff76eb0b6fe50ba0433b4ac9842799160ff8019601654169116809117601655604051908152a1565b6001600160a01b03165f818152601960205260408120805460ff191660011790557f4f783c179409b4127238bc9c990bc99b9a651666a0d20b51d6c42849eb88466d9080a2565b61385b90610f167f00000000000000000000000000000000000000000000000000000000000000008092612f8b565b9182918084106138685750565b836371c4efed60e01b5f5260045260245260445ffd5b63ffffffff16805f52600160205260405f205490811561389c575090565b63f6ff4fb760e01b5f5260045260245ffd5b3561063681613664565b610636939260809260018060a01b0316825260208201525f60408201528160608201520190610601565b6001600160a01b03165f818152600660205260409020919290916139079084906105a2565b5460018101613917575b50505050565b818110613979578215613966576001600160a01b0384161561395357613949925f526006602052039160405f206105a2565b555f808080613911565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b83637dc7a0d960e11b5f5260018060a01b031660045260245260445260645ffd5b6001600160a01b038116939291908415613a56576001600160a01b0382168015613a43576139c883836154de565b156127bd576139d682610589565b5495848710613a1d57846107b89697036139ef84610589565b556139f984610589565b8054860190556040518581525f516020615f975f395f51905f5290602090a3615b80565b63391434e360e21b5f526001600160a01b0383166004526024879052604485905260645ffd5b63ec442f0560e01b5f525f60045260245ffd5b634b637e8f60e11b5f525f60045260245ffd5b5f546001600160a01b03163303613a7c57565b63118cdaa760e01b5f523360045260245ffd5b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480613b82575b15613aea577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a08152613b7c60c08261122b565b51902090565b507f00000000000000000000000000000000000000000000000000000000000000004614613ac1565b65ffffffffffff421680831015613c7957506001600160a01b03165f908152600e6020526040902090613bdd9061401a565b8154905f829160058411613c26575b613bf7935084614fd9565b80613c0c5750505f5b6001600160d01b031690565b613c1590613c8f565b905f5260205f20015460301c613c00565b9192613c3181614e7b565b8103908111611bbd57613bf793855f5265ffffffffffff8260205f2001541665ffffffffffff8516105f14613c67575091613bec565b929150613c7390614049565b90613bec565b82637669fc0f60e11b5f5260045260245260445ffd5b5f19810191908211611bbd57565b91908203918211611bbd57565b60165490613cc2600883901c64ffffffffff166131a5565b90818410613d9057613cd59060176105a2565b6001600160e01b0390613cef9063ffffffff861690614992565b169283613d8a57613d01929350613c9d565b613d146131a560145464ffffffffff1690565b9182821115613d7b5760ff16613d2981613397565b80613d455750613d3f6106369260155492613c9d565b90614b25565b80613d51600192613397565b03613d6c57613d666106369260155492613c9d565b90614a0c565b6346b2fddf60e11b5f5260045ffd5b505050670de0b6b3a764000090565b50505090565b505050505f90565b9091613daf61063693604084526040840190610601565b916020818403910152610601565b9091613e22613e4893613e05613df96020860135927f000000000000000000000000000000000000000000000000000000000000000090612f8b565b6001600160401b031690565b613e1c613e1560a0870187613628565b3691613485565b91614c30565b93909283945f14613eb4576002905b612355613e3d82612f5a565b916080810190613628565b60045490926001600160a01b03909116908382613e6457505050565b60405163043a78eb60e01b815292602092849283918291613e889160048401613d98565b03915afa8015610bd757613e995750565b613eb19060203d6020116117c9576117bb818361122b565b50565b600190613e31565b919082604091031261058557604051613ed4816111f0565b6020808294805184520151910152565b906040828203126105855761063691613ebc565b906020909392936040835263ffffffff81511660408401528181015160608401526080613f4c613f36604084015160a08488015260e0870190610601565b6060840151868203603f190160a0880152610601565b910151151560c08401526001600160a01b03909416910152565b6001600160a01b0381168015613a5657613f805f836154de565b156127bd57613f8e82610589565b54838110613fd257915f8092856107b8969503613faa84610589565b556007805486900390556040518581525f516020615f975f395f51905f5290602090a3615b80565b63391434e360e21b5f526001600160a01b038316600452602452604483905260645ffd5b61400864ffffffffff926001926105a2565b015416151590565b6107b890336144c2565b65ffffffffffff81116140325765ffffffffffff1690565b6306dfcc6560e41b5f52603060045260245260445ffd5b9060018201809211611bbd57565b91908201809211611bbd57565b64ffffffffff1662278d0081108015614091575b61407f5750565b6344aa7c4560e01b5f5260045260245ffd5b506301e187e08111614078565b6706f05b59d3b2000081116140b05750565b6306f18fc760e31b5f5260045260245ffd5b64ffffffffff1664ffffffffff19601454161760145560155560028110156133a1576016805465ffffffffffff191660ff92909216919091174260081b65ffffffffff0016179055565b91906001600160a01b0383168015613a4357614128845f6154de565b156127bd5761414161413c83600754614057565b600755565b61414a84610589565b8054830190556040518281525f905f516020615f975f395f51905f5290602090a3600754926001600160d01b038085116141cf575061418b9293505f615b80565b7f00000000000000000000000000000000000000000000000000000000000000006007548181116141ba575050565b63279e7e1560e21b5f5260045260245260445ffd5b630e58ae9360e11b5f52600485905260245260445ffd5b80518210156136235760209160051b010190565b601f821161420757505050565b5f5260205f20906020601f840160051c8301931061423f575b601f0160051c01905b818110614234575050565b5f8155600101614229565b9091508190614220565b91909182516001600160401b03811161120b576142708161426a8454611123565b846141fa565b6020601f82116001146142af5781906142a09394955f926142a4575b50508160011b915f199060031b1c19161790565b9055565b015190505f8061428c565b601f198216906142c2845f5260205f2090565b915f5b8181106142fc575095836001959697106142e4575b505050811b019055565b01515f1960f88460031b161c191690555f80806142da565b9192602060018192868b0151815501940192016142c5565b602081016020825282518091526040820191602060408360051b8301019401925f915b83831061434657505050505090565b9091929394602080614389600193603f19868203018752606060408b5163ffffffff815116845261ffff8682015116868501520151918160408201520190610601565b97019301930191939290614337565b5f5b815181101561442357806143bd60406143b5600194866141e6565b510151614455565b61441d60406143cc83866141e6565b51015163ffffffff6143de84876141e6565b5151165f52600360205261441860405f2061440860206143fe878a6141e6565b51015161ffff1690565b61ffff165f5260205260405f2090565b614249565b0161439a565b506132287fbe4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b6749160405191829182614314565b600361ffff600283015116036144685750565b604051639a6d49cd60e01b8152602060048201529081906123af906024830190610601565b604290614498613a8f565b906040519161190160f01b8352600283015260228201522090565b9161063693916125d59361505f565b6001600160a01b038181165f818152600d6020526040812080548685166001600160a01b03198216811790925594959490931693929184917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9080a461452783610589565b5460125461453f90610a67906001600160a01b031681565b93602060405180966370a0823160e01b825281806145608660048301610911565b03915afa948515610bd7575f95614687575b5060115461458a90610a67906001600160a01b031681565b60405163baf3510760e01b8152602081806145a88660048301610911565b0381855afa908115610bd7575f91614668575b506001600160a01b031615614654576145ed9291602091604051808096819463baf3510760e01b835260048301610911565b03915afa8015610bd7576107b89561461361461a9261461f955f91614625575b50610589565b5492614057565b614057565b91615172565b614647915060203d60201161464d575b61463f818361122b565b81019061515d565b5f61460d565b503d614635565b505061461f9061461a6107b8955f92614057565b614681915060203d60201161464d5761463f818361122b565b5f6145bb565b6146a191955060203d6020116130d2576130c4818361122b565b935f614572565b939192506146db90610f167f00000000000000000000000000000000000000000000000000000000000000008092612f8b565b9180831061102957506107b8828094613f66565b906080828203126105855761472990604080519361470c85611210565b80518552602081015161471e81613664565b602086015201613ebc565b604082015290565b61478e608094926147aa9694614745613751565b5060206147528651615294565b950191825180614812575b506147678561387e565b9251151592614777610f5e611ed1565b602086015260408501526060840152151585830152565b6040518095819482936302637a4560e41b845260048401613ef8565b03917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1908115610bd7575f916147e9575090565b610636915060803d60801161480b575b614803818361122b565b8101906146ef565b503d6147f9565b61481b906152b1565b5f61475d565b6001600160a01b03165f908152600c6020526040902080546001810190915590565b6001600160a01b0316908115613966576001600160a01b038116928315613953578061489b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92593855f52600660205260405f206105a2565b55604051908152602090a3565b90602011610585573590565b90602811610585576020013560c01c90565b610636906001600160401b037f00000000000000000000000000000000000000000000000000000000000000009116612f78565b816001600160a01b03821615614914575b6106369161410c565b61dead915061490b565b9080602811610585576106369136916027190190602801613485565b60405160c09190911b6001600160c01b031916602082015260e09190911b6001600160e01b0319166028820152602c8101919091529061063690829061498490604c8301906134d8565b03601f19810183528261122b565b9081549063ffffffff5f91165b8282106149cb575050806149b35750505f90565b6149bc90613c8f565b905f5260205f20015460201c90565b90916149d7818461579f565b90845f528263ffffffff8360205f20015416115f146149f95750915b9061499f565b925060018101809111156149f357612f64565b9080158015614aa0575b614a9257670de0b6b3a7640000821015614a7f5781670de0b6b3a7640000148015614a85575b614a7f57614a5391670de0b6b3a76400000361555c565b8015614a7a57614a6b90670de0b6b3a764000061597d565b8015614a7a57610636906155b5565b505f90565b50505f90565b5063ffffffff8111614a3c565b5050670de0b6b3a764000090565b508115614a16565b9180158015614b1d575b614b1857670de0b6b3a7640000821015614b04578215614b045781670de0b6b3a7640000148015614b0b575b614b0457614af591670de0b6b3a76400000361555c565b8015614a7f57614a6b9161597d565b5050505f90565b5063ffffffff8111614ade565b505090565b508115614ab2565b81158015614ba9575b614a9257670de0b6b3a7640000811015614a7f57801580159081614b90575b50614a7f5702670de0b6b3a7640000811015614a7a57614b8261063691670de0b6b3a764000003670de0b6b3a7640000612f78565b670de0b6b3a7640000900490565b9050612f955780670de0b6b3a76400000482115f614b4d565b508015614b2e565b919081158015614c28575b614b1857670de0b6b3a7640000811015614b04578215614b0457801580159081614c0f575b50614b045702670de0b6b3a7640000811015614a7f5761063691614b8291670de0b6b3a76400000390612f78565b9050612f955780670de0b6b3a76400000482115f614be1565b508015614bbc565b82511580159390614c735790614984614c7092604051948593602085015260018060c01b03199060c01b16604084015233604884015260688301906134d8565b91565b509060405191602083015260018060c01b03199060c01b16604082015260288152614c7060488261122b565b6001600160a01b0381165f9081526013602052604090206001015464ffffffffff1615614cc95750565b6132287f9b44a2c7f9f0b5aa4e7da60d8a2325796c57f93a45559d66515743ffbd8a610391614d43604051614cfd816111f0565b670de0b6b3a76400008152600164ffffffffff602083018142168152614d248660136105a2565b93518455511691019064ffffffffff1664ffffffffff19825416179055565b614d5e614d518260176105a2565b63ffffffff421690615610565b505060405191829182610911565b939291906001600160a01b038116908115614de157614d8b9085615f3e565b906001600160a01b03808316919085168214614dd7578115918215614dcd575b5050614dc55760018201809211611bbd5761063694614d6c565b509250505090565b1490505f80614dab565b5050509250505090565b5050505050505f90565b60ff8114614e315760ff811690601f8211614e225760405191614e0f60408461122b565b6020808452838101919036833783525290565b632cd44ac360e21b5f5260045ffd5b50604051610636816112ac81600a61115b565b60ff8114614e685760ff811690601f8211614e225760405191614e0f60408461122b565b50604051610636816112ac81600b61115b565b600181111561063657806001600160801b821015614f9c575b614f42614f38614f2e614f24614f1a614f10614eff614f49976004614f4e9a600160401b811015614f8f575b640100000000811015614f82575b62010000811015614f75575b610100811015614f68575b6010811015614f5b575b1015614f53575b60030260011c90565b614f09818b612f8b565b0160011c90565b614f09818a612f8b565b614f098189612f8b565b614f098188612f8b565b614f098187612f8b565b614f098186612f8b565b8093612f8b565b821190565b900390565b60011b614ef6565b60041c9160021b91614eef565b60081c9160041b91614ee5565b60101c9160081b91614eda565b60201c9160101b91614ece565b60401c9160201b91614ec0565b5050614f4e614f49614f42614f38614f2e614f24614f1a614f10614eff614fc38a60801c90565b9850600160401b9750614e949650505050505050565b905b838310614fe85750505090565b909192614ff5818561579f565b90835f5265ffffffffffff8260205f2001541665ffffffffffff8416105f146150225750925b9190614fdb565b9350600181018091111561501b57612f64565b805490816150435750505f90565b815f19810111611bbd575f525f199060205f2001015460301c90565b91906fa2a8918ca85bafe22016d0b997e4df60600160ff1b0384116150cc579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610bd7575f516001600160a01b038116156150c257905f905f90565b505f906001905f90565b5050505f9160039190565b600411156133a157565b6150ea816150d7565b806150f3575050565b6150fc816150d7565b600181036151135763f645eedf60e01b5f5260045ffd5b61511c816150d7565b60028103615137575063fce698f760e01b5f5260045260245ffd5b806151436003926150d7565b1461514b5750565b6335e2f38360e21b5f5260045260245ffd5b90816020910312610585575161063681610574565b6001600160a01b0380831693929190811690818514158061528b575b61519a575b5050505050565b8161521e575b5050826151af575b8080615193565b6001600160a01b03165f908152600e602052604090207fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724916151fb916151f590916157b4565b90615818565b604080516001600160d01b039384168152919092166020820152a25f80806151a8565b6001600160a01b03165f908152600e602052604090207fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7249061526990615263866157b4565b906157e5565b604080516001600160d01b039384168152919092166020820152a25f806151a0565b5083151561518e565b80340361529e5790565b6304fb820960e51b5f523460045260245ffd5b60405163393f876560e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690602081600481855afa908115610bd7575f9161538f575b506001600160a01b0316918215615380576020915f9160405190848201926323b872dd60e01b8452336024840152604483015260648201526064815261534760848261122b565b519082855af1156130fe575f513d6153775750803b155b6153655750565b635274afe760e01b5f5260045260245ffd5b6001141561535e565b6329b99a9560e11b5f5260045ffd5b6153a8915060203d60201161464d5761463f818361122b565b5f615300565b8054821015613623575f5260205f2001905f90565b93909290916001600160a01b038416908115614de1576002811015614de1576153ec8585615f3e565b916001600160a01b03808416919085168214806154d5575b6154c55781151591826154ba575b5050806154aa575b615493575050505061542f61240c8284613ff6565b61543c576106369161587f565b5060038101546106369161546361545d600884901c64ffffffffff166131a5565b42613c9d565b9064ffffffffff61548b6154846001600285015494015464ffffffffff1690565b9460ff1690565b9316916158c7565b61063695929394506154a490614049565b916153c3565b506154b58287613ff6565b61541a565b141590505f80615412565b505050509150506106369161587f565b50821515615404565b6001600160a01b03168015801561554b575b6155445760ff60185416615544575f52601960205260ff60405f205416908115615523575b5061551e575f90565b600190565b6001600160a01b03165f9081526019602052604081205460ff169150615515565b5050600190565b506001600160a01b038216156154f0565b8060018316156155a6575b9160011c90815b61557757505090565b806155819161597d565b9060018116615595575b60011c908161556e565b91816155a09161597d565b9161558b565b50670de0b6b3a7640000615567565b670de0b6b3a764000061063691615ac2565b8054600160401b81101561120b576155e4916001820181556153ae565b61560b57815160209283015190921b63ffffffff191663ffffffff92909216919091179055565b611110565b805490919080156156cc5761562761563291613c8f565b835f5260205f200190565b9081549261564d6156468563ffffffff1690565b9460201c90565b9363ffffffff80841691168181116156bd5703615689575050805463ffffffff166503782dace9d960321b1790555b90670de0b6b3a764000090565b6156b892506156a5615699611ec2565b63ffffffff9093168352565b670de0b6b3a764000060208301526155c7565b61567c565b632520601d60e01b5f5260045ffd5b506156dc916156a5615699611ec2565b5f90670de0b6b3a764000090565b805492939280156157755761570161570c91613c8f565b825f5260205f200190565b8054602081901c9363ffffffff918216929181168084116156bd5787930361574f575061574b92509063ffffffff82549181199060201b169116179055565b9190565b91505061574b91615761615699611ec2565b6001600160e01b03861660208301526155c7565b509061579a91615786615699611ec2565b6001600160e01b03851660208301526155c7565b5f9190565b90808216911860011c8101809111611bbd5790565b6001600160d01b0381116157ce576001600160d01b031690565b6306dfcc6560e41b5f5260d060045260245260445ffd5b906157ef82615035565b6001600160d01b0391821690821603908111611bbd576109f39165ffffffffffff421690615c04565b9061582282615035565b6001600160d01b0391821690821601908111611bbd576109f39165ffffffffffff421690615c04565b615855600f615035565b6001600160d01b0391821690821603908111611bbd576109f3904265ffffffffffff16600f615c04565b9061588a90826105a2565b9064ffffffffff600183015416420390428211611bbd5761063692549160028201549060ff600364ffffffffff6001860154169401541693615930565b9192909280831115615920578203918211611bbd5760028110156133a157806158fd575061063691670de0b6b3a7640000614bb1565b80615909600192613397565b03613d6c5761063691670de0b6b3a7640000614aa8565b50505050670de0b6b3a764000090565b93909280841115615976578303928311611bbd5760028110156133a1578061595c575061063692614bb1565b80615968600192613397565b03613d6c5761063692614aa8565b5050505090565b9091905f1983820983820291828083109203918083039214615a0157670de0b6b3a76400008210156159ea577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b8490635173648d60e01b5f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b905f19670de0b6b3a76400008309670de0b6b3a7640000830290818082109103908082039114615ab257670de0b6b3a7640000811015615a8d57670de0b6b3a7640000807faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b630c740aef60e31b5f526004849052670de0b6b3a7640000602481905260445260645ffd5b50670de0b6b3a764000090049150565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414615b745781841015615b5357670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b630c740aef60e31b5f52600452670de0b6b3a764000060245260445260645ffd5b50906106369250612f8b565b9190615b8c8184615cb7565b615b97838386615d3e565b90159081615bb3575b50615baa57505050565b6107b892615e8b565b9050155f615ba0565b8054600160401b81101561120b57615bd9916001820181556153ae565b61560b57815160209092015160301b65ffffffffffff191665ffffffffffff92909216919091179055565b80549293928015615c9257615701615c1b91613c8f565b8054603081901c9365ffffffffffff918216929181168084116156bd57879303615c5e575061574b92509065ffffffffffff82549181199060301b169116179055565b91505061574b91615c7e615c70611ec2565b65ffffffffffff9093168352565b6001600160d01b0386166020830152615bbc565b509061579a91615ca3615c70611ec2565b6001600160d01b0385166020830152615bbc565b6012546040516376de574360e01b81526001600160a01b039091169190602081600481865afa908115610bd7575f91615d1f575b506001600160a01b03918216911614918215615d0c575b505061551e575f90565b6001600160a01b03161490505f80615d02565b615d38915060203d60201161464d5761463f818361122b565b5f615ceb565b60115490929190615d5990610a67906001600160a01b031681565b602060405180926305e5f31960e21b82528180615d798760048301610911565b03915afa908115610bd7575f91615e6c575b506001600160a01b03811680615e41575050601154615dd693602091615dbb90610a67906001600160a01b031681565b60405180809781946305e5f31960e21b835260048301610911565b03915afa928315610bd7575f93615e20575b506001600160a01b03831680615e0057505050505f90565b6001600160a01b03821614615e185761551e92615e8b565b505050600190565b615e3a91935060203d60201161464d5761463f818361122b565b915f615de8565b9091506001600160a01b03841603615e5b57505050600190565b615e6492615e8b565b5f8080615e18565b615e85915060203d60201161464d5761463f818361122b565b5f615d8b565b9091906001600160a01b03168015615ef2575b6107b8926001600160a01b0316908115615eda575b5f908152600d6020526040808220549282529020546001600160a01b039081169116615172565b615eeb615ee6846157b4565b61584b565b5050615eb3565b615efb826157b4565b615f05600f615035565b6001600160d01b039182169082160193908411611bbd576107b893615f34904265ffffffffffff16600f615c04565b9050509250615e9e565b600314615f5957634e487b7160e01b5f52605160045260245ffd5b6001600160a01b039081165f908152600d6020526040902054169056fe7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220ae5238dc818e8db06a027ff7118af608ea4972536e77bc0dfc25f89cab2d232b64736f6c634300081c003361010080604052346101fc57604081612f808038038091610020828561021b565b8339810103126101fc576100338161023e565b906001600160a01b03906100499060200161023e565b168015610208576040516301ffc9a760e01b815263261c910560e21b6004820152602081602481855afa908115610198575f916101c9575b50156101b7576080526001600160a01b0381169081156101895760c082905260a05260405190610d0c8083016001600160401b038111848210176101a3576020928492612274843981520301905ff08015610198576001600160a01b031660e0523015610189576007546001600160a01b03811661017a576001600160a01b0319163017600755604051612021908161025382396080518181816102530152818161047901528181610a39015281816110fd015261147a015260a05181818161077901528181610d54015281816119650152611c44015260c05181611b03015260e05181818161081601528181610d100152611cda0152f35b6336f62bb160e01b5f5260045ffd5b6334566e4b60e21b5f5260045ffd5b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b6347bd7c1d60e01b5f5260045260245ffd5b90506020813d602011610200575b816101e46020938361021b565b810103126101fc575180151581036101fc575f610081565b5f80fd5b3d91506101d7565b6347bd7c1d60e01b5f525f60045260245ffd5b601f909101601f19168101906001600160401b038211908210176101a357604052565b51906001600160a01b03821682036101fc5756fe60806040526004361015610011575f80fd5b5f3560e01c8063055de2751461159857806318160ddd1461157b578063211dc32d1461154f5780632378bea61461142c57806324ea54f4146113f25780632e17de78146113c25780633d18b912146112e65780633d509c97146110b657806348e5d9f8146110525780635336e38e1461102f5780635eeb2e0f14610f35578063638634ee14610f12578063647654b414610ede57806366e943f114610ea457806369b3054b14610e435780637035ab9814610df3578063705b504a14610dbb57806370a0823114610d8357806372f702f314610d3f57806376de574314610cfb57806377df7b6a14610cd85780637bb7bed114610c88578063a2f1b4c914610c66578063a3cd8ac4146109e3578063a694fc3a14610745578063a89f38a31461070b578063b5fd73f8146106c9578063bcd11014146106a6578063bf199e621461068a578063c00007b01461059f578063c0b534c214610565578063ccc574901461053e578063cecc238f14610515578063dae21dab1461041f578063e70b9e27146103cf578063e9fad8ee146102c8578063ebc136d0146101ea5763f1229777146101bb575f80fd5b346101e65760203660031901126101e65760206101de6101d9611687565b611872565b604051908152f35b5f80fd5b346101e65760203660031901126101e657610203611687565b604051632474521560e21b81527fb00be3d6a5434b97b328543d1486d56adcb7e74080170d1cdd7e0306c3d9ba3d60048201526001600160a01b03918216602482015290602090829060449082907f0000000000000000000000000000000000000000000000000000000000000000165afa80156102bd576020915f91610290575b506040519015158152f35b6102b09150823d84116102b6575b6102a88183611781565b8101906117b7565b82610285565b503d61029e565b6040513d5f823e3d90fd5b346101e6575f3660031901126101e6576102e0611903565b5f805433915b818110610316575f5f516020611fcc5f395f51905f525d335f52600660205261031460405f20543333611c10565b005b80610322600192611d88565b838060a01b0391549060031b1c1661033933611a34565b805f52600460205260405f20855f5260205260405f20548061035e575b5050016102e6565b815f52600460205260405f20865f526020525f60408120556103af60405163a9059cbb60e01b60208201526103a98161039b853360248401611bf5565b03601f198101835282611781565b83611ee2565b6040519081525f516020611f8c5f395f51905f5260203392a38480610356565b346101e65760403660031901126101e6576103e8611687565b6103f061169d565b6001600160a01b039182165f908152600460209081526040808320949093168252928352819020549051908152f35b346101e65760203660031901126101e657610438611687565b604051632474521560e21b81527f025d8bbf3268be680d2605ebf6da15063b9915615bf1087dab336efc1bf970cb60048201523360248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156102bd575f916104f6575b50156104e3576001600160a01b03811690816104c957005b6104d290611938565b905f52600860205260405f20555f80f35b630a4510f960e31b5f523360045260245ffd5b61050f915060203d6020116102b6576102a88183611781565b826104b1565b346101e65760403660031901126101e65761052e611687565b5063f8b964a760e01b5f5260045ffd5b346101e6575f3660031901126101e65760206040515f516020611fac5f395f51905f528152f35b346101e6575f3660031901126101e65760206040517f025d8bbf3268be680d2605ebf6da15063b9915615bf1087dab336efc1bf970cb8152f35b346101e65760203660031901126101e6576105b8611687565b6105c0611903565b6001600160a01b03165f818152600160205260409020541561067b576105e533611a34565b5f81815260046020908152604080832033845290915290205480610616575b5f5f516020611fcc5f395f51905f525d005b815f52600460205260405f2060018060a01b0333165f526020525f604081205561065b60405163a9059cbb60e01b60208201526103a98161039b853360248401611bf5565b6040519081525f516020611f8c5f395f51905f5260203392a38080610604565b63064fed9960e31b5f5260045ffd5b346101e6575f3660031901126101e65760205f54604051908152f35b346101e65760203660031901126101e65760206101de6106c4611687565b61180e565b346101e65760203660031901126101e65760206107016001600160a01b036106ef611687565b165f52600160205260405f2054151590565b6040519015158152f35b346101e6575f3660031901126101e65760206040517fb00be3d6a5434b97b328543d1486d56adcb7e74080170d1cdd7e0306c3d9ba3d8152f35b346101e65760203660031901126101e65760043561076233611aed565b61076b33611a34565b33156109d45780156109c5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031680156109b657604051632c3e6f0f60e11b8152336004820152602081602481855afa9081156102bd575f91610987575b506001600160a01b031615610978576107ec82600554611865565b600555335f52600660205260405f20610806838254611865565b905561081482303384611e9c565b7f00000000000000000000000000000000000000000000000000000000000000009060405160205f81830163095ea7b360e01b81526108698461085b898960248401611bf5565b03601f198101865285611781565b83519082865af15f513d8261095c575b50501561090b575b5050602060405180926317a790f160e11b8252815f816108a5883060048401611bf5565b03926001600160a01b03165af180156102bd576108ee575b5060405190815233907f5dac0c1b1112564a045ba943c9d50270893e8e826c49be8e7073adc713ab7bd760203392a3005b6109069060203d6020116102b6576102a88183611781565b6108bd565b60405163095ea7b360e01b60208201526001600160a01b03841660248201525f604480830191909152815261095592906109509061094a606482611781565b82611ee2565b611ee2565b8280610881565b9091506109705750813b15155b8580610879565b600114610969565b634e66b6bb60e11b5f5260045ffd5b6109a9915060203d6020116109af575b6109a18183611781565b810190611bd6565b836107d1565b503d610997565b63417198d360e01b5f5260045ffd5b636a76ff9f60e01b5f5260045ffd5b63da52720960e01b5f5260045ffd5b346101e65760603660031901126101e6576109fc611687565b6024359060443591604051632474521560e21b81525f516020611fac5f395f51905f52600482015233602482015260208160448160018060a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9081156102bd575f91610c47575b5015610c34575f545f5b818110610bec5750506001600160a01b0382165f818152600260205260409020909390928115610bdd576301da9c008211610bce57610abd855f52600160205260405f2054151590565b15610b715750600283015403610b62575b610ada81303386611e9c565b670de0b6b3a7640000810290808204670de0b6b3a76400001481151715610b4e5782610b43602093610b3260027fac24935fd910bc682b5ccb1a07b718cadf8cf2f6d1404c4f3ddc3662dae40e2997015480926116b3565b600184015542600384015542611865565b9055604051908152a2005b634e487b7160e01b5f52601160045260245ffd5b6333fec8c760e21b5f5260045ffd5b90610b7b85611f3a565b15610bbf577f68e3e9397770d9dfa88c0953a34e1a70a05416b3895957f5b689787a920791c491816002860155610bb760405192839283611bf5565b0390a1610ace565b632b3d7ad960e01b5f5260045ffd5b631fb7569160e21b5f5260045ffd5b637ffcfc9f60e11b5f5260045ffd5b80610bf8600192611d88565b838060a01b0391549060031b1c16805f5260026020526003610c2b60405f2092610c2181611872565b60048501556117cf565b91015501610a73565b630ea7d7ed60e21b5f523360045260245ffd5b610c60915060203d6020116102b6576102a88183611781565b84610a69565b346101e6575f3660031901126101e6576020604051670de0b6b3a76400008152f35b346101e65760203660031901126101e6576004355f54811015610cc957610cb0602091611d88565b905460405160039290921b1c6001600160a01b03168152f35b634e23d03560e01b5f5260045ffd5b346101e6575f3660031901126101e65760206702c68af0bb140000604051908152f35b346101e6575f3660031901126101e6576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101e6575f3660031901126101e6576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101e65760203660031901126101e6576001600160a01b03610da4611687565b165f526006602052602060405f2054604051908152f35b346101e65760203660031901126101e6576001600160a01b03610ddc611687565b165f526008602052602060405f2054604051908152f35b346101e65760403660031901126101e657610e0c611687565b610e1461169d565b6001600160a01b039182165f908152600360209081526040808320949093168252928352819020549051908152f35b346101e65760403660031901126101e65760043560038110156101e657602090610e6b61169d565b604051908382019260f81b835260018060601b03199060601b16602182015260158152610e99603582611781565b519020604051908152f35b346101e6575f3660031901126101e65760206040517f0d186688925976bbe6755ae984501c8e3e2b103a7af59fd803ab9c6d891ae7e08152f35b346101e65760603660031901126101e657610ef7611687565b50604435801515036101e657635f6cc16b60e01b5f5260045ffd5b346101e65760203660031901126101e65760206101de610f30611687565b6117cf565b346101e65760403660031901126101e657610f4e611687565b610f5661169d565b610f5e611903565b6001600160a01b03165f818152600160205260409020549091901561067b57610f8681611a34565b815f52600460205260405f2060018060a01b0382165f5260205260405f20549081610fbd575f5f516020611fcc5f395f51905f525d005b60205f516020611f8c5f395f51905f5291845f526004825260405f2060018060a01b0382165f5282525f604081205561101660405163a9059cbb60e01b848201526110108161039b888660248401611bf5565b86611ee2565b6040519384526001600160a01b031692a3808080610604565b346101e65760203660031901126101e65760206101de61104d611687565b611938565b346101e65760203660031901126101e6576001600160a01b03611073611687565b165f52600260205260a060405f20805490600181015490600281015460046003830154920154926040519485526020850152604084015260608301526080820152f35b346101e65760203660031901126101e6576110cf611687565b604051632474521560e21b81525f516020611fac5f395f51905f5260048201523360248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156102bd575f916112c7575b5015610c34576001600160a01b03165f818152600160205260409020541561067b57805f52600260205260405f20544211156112b8576040516370a0823160e01b8152306004820152602081602481855afa9081156102bd575f91611286575b5060405163313ce56760e01b8152602081600481865afa5f9181611248575b506112165750655af3107a40005b811161120457506111d281611dc7565b1561067b5760207f66257bcef574219c04f7c05f7a1c78d599da10491294c92a5805c48b4cdf500991604051908152a1005b633007cea360e01b5f5260045260245ffd5b60ff1660048111611229575060016111c2565b6003190160ff8111610b4e5760ff16604d8111610b4e57600a0a6111c2565b9091506020813d60201161127e575b8161126460209383611781565b810103126101e6575160ff811681036101e65790846111b4565b3d9150611257565b90506020813d6020116112b0575b816112a160209383611781565b810103126101e6575182611195565b3d9150611294565b63d9ba1add60e01b5f5260045ffd5b6112e0915060203d6020116102b6576102a88183611781565b82611135565b346101e6575f3660031901126101e6576112fe611903565b5f805433915b81811061131d575f5f516020611fcc5f395f51905f525d005b80611329600192611d88565b838060a01b0391549060031b1c1661134033611a34565b805f52600460205260405f20855f5260205260405f205480611365575b505001611304565b815f52600460205260405f20865f526020525f60408120556113a260405163a9059cbb60e01b60208201526103a98161039b853360248401611bf5565b6040519081525f516020611f8c5f395f51905f5260203392a3848061135d565b346101e65760203660031901126101e6576113dc33611a34565b6113e533611aed565b6103146004353333611c10565b346101e6575f3660031901126101e65760206040517f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50418152f35b346101e65760403660031901126101e657611445611687565b604051632474521560e21b81525f516020611fac5f395f51905f526004820152336024828101919091523591906020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156102bd575f91611530575b5015610c34576001600160a01b03165f818152600160205260409020549091901561067b578015610bdd576301da9c008111610bce57815f52600260205260405f2080544211156112b857817fad2f86b01ed93b4b3a150d448c61a4f5d8d38075d3c0c64cc0a26fd6e1f495459260026020930155604051908152a2005b611549915060203d6020116102b6576102a88183611781565b836114b2565b346101e65760403660031901126101e65760206101de61156d611687565b61157561169d565b906116e4565b346101e6575f3660031901126101e6576020600554604051908152f35b346101e65760203660031901126101e6576115b1611687565b6115b9611903565b5f80546001600160a01b0383169290915b8281106115e3575f5f516020611fcc5f395f51905f525d005b806115ef600192611d88565b838060a01b0391549060031b1c1661160684611a34565b805f52600460205260405f20865f526020528560405f20548061162d575b505050016115ca565b60205f516020611f8c5f395f51905f5291845f526004825260405f20845f5282525f604081205561167860405163a9059cbb60e01b848201526110108161039b858d60248401611bf5565b604051908152a3858581611624565b600435906001600160a01b03821682036101e657565b602435906001600160a01b03821682036101e657565b81156116bd570490565b634e487b7160e01b5f52601260045260245ffd5b81810292918115918404141715610b4e57565b61177d9061174b611777670de0b6b3a76400009460018060a01b0384165f5260066020528561175160405f205461174b61171d85611872565b6001600160a01b039586165f818152600360209081526040808320998d168352989052969096205490611801565b906116d1565b04905f52600460205260405f2060018060a01b0385165f5260205260405f205490611865565b91611938565b0490565b90601f8019910116810190811067ffffffffffffffff8211176117a357604052565b634e487b7160e01b5f52604160045260245ffd5b908160209103126101e6575180151581036101e65790565b6001600160a01b03165f818152600260205260409020544210156117f257504290565b5f52600260205260405f205490565b91908203918211610b4e57565b6001600160a01b03165f9081526002602052604090208054670de0b6b3a7640000914282111561185057600161184861177d934290611801565b9101546116d1565b61177d915060026001820154910154906116d1565b91908201809211610b4e57565b60055480156118e557906118dc6118e2926118d760018060a01b038416805f5260026020526118c16118ab600460405f200154966117cf565b825f526002602052600360405f20015490611801565b905f526002602052600160405f200154906116d1565b6116b3565b90611865565b90565b506001600160a01b03165f9081526002602052604090206004015490565b5f516020611fcc5f395f51905f525c6119295760015f516020611fcc5f395f51905f525d565b633ee5aeb560e01b5f5260045ffd5b60405163f56a47a560e01b81526001600160a01b03918216600482018190529091602090839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa9182156102bd575f92611a00575b50805f52600860205260405f2054156119fc576702c68af0bb14000091828102928184041490151715610b4e575f52600860205260405f205490670b1a2bc2ec50000091828102928184041490151715610b4e57670de0b6b3a76400009161177d91611865565b5090565b9091506020813d602011611a2c575b81611a1c60209383611781565b810103126101e65751905f611995565b3d9150611a0f565b5f54905f5b828110611a4557505050565b80611a51600192611d88565b838060a01b0391549060031b1c16805f52600260205260405f20611a7482611872565b90600481019182556003611a87846117cf565b910155838060a01b038516611a9f575b505001611a39565b611aa982866116e4565b825f52600460205260405f20858060a01b0387165f5260205260405f205554905f52600360205260405f20838060a01b0385165f5260205260405f20555f80611a97565b5f906001600160a01b031680611b01575050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156101e6575f8091602460405180948193633e4986ef60e11b83528760048401525af180156102bd57611bc1575b506007546001600160a01b031690813b15611bbd57829160248392604051948593849263dae21dab60e01b845260048401525af18015611bb257611b9d575050565b611ba8828092611781565b611baf5750565b80fd5b6040513d84823e3d90fd5b8280fd5b611bce9192505f90611781565b5f905f611b5b565b908160209103126101e657516001600160a01b03811681036101e65790565b6001600160a01b039091168152602081019190915260400190565b8215611d7957604051632c3e6f0f60e11b81526001600160a01b0383811660048301819052949190602090829060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa9081156102bd575f91611d5a575b506001600160a01b03161561097857602081611cd593611c9682600554611801565b60055560018060a01b031694855f526006835260405f20611cb8838254611801565b905560405163040b850f60e31b8152948592839260048401611bf5565b03815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19081156102bd577fd8654fcc8cf5b36d30b3f5e4688fc78118e6d68de60b9994e09902268b57c3e392602092611d3f575b50604051908152a3565b611d5590833d85116102b6576102a88183611781565b611d35565b611d73915060203d6020116109af576109a18183611781565b5f611c74565b6310356e5960e21b5f5260045ffd5b5f54811015611d9e575f805260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b8054821015611d9e575f5260205f2001905f90565b5f818152600160205260409020548015611e96575f198101818111610b4e575f545f19810191908211610b4e57818103611e4a575b5050505f548015611e36575f1901611e14815f611db2565b8154905f199060031b1b191690555f555f5260016020525f6040812055600190565b634e487b7160e01b5f52603160045260245ffd5b611e80611e5a611e6a935f611db2565b90549060031b1c9283925f611db2565b819391549060031b91821b915f19901b19161790565b90555f52600160205260405f20555f8080611dfc565b50505f90565b6040516323b872dd60e01b60208201526001600160a01b039283166024820152929091166044830152606480830193909352918152611ee091610950608483611781565b565b905f602091828151910182855af1156102bd575f513d611f3157506001600160a01b0381163b155b611f115750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415611f0a565b805f52600160205260405f2054155f14611f86575f54600160401b8110156117a357611f70611e6a8260018594015f555f611db2565b90555f54905f52600160205260405f2055600190565b505f9056fe540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f559b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220b524491f21fce77ebd055b2f250942de09b9c3293355e54b7894dc038b80e6ea64736f6c634300081c003360a0806040523461037b57602081610d0c803803809161001f828561037f565b83398101031261037b57516001600160a01b0381169081900361037b57604051906702bb930b83832b2160c51b60208301526529bab6b6b2b960d11b6028830152600e825261006f602e8361037f565b60405190607760f81b60208301526329aaa6a960e11b60218301526005825261009960258361037f565b82516001600160401b03811161028c57600354600181811c91168015610371575b602082101461026e57601f811161030e575b506020601f82116001146102ab57819293945f926102a0575b50508160011b915f199060031b1c1916176003555b81516001600160401b03811161028c57600454600181811c91168015610282575b602082101461026e57601f811161020b575b50602092601f82116001146101aa57928192935f9261019f575b50508160011b915f199060031b1c1916176004555b30811461018c5760805260405161096990816103a382396080518181816102750152818161033401526107ae0152f35b63438d6fe360e01b5f523060045260245ffd5b015190505f80610147565b601f1982169360045f52805f20915f5b8681106101f357508360019596106101db575b505050811b0160045561015c565b01515f1960f88460031b161c191690555f80806101cd565b919260206001819286850151815501940192016101ba565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610264575b601f0160051c01905b818110610259575061012d565b5f815560010161024c565b9091508190610243565b634e487b7160e01b5f52602260045260245ffd5b90607f169061011b565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100e5565b601f1982169060035f52805f20915f5b8181106102f6575095836001959697106102de575b505050811b016003556100fa565b01515f1960f88460031b161c191690555f80806102d0565b9192602060018192868b0151815501940192016102bb565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c81019160208410610367575b601f0160051c01905b81811061035c57506100cc565b5f815560010161034f565b9091508190610346565b90607f16906100ba565b5f80fd5b601f909101601f19168101906001600160401b0382119082101761028c5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461065557508063095ea7b3146105d357806318160ddd146105b6578063205c2878146104d157806323b872dd146103f15780632f4f21e2146102c9578063313ce567146102a45780636f307dc31461026057806370a082311461022957806395d89b4114610125578063a9059cbb146100f45763dd62ed3e146100a0575f80fd5b346100f05760403660031901126100f0576100b9610737565b6100c161074d565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b5f80fd5b346100f05760403660031901126100f05761011a610110610737565b602435903361082c565b602060405160018152f35b346100f0575f3660031901126100f0576040515f6004548060011c9060018116801561021f575b60208310811461020b578285529081156101e75750600114610189575b6101858361017981850382610763565b6040519182918261070d565b0390f35b60045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106101cd57509091508101602001610179610169565b9192600181602092548385880101520191019092916101b5565b60ff191660208086019190915291151560051b840190910191506101799050610169565b634e487b7160e01b5f52602260045260245ffd5b91607f169161014c565b346100f05760203660031901126100f0576001600160a01b0361024a610737565b165f525f602052602060405f2054604051908152f35b346100f0575f3660031901126100f0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346100f0575f3660031901126100f05760206102be610799565b60ff60405191168152f35b346100f05760403660031901126100f0576102e2610737565b602435903033146103de576001600160a01b0316903082146103cb576103586040516323b872dd60e01b602082015233602482015230604482015282606482015260648152610332608482610763565b7f00000000000000000000000000000000000000000000000000000000000000006108b0565b81156103b857600254908082018092116103a45760205f5160206109145f395f51905f52915f9360025584845283825260408420818154019055604051908152a3602060405160018152f35b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b5063ec442f0560e01b5f5260045260245ffd5b634b637e8f60e11b5f523060045260245ffd5b346100f05760603660031901126100f05761040a610737565b61041261074d565b6001600160a01b0382165f818152600160208181526040808420338552909152909120549193604435939290918101610451575b5061011a935061082c565b8381106104b65784156104a35733156104905761011a945f52600160205260405f2060018060a01b0333165f526020528360405f209103905584610446565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b346100f05760403660031901126100f0576104ea610737565b602435906001600160a01b03163081146105a457331561059157335f525f60205260405f205482811061057657918061011a93335f525f6020520360405f205580600254036002555f6040518281525f5160206109145f395f51905f5260203392a36040519163a9059cbb60e01b60208401526024830152604482015260448152610332606482610763565b905063391434e360e21b5f523360045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd5b63ec442f0560e01b5f5260045260245ffd5b346100f0575f3660031901126100f0576020600254604051908152f35b346100f05760403660031901126100f0576105ec610737565b6024359033156104a3576001600160a01b031690811561049057335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346100f0575f3660031901126100f0575f6003548060011c90600181168015610703575b60208310811461020b578285529081156101e757506001146106a5576101858361017981850382610763565b60035f9081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b8082106106e957509091508101602001610179610169565b9192600181602092548385880101520191019092916106d1565b91607f1691610679565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100f057565b602435906001600160a01b03821682036100f057565b90601f8019910116810190811067ffffffffffffffff82111761078557604052565b634e487b7160e01b5f52604160045260245ffd5b60405163313ce56760e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa5f91816107ee575b506107eb5750601290565b90565b9091506020813d602011610824575b8161080a60209383610763565b810103126100f0575160ff811681036100f057905f6107e0565b3d91506107fd565b6001600160a01b0316908115610591576001600160a01b03169182156103b857815f525f60205260405f205481811061089757815f5160206109145f395f51905f5292602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b905f602091828151910182855af115610908575f513d6108ff57506001600160a01b0381163b155b6108df5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156108d8565b6040513d5f823e3d90fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220262c1e8f42bd9cb42e703818be875d71500d533988631afe0dc244d33ca615cb64736f6c634300081c00330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b000000000000000000000000b0f758323d3798a6a567c1601d84f30d1bcaaa0b000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c250000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000000000000000000067d17b040000000000000000000000000000000000000000000000000000000000002105000000000000000000000000000000000000000000000000000000000000000b42756d6d6572546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642554d4d45520000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806306c933d81461056f57806306fdde031461056a578063095ea7b3146105655780630d35b415146105605780630dce88f41461055b578063111ecdad1461055657806313137d6514610551578063134d4f251461054c578063156a0d0f1461054757806317442b701461054257806318160ddd1461053d5780631f5e13341461053857806323b872dd1461053357806324ea54f41461052e578063313ce567146105295780633400288b14610524578063355274ea1461051f5780633644e5151461051a5780633a46b1a8146105155780633b6f743b14610510578063412290811461050b57806342966c68146105065780634bf5d7e91461050157806352ae2879146103d05780635535d461146104fc578063587cde1e146104f75780635a0dfe4d146104f25780635c19a95c146104ed5780635e280f11146104e857806366e943f1146104e357806369b3054b146104de5780636fc1b31e146104d95780636fcfff45146104d457806370a08231146104cf578063715018a6146104ca57806379cc6790146104c55780637c930dde146104c05780637d25a05e146104bb5780637ecebe00146104b657806382413eac146104b157806382c4e4ca146104ac57806384b0196e146104a7578063857749b0146104a25780638ab1d6811461049d5780638da5cb5b146104985780638e539e8c1461049357806391ddadf41461048e578063929f58401461048957806392a525d514610484578063934cc3101461047f57806395d89b411461047a578063963efcaa146104755780639ab24eb0146104705780639db6468c1461046b5780639de048dc146104665780639f68b96414610461578063a89f38a31461045c578063a9059cbb14610457578063af35c6c714610452578063b5e86d4f1461044d578063b731ea0a14610448578063b98bd07014610443578063bb0b6a531461043e578063bc70b35414610439578063bd815db014610434578063bef97c871461042f578063c0b534c21461042a578063c3cda52014610425578063c7c7f5b314610420578063ca5eb5e11461041b578063ccc5749014610416578063d045a0dc14610411578063d42438851461040c578063d505accf14610407578063dd62ed3e14610402578063defe2053146103fd578063e0cf01ae146103f8578063e43252d7146103f3578063ea4ebdca146103ee578063ebc136d0146103e9578063f1127ed8146103e4578063f2fde38b146103df578063f3cc0393146103da578063f56a47a5146103d5578063fc0c546a146103d05763ff7bd03d146103cb575f80fd5b612ee6565b6110d6565b612eb9565b612e8e565b612e05565b612d55565b612c83565b612c5f565b612bae565b612b01565b612ad9565b612a87565b612974565b612904565b6128d3565b6128ac565b61280f565b61267a565b61252d565b6124d3565b6124b1565b61235d565b612309565b6122d0565b6121ed565b612173565b61213c565b612099565b61206f565b612035565b61201b565b611f73565b611efe565b611e58565b611e1e565b611d79565b611d0e565b611c61565b611bf9565b611bd7565b611abf565b611a98565b6119d4565b6119b9565b6118bc565b61188f565b611831565b6117f6565b6117d0565b6116e9565b6116b5565b61165e565b611623565b6115bb565b61154b565b6114dc565b6114a2565b61145e565b611350565b61130a565b6112c7565b61124c565b611086565b611067565b61103f565b610e8c565b610e32565b610e10565b610dd6565b610d51565b610d28565b610cee565b610cae565b610c93565b610c76565b610c55565b610c2f565b610c14565b6109f7565b610924565b6108d7565b6107f6565b610713565b610639565b6105b7565b6001600160a01b0381160361058557565b5f80fd5b6001600160a01b03165f90815260056020526040902090565b9060018060a01b03165f5260205260405f2090565b34610585576020366003190112610585576004356105d481610574565b60018060a01b03165f526019602052602060ff60405f2054166040519015158152f35b5f91031261058557565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b906020610636928181520190610601565b90565b34610585575f366003190112610585576040515f60085461065981611123565b80845290600181169081156106ef5750600114610691575b61068d836106818185038261122b565b60405191829182610625565b0390f35b60085f9081527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3939250905b8082106106d557509091508101602001610681610671565b9192600181602092548385880101520191019092916106bd565b60ff191660208086019190915291151560051b840190910191506106819050610671565b346105855760403660031901126105855761073d60043561073381610574565b6024359033614843565b602060405160018152f35b908160e09103126105855790565b939291906107728560a081019260208091805184520151910152565b60a06040860152815180915260c0850190602060c08260051b8801019301915f905b8282106107ba57505050509060606107b89294019060208091805184520151910152565b565b909192936020806107e860019360bf198c82030186526040838a518051845201519181858201520190610601565b960192019201909291610794565b34610585576020366003190112610585576004356001600160401b03811161058557610826903690600401610748565b61082e612f2b565b50610837612f2b565b50604051610844816111f0565b5f81526001600160401b036020820152602060405192610864828561122b565b5f8452601f1982015f5b8181106108b45750509061089861068d926040810135610892606083013592612f5a565b5061382c565b90916108a2611ec2565b92835282015260405193849384610756565b83906040516108c2816111f0565b5f81526060838201528282890101520161086e565b34610585575f3660031901126105855760206040517f0000000000000000000000000000000000000000000000000000000067d17b048152f35b6001600160a01b03909116815260200190565b34610585575f366003190112610585576004546040516001600160a01b039091168152602090f35b606090600319011261058557600490565b9181601f84011215610585578235916001600160401b038311610585576020838186019501011161058557565b90600319820160e081126105855760601361058557600491606435916084356001600160401b03811161058557826109c49160040161095d565b9290929160a4356109d481610574565b9160c435906001600160401b038211610585576109f39160040161095d565b9091565b610a003661098a565b50919492915050337f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031603610c01578135610a4281610d43565b610a4b8161387e565b906020840135809203610bdc575050610a73610a6785836148a8565b6001600160a01b031690565b93610a99610a89610a8483856148b4565b6148c6565b610a9285612f5a565b50866148fa565b91610aa48260281090565b610afc575b5050610ad57fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c92612f5a565b6040805163ffffffff92909216825260208201929092526001600160a01b039490941693a3005b9082610b2792610b21610b11604088016138ae565b93610b1b88612f5a565b9261491e565b9261493a565b917f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b0316803b1561058557604051633e5ac80960e11b8152935f918591829084908290610b80908b8d600485016138b8565b03925af1908115610bd7577fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c93610ad592610bbd575b5092610aa9565b80610bcb5f610bd19361122b565b806105f7565b5f610bb6565b6130fe565b80610beb63ffffffff92610d43565b63309afaf360e21b5f521660045260245260445ffd5b6391ac5e4f60e01b5f523360045260245ffd5b34610585575f36600319011261058557602060405160028152f35b34610585575f366003190112610585576040805162b9270b60e21b815260016020820152f35b34610585575f36600319011261058557604080516001815260026020820152f35b34610585575f366003190112610585576020600754604051908152f35b34610585575f36600319011261058557602060405160018152f35b346105855760603660031901126105855761073d600435610cce81610574565b602435610cda81610574565b60443591610ce98333836138e2565b61399a565b34610585575f3660031901126105855760206040517f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50418152f35b34610585575f36600319011261058557602060405160128152f35b63ffffffff81160361058557565b34610585576040366003190112610585577f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b600435610d8f81610d43565b60243590610d9b613a69565b63ffffffff81165f5260016020528160405f2055610dd1604051928392836020909392919363ffffffff60408201951681520152565b0390a1005b34610585575f3660031901126105855760206040517f0000000000000000000000000000000000000000033b2e3c9fd0803ce80000008152f35b34610585575f366003190112610585576020610e2a613a8f565b604051908152f35b34610585576040366003190112610585576020670de0b6b3a7640000610e79600435610e5d81610574565b610e73602435610e6d8184613bab565b92613caa565b90612f78565b04604051908152f35b8015150361058557565b34610585576040366003190112610585576004356001600160401b03811161058557610ebc903690600401610748565b602435610ec881610e82565b610ed0612f2b565b50813591606081013590610f1b6040820135610eeb86610d43565b610f167f000000000000000000000000000000000000000000000000000000e8d4a510008092612f8b565b612f78565b9180831061102957610f9c604086610f8187610f378888613dbd565b90610f4185610d43565b610f49612f2b565b50610f538561387e565b610f6a610f5e611ed1565b63ffffffff9097168752565b602086015285850152606084015215156080830152565b815180938192631bb8518b60e31b8352309060048401613ef8565b03817f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b03165afa8015610bd75761068d915f91610ffa575b5060405191829182815181526020918201519181019190915260400190565b61101c915060403d604011611022575b611014818361122b565b810190613ee4565b82610fdb565b503d61100a565b826371c4efed60e01b5f5260045260245260445ffd5b34610585575f366003190112610585576011546040516001600160a01b039091168152602090f35b346105855760203660031901126105855761108460043533613f66565b005b34610585575f3660031901126105855761068d6040516110a760408261122b565b600e81526d06d6f64653d74696d657374616d760941b6020820152604051918291602083526020830190610601565b34610585575f366003190112610585576020604051308152f35b6024359061ffff8216820361058557565b359061ffff8216820361058557565b634e487b7160e01b5f525f60045260245ffd5b90600182811c92168015611151575b602083101461113d57565b634e487b7160e01b5f52602260045260245ffd5b91607f1691611132565b5f929181549161116a83611123565b80835292600181169081156111bf575060011461118657505050565b5f9081526020812093945091925b8383106111a5575060209250010190565b600181602092949394548385870101520191019190611194565b915050602093945060ff929192191683830152151560051b010190565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761120b57604052565b6111dc565b606081019081106001600160401b0382111761120b57604052565b90601f801991011681019081106001600160401b0382111761120b57604052565b346105855760403660031901126105855761068d6112ac6112b36112a060043561127581610d43565b63ffffffff6112826110f0565b91165f52600360205260405f209061ffff165f5260205260405f2090565b6040519283809261115b565b038261122b565b604051918291602083526020830190610601565b34610585576020366003190112610585576004356112e481610574565b60018060a01b03165f52600d602052602060018060a01b0360405f205416604051908152f35b3461058557604036600319011261058557602061134660043561132c81610d43565b6024359063ffffffff165f52600160205260405f20541490565b6040519015158152f35b346105855760203660031901126105855760043561136d81610574565b3361137c575b61108490612fc4565b7f000000000000000000000000424aa31d64cabd39ea8b133be844d935d666f40e6001600160a01b0316803b15610585575f6040518092633e4986ef60e11b82528183816113cd3360048301610911565b03925af18015610bd75761144a575b506010546113f2906001600160a01b0316610a67565b90813b15610585575f604051809363dae21dab60e01b825281838161141a3360048301610911565b03925af1918215610bd75761108492611436575b509050611373565b80610bcb5f6114449361122b565b5f61142e565b80610bcb5f6114589361122b565b5f6113dc565b34610585575f366003190112610585576040517f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b03168152602090f35b34610585575f3660031901126105855760206040517f0d186688925976bbe6755ae984501c8e3e2b103a7af59fd803ab9c6d891ae7e08152f35b346105855760403660031901126105855760043560038110156105855761068d9060243561150981610574565b60405190602082019260f81b835260018060601b03199060601b1660218201526015815261153860358261122b565b5190206040519081529081906020820190565b34610585576020366003190112610585577ff0be4f1e87349231d80c36b33f9e8639658eeaf474014dee15a3e6a4d4414197602060043561158b81610574565b611593613a69565b600480546001600160a01b0319166001600160a01b03929092169182179055604051908152a1005b34610585576020366003190112610585576004356115d881610574565b6001600160a01b03165f908152600e602052604090205463ffffffff811161160c5760405163ffffffff9091168152602090f35b6306dfcc6560e41b5f52602060045260245260445ffd5b346105855760203660031901126105855760043561164081610574565b60018060a01b03165f526005602052602060405f2054604051908152f35b34610585575f36600319011261058557611676613a69565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610585576040366003190112610585576110846004356116d581610574565b602435906116e48233836138e2565b613f66565b346105855760203660031901126105855760043561170681610574565b604051632474521560e21b81527f025d8bbf3268be680d2605ebf6da15063b9915615bf1087dab336efc1bf970cb60048201523360248201526020816044816001600160a01b037f000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c25165afa908115610bd7575f916117a1575b501561178e5761108490613132565b630a4510f960e31b5f523360045260245ffd5b6117c3915060203d6020116117c9575b6117bb818361122b565b81019061311d565b5f61177f565b503d6117b1565b34610585576040366003190112610585576117ec600435610d43565b60206040515f8152f35b346105855760203660031901126105855760043561181381610574565b60018060a01b03165f52600c602052602060405f2054604051908152f35b346105855760a03660031901126105855761184b3661094c565b506064356001600160401b0381116105855761186b90369060040161095d565b5050602060843561187b81610574565b6040516001600160a01b0390911630148152f35b34610585576020366003190112610585576020610e2a60036004356118b381610574565b5f816013614d6c565b34610585575f366003190112610585576119606118f87f42756d6d6572546f6b656e00000000000000000000000000000000000000000b614deb565b6119217f3100000000000000000000000000000000000000000000000000000000000001614e44565b6020604051611930828261122b565b5f81528161196e81830194601f198301368737604051978897600f60f81b895260e0858a015260e0890190610601565b908782036040890152610601565b914660608701523060808701525f60a087015285830360c087015251918281520192915f5b8281106119a257505050500390f35b835185528695509381019392810192600101611993565b34610585575f36600319011261058557602060405160068152f35b34610585576020366003190112610585576004356119f181610574565b604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c256001600160a01b03165afa908115610bd7575f91611a79575b5015611a66576110849061324b565b630ea7d7ed60e21b5f523360045260245ffd5b611a92915060203d6020116117c9576117bb818361122b565b5f611a57565b34610585575f366003190112610585575f546040516001600160a01b039091168152602090f35b34610585576020366003190112610585574265ffffffffffff1660043581811015611bc257611aed9061401a565b600f54905f829160058411611b69575b611b099350600f614fd9565b80611b2e575061068d5f5b6040516001600160d01b0390911681529081906020820190565b611b3a61068d91613c8f565b600f5f527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802015460301c611b14565b9192611b7481614e7b565b8103908111611bbd57611b0993600f5f5265ffffffffffff8260205f2001541665ffffffffffff8516105f14611bab575091611afd565b929150611bb790614049565b90611afd565b612f64565b637669fc0f60e11b5f5260045260245260445ffd5b34610585575f36600319011261058557602060405165ffffffffffff42168152f35b34610585575f36600319011261058557602060405163ffffffff7f0000000000000000000000000000000000000000000000000000000000002105168152f35b6004359064ffffffffff8216820361058557565b6024359064ffffffffff8216820361058557565b3461058557602036600319011261058557611c7a611c39565b604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c256001600160a01b03165afa908115610bd7575f91611cef575b5015611a66576110849061328f565b611d08915060203d6020116117c9576117bb818361122b565b5f611ce0565b3461058557604036600319011261058557600435611d2b81610574565b60243580611d6857506001600160a01b03165f908152600e602090815260409091206001600160d01b0390611d5f90615035565b16604051908152f35b611d7490602092613bab565b610e2a565b34610585575f366003190112610585576040515f600954611d9981611123565b80845290600181169081156106ef5750600114611dc05761068d836106818185038261122b565b60095f9081527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af939250905b808210611e0457509091508101602001610681610671565b919260018160209254838588010152019101909291611dec565b34610585575f3660031901126105855760206040517f000000000000000000000000000000000000000000000000000000e8d4a510008152f35b34610585576020366003190112610585576020610e2a611ebd600435611e7d81610574565b611eb76003611ea4611e9f8460018060a01b03165f52600e60205260405f2090565b615035565b6001600160d01b0316925f8160136153c3565b9061597d565b615a12565b604051906107b860408361122b565b604051906107b860a08361122b565b60643590600282101561058557565b60043590600282101561058557565b346105855760a03660031901126105855760405160a08101908082106001600160401b0383111761120b5761108491604052611f3960043590565b8152611f43611c4d565b60208201526044356040820152611f58611ee0565b6060820152608435611f6981610574565b60808201526132dc565b3461058557602036600319011261058557600435604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c256001600160a01b03165afa908115610bd7575f91611ffc575b5015611a6657611084906133a6565b612015915060203d6020116117c9576117bb818361122b565b5f611fed565b34610585575f3660031901126105855760206040515f8152f35b34610585575f3660031901126105855760206040517fb00be3d6a5434b97b328543d1486d56adcb7e74080170d1cdd7e0306c3d9ba3d8152f35b346105855760403660031901126105855761073d60043561208f81610574565b602435903361399a565b34610585575f36600319011261058557604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c256001600160a01b03165afa908115610bd7575f9161211d575b5015611a6657611084613405565b612136915060203d6020116117c9576117bb818361122b565b5f61210f565b34610585575f366003190112610585576015546301e187e08102908082046301e187e01490151715611bbd57602090604051908152f35b34610585575f366003190112610585576002546040516001600160a01b039091168152602090f35b906020600319830112610585576004356001600160401b0381116105855760040182601f82011215610585578035926001600160401b038411610585576020808301928560051b010111610585579190565b34610585576121fb3661219b565b90612204613a69565b61220d82612f43565b9061221b604051928361122b565b828252602082019260051b8101903682116105855780935b8285106122435761108484614398565b84356001600160401b03811161058557820190606082360312610585576040519161226d83611210565b803561227881610d43565b835261228660208201611101565b60208401526040810135906001600160401b03821161058557019036601f83011215610585576020926122c0849336908581359101613485565b6040820152815201940193612233565b346105855760203660031901126105855763ffffffff6004356122f281610d43565b165f526001602052602060405f2054604051908152f35b346105855760603660031901126105855760043561232681610d43565b61232e6110f0565b604435906001600160401b0382116105855761068d926123556112b393369060040161095d565b92909161354a565b6123663661219b565b5f5b8181106123d557604051638e9e709960e01b81525f81600481335afa8015610bd7576123af915f916123b3575b50604051638351eea760e01b815291829160048301610625565b0390fd5b6123cf91503d805f833e6123c7818361122b565b8101906136ef565b82612395565b6123e0818385613600565b9061241061240c6123f084612f5a565b60208501359063ffffffff165f52600160205260405f20541490565b1590565b6124a85760c08201359160a081013561242d610100830183613628565b94909161243c60e0850161365a565b9361244b610120820182613628565b959095303b15610585575f96612478926040519a8b9889978897633411683760e21b895260048901613675565b0391305af1918215610bd757600192612494575b505b01612368565b80610bcb5f6124a29361122b565b5f61248c565b6001915061248e565b34610585575f36600319011261058557602060ff601854166040519015158152f35b34610585575f3660031901126105855760206040517f025d8bbf3268be680d2605ebf6da15063b9915615bf1087dab336efc1bf970cb8152f35b6064359060ff8216820361058557565b6084359060ff8216820361058557565b346105855760c03660031901126105855760043561254a81610574565b6024359060443561255961250d565b6084359060a4359280421161261757916125de93916125d06125d59460405160208101917fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf835260018060a01b038a1660408301528a60608301526080820152608081526125c860a08261122b565b51902061448d565b61505f565b909291926150e1565b6125e781614821565b8093036125f85761108492506144c2565b90506301d4b62360e61b5f5260018060a01b031660045260245260445ffd5b632341d78760e11b5f5260045260245ffd5b9160806107b8929493612669604060c0830197805184526001600160401b0360208201511660208501520151604083019060208091805184520151910152565b019060208091805184520151910152565b6080366003190112610585576004356001600160401b038111610585576126a5903690600401610748565b604036602319011261058557606435906126be82610574565b6126c6613751565b506126cf612f2b565b506126e66001600160a01b03602083013516610a67565b6126f561240c60185460ff1690565b90816127e0575b816127cc575b506127bd5761274e916127286040830135606084013561272185612f5a565b91336146a8565b9390916127358585613dbd565b61273e86612f5a565b9161274836613777565b92614731565b917f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a612778611ec2565b9483865280602087015261278d855193612f5a565b6040805163ffffffff9290921682526020820195909552938401523392606090a361068d60405192839283612629565b638cd22d1960e01b5f5260045ffd5b6001600160a01b031633141590505f612702565b905061280961240c6128028360018060a01b03165f52601960205260405f2090565b5460ff1690565b906126fc565b34610585575f60203660031901126105855760043561282d81610574565b612835613a69565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031690813b156105855760405163ca5eb5e160e01b81526001600160a01b039091166004820152905f908290602490829084905af18015610bd7576128a0575080f35b61108491505f9061122b565b34610585575f3660031901126105855760206040515f516020615f775f395f51905f528152f35b6128dc3661098a565b50505092903033036128f557610a73610a6785836148a8565b63029a949d60e31b5f5260045ffd5b34610585576020366003190112610585577fd48d879cef83a1c0bdda516f27b13ddb1b3f8bbac1c9e1511bb2a659c2427760602060043561294481610574565b61294c613a69565b600280546001600160a01b0319166001600160a01b03929092169182179055604051908152a1005b346105855760e03660031901126105855760043561299181610574565b60243561299d81610574565b60443590606435926129ad61251d565b60a43560c43590864211612a7457612a3992612a346129cb86614821565b9860405160208101917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9835260018060a01b0389169b8c604084015260018060a01b038b1660608401528b608084015260a083015260c082015260c081526125c860e08261122b565b6144b3565b936001600160a01b03851603612a53576110849350614843565b6325c0072360e11b5f526001600160a01b038085166004521660245260445ffd5b8663313c898160e11b5f5260045260245ffd5b34610585576040366003190112610585576020612ad0600435612aa981610574565b60243590612ab682610574565b6001600160a01b03165f90815260068452604090206105a2565b54604051908152f35b34610585575f366003190112610585576012546040516001600160a01b039091168152602090f35b3461058557602036600319011261058557612b1a611eef565b604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c256001600160a01b03165afa908115610bd7575f91612b8f575b5015611a66576110849061379f565b612ba8915060203d6020116117c9576117bb818361122b565b5f612b80565b3461058557602036600319011261058557600435612bcb81610574565b604051632474521560e21b81525f516020615f775f395f51905f5260048201523360248201526020816044817f000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c256001600160a01b03165afa908115610bd7575f91612c40575b5015611a6657611084906137e5565b612c59915060203d6020116117c9576117bb818361122b565b5f612c31565b34610585575f36600319011261058557602064ffffffffff60145416604051908152f35b3461058557602036600319011261058557600435612ca081610574565b604051632474521560e21b81527fb00be3d6a5434b97b328543d1486d56adcb7e74080170d1cdd7e0306c3d9ba3d60048201526001600160a01b03918216602482015290602090829060449082907f000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c25165afa8015610bd75761068d915f91612d36575b5060405190151581529081906020820190565b612d4f915060203d6020116117c9576117bb818361122b565b5f612d23565b346105855760403660031901126105855761068d612dbb600435612d7881610574565b60243590612d8582610d43565b612d8d612f2b565b50612d96612f2b565b506001600160a01b03165f908152600e60205260409020612db5612f2b565b506153ae565b5060405190612dc9826111f0565b5465ffffffffffff811680835260309190911c60209283019081526040805192835290516001600160d01b031692820192909252918291820190565b3461058557602036600319011261058557600435612e2281610574565b612e2a613a69565b6001600160a01b03168015612e7b575f80546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b631e4fbdf760e01b5f525f60045260245ffd5b34610585576040366003190112610585576020610e2a600435612eb081610574565b60243590613caa565b34610585576020366003190112610585576020610e2a6003600435612edd81610574565b5f8160136153c3565b34610585576060366003190112610585576020612f023661094c565b63ffffffff8135612f1281610d43565b165f52600182528160405f205491013560405191148152f35b60405190612f38826111f0565b5f6020838281520152565b6001600160401b03811161120b5760051b60200190565b3561063681610d43565b634e487b7160e01b5f52601160045260245ffd5b81810292918115918404141715611bbd57565b8115612f95570490565b634e487b7160e01b5f52601260045260245ffd5b6001600160401b03811161120b57601f01601f191660200190565b63ffffffff7f0000000000000000000000000000000000000000000000000000000000002105168046036130d957506001600160a01b03811615908161304c575b6107b8911580613023575b156140105761301e81614c9f565b614010565b506001600160a01b0381165f9081526013602052604090206001015464ffffffffff1615613010565b60125461306390610a67906001600160a01b031681565b602060405180926370a0823160e01b825281806130833360048301610911565b03915afa908115610bd7575f916130aa575b501561300557630e7ae57960e01b5f5260045ffd5b6130cc915060203d6020116130d2575b6130c4818361122b565b8101906130ef565b5f613095565b503d6130ba565b6322a45b8960e21b5f524660045260245260445ffd5b90816020910312610585575190565b6040513d5f823e3d90fd5b634e487b7160e01b5f52602160045260245ffd5b90816020910312610585575161063681610e82565b7f7d4f30fa682bd557f547a1f7245a280525fd183bdb54917c56ec7ef22e5b532a9061315d81614c9f565b6001600160a01b0381165f90815260136020526040902060018101805491929161318e9064ffffffffff1642613c9d565b928054936131af6131a560145464ffffffffff1690565b64ffffffffff1690565b1061322d575b6001600160a01b0383165f908152601760205260409020613209929185916131ef906001600160e01b038416904263ffffffff16906156ea565b505055805464ffffffffff19164264ffffffffff16179055565b604080516001600160a01b039092168252602082019290925290819081015b0390a1565b9250613209906132426003845f8160136153c3565b939091506131b5565b6001600160a01b03165f818152601960205260408120805460ff191690557f535611fb62fa2a833988f283b779e417e996813e44046f521d76c17b5943b08c9080a2565b602064ffffffffff7f9ec539ec1ff2fdcda111a25f0c7d902ff0205d74dfaa05f434eecc8cdea9e8b1926132c281614064565b168064ffffffffff196014541617601455604051908152a1565b6132e4613a69565b60ff601a5416613389578061337060406133779301613303815161409e565b61335b61334f602085019261331f64ffffffffff855116614064565b6080860151601180546001600160a01b0319166001600160a01b0392909216919091179055516301e187e0900490565b915164ffffffffff1690565b9060608401519161336b83613397565b6140c2565b513361410c565b6107b8600160ff19601a541617601a55565b62dc149f60e41b5f5260045ffd5b600211156133a157565b613109565b6301e187e0906133b58161409e565b04670de0b6b3a764000081116133f6576020817f179ae38251712f92ada204166c624f1fd16102c85f82e13348393a898b04e9d292601555604051908152a1565b630678582160e51b5f5260045ffd5b60185460ff8116613476577f0000000000000000000000000000000000000000000000000000000067d17b0442106134675760ff19166001176018557feadb24812ab3c9a55c774958184293ebdb6c7f6a2dbab11f397d80c86feb65d35f80a1565b63be5fb0cb60e01b5f5260045ffd5b6385e1a58160e01b5f5260045ffd5b92919261349182612fa9565b9161349f604051938461122b565b829481845281830111610585578281602093845f960137010152565b909291928360021161058557831161058557600201916001190190565b805191908290602001825e015f815290565b61350493926107b8928160405196879460208601906134d8565b918237015f815203601f19810184528361122b565b908060209392818452848401375f828201840152601f01601f1916010190565b916020610636938181520191613519565b6112a06112ac9263ffffffff61357b9397959697165f52600360205260405f209061ffff165f5260205260405f2090565b8051156135de5783156135d85760028410156135af5750506123af604051928392639a6d49cd60e01b845260048401613539565b9092806135d291610636946135cd6135c8368484613485565b614455565b6134bb565b916134ea565b92509050565b509190610636913691613485565b634e487b7160e01b5f52603260045260245ffd5b91908110156136235760051b8101359061013e1981360301821215610585570190565b6135ec565b903590601e198136030182121561058557018035906001600160401b0382116105855760200191813603831361058557565b3561063681610574565b6001600160401b0381160361058557565b9290936136d1926001600160401b0360406106369a98999763ffffffff813561369d81610d43565b1688526020810135602089015201356136b581613664565b166040860152606085015260e0608085015260e0840191613519565b6001600160a01b0390941660a082015280840360c090910152613519565b602081830312610585578051906001600160401b038211610585570181601f820112156105855780519061372282612fa9565b92613730604051948561122b565b8284526020838301011161058557815f9260208093018386015e8301015290565b6040519061375e82611210565b815f81525f60208201526040613772612f2b565b910152565b60409060231901126105855760405190613790826111f0565b60243582526044356020830152565b60028110156133a15760207f7b7c2a74bf19219346c0b038bc25beb1372ff76eb0b6fe50ba0433b4ac9842799160ff8019601654169116809117601655604051908152a1565b6001600160a01b03165f818152601960205260408120805460ff191660011790557f4f783c179409b4127238bc9c990bc99b9a651666a0d20b51d6c42849eb88466d9080a2565b61385b90610f167f000000000000000000000000000000000000000000000000000000e8d4a510008092612f8b565b9182918084106138685750565b836371c4efed60e01b5f5260045260245260445ffd5b63ffffffff16805f52600160205260405f205490811561389c575090565b63f6ff4fb760e01b5f5260045260245ffd5b3561063681613664565b610636939260809260018060a01b0316825260208201525f60408201528160608201520190610601565b6001600160a01b03165f818152600660205260409020919290916139079084906105a2565b5460018101613917575b50505050565b818110613979578215613966576001600160a01b0384161561395357613949925f526006602052039160405f206105a2565b555f808080613911565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b83637dc7a0d960e11b5f5260018060a01b031660045260245260445260645ffd5b6001600160a01b038116939291908415613a56576001600160a01b0382168015613a43576139c883836154de565b156127bd576139d682610589565b5495848710613a1d57846107b89697036139ef84610589565b556139f984610589565b8054860190556040518581525f516020615f975f395f51905f5290602090a3615b80565b63391434e360e21b5f526001600160a01b0383166004526024879052604485905260645ffd5b63ec442f0560e01b5f525f60045260245ffd5b634b637e8f60e11b5f525f60045260245ffd5b5f546001600160a01b03163303613a7c57565b63118cdaa760e01b5f523360045260245ffd5b307f000000000000000000000000424aa31d64cabd39ea8b133be844d935d666f40e6001600160a01b03161480613b82575b15613aea577f9db7ae0ed8bd2cbb30fe0e1ba077f48f2bcab379d244f7275fee9b4ae812e7ca90565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f1c6b11da5cc464c5dec19f61bc70e7edbc6de539b1958ff7a9512b417afb7cd560408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a08152613b7c60c08261122b565b51902090565b507f00000000000000000000000000000000000000000000000000000000000000924614613ac1565b65ffffffffffff421680831015613c7957506001600160a01b03165f908152600e6020526040902090613bdd9061401a565b8154905f829160058411613c26575b613bf7935084614fd9565b80613c0c5750505f5b6001600160d01b031690565b613c1590613c8f565b905f5260205f20015460301c613c00565b9192613c3181614e7b565b8103908111611bbd57613bf793855f5265ffffffffffff8260205f2001541665ffffffffffff8516105f14613c67575091613bec565b929150613c7390614049565b90613bec565b82637669fc0f60e11b5f5260045260245260445ffd5b5f19810191908211611bbd57565b91908203918211611bbd57565b60165490613cc2600883901c64ffffffffff166131a5565b90818410613d9057613cd59060176105a2565b6001600160e01b0390613cef9063ffffffff861690614992565b169283613d8a57613d01929350613c9d565b613d146131a560145464ffffffffff1690565b9182821115613d7b5760ff16613d2981613397565b80613d455750613d3f6106369260155492613c9d565b90614b25565b80613d51600192613397565b03613d6c57613d666106369260155492613c9d565b90614a0c565b6346b2fddf60e11b5f5260045ffd5b505050670de0b6b3a764000090565b50505090565b505050505f90565b9091613daf61063693604084526040840190610601565b916020818403910152610601565b9091613e22613e4893613e05613df96020860135927f000000000000000000000000000000000000000000000000000000e8d4a5100090612f8b565b6001600160401b031690565b613e1c613e1560a0870187613628565b3691613485565b91614c30565b93909283945f14613eb4576002905b612355613e3d82612f5a565b916080810190613628565b60045490926001600160a01b03909116908382613e6457505050565b60405163043a78eb60e01b815292602092849283918291613e889160048401613d98565b03915afa8015610bd757613e995750565b613eb19060203d6020116117c9576117bb818361122b565b50565b600190613e31565b919082604091031261058557604051613ed4816111f0565b6020808294805184520151910152565b906040828203126105855761063691613ebc565b906020909392936040835263ffffffff81511660408401528181015160608401526080613f4c613f36604084015160a08488015260e0870190610601565b6060840151868203603f190160a0880152610601565b910151151560c08401526001600160a01b03909416910152565b6001600160a01b0381168015613a5657613f805f836154de565b156127bd57613f8e82610589565b54838110613fd257915f8092856107b8969503613faa84610589565b556007805486900390556040518581525f516020615f975f395f51905f5290602090a3615b80565b63391434e360e21b5f526001600160a01b038316600452602452604483905260645ffd5b61400864ffffffffff926001926105a2565b015416151590565b6107b890336144c2565b65ffffffffffff81116140325765ffffffffffff1690565b6306dfcc6560e41b5f52603060045260245260445ffd5b9060018201809211611bbd57565b91908201809211611bbd57565b64ffffffffff1662278d0081108015614091575b61407f5750565b6344aa7c4560e01b5f5260045260245ffd5b506301e187e08111614078565b6706f05b59d3b2000081116140b05750565b6306f18fc760e31b5f5260045260245ffd5b64ffffffffff1664ffffffffff19601454161760145560155560028110156133a1576016805465ffffffffffff191660ff92909216919091174260081b65ffffffffff0016179055565b91906001600160a01b0383168015613a4357614128845f6154de565b156127bd5761414161413c83600754614057565b600755565b61414a84610589565b8054830190556040518281525f905f516020615f975f395f51905f5290602090a3600754926001600160d01b038085116141cf575061418b9293505f615b80565b7f0000000000000000000000000000000000000000033b2e3c9fd0803ce80000006007548181116141ba575050565b63279e7e1560e21b5f5260045260245260445ffd5b630e58ae9360e11b5f52600485905260245260445ffd5b80518210156136235760209160051b010190565b601f821161420757505050565b5f5260205f20906020601f840160051c8301931061423f575b601f0160051c01905b818110614234575050565b5f8155600101614229565b9091508190614220565b91909182516001600160401b03811161120b576142708161426a8454611123565b846141fa565b6020601f82116001146142af5781906142a09394955f926142a4575b50508160011b915f199060031b1c19161790565b9055565b015190505f8061428c565b601f198216906142c2845f5260205f2090565b915f5b8181106142fc575095836001959697106142e4575b505050811b019055565b01515f1960f88460031b161c191690555f80806142da565b9192602060018192868b0151815501940192016142c5565b602081016020825282518091526040820191602060408360051b8301019401925f915b83831061434657505050505090565b9091929394602080614389600193603f19868203018752606060408b5163ffffffff815116845261ffff8682015116868501520151918160408201520190610601565b97019301930191939290614337565b5f5b815181101561442357806143bd60406143b5600194866141e6565b510151614455565b61441d60406143cc83866141e6565b51015163ffffffff6143de84876141e6565b5151165f52600360205261441860405f2061440860206143fe878a6141e6565b51015161ffff1690565b61ffff165f5260205260405f2090565b614249565b0161439a565b506132287fbe4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b6749160405191829182614314565b600361ffff600283015116036144685750565b604051639a6d49cd60e01b8152602060048201529081906123af906024830190610601565b604290614498613a8f565b906040519161190160f01b8352600283015260228201522090565b9161063693916125d59361505f565b6001600160a01b038181165f818152600d6020526040812080548685166001600160a01b03198216811790925594959490931693929184917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9080a461452783610589565b5460125461453f90610a67906001600160a01b031681565b93602060405180966370a0823160e01b825281806145608660048301610911565b03915afa948515610bd7575f95614687575b5060115461458a90610a67906001600160a01b031681565b60405163baf3510760e01b8152602081806145a88660048301610911565b0381855afa908115610bd7575f91614668575b506001600160a01b031615614654576145ed9291602091604051808096819463baf3510760e01b835260048301610911565b03915afa8015610bd7576107b89561461361461a9261461f955f91614625575b50610589565b5492614057565b614057565b91615172565b614647915060203d60201161464d575b61463f818361122b565b81019061515d565b5f61460d565b503d614635565b505061461f9061461a6107b8955f92614057565b614681915060203d60201161464d5761463f818361122b565b5f6145bb565b6146a191955060203d6020116130d2576130c4818361122b565b935f614572565b939192506146db90610f167f000000000000000000000000000000000000000000000000000000e8d4a510008092612f8b565b9180831061102957506107b8828094613f66565b906080828203126105855761472990604080519361470c85611210565b80518552602081015161471e81613664565b602086015201613ebc565b604082015290565b61478e608094926147aa9694614745613751565b5060206147528651615294565b950191825180614812575b506147678561387e565b9251151592614777610f5e611ed1565b602086015260408501526060840152151585830152565b6040518095819482936302637a4560e41b845260048401613ef8565b03917f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b03165af1908115610bd7575f916147e9575090565b610636915060803d60801161480b575b614803818361122b565b8101906146ef565b503d6147f9565b61481b906152b1565b5f61475d565b6001600160a01b03165f908152600c6020526040902080546001810190915590565b6001600160a01b0316908115613966576001600160a01b038116928315613953578061489b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92593855f52600660205260405f206105a2565b55604051908152602090a3565b90602011610585573590565b90602811610585576020013560c01c90565b610636906001600160401b037f000000000000000000000000000000000000000000000000000000e8d4a510009116612f78565b816001600160a01b03821615614914575b6106369161410c565b61dead915061490b565b9080602811610585576106369136916027190190602801613485565b60405160c09190911b6001600160c01b031916602082015260e09190911b6001600160e01b0319166028820152602c8101919091529061063690829061498490604c8301906134d8565b03601f19810183528261122b565b9081549063ffffffff5f91165b8282106149cb575050806149b35750505f90565b6149bc90613c8f565b905f5260205f20015460201c90565b90916149d7818461579f565b90845f528263ffffffff8360205f20015416115f146149f95750915b9061499f565b925060018101809111156149f357612f64565b9080158015614aa0575b614a9257670de0b6b3a7640000821015614a7f5781670de0b6b3a7640000148015614a85575b614a7f57614a5391670de0b6b3a76400000361555c565b8015614a7a57614a6b90670de0b6b3a764000061597d565b8015614a7a57610636906155b5565b505f90565b50505f90565b5063ffffffff8111614a3c565b5050670de0b6b3a764000090565b508115614a16565b9180158015614b1d575b614b1857670de0b6b3a7640000821015614b04578215614b045781670de0b6b3a7640000148015614b0b575b614b0457614af591670de0b6b3a76400000361555c565b8015614a7f57614a6b9161597d565b5050505f90565b5063ffffffff8111614ade565b505090565b508115614ab2565b81158015614ba9575b614a9257670de0b6b3a7640000811015614a7f57801580159081614b90575b50614a7f5702670de0b6b3a7640000811015614a7a57614b8261063691670de0b6b3a764000003670de0b6b3a7640000612f78565b670de0b6b3a7640000900490565b9050612f955780670de0b6b3a76400000482115f614b4d565b508015614b2e565b919081158015614c28575b614b1857670de0b6b3a7640000811015614b04578215614b0457801580159081614c0f575b50614b045702670de0b6b3a7640000811015614a7f5761063691614b8291670de0b6b3a76400000390612f78565b9050612f955780670de0b6b3a76400000482115f614be1565b508015614bbc565b82511580159390614c735790614984614c7092604051948593602085015260018060c01b03199060c01b16604084015233604884015260688301906134d8565b91565b509060405191602083015260018060c01b03199060c01b16604082015260288152614c7060488261122b565b6001600160a01b0381165f9081526013602052604090206001015464ffffffffff1615614cc95750565b6132287f9b44a2c7f9f0b5aa4e7da60d8a2325796c57f93a45559d66515743ffbd8a610391614d43604051614cfd816111f0565b670de0b6b3a76400008152600164ffffffffff602083018142168152614d248660136105a2565b93518455511691019064ffffffffff1664ffffffffff19825416179055565b614d5e614d518260176105a2565b63ffffffff421690615610565b505060405191829182610911565b939291906001600160a01b038116908115614de157614d8b9085615f3e565b906001600160a01b03808316919085168214614dd7578115918215614dcd575b5050614dc55760018201809211611bbd5761063694614d6c565b509250505090565b1490505f80614dab565b5050509250505090565b5050505050505f90565b60ff8114614e315760ff811690601f8211614e225760405191614e0f60408461122b565b6020808452838101919036833783525290565b632cd44ac360e21b5f5260045ffd5b50604051610636816112ac81600a61115b565b60ff8114614e685760ff811690601f8211614e225760405191614e0f60408461122b565b50604051610636816112ac81600b61115b565b600181111561063657806001600160801b821015614f9c575b614f42614f38614f2e614f24614f1a614f10614eff614f49976004614f4e9a600160401b811015614f8f575b640100000000811015614f82575b62010000811015614f75575b610100811015614f68575b6010811015614f5b575b1015614f53575b60030260011c90565b614f09818b612f8b565b0160011c90565b614f09818a612f8b565b614f098189612f8b565b614f098188612f8b565b614f098187612f8b565b614f098186612f8b565b8093612f8b565b821190565b900390565b60011b614ef6565b60041c9160021b91614eef565b60081c9160041b91614ee5565b60101c9160081b91614eda565b60201c9160101b91614ece565b60401c9160201b91614ec0565b5050614f4e614f49614f42614f38614f2e614f24614f1a614f10614eff614fc38a60801c90565b9850600160401b9750614e949650505050505050565b905b838310614fe85750505090565b909192614ff5818561579f565b90835f5265ffffffffffff8260205f2001541665ffffffffffff8416105f146150225750925b9190614fdb565b9350600181018091111561501b57612f64565b805490816150435750505f90565b815f19810111611bbd575f525f199060205f2001015460301c90565b91906fa2a8918ca85bafe22016d0b997e4df60600160ff1b0384116150cc579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610bd7575f516001600160a01b038116156150c257905f905f90565b505f906001905f90565b5050505f9160039190565b600411156133a157565b6150ea816150d7565b806150f3575050565b6150fc816150d7565b600181036151135763f645eedf60e01b5f5260045ffd5b61511c816150d7565b60028103615137575063fce698f760e01b5f5260045260245ffd5b806151436003926150d7565b1461514b5750565b6335e2f38360e21b5f5260045260245ffd5b90816020910312610585575161063681610574565b6001600160a01b0380831693929190811690818514158061528b575b61519a575b5050505050565b8161521e575b5050826151af575b8080615193565b6001600160a01b03165f908152600e602052604090207fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724916151fb916151f590916157b4565b90615818565b604080516001600160d01b039384168152919092166020820152a25f80806151a8565b6001600160a01b03165f908152600e602052604090207fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7249061526990615263866157b4565b906157e5565b604080516001600160d01b039384168152919092166020820152a25f806151a0565b5083151561518e565b80340361529e5790565b6304fb820960e51b5f523460045260245ffd5b60405163393f876560e21b81527f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031690602081600481855afa908115610bd7575f9161538f575b506001600160a01b0316918215615380576020915f9160405190848201926323b872dd60e01b8452336024840152604483015260648201526064815261534760848261122b565b519082855af1156130fe575f513d6153775750803b155b6153655750565b635274afe760e01b5f5260045260245ffd5b6001141561535e565b6329b99a9560e11b5f5260045ffd5b6153a8915060203d60201161464d5761463f818361122b565b5f615300565b8054821015613623575f5260205f2001905f90565b93909290916001600160a01b038416908115614de1576002811015614de1576153ec8585615f3e565b916001600160a01b03808416919085168214806154d5575b6154c55781151591826154ba575b5050806154aa575b615493575050505061542f61240c8284613ff6565b61543c576106369161587f565b5060038101546106369161546361545d600884901c64ffffffffff166131a5565b42613c9d565b9064ffffffffff61548b6154846001600285015494015464ffffffffff1690565b9460ff1690565b9316916158c7565b61063695929394506154a490614049565b916153c3565b506154b58287613ff6565b61541a565b141590505f80615412565b505050509150506106369161587f565b50821515615404565b6001600160a01b03168015801561554b575b6155445760ff60185416615544575f52601960205260ff60405f205416908115615523575b5061551e575f90565b600190565b6001600160a01b03165f9081526019602052604081205460ff169150615515565b5050600190565b506001600160a01b038216156154f0565b8060018316156155a6575b9160011c90815b61557757505090565b806155819161597d565b9060018116615595575b60011c908161556e565b91816155a09161597d565b9161558b565b50670de0b6b3a7640000615567565b670de0b6b3a764000061063691615ac2565b8054600160401b81101561120b576155e4916001820181556153ae565b61560b57815160209283015190921b63ffffffff191663ffffffff92909216919091179055565b611110565b805490919080156156cc5761562761563291613c8f565b835f5260205f200190565b9081549261564d6156468563ffffffff1690565b9460201c90565b9363ffffffff80841691168181116156bd5703615689575050805463ffffffff166503782dace9d960321b1790555b90670de0b6b3a764000090565b6156b892506156a5615699611ec2565b63ffffffff9093168352565b670de0b6b3a764000060208301526155c7565b61567c565b632520601d60e01b5f5260045ffd5b506156dc916156a5615699611ec2565b5f90670de0b6b3a764000090565b805492939280156157755761570161570c91613c8f565b825f5260205f200190565b8054602081901c9363ffffffff918216929181168084116156bd5787930361574f575061574b92509063ffffffff82549181199060201b169116179055565b9190565b91505061574b91615761615699611ec2565b6001600160e01b03861660208301526155c7565b509061579a91615786615699611ec2565b6001600160e01b03851660208301526155c7565b5f9190565b90808216911860011c8101809111611bbd5790565b6001600160d01b0381116157ce576001600160d01b031690565b6306dfcc6560e41b5f5260d060045260245260445ffd5b906157ef82615035565b6001600160d01b0391821690821603908111611bbd576109f39165ffffffffffff421690615c04565b9061582282615035565b6001600160d01b0391821690821601908111611bbd576109f39165ffffffffffff421690615c04565b615855600f615035565b6001600160d01b0391821690821603908111611bbd576109f3904265ffffffffffff16600f615c04565b9061588a90826105a2565b9064ffffffffff600183015416420390428211611bbd5761063692549160028201549060ff600364ffffffffff6001860154169401541693615930565b9192909280831115615920578203918211611bbd5760028110156133a157806158fd575061063691670de0b6b3a7640000614bb1565b80615909600192613397565b03613d6c5761063691670de0b6b3a7640000614aa8565b50505050670de0b6b3a764000090565b93909280841115615976578303928311611bbd5760028110156133a1578061595c575061063692614bb1565b80615968600192613397565b03613d6c5761063692614aa8565b5050505090565b9091905f1983820983820291828083109203918083039214615a0157670de0b6b3a76400008210156159ea577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b8490635173648d60e01b5f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b905f19670de0b6b3a76400008309670de0b6b3a7640000830290818082109103908082039114615ab257670de0b6b3a7640000811015615a8d57670de0b6b3a7640000807faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b630c740aef60e31b5f526004849052670de0b6b3a7640000602481905260445260645ffd5b50670de0b6b3a764000090049150565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414615b745781841015615b5357670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b630c740aef60e31b5f52600452670de0b6b3a764000060245260445260645ffd5b50906106369250612f8b565b9190615b8c8184615cb7565b615b97838386615d3e565b90159081615bb3575b50615baa57505050565b6107b892615e8b565b9050155f615ba0565b8054600160401b81101561120b57615bd9916001820181556153ae565b61560b57815160209092015160301b65ffffffffffff191665ffffffffffff92909216919091179055565b80549293928015615c9257615701615c1b91613c8f565b8054603081901c9365ffffffffffff918216929181168084116156bd57879303615c5e575061574b92509065ffffffffffff82549181199060301b169116179055565b91505061574b91615c7e615c70611ec2565b65ffffffffffff9093168352565b6001600160d01b0386166020830152615bbc565b509061579a91615ca3615c70611ec2565b6001600160d01b0385166020830152615bbc565b6012546040516376de574360e01b81526001600160a01b039091169190602081600481865afa908115610bd7575f91615d1f575b506001600160a01b03918216911614918215615d0c575b505061551e575f90565b6001600160a01b03161490505f80615d02565b615d38915060203d60201161464d5761463f818361122b565b5f615ceb565b60115490929190615d5990610a67906001600160a01b031681565b602060405180926305e5f31960e21b82528180615d798760048301610911565b03915afa908115610bd7575f91615e6c575b506001600160a01b03811680615e41575050601154615dd693602091615dbb90610a67906001600160a01b031681565b60405180809781946305e5f31960e21b835260048301610911565b03915afa928315610bd7575f93615e20575b506001600160a01b03831680615e0057505050505f90565b6001600160a01b03821614615e185761551e92615e8b565b505050600190565b615e3a91935060203d60201161464d5761463f818361122b565b915f615de8565b9091506001600160a01b03841603615e5b57505050600190565b615e6492615e8b565b5f8080615e18565b615e85915060203d60201161464d5761463f818361122b565b5f615d8b565b9091906001600160a01b03168015615ef2575b6107b8926001600160a01b0316908115615eda575b5f908152600d6020526040808220549282529020546001600160a01b039081169116615172565b615eeb615ee6846157b4565b61584b565b5050615eb3565b615efb826157b4565b615f05600f615035565b6001600160d01b039182169082160193908411611bbd576107b893615f34904265ffffffffffff16600f615c04565b9050509250615e9e565b600314615f5957634e487b7160e01b5f52605160045260245ffd5b6001600160a01b039081165f908152600d6020526040902054169056fe7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220ae5238dc818e8db06a027ff7118af608ea4972536e77bc0dfc25f89cab2d232b64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b000000000000000000000000b0f758323d3798a6a567c1601d84f30d1bcaaa0b000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c250000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000000000000000000067d17b040000000000000000000000000000000000000000000000000000000000002105000000000000000000000000000000000000000000000000000000000000000b42756d6d6572546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000642554d4d45520000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : params (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [3] : 0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b
Arg [4] : 000000000000000000000000b0f758323d3798a6a567c1601d84f30d1bcaaa0b
Arg [5] : 000000000000000000000000244d9affcca2eafd689b0393bf15f26f79364c25
Arg [6] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000067d17b04
Arg [8] : 0000000000000000000000000000000000000000000000000000000000002105
Arg [9] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [10] : 42756d6d6572546f6b656e000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [12] : 42554d4d45520000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ 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.