Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60a06040 | 19021984 | 261 days ago | IN | 0 ETH | 0.14978997 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
StakeTogetherV3
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2023 Stake Together Labs <[email protected]> // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.22; import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol'; import '@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol'; import '@openzeppelin/contracts/utils/math/Math.sol'; import '@openzeppelin/contracts/utils/Address.sol'; import '../interfaces/IDepositContract.sol'; import '../interfaces/IAirdrop.sol'; import '../interfaces/IRouter.sol'; import '../interfaces/IStakeTogether.sol'; import '../interfaces/IWithdrawals.sol'; /// @title StakeTogether Pool Contract /// @notice The StakeTogether contract is the primary entry point for interaction with the StakeTogether protocol. /// It provides functionalities for staking, withdrawals, fee management, and interactions with pools and validators. /// @custom:security-contact [email protected] contract StakeTogetherV3 is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, PausableUpgradeable, AccessControlUpgradeable, ERC20PermitUpgradeable, UUPSUpgradeable, ReentrancyGuardUpgradeable, IStakeTogether { bytes32 public constant UPGRADER_ROLE = keccak256('UPGRADER_ROLE'); /// Role for managing upgrades. bytes32 public constant ADMIN_ROLE = keccak256('ADMIN_ROLE'); /// Role for administration. bytes32 public constant POOL_MANAGER_ROLE = keccak256('POOL_MANAGER_ROLE'); /// Role for managing pools. bytes32 public constant VALIDATOR_ORACLE_ROLE = keccak256('VALIDATOR_ORACLE_ROLE'); /// Role for managing validator oracles. bytes32 public constant VALIDATOR_ORACLE_MANAGER_ROLE = keccak256('VALIDATOR_ORACLE_MANAGER_ROLE'); /// Role for managing validator oracle managers. bytes32 public constant VALIDATOR_ORACLE_SENTINEL_ROLE = keccak256('VALIDATOR_ORACLE_SENTINEL_ROLE'); /// Role for sentinel functionality in validator oracle management. bytes32 public constant ANTI_FRAUD_MANAGER_ROLE = keccak256('ANTI_FRAUD_MANAGER_ROLE'); // Role for anti-fraud managers. bytes32 public constant ANTI_FRAUD_SENTINEL_ROLE = keccak256('ANTI_FRAUD_SENTINEL_ROLE'); // Role for sentinel functionality in anti-fraud management. uint256 public version; /// Contract version. IAirdrop public airdrop; /// Airdrop contract instance. IDepositContract public deposit; /// Deposit contract interface. IRouter public router; /// Address of the contract router. IWithdrawals public withdrawals; /// Withdrawals contract instance. bytes public withdrawalCredentials; /// Credentials for withdrawals. uint256 public beaconBalance; /// Beacon balance (includes transient Beacon balance on router). uint256 public withdrawBalance; /// Pending withdraw balance to be withdrawn from router. Config public config; /// Configuration settings for the protocol. mapping(address => uint256) public shares; /// Mapping of addresses to their shares. uint256 public totalShares; /// Total number of shares. mapping(address => mapping(address => uint256)) private allowances; /// Allowances mapping. mapping(address => uint256) private lastOperationBlock; // Mapping of addresses to their last operation block. mapping(address => uint256) private nextWithdrawBlock; // Mapping the next block for withdraw mapping(address => uint256) private nextWithdrawBeaconBlock; // Mapping the next block for withdraw from beacon uint256 public lastResetBlock; /// Block number of the last reset. uint256 public totalDeposited; /// Total amount deposited. uint256 public totalWithdrawnPool; /// Total amount withdrawn pool. uint256 public totalWithdrawnValidator; /// Total amount withdrawn validator. mapping(address => bool) public pools; /// Mapping of pool addresses. address[] private validatorsOracle; /// List of validator oracles. mapping(address => uint256) private validatorsOracleIndices; /// Mapping of validator oracle indices. uint256 public currentOracleIndex; /// Current index of the oracle. mapping(bytes => bool) public validators; /// Mapping of validators. mapping(FeeRole => address payable) private feesRole; /// Mapping of fee roles to addresses. mapping(FeeType => Fee) private fees; /// Mapping of fee types to fee details. mapping(address => bool) private antiFraudList; /// Mapping of anti-fraud addresses. /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @notice Stake Together Pool Initialization function initializeV3() public onlyRole(UPGRADER_ROLE) { version = 3; } /// @notice Pauses the contract, preventing certain actions. /// @dev Only callable by the admin role. function pause() external onlyRole(ADMIN_ROLE) { _pause(); } /// @notice Unpauses the contract, allowing actions to resume. /// @dev Only callable by the admin role. function unpause() external onlyRole(ADMIN_ROLE) { _unpause(); } /// @notice Internal function to authorize an upgrade. /// @dev Only callable by the upgrader role. /// @param _newImplementation Address of the new contract implementation. function _authorizeUpgrade(address _newImplementation) internal override onlyRole(UPGRADER_ROLE) {} /// @notice Receive function to accept incoming ETH transfers. /// @dev Non-reentrant to prevent re-entrancy attacks. receive() external payable { emit ReceiveEther(msg.value); } modifier nonFlashLoan() { if (block.number <= lastOperationBlock[msg.sender]) { revert FlashLoan(); } _; } /************ ** CONFIG ** ************/ /// @notice Sets the configuration for the Stake Together Protocol. /// @dev Only callable by the admin role. /// @param _config Configuration settings to be applied. function setConfig(Config memory _config) external onlyRole(ADMIN_ROLE) { if (_config.poolSize < config.validatorSize) revert InvalidSize(); config = _config; emit SetConfig(_config); } /************ ** SHARES ** ************/ /// @notice Returns the total supply of the pool (contract balance + beacon balance). /// @return Total supply value. function totalSupply() public view override(ERC20Upgradeable, IStakeTogether) returns (uint256) { return address(this).balance + beaconBalance - withdrawBalance; } /// @notice Calculates the shares amount by wei. /// @param _account The address of the account. /// @return Balance value of the given account. function balanceOf( address _account ) public view override(ERC20Upgradeable, IStakeTogether) returns (uint256) { return weiByShares(shares[_account]); } /// @notice Calculates the wei amount by shares. /// @param _sharesAmount Amount of shares. /// @return Equivalent amount in wei. function weiByShares(uint256 _sharesAmount) public view returns (uint256) { return Math.mulDiv(_sharesAmount, totalSupply(), totalShares, Math.Rounding.Ceil); } /// @notice Calculates the shares amount by wei. /// @param _amount Amount in wei. /// @return Equivalent amount in shares. function sharesByWei(uint256 _amount) public view returns (uint256) { return Math.mulDiv(_amount, totalShares, totalSupply()); } /// @notice Transfers an amount of wei to the specified address. /// @param _to The address to transfer to. /// @param _amount The amount to be transferred. /// @return True if the transfer was successful. function transfer( address _to, uint256 _amount ) public override(ERC20Upgradeable, IStakeTogether) returns (bool) { if (isListedInAntiFraud(msg.sender)) revert ListedInAntiFraud(); if (isListedInAntiFraud(_to)) revert ListedInAntiFraud(); _transfer(msg.sender, _to, _amount); return true; } /// @notice Transfers tokens from one address to another using an allowance mechanism. /// @param _from Address to transfer from. /// @param _to Address to transfer to. /// @param _amount Amount of tokens to transfer. /// @return A boolean value indicating whether the operation succeeded. function transferFrom( address _from, address _to, uint256 _amount ) public override(ERC20Upgradeable, IStakeTogether) returns (bool) { if (isListedInAntiFraud(_from)) revert ListedInAntiFraud(); if (isListedInAntiFraud(_to)) revert ListedInAntiFraud(); if (isListedInAntiFraud(msg.sender)) revert ListedInAntiFraud(); _spendAllowance(_from, msg.sender, _amount); _transfer(_from, _to, _amount); return true; } /// @notice Transfers an amount of wei from one address to another. /// @param _from The address to transfer from. /// @param _to The address to transfer to. /// @param _amount The amount to be transferred. function _update( address _from, address _to, uint256 _amount ) internal override nonReentrant nonFlashLoan whenNotPaused { if (block.number < nextWithdrawBlock[msg.sender]) revert EarlyTransfer(); lastOperationBlock[msg.sender] = block.number; uint256 _sharesToTransfer = sharesByWei(_amount); _transferShares(_from, _to, _sharesToTransfer); emit Transfer(_from, _to, _amount); } /// @notice Internal function to handle the transfer of shares. /// @param _from The address to transfer from. /// @param _to The address to transfer to. /// @param _sharesAmount The number of shares to be transferred. function _transferShares(address _from, address _to, uint256 _sharesAmount) private whenNotPaused { if (isListedInAntiFraud(_from)) revert ListedInAntiFraud(); if (isListedInAntiFraud(_to)) revert ListedInAntiFraud(); if (_from == address(0)) revert ZeroAddress(); if (_to == address(0)) revert ZeroAddress(); if (_sharesAmount > shares[_from]) revert InsufficientShares(); shares[_from] -= _sharesAmount; shares[_to] += _sharesAmount; emit TransferShares(_from, _to, _sharesAmount); } /// @notice Returns the remaining number of tokens that an spender is allowed to spend on behalf of a token owner. /// @param _account Address of the token owner. /// @param _spender Address of the spender. /// @return A uint256 value representing the remaining number of tokens available for the spender. function allowance( address _account, address _spender ) public view override(ERC20Upgradeable, IStakeTogether) returns (uint256) { return allowances[_account][_spender]; } /// @notice Sets the amount `_amount` as allowance of `_spender` over the caller's tokens. /// @param _spender Address of the spender. /// @param _amount Amount of allowance to be set. /// @return A boolean value indicating whether the operation succeeded. function approve( address _spender, uint256 _amount ) public override(ERC20Upgradeable, IStakeTogether) returns (bool) { _approve(msg.sender, _spender, _amount, true); return true; } /// @notice Internal function to set the approval amount for a given spender and owner. /// @param _account Address of the token owner. /// @param _spender Address of the spender. /// @param _amount Amount of allowance to be set. function _approve( address _account, address _spender, uint256 _amount, bool emitEvent ) internal override { if (_account == address(0)) revert ZeroAddress(); if (_spender == address(0)) revert ZeroAddress(); allowances[_account][_spender] = _amount; if (emitEvent) { emit Approval(_account, _spender, _amount); } } /// @notice Internal function to deduct the allowance for a given spender, if any. /// @param _account Address of the token owner. /// @param _spender Address of the spender. /// @param _amount Amount to be deducted from the allowance. function _spendAllowance(address _account, address _spender, uint256 _amount) internal override { uint256 currentAllowance = allowances[_account][_spender]; if (currentAllowance != ~uint256(0)) { if (currentAllowance < _amount) revert InsufficientAllowance(); _approve(_account, _spender, currentAllowance - _amount, true); } } /// @notice Internal function to mint shares to a given address. /// @param _to Address to mint shares to. /// @param _sharesAmount Amount of shares to mint. function _mintShares(address _to, uint256 _sharesAmount) private whenNotPaused { if (_to == address(0)) revert ZeroAddress(); shares[_to] += _sharesAmount; totalShares += _sharesAmount; emit MintShares(_to, _sharesAmount); emit Transfer(address(0), _to, weiByShares(_sharesAmount)); } /// @notice Internal function to burn shares from a given address. /// @param _account Address to burn shares from. /// @param _sharesAmount Amount of shares to burn. function _burnShares(address _account, uint256 _sharesAmount) private whenNotPaused { if (_account == address(0)) revert ZeroAddress(); if (_sharesAmount > shares[_account]) revert InsufficientShares(); shares[_account] -= _sharesAmount; totalShares -= _sharesAmount; emit BurnShares(_account, _sharesAmount); emit Transfer(_account, address(0), weiByShares(_sharesAmount)); } /*********** ** STAKE ** ***********/ /// @notice Deposits the base amount to the specified address. /// @param _to The address to deposit to. /// @param _depositType The type of deposit (Pool or Donation). /// @param _referral The referral address. function _depositBase( address _to, DepositType _depositType, address _pool, bytes calldata _referral ) private { if (!config.feature.Deposit) revert FeatureDisabled(); if (!(totalSupply() > 0)) revert ZeroSupply(); if (antiFraudList[_to]) revert ListedInAntiFraud(); if (msg.value < config.minDepositAmount) revert LessThanMinimumDeposit(); if (!pools[_pool]) revert PoolNotFound(); _resetLimits(); totalDeposited += msg.value; lastOperationBlock[msg.sender] = block.number; nextWithdrawBlock[msg.sender] = block.number + config.withdrawDelay; if (totalDeposited > config.depositLimit) { emit DepositLimitWasReached(_to, msg.value); revert DepositLimitReached(); } emit DepositBase(_to, msg.value, _depositType, _pool, _referral); _processFeeEntry(_to, msg.value); } /// @notice Deposits into the pool with specific delegations. /// @param _pool The address of the pool to deposit to. /// @param _referral The referral address. function depositPool( address _pool, bytes calldata _referral ) external payable nonReentrant nonFlashLoan whenNotPaused { _depositBase(msg.sender, DepositType.Pool, _pool, _referral); } /// @notice Deposits a donation to the specified address. /// @param _to The address to deposit to. /// @param _referral The referral address. function depositDonation( address _to, address _pool, bytes calldata _referral ) external payable nonReentrant nonFlashLoan whenNotPaused { _depositBase(_to, DepositType.Donation, _pool, _referral); } /// @notice Withdraws the base amount with the specified withdrawal type. /// @param _amount The amount to withdraw. /// @param _withdrawType The type of withdrawal (Pool or Validator). function _withdrawBase(uint256 _amount, WithdrawType _withdrawType, address _pool) private { if (antiFraudList[msg.sender]) revert ListedInAntiFraud(); if (_amount == 0) revert ZeroAmount(); if (_amount > balanceOf(msg.sender)) revert InsufficientAccountBalance(); if (_amount < config.minWithdrawAmount) revert LessThanMinimumWithdraw(); if (block.number < nextWithdrawBlock[msg.sender]) revert EarlyTransfer(); _resetLimits(); lastOperationBlock[msg.sender] = block.number; if (_withdrawType == WithdrawType.Pool) { totalWithdrawnPool += _amount; if (totalWithdrawnPool > config.withdrawalPoolLimit) { emit WithdrawalsLimitWasReached(msg.sender, _amount, _withdrawType); revert WithdrawalsPoolLimitReached(); } } else { totalWithdrawnValidator += _amount; if (totalWithdrawnValidator > config.withdrawalValidatorLimit) { emit WithdrawalsLimitWasReached(msg.sender, _amount, _withdrawType); revert WithdrawalsValidatorLimitWasReached(); } } emit WithdrawBase(msg.sender, _amount, _withdrawType, _pool); uint256 sharesToBurn = Math.mulDiv(_amount, shares[msg.sender], balanceOf(msg.sender)); _burnShares(msg.sender, sharesToBurn); } /// @notice Withdraws from the pool with specific delegations and transfers the funds to the sender. /// @param _amount The amount to withdraw. /// @param _pool The address of the pool to withdraw from. function withdrawPool(uint256 _amount, address _pool) external nonReentrant nonFlashLoan whenNotPaused { if (!config.feature.WithdrawPool) revert FeatureDisabled(); if (_amount > address(this).balance) revert InsufficientPoolBalance(); _withdrawBase(_amount, WithdrawType.Pool, _pool); Address.sendValue(payable(msg.sender), _amount); } /// @notice Withdrawals from the beacon chain. /// @param _amount The amount to withdraw. /// @param _pool The address of the pool to withdraw from. function withdrawBeacon( uint256 _amount, address _pool ) external nonReentrant nonFlashLoan whenNotPaused { if (!config.feature.WithdrawBeacon) revert FeatureDisabled(); if (_amount <= address(this).balance) revert WithdrawFromPool(); if (_amount + withdrawBalance > beaconBalance) revert InsufficientBeaconBalance(); nextWithdrawBeaconBlock[msg.sender] = block.number + config.withdrawBeaconDelay; _withdrawBase(_amount, WithdrawType.Validator, _pool); _setWithdrawBalance(withdrawBalance + _amount); withdrawals.mint(msg.sender, _amount); } /// @notice Resets the daily limits for deposits and withdrawals. function _resetLimits() private { if (block.number > lastResetBlock + config.blocksPerDay) { totalDeposited = 0; totalWithdrawnPool = 0; totalWithdrawnValidator = 0; lastResetBlock = block.number; } } /// @notice Get the next withdraw block for account /// @param _account the address of the account. function getWithdrawBlock(address _account) external view returns (uint256) { return nextWithdrawBlock[_account]; } /// @notice Get the next withdraw beacon block for account /// @param _account the address of the account. function getWithdrawBeaconBlock(address _account) external view returns (uint256) { return nextWithdrawBeaconBlock[_account]; } /**************** ** ANTI-FRAUD ** ****************/ /// @notice Adds an address to the anti-fraud list. /// @dev Only a user with the ANTI_FRAUD_SENTINEL_ROLE or ANTI_FRAUD_MANAGER_ROLE can add addresses. /// @param _account The address to be added to the anti-fraud list. function addToAntiFraud(address _account) external { if (!hasRole(ANTI_FRAUD_SENTINEL_ROLE, msg.sender) && !hasRole(ANTI_FRAUD_MANAGER_ROLE, msg.sender)) revert NotAuthorized(); if (_account == address(0)) revert ZeroAddress(); antiFraudList[_account] = true; emit SetAntiFraudStatus(msg.sender, _account, true); } /// @notice Removes an address from the anti-fraud list. /// @dev Only a user with the ANTI_FRAUD_MANAGER_ROLE can remove addresses. /// @param _account The address to be removed from the anti-fraud list. function removeFromAntiFraud(address _account) external { if (!hasRole(ANTI_FRAUD_MANAGER_ROLE, msg.sender)) revert NotAuthorized(); if (_account == address(0)) revert ZeroAddress(); if (!antiFraudList[_account]) revert NotInAntiFraudList(); antiFraudList[_account] = false; emit SetAntiFraudStatus(msg.sender, _account, false); } /// @notice Check if an address is listed in the anti-fraud list. /// @param _account The address to be checked. /// @return true if the address is in the anti-fraud list, false otherwise. function isListedInAntiFraud(address _account) public view returns (bool) { return antiFraudList[_account]; } /*********** ** POOLS ** ***********/ /// @notice Adds a permissionless pool with a specified address and listing status if feature enabled. /// @param _pool The address of the pool to add. /// @param _listed The listing status of the pool. /// @param _social The kind of pool. /// @param _index Checked if the pool is a index function addPool( address _pool, bool _listed, bool _social, bool _index ) external payable nonReentrant whenNotPaused nonFlashLoan { if (_pool == address(0)) revert ZeroAddress(); if (pools[_pool]) revert PoolExists(); if (!hasRole(POOL_MANAGER_ROLE, msg.sender) || msg.value > 0) { if (!config.feature.AddPool) revert FeatureDisabled(); if (msg.value != fees[FeeType.Pool].value) revert InvalidValue(); _processFeePool(); } pools[_pool] = true; lastOperationBlock[msg.sender] = block.number; emit AddPool(_pool, _listed, _social, _index, msg.value); } /// @notice Removes a pool by its address. /// @param _pool The address of the pool to remove. function removePool(address _pool) external nonFlashLoan whenNotPaused onlyRole(POOL_MANAGER_ROLE) { if (!pools[_pool]) revert PoolNotFound(); pools[_pool] = false; lastOperationBlock[msg.sender] = block.number; emit RemovePool(_pool); } /// @notice Updates delegations for the sender's address. /// @param _delegations The array of delegations to update. function updateDelegations(Delegation[] memory _delegations) external { uint256 totalPercentage = 0; if (shares[msg.sender] > 0) { if (_delegations.length > config.maxDelegations) revert MaxDelegations(); for (uint256 i = 0; i < _delegations.length; i++) { if (!pools[_delegations[i].pool]) revert PoolNotFound(); totalPercentage += _delegations[i].percentage; } if (totalPercentage != 1 ether) revert InvalidTotalPercentage(); } else { if (_delegations.length != 0) revert ShouldBeZeroLength(); } emit UpdateDelegations(msg.sender, _delegations); } /*********************** ** VALIDATORS ORACLE ** ***********************/ /// @notice Adds a new validator oracle by its address. /// @param _account The address of the validator oracle to add. function addValidatorOracle(address _account) external onlyRole(VALIDATOR_ORACLE_MANAGER_ROLE) { if (validatorsOracleIndices[_account] != 0) revert ValidatorOracleExists(); validatorsOracle.push(_account); validatorsOracleIndices[_account] = validatorsOracle.length; _grantRole(VALIDATOR_ORACLE_ROLE, _account); emit AddValidatorOracle(_account); } /// @notice Removes a validator oracle by its address. /// @param _account The address of the validator oracle to remove. function removeValidatorOracle(address _account) external onlyRole(VALIDATOR_ORACLE_MANAGER_ROLE) { if (validatorsOracleIndices[_account] == 0) revert ValidatorOracleNotFound(); uint256 index = validatorsOracleIndices[_account] - 1; if (index < validatorsOracle.length - 1) { address lastAddress = validatorsOracle[validatorsOracle.length - 1]; validatorsOracle[index] = lastAddress; validatorsOracleIndices[lastAddress] = index + 1; } validatorsOracle.pop(); delete validatorsOracleIndices[_account]; bool isCurrentOracle = (index == currentOracleIndex); if (isCurrentOracle) { currentOracleIndex = (currentOracleIndex + 1) % validatorsOracle.length; } _revokeRole(VALIDATOR_ORACLE_ROLE, _account); emit RemoveValidatorOracle(_account); } /// @notice Checks if an address is a validator oracle. /// @param _account The address to check. /// @return True if the address is a validator oracle, false otherwise. function isValidatorOracle(address _account) public view returns (bool) { return hasRole(VALIDATOR_ORACLE_ROLE, _account) && validatorsOracleIndices[_account] > 0; } /// @notice Forces the selection of the next validator oracle. function forceNextValidatorOracle() external { if ( !hasRole(VALIDATOR_ORACLE_SENTINEL_ROLE, msg.sender) && !hasRole(VALIDATOR_ORACLE_MANAGER_ROLE, msg.sender) ) revert NotAuthorized(); _nextValidatorOracle(); } /// @notice Internal function to update the current validator oracle. function _nextValidatorOracle() private { currentOracleIndex = (currentOracleIndex + 1) % validatorsOracle.length; emit NextValidatorOracle(currentOracleIndex, validatorsOracle[currentOracleIndex]); } /**************** ** VALIDATORS ** ****************/ /// @notice Sets the beacon balance to the specified amount. /// @param _amount The amount to set as the beacon balance. /// @dev Only the router address can call this function. function setBeaconBalance(uint256 _amount) external payable nonReentrant { if (msg.sender != address(router)) revert OnlyRouter(); _setBeaconBalance(_amount); } /// @notice Internal function to set the beacon balance. /// @param _amount The amount to set as the beacon balance. function _setBeaconBalance(uint256 _amount) private { beaconBalance = _amount; emit SetBeaconBalance(_amount); } /// @notice Sets the pending withdraw balance to the specified amount. /// @param _amount The amount to set as the pending withdraw balance. /// @dev Only the router address can call this function. function setWithdrawBalance(uint256 _amount) external payable nonReentrant { if (msg.sender != address(router)) revert OnlyRouter(); _setWithdrawBalance(_amount); } /// @notice Internal function to set the pending withdraw balance. /// @param _amount The amount to set as the pending withdraw balance. function _setWithdrawBalance(uint256 _amount) private { withdrawBalance = _amount; emit SetWithdrawBalance(_amount); } /// @notice Initiates a transfer to anticipate a validator's withdrawal. /// @dev Only a valid validator oracle can initiate this anticipation request. /// This function also checks the balance constraints before processing. function anticipateWithdrawBeacon() external nonReentrant whenNotPaused { if (!isValidatorOracle(msg.sender)) revert OnlyValidatorOracle(); if (msg.sender != validatorsOracle[currentOracleIndex]) revert NotIsCurrentValidatorOracle(); if (withdrawBalance == 0) revert WithdrawZeroBalance(); uint256 routerBalance = address(router).balance; if (routerBalance > withdrawBalance) revert RouterAlreadyHaveBalance(); uint256 diffAmount = withdrawBalance - routerBalance; if (address(this).balance < diffAmount) revert NotEnoughPoolBalance(); _setBeaconBalance(beaconBalance + diffAmount); emit AnticipateWithdrawBeacon(msg.sender, diffAmount); router.receiveWithdrawEther{ value: diffAmount }(); } /// @notice Creates a new validator with the given parameters. /// @param _publicKey The public key of the validator. /// @param _signature The signature of the validator. /// @param _depositDataRoot The deposit data root for the validator. /// @dev Only a valid validator oracle can call this function. function addValidator( bytes calldata _publicKey, bytes calldata _signature, bytes32 _depositDataRoot ) external nonReentrant whenNotPaused { if (!isValidatorOracle(msg.sender)) revert OnlyValidatorOracle(); if (msg.sender != validatorsOracle[currentOracleIndex]) revert NotIsCurrentValidatorOracle(); if (address(this).balance < config.poolSize) revert NotEnoughBalanceOnPool(); if (validators[_publicKey]) revert ValidatorExists(); if (address(router).balance < withdrawBalance) revert ShouldAnticipateWithdraw(); validators[_publicKey] = true; _nextValidatorOracle(); _setBeaconBalance(beaconBalance + config.validatorSize); emit AddValidator( msg.sender, config.validatorSize, _publicKey, withdrawalCredentials, _signature, _depositDataRoot ); deposit.deposit{ value: config.validatorSize }( _publicKey, withdrawalCredentials, _signature, _depositDataRoot ); _processFeeValidator(); } /************* ** Airdrop ** *************/ /// @notice Function to claim rewards by transferring shares, accessible only by the airdrop fee address. /// @param _account Address to transfer the claimed rewards to. /// @param _sharesAmount Amount of shares to claim as rewards. function claimAirdrop(address _account, uint256 _sharesAmount) external whenNotPaused { if (msg.sender != address(airdrop)) revert OnlyAirdrop(); _transferShares(address(airdrop), _account, _sharesAmount); } /***************** ** FEES ** *****************/ /// @notice Returns an array of fee roles. /// @return roles An array of FeeRole. function getFeesRoles() public pure returns (FeeRole[4] memory) { return [FeeRole.Airdrop, FeeRole.Operator, FeeRole.StakeTogether, FeeRole.Sender]; } /// @notice Sets the fee address for a given role. /// @param _role The role for which the address will be set. /// @param _address The address to set. /// @dev Only an admin can call this function. function setFeeAddress(FeeRole _role, address payable _address) external onlyRole(ADMIN_ROLE) { if (_address == address(0)) revert ZeroAddress(); feesRole[_role] = _address; if (_role == FeeRole.Airdrop) { feesRole[_role] = payable(airdrop); } else { feesRole[_role] = _address; } emit SetFeeAddress(_role, _address); } /// @notice Gets the fee address for a given role. /// @param _role The role for which the address will be retrieved. /// @return The address associated with the given role. function getFeeAddress(FeeRole _role) public view returns (address) { return feesRole[_role]; } /// @notice Sets the fee for a given fee type. /// @param _feeType The type of fee to set. /// @param _value The value of the fee. /// @param _allocations The allocations for the fee. /// @dev Only an admin can call this function. function setFee( FeeType _feeType, uint256 _value, uint256[] calldata _allocations ) external onlyRole(ADMIN_ROLE) { if (_allocations.length != 4) revert InvalidLength(); uint256 sum = 0; for (uint256 i = 0; i < _allocations.length; i++) { fees[_feeType].allocations[FeeRole(i)] = _allocations[i]; sum += _allocations[i]; } if (sum != 1 ether) revert InvalidSum(); fees[_feeType].value = _value; emit SetFee(_feeType, _value, _allocations); } /// @notice Get the fee for a given fee type. /// @param _feeType The type of fee to get. function getFee(FeeType _feeType) external view returns (uint256) { return fees[_feeType].value; } /// @notice Distributes fees according to their type, amount, and the destination. /// @param _feeType The type of fee being distributed. /// @param _sharesAmount The total shares amount for the fee. /// @param _to The address to distribute the fees. /// @dev This function computes how the fees are allocated to different roles. function _distributeFees(FeeType _feeType, uint256 _sharesAmount, address _to) private { uint256[4] memory allocatedShares; FeeRole[4] memory roles = getFeesRoles(); uint256 feeValue = fees[_feeType].value; uint256 feeShares = Math.mulDiv(_sharesAmount, feeValue, 1 ether); uint256 totalAllocatedShares = 0; for (uint256 i = 0; i < roles.length - 1; i++) { if (getFeeAddress(roles[i]) == address(0)) revert ZeroAddress(); uint256 allocation = fees[_feeType].allocations[roles[i]]; allocatedShares[i] = Math.mulDiv(feeShares, allocation, 1 ether); totalAllocatedShares += allocatedShares[i]; } allocatedShares[3] = _sharesAmount - totalAllocatedShares; uint256 length = (_feeType == FeeType.Entry) ? roles.length : roles.length - 1; for (uint256 i = 0; i < length; i++) { if (allocatedShares[i] > 0) { if (_feeType == FeeType.Entry && roles[i] == FeeRole.Sender) { _mintShares(_to, allocatedShares[i]); } else { _mintShares(getFeeAddress(roles[i]), allocatedShares[i]); emit MintFeeShares(getFeeAddress(roles[i]), allocatedShares[i], _feeType, roles[i]); } } } } /// @notice Processes a stake entry and distributes the associated fees. /// @param _to The address to receive the stake entry. /// @param _amount The amount staked. /// @dev Calls the distributeFees function internally. function _processFeeEntry(address _to, uint256 _amount) private { uint256 sharesAmount = Math.mulDiv(_amount, totalShares, totalSupply() - _amount); _distributeFees(FeeType.Entry, sharesAmount, _to); } /// @notice Process staking rewards and distributes the rewards based on shares. /// @param _sharesAmount The amount of shares related to the staking rewards. /// @dev The caller should be the router contract. This function will also emit the ProcessStakeRewards event. function processFeeRewards(uint256 _sharesAmount) external payable nonReentrant whenNotPaused { if (msg.sender != address(router)) revert OnlyRouter(); _distributeFees(FeeType.Rewards, _sharesAmount, address(0)); emit ProcessStakeRewards(msg.value, _sharesAmount); } /// @notice Processes the staking pool fee and distributes it accordingly. /// @dev Calculates the shares amount and then distributes the staking pool fee. function _processFeePool() private { uint256 amount = fees[FeeType.Pool].value; uint256 sharesAmount = Math.mulDiv(amount, totalShares, totalSupply() - amount); _distributeFees(FeeType.Pool, sharesAmount, address(0)); } /// @notice Transfers the staking validator fee to the operator role. /// @dev Transfers the associated amount to the Operator's address. function _processFeeValidator() private { emit ProcessStakeValidator(getFeeAddress(FeeRole.Operator), fees[FeeType.Validator].value); Address.sendValue(payable(getFeeAddress(FeeRole.Operator)), fees[FeeType.Validator].value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl struct AccessControlStorage { mapping(bytes32 role => RoleData) _roles; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800; function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) { assembly { $.slot := AccessControlStorageLocation } } /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); return $._roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { AccessControlStorage storage $ = _getAccessControlStorage(); return $._roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { AccessControlStorage storage $ = _getAccessControlStorage(); bytes32 previousAdminRole = getRoleAdmin(role); $._roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); if (!hasRole(role, account)) { $._roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); if (hasRole(role, account)) { $._roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC1967-compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol"; import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. */ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors { /// @custom:storage-location erc7201:openzeppelin.storage.ERC20 struct ERC20Storage { mapping(address account => uint256) _balances; mapping(address account => mapping(address spender => uint256)) _allowances; uint256 _totalSupply; string _name; string _symbol; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; function _getERC20Storage() private pure returns (ERC20Storage storage $) { assembly { $.slot := ERC20StorageLocation } } /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { ERC20Storage storage $ = _getERC20Storage(); $._name = name_; $._symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); return $._allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `value`. * - the caller must have allowance for ``from``'s tokens of at least * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @dev Moves a `value` amount of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(from, to, value); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (from == address(0)) { // Overflow check required: The rest of the code assumes that totalSupply never overflows $._totalSupply += value; } else { uint256 fromBalance = $._balances[from]; if (fromBalance < value) { revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { // Overflow not possible: value <= fromBalance <= totalSupply. $._balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. $._totalSupply -= value; } } else { unchecked { // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. $._balances[to] += value; } } emit Transfer(from, to, value); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } _update(account, address(0), value); } /** * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { _approve(owner, spender, value, true); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * ``` * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { ERC20Storage storage $ = _getERC20Storage(); if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } $._allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.20; import {ERC20Upgradeable} from "../ERC20Upgradeable.sol"; import {ContextUpgradeable} from "../../../utils/ContextUpgradeable.sol"; import {Initializable} from "../../../proxy/utils/Initializable.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 ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable { function __ERC20Burnable_init() internal onlyInitializing { } function __ERC20Burnable_init_unchained() internal onlyInitializing { } /** * @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/ERC20Permit.sol) pragma solidity ^0.8.20; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {ERC20Upgradeable} from "../ERC20Upgradeable.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {EIP712Upgradeable} from "../../../utils/cryptography/EIP712Upgradeable.sol"; import {NoncesUpgradeable} from "../../../utils/NoncesUpgradeable.sol"; import {Initializable} from "../../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20Permit, EIP712Upgradeable, NoncesUpgradeable { bytes32 private constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev Permit deadline has expired. */ error ERC2612ExpiredSignature(uint256 deadline); /** * @dev Mismatched signature. */ error ERC2612InvalidSigner(address signer, address owner); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ function __ERC20Permit_init(string memory name) internal onlyInitializing { __EIP712_init_unchained(name, "1"); } function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {} /** * @inheritdoc IERC20Permit */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { if (block.timestamp > deadline) { revert ERC2612ExpiredSignature(deadline); } bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); if (signer != owner) { revert ERC2612InvalidSigner(signer, owner); } _approve(owner, spender, value); } /** * @inheritdoc IERC20Permit */ function nonces(address owner) public view virtual override(IERC20Permit, NoncesUpgradeable) returns (uint256) { return super.nonces(owner); } /** * @inheritdoc IERC20Permit */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view virtual returns (bytes32) { return _domainSeparatorV4(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.20; import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. */ abstract contract EIP712Upgradeable is Initializable, IERC5267 { bytes32 private constant TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @custom:storage-location erc7201:openzeppelin.storage.EIP712 struct EIP712Storage { /// @custom:oz-renamed-from _HASHED_NAME bytes32 _hashedName; /// @custom:oz-renamed-from _HASHED_VERSION bytes32 _hashedVersion; string _name; string _version; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.EIP712")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100; function _getEIP712Storage() private pure returns (EIP712Storage storage $) { assembly { $.slot := EIP712StorageLocation } } /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { EIP712Storage storage $ = _getEIP712Storage(); $._name = name; $._version = version; // Reset prior values in storage if upgrading $._hashedName = 0; $._hashedVersion = 0; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(); } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {IERC-5267}. */ function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { EIP712Storage storage $ = _getEIP712Storage(); // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized // and the EIP712 domain is not reliable, as it will be missing name and version. require($._hashedName == 0 && $._hashedVersion == 0, "EIP712: Uninitialized"); return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Name() internal view virtual returns (string memory) { EIP712Storage storage $ = _getEIP712Storage(); return $._name; } /** * @dev The version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Version() internal view virtual returns (string memory) { EIP712Storage storage $ = _getEIP712Storage(); return $._version; } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. */ function _EIP712NameHash() internal view returns (bytes32) { EIP712Storage storage $ = _getEIP712Storage(); string memory name = _EIP712Name(); if (bytes(name).length > 0) { return keccak256(bytes(name)); } else { // If the name is empty, the contract may have been upgraded without initializing the new storage. // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. bytes32 hashedName = $._hashedName; if (hashedName != 0) { return hashedName; } else { return keccak256(""); } } } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. */ function _EIP712VersionHash() internal view returns (bytes32) { EIP712Storage storage $ = _getEIP712Storage(); string memory version = _EIP712Version(); if (bytes(version).length > 0) { return keccak256(bytes(version)); } else { // If the version is empty, the contract may have been upgraded without initializing the new storage. // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. bytes32 hashedVersion = $._hashedVersion; if (hashedVersion != 0) { return hashedVersion; } else { return keccak256(""); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165Upgradeable is Initializable, IERC165 { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides tracking nonces for addresses. Nonces will only increment. */ abstract contract NoncesUpgradeable is Initializable { /** * @dev The nonce used for an `account` is not the expected current nonce. */ error InvalidAccountNonce(address account, uint256 currentNonce); /// @custom:storage-location erc7201:openzeppelin.storage.Nonces struct NoncesStorage { mapping(address account => uint256) _nonces; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Nonces")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00; function _getNoncesStorage() private pure returns (NoncesStorage storage $) { assembly { $.slot := NoncesStorageLocation } } function __Nonces_init() internal onlyInitializing { } function __Nonces_init_unchained() internal onlyInitializing { } /** * @dev Returns the next unused nonce for an address. */ function nonces(address owner) public view virtual returns (uint256) { NoncesStorage storage $ = _getNoncesStorage(); return $._nonces[owner]; } /** * @dev Consumes a nonce. * * Returns the current value and increments nonce. */ function _useNonce(address owner) internal virtual returns (uint256) { NoncesStorage storage $ = _getNoncesStorage(); // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be // decremented or reset. This guarantees that the nonce never overflows. unchecked { // It is important to do x++ and not ++x here. return $._nonces[owner]++; } } /** * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. */ function _useCheckedNonce(address owner, uint256 nonce) internal virtual { uint256 current = _useNonce(owner); if (nonce != current) { revert InvalidAccountNonce(owner, current); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Pausable struct PausableStorage { bool _paused; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300; function _getPausableStorage() private pure returns (PausableStorage storage $) { assembly { $.slot := PausableStorageLocation } } /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { PausableStorage storage $ = _getPausableStorage(); $._paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { PausableStorage storage $ = _getPausableStorage(); return $._paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.20; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.20; import {IBeacon} from "../beacon/IBeacon.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. */ library ERC1967Utils { // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. // This will be fixed in Solidity 0.8.21. At that point we should remove these events. /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.20; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS } /** * @dev The signature derives the `address(0)`. */ error ECDSAInvalidSignature(); /** * @dev The signature has an invalid length. */ error ECDSAInvalidSignatureLength(uint256 length); /** * @dev The signature has an S value that is in the upper half order. */ error ECDSAInvalidSignatureS(bytes32 s); /** * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not * return address(0) without also returning an error description. Errors are documented using an enum (error type) * and a bytes32 providing additional information about the error. * * If no error is returned, then the address can be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { unchecked { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); // We do not check for an overflow here since the shift operation results in 0 or 1. uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); _throwError(error, errorArg); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError, bytes32) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS, s); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature, bytes32(0)); } return (signer, RecoverError.NoError, bytes32(0)); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); _throwError(error, errorArg); return recovered; } /** * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. */ function _throwError(RecoverError error, bytes32 errorArg) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert ECDSAInvalidSignature(); } else if (error == RecoverError.InvalidSignatureLength) { revert ECDSAInvalidSignatureLength(uint256(errorArg)); } else if (error == RecoverError.InvalidSignatureS) { revert ECDSAInvalidSignatureS(errorArg); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an EIP-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @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 ERC1967 implementation slot: * ```solidity * contract ERC1967 { * 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; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 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 `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 } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-FileCopyrightText: 2023 Stake Together Labs <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.22; /// @title Interface for the Airdrop functionality within the Stake Together protocol. /// @notice A contract that represents the Airdrop functionality. /// @custom:security-contact [email protected] interface IAirdrop { /// @notice Thrown if a claim has already been made for a given block and index. error AlreadyClaimed(); /// @notice Thrown if the Merkle Proof verification fails. error InvalidProof(); /// @notice Thrown if the listed in anti-fraud. error ListedInAntiFraud(); /// @notice Thrown if the Merkle Root is not set for a given block number. error MerkleRootNotSet(); /// @notice This error is thrown when trying to set a Merkle Root that has already been set for a given block. error MerkleRootAlreadySetForBlock(); /// @notice This error is thrown when there is no extra ETH available for transfer. error NoExtraAmountAvailable(); /// @notice This error is thrown when an action is performed by an address that is not the router. error OnlyRouter(); /// @notice This error is thrown when trying to set the router address that is already set. error RouterAlreadySet(); /// @notice This error is thrown when trying to set the stakeTogether address that is already set. error StakeTogetherAlreadySet(); /// @notice Thrown if the shares amount being claimed is zero. error ZeroAmount(); /// @notice Thrown if the address trying to make a claim is the zero address. error ZeroAddress(); /// @notice Emitted when a new Merkle root is added. /// @param reportBlock The block report number corresponding to the Merkle root. /// @param merkleRoot The Merkle root. event AddMerkleRoot(uint256 indexed reportBlock, bytes32 merkleRoot); /// @notice Emitted when a claim is processed. /// @param blockNumber The report block number related to the claim. /// @param index The index of the claim within the Merkle tree. /// @param account The address of the account making the claim. /// @param sharesAmount The amount of shares claimed. /// @param merkleProof The Merkle proof corresponding to the claim. event Claim( uint256 indexed blockNumber, uint256 index, address indexed account, uint256 sharesAmount, bytes32[] merkleProof ); /// @notice Emitted when a batch of claims is processed. /// @param claimer The address making the batch claims. /// @param numClaims The number of claims in the batch. /// @param totalAmount The total amount of the claims in the batch. event ClaimBatch(address indexed claimer, uint256 numClaims, uint256 totalAmount); /// @notice Emitted when ETH is received by the contract. /// @param amount The amount of ETH received. event ReceiveEther(uint256 indexed amount); /// @notice Emitted when the router address is set. /// @param router The address of the router. event SetRouter(address indexed router); /// @notice Emitted when the StakeTogether contract address is set. /// @param stakeTogether The address of the StakeTogether contract. event SetStakeTogether(address indexed stakeTogether); /// @notice Initializes the contract with initial settings. function initialize() external; /// @notice Pauses all contract functionalities. /// @dev Only callable by the admin role. function pause() external; /// @notice Unpauses all contract functionalities. /// @dev Only callable by the admin role. function unpause() external; /// @notice Receives Ether and emits an event logging the sender and amount. receive() external payable; /// @notice Transfers any extra amount of ETH in the contract to the StakeTogether fee address. /// @dev Only callable by the admin role. function transferExtraAmount() external; /// @notice Sets the StakeTogether contract address. /// @param _stakeTogether The address of the StakeTogether contract. /// @dev Only callable by the admin role. function setStakeTogether(address _stakeTogether) external; /// @notice Sets the Router contract address. /// @param _router The address of the router. /// @dev Only callable by the admin role. function setRouter(address _router) external; /// @notice Adds a new Merkle root for a given block number. /// @param _reportBlock The report block number. /// @param _root The Merkle root. /// @dev Only callable by the router. function addMerkleRoot(uint256 _reportBlock, bytes32 _root) external; /// @notice Claims a reward for a specific report block number. /// @param _reportBlock The report block number. /// @param _index The index in the Merkle tree. /// @param _account The address claiming the reward. /// @param _sharesAmount The amount of shares to claim. /// @param merkleProof The Merkle proof required to claim the reward. /// @dev Verifies the Merkle proof and transfers the reward shares. function claim( uint256 _reportBlock, uint256 _index, address _account, uint256 _sharesAmount, bytes32[] calldata merkleProof ) external; /// @notice Checks if a reward has been claimed for a specific index and block number. /// @param _reportBlock The block number. /// @param _index The index in the Merkle tree. /// @return Returns true if the reward has been claimed, false otherwise. function isClaimed(uint256 _reportBlock, uint256 _index) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.22; // This interface is designed to be compatible with the Vyper version. /// @notice This is the Ethereum 2.0 deposit contract interface. /// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs interface IDepositContract { /// @notice A processed deposit event. event DepositEvent( bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index ); /// @notice Submit a Phase 0 DepositData object. /// @param pubkey A BLS12-381 public key. /// @param withdrawal_credentials Commitment to a public key for withdrawals. /// @param signature A BLS12-381 signature. /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. /// Used as a protection against malformed input. function deposit( bytes calldata pubkey, bytes calldata withdrawal_credentials, bytes calldata signature, bytes32 deposit_data_root ) external payable; /// @notice Query the current deposit root hash. /// @return The deposit root hash. function get_deposit_root() external view returns (bytes32); /// @notice Query the current deposit count. /// @return The deposit count encoded as a little endian 64-bit number. function get_deposit_count() external view returns (bytes memory); }
// SPDX-FileCopyrightText: 2023 Stake Together Labs <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.22; /// @title StakeTogether Report Configuration /// @notice This module includes configuration and reports related to the StakeTogether protocol. /// @custom:security-contact [email protected] interface IRouter { /// @notice Emitted when a report for a specific block has already been executed. error AlreadyExecuted(); /// @notice Emitted when an oracle has already reported for a specific block. error AlreadyReported(); /// @notice Emitted when the beacon's balance is not enough to cover the loss amount. error BeaconBalanceTooLow(); /// @notice Emitted when the block number has not yet reached the expected value for reporting. error BlockNumberNotReached(); /// @notice Emitted when the report configuration is not yet set. error ConfigNotSet(); /// @notice Emitted when the consensus is not yet delayed. error ConsensusNotDelayed(); /// @notice Emitted when trying to execute too early. error EarlyExecution(); /// @notice Emitted when the report's profit amount A is not enough for execution. error IncreaseOraclesToUseMargin(); /// @notice Emitted when ETH balance is not enough for transaction. error InsufficientEthBalance(); /// @notice Emitted when the oracles' margin is too high. error MarginTooHigh(); /// @notice Emitted when there's no active consensus for a report block. error NoActiveConsensus(); /// @notice Emitted when there is no pending execution for consensus. error NoPendingExecution(); /// @notice Emitted when the report block is not yet reached. error OracleAlreadyReported(); /// @notice Emitted when an oracle is not in the report oracles list. error OracleNotExists(); /// @notice Emitted when an oracle is already in the report oracles list. error OracleExists(); /// @notice Emitted when an oracle is already blacklisted. error OracleAlreadyBlacklisted(); /// @notice Emitted when an oracle is blacklisted. error OracleBlacklisted(); /// @notice Emitted when an oracle is not blacklisted. error OracleNotBlacklisted(); /// @notice Emitted when an oracle is active. error OnlyActiveOracle(); /// @notice Emitted when an action is attempted by an address other than the stakeTogether contract. error OnlyStakeTogether(); /// @notice Emitted when there is a pending execution for consensus. error PendingExecution(); /// @notice Emitted when the report delay blocks are too high. error ReportDelayBlocksTooHigh(); /// @notice Emitted when a report for a specific block has already been revoked. error ReportRevoked(); /// Emits when the report block is not greater than the last executed reportBlock. error ReportBlockShouldBeGreater(); /// @notice Emitted when there are not enough oracles to use the margin. error RequiredMoreOracles(); /// @notice Emitted when the quorum is not yet reached for consensus. error QuorumNotReached(); /// @notice Emitted when a sentinel exists in the oracles list. error SentinelExists(); /// @notice Emitted when a sentinel does not exist in the oracles list. error SentinelNotExists(); /// @notice Emitted when trying to set the stakeTogether address that is already set. error StakeTogetherAlreadySet(); /// @notice Emitted when the stakeTogether's withdraw balance is not enough. error WithdrawBalanceTooLow(); /// @notice Thrown if the address trying to make a claim is the zero address. error ZeroAddress(); /// @dev Config structure used for configuring the reporting mechanism in StakeTogether protocol. /// @param bunkerMode A boolean flag to indicate whether the bunker mode is active or not. /// @param reportFrequency The frequency in which reports need to be generated. /// @param reportDelayBlock The number of blocks to delay before a report is considered. /// @param oracleQuorum The quorum required among oracles for a report to be considered. struct Config { uint256 reportFrequency; uint256 reportDelayBlock; uint256 reportNoConsensusMargin; uint256 oracleQuorum; } /// @dev Report structure used for reporting the state of the protocol at different report blocks. /// @param reportBlock The specific block period for which this report is generated. /// @param merkleRoot The Merkle root hash representing the state of the data at this reportBlock. /// @param profitAmount The total profit amount generated during this reportBlock. /// @param profitShares The distribution of profits among stakeholders for this reportBlock. /// @param lossAmount The total loss amount incurred during this reportBlock. /// @param withdrawAmount The total amount withdrawn by users during this reportBlock. /// @param withdrawRefundAmount The amount refunded to users on withdrawal during this reportBlock. /// @param accumulatedReports The total number of reports accumulated up to this reportBlock. struct Report { uint256 reportBlock; bytes32 merkleRoot; uint256 profitAmount; uint256 profitShares; uint256 lossAmount; uint256 withdrawAmount; uint256 withdrawRefundAmount; uint256 accumulatedReports; } /// @notice Emitted when a new oracle is added for reporting. /// @param reportOracle The address of the oracle that was added. event AddReportOracle(address indexed reportOracle); /// @notice Emitted when an oracle is blacklisted. /// @param reportOracle The address of the oracle that was blacklisted. event BlacklistReportOracle(address indexed reportOracle); /// @notice Emitted when a report is approved by consensus. /// @param report The report details. event ConsensusApprove(uint256 indexed reportBlock, Report report); /// @notice Emitted when a report is approved by consensus. /// @param report The report details. event ConsensusFail(uint256 indexed reportBlock, Report report); /// @notice Emitted when a report is executed. /// @param sender The sneder oracle that execute the report. /// @param report The report details. event ExecuteReport(address indexed sender, uint256 indexed reportBlock, Report report); /// @notice Emitted when the contract receives ether. /// @param amount The amount of ether received. event ReceiveEther(uint256 indexed amount); /// @notice Emitted when Ether is received from Stake Together /// @param amount The amount of Ether received event ReceiveWithdrawEther(uint256 indexed amount); /// @notice Emitted when an oracle is removed from reporting. /// @param reportOracle The address of the oracle that was removed. event RemoveReportOracle(address indexed reportOracle); /// @notice Emitted when a consensus report is revoked. /// @param sender The sentinel that execute the revoke. /// @param reportBlock The block number at which the consensus was revoked. event RevokeConsensusReport(address indexed sender, uint256 indexed reportBlock); /// @notice Emitted when bunker mode is set. /// @param bunkerMode The bunker mode flag. event SetBunkerMode(bool indexed bunkerMode); /// @notice Emitted when the protocol configuration is updated. /// @param config The updated configuration. event SetConfig(Config indexed config); /// @notice Emitted when the StakeTogether address is set. /// @param stakeTogether The address of the StakeTogether contract. event SetStakeTogether(address indexed stakeTogether); /// @notice Emitted when the next report frequency is skipped. /// @param reportBlock The reportBlock for which the report frequency was skipped. /// @param reportNextBlock The block number at which the report frequency was skipped. event AdvanceNextBlock(uint256 indexed reportBlock, uint256 indexed reportNextBlock); /// @notice Emitted when a report is submitted. /// @param sender The address of the oracle that submitted the report. /// @param report The details of the submitted report. event SubmitReport(address indexed sender, Report indexed report); /// @notice Emitted when an oracle is unblacklisted. /// @param reportOracle The address of the oracle that was unblacklisted. event UnBlacklistReportOracle(address indexed reportOracle); /// @notice Initializes the contract after deployment. /// @dev Initializes various base contract functionalities and sets the initial state. /// @param _airdrop The address of the Airdrop contract. /// @param _withdrawals The address of the Withdrawals contract. function initialize(address _airdrop, address _withdrawals) external; /// @notice Pauses the contract functionalities. /// @dev Only the ADMIN_ROLE can pause the contract. function pause() external; /// @notice Resumes the contract functionalities after being paused. /// @dev Only the ADMIN_ROLE can unpause the contract. function unpause() external; /// @notice Receive ether to the contract. /// @dev An event is emitted with the amount of ether received. receive() external payable; /// @notice Allows the Stake Together to send ETH to the contract. /// @dev This function can only be called by the Stake Together. function receiveWithdrawEther() external payable; /// @notice Sets the address for the StakeTogether contract. /// @dev Only the ADMIN_ROLE can set the address, and the provided address must not be zero. /// @param _stakeTogether The address of the StakeTogether contract. function setStakeTogether(address _stakeTogether) external; /// @notice Sets the configuration parameters for the contract. /// @dev Only the ADMIN_ROLE can set the configuration, and it ensures a minimum report delay block. /// @param _config A struct containing various configuration parameters. function setConfig(Config memory _config) external; /// @notice Checks if an address is an active report oracle. /// @param _account Address of the oracle to be checked. function isReportOracle(address _account) external returns (bool); /// @notice Checks if a report oracle is blacklisted. /// @param _account Address of the oracle to be checked. function isReportOracleBlackListed(address _account) external view returns (bool); /// @notice Adds a new report oracle. /// @dev Only an account with the ORACLE_REPORT_MANAGER_ROLE can call this function. /// @param _account Address of the oracle to be added. function addReportOracle(address _account) external; /// @notice Removes an existing report oracle. /// @dev Only an account with the ORACLE_REPORT_MANAGER_ROLE can call this function. /// @param _account Address of the oracle to be removed. function removeReportOracle(address _account) external; /// @notice Blacklists a report oracle. /// @dev Only an account with the ORACLE_SENTINEL_ROLE can call this function. /// @param _account Address of the oracle to be blacklisted. function blacklistReportOracle(address _account) external; /// @notice Removes a report oracle from the blacklist. /// @dev Only an account with the ORACLE_SENTINEL_ROLE can call this function. /// @param _account Address of the oracle to be removed from the blacklist. function unBlacklistReportOracle(address _account) external; /// @notice Adds a new sentinel account. /// @dev Only an account with the ADMIN_ROLE can call this function. /// @param _account Address of the account to be added as sentinel. function addSentinel(address _account) external; /// @notice Removes an existing sentinel account. /// @dev Only an account with the ADMIN_ROLE can call this function. /// @param _account Address of the sentinel account to be removed. function removeSentinel(address _account) external; /// @notice Submit a report for the current reporting block. /// @dev Handles report submissions, checking for consensus or thresholds and preps next block if needed. /// It uses a combination of total votes for report to determine consensus. /// @param _report Data structure of the report. function submitReport(Report calldata _report) external; /// @notice Allows an active report oracle to execute an approved report. /// @dev Executes the actions based on the consensus-approved report. /// @param _report The data structure containing report details. function executeReport(Report calldata _report) external; /// @notice Forces to advance to nextReportBlock. function forceNextReportBlock() external; /// @notice Computes and returns the hash of a given report. /// @param _report The data structure containing report details. function getReportHash(Report calldata _report) external pure returns (bytes32); // @notice Revokes a consensus-approved report for a given reportBlock. /// @dev Only accounts with the ORACLE_SENTINEL_ROLE can call this function. /// @param _reportBlock The reportBlock for which the report was approved. function revokeConsensusReport(uint256 _reportBlock) external; /// @notice Validates if conditions to submit a report for an reportBlock are met. /// @dev Verifies conditions such as block number, consensus reportBlock, executed reports, and oracle votes. /// @param _report The data structure containing report details. function isReadyToSubmit(Report calldata _report) external view returns (bytes32); /// @notice Validates if conditions to execute a report are met. /// @dev Verifies conditions like revoked reports, executed reports, consensus reports, and beacon balance. /// @param _report The data structure containing report details. function isReadyToExecute(Report calldata _report) external view returns (bytes32); /// @notice Returns the next report block. function reportBlock() external view returns (uint256); }
// SPDX-FileCopyrightText: 2023 Stake Together Labs <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.22; /// @title StakeTogether Interface /// @notice This interface defines the essential structures and functions for the StakeTogether protocol. /// @custom:security-contact [email protected] interface IStakeTogether { /// @notice Thrown if the deposit limit is reached. error DepositLimitReached(); /// @notice Thrown if the transfer is too early to be executed. error EarlyTransfer(); /// @notice Thrown if the feature is disabled. error FeatureDisabled(); /// @notice Thrown if the operation is a FlashLoan. error FlashLoan(); /// @notice Thrown if there is insufficient beacon balance. error InsufficientBeaconBalance(); /// @notice Thrown if there are insufficient funds in the account. error InsufficientAccountBalance(); /// @notice Thrown if the allowance is insufficient. error InsufficientAllowance(); /// @notice Thrown if there is insufficient pool balance. error InsufficientPoolBalance(); /// @notice Thrown if there are insufficient shares. error InsufficientShares(); /// @notice Thrown if the allocations length is invalid. error InvalidLength(); /// @notice Thrown if the total percentage is invalid. error InvalidSum(); /// @notice Thrown if the value is invalid. error InvalidValue(); /// @notice Thrown if the pool size is less than the validator size. error InvalidSize(); /// @notice Thrown if the total percentage is not equal to 1 ether. error InvalidTotalPercentage(); /// @notice Thrown if the total supply is invalid. error InvalidTotalSupply(); /// @notice Thrown if the number of delegations exceeds the maximum limit. error MaxDelegations(); /// @notice Thrown if the withdrawal amount is less than the minimum required. error LessThanMinimumWithdraw(); /// @notice Thrown if the caller is not the airdrop. error OnlyAirdrop(); /// @notice Thrown if the caller is not the router. error OnlyRouter(); /// @notice Thrown if the caller is not a validator oracle. error OnlyValidatorOracle(); /// @notice Thrown if the caller does not have the appropriate role. error NotAuthorized(); /// @notice Thrown if the account is not in anti-fraud list. error NotInAntiFraudList(); /// @notice Thrown if the caller is not the current oracle. error NotIsCurrentValidatorOracle(); /// @notice Thrown if there is not enough pool balance. error NotEnoughPoolBalance(); /// @notice Thrown if there is not enough balance on pool. error NotEnoughBalanceOnPool(); /// @notice Thrown if the pool is not found. error PoolNotFound(); /// @notice Thrown if the pool already exists. error PoolExists(); /// @notice Thrown if the listed in anti-fraud. error ListedInAntiFraud(); /// @notice Thrown if the router balance is greater than the withdrawal balance. error RouterAlreadyHaveBalance(); /// @notice Thrown if the router balance is lower than the withdrawal balance. error ShouldAnticipateWithdraw(); /// @notice Thrown if the delegations length should be zero. error ShouldBeZeroLength(); /// @notice Thrown if the validator oracle already exists. error ValidatorOracleExists(); /// @notice Thrown if the validator oracle is not found. error ValidatorOracleNotFound(); /// @notice Thrown if the withdrawal amount is zero. error ZeroAmount(); /// @notice Thrown if the address is the zero address. error ZeroAddress(); /// @notice Thrown if there is zero supply. error ZeroSupply(); /// @notice Thrown if the deposit amount is less than the minimum required. error LessThanMinimumDeposit(); /// @notice Thrown if the withdrawal pool limit is reached. error WithdrawalsPoolLimitReached(); /// @notice Thrown if the withdrawal validator limit is reached. error WithdrawalsValidatorLimitWasReached(); /// @notice Thrown if the withdrawal balance is zero. error WithdrawZeroBalance(); /// @notice Thrown if the amount is not greater than the pool balance. error WithdrawFromPool(); /// @notice Thrown if the validator already exists. error ValidatorExists(); /// @notice Configuration for the StakeTogether protocol. struct Config { uint256 blocksPerDay; /// Number of blocks per day. uint256 depositLimit; /// Maximum amount of deposit. uint256 maxDelegations; /// Maximum number of delegations. uint256 minDepositAmount; /// Minimum amount to deposit. uint256 minWithdrawAmount; /// Minimum amount to withdraw. uint256 poolSize; /// Size of the pool. uint256 validatorSize; /// Size of the validator. uint256 withdrawalPoolLimit; /// Maximum amount of pool withdrawal. uint256 withdrawalValidatorLimit; /// Maximum amount of validator withdrawal. uint256 withdrawDelay; /// Delay Blocks for withdrawal. uint256 withdrawBeaconDelay; /// Delay Blocks for beacon withdrawal. Feature feature; /// Additional features configuration. } /// @notice Represents a delegation, including the pool address and shares. struct Delegation { address pool; /// Address of the delegated pool. uint256 percentage; /// Number of percentage in the delegation. } /// @notice Toggleable features for the protocol. struct Feature { bool AddPool; /// Enable/disable pool addition. bool Deposit; /// Enable/disable deposits. bool WithdrawPool; /// Enable/disable pool withdrawals. bool WithdrawBeacon; /// Enable/disable validator withdrawals. } /// @notice Represents the fee structure. struct Fee { uint256 value; /// Value of the fee. mapping(FeeRole => uint256) allocations; /// Allocation of fees among different roles. } /// @notice Types of deposits available. enum DepositType { Donation, /// Donation type deposit. Pool /// Pool type deposit. } /// @notice Types of withdrawals available. enum WithdrawType { Pool, /// Pool type withdrawal. Validator /// Validator type withdrawal. } /// @notice Types of fees within the protocol. enum FeeType { Entry, /// Fee for entering a stake. Rewards, /// Fee for staking rewards. Pool, /// Fee for pool staking. Validator /// Fee for validator staking. } /// @notice Different roles that are used in fee allocation enum FeeRole { Airdrop, Operator, StakeTogether, Sender } /// @notice Emitted when a pool is added /// @param pool The address of the pool /// @param listed Indicates if the pool is listed /// @param social Indicates if the pool is social /// @param index Indicates if the pool is an index /// @param amount The amount associated with the pool event AddPool(address indexed pool, bool listed, bool social, bool index, uint256 amount); /// @notice Emitted when a validator oracle is added /// @param account The address of the account event AddValidatorOracle(address indexed account); /// @notice Emitted when withdraw is prioritized /// @param oracle The address of the oracle /// @param amount The amount for the validator event AnticipateWithdrawBeacon(address indexed oracle, uint256 amount); /// @notice Emitted when shares are burned /// @param account The address of the account /// @param sharesAmount The amount of shares burned event BurnShares(address indexed account, uint256 sharesAmount); /// @notice Emitted when a validator is created /// @param oracle The address of the oracle /// @param amount The amount for the validator /// @param publicKey The public key of the validator /// @param withdrawalCredentials The withdrawal credentials /// @param signature The signature /// @param depositDataRoot The deposit data root event AddValidator( address indexed oracle, uint256 amount, bytes publicKey, bytes withdrawalCredentials, bytes signature, bytes32 depositDataRoot ); /// @notice Emitted when a base deposit is made /// @param to The address to deposit to /// @param amount The deposit amount /// @param depositType The type of deposit (Donation, Pool) /// @param pool The address of the pool /// @param referral The address of the referral event DepositBase( address indexed to, uint256 amount, DepositType depositType, address indexed pool, bytes indexed referral ); /// @notice Emitted when the deposit limit is reached /// @param sender The address of the sender /// @param amount The amount deposited event DepositLimitWasReached(address indexed sender, uint256 amount); /// @notice Emitted when rewards are minted /// @param to The address to mint to /// @param sharesAmount The amount of shares minted /// @param feeType The type of fee (e.g., StakeEntry, ProcessStakeRewards) /// @param feeRole The role associated with the fee event MintFeeShares( address indexed to, uint256 sharesAmount, FeeType indexed feeType, FeeRole indexed feeRole ); /// @notice Emitted when shares are minted /// @param to The address to mint to /// @param sharesAmount The amount of shares minted event MintShares(address indexed to, uint256 sharesAmount); /// @notice Emitted when the next validator oracle is set /// @param index The index of the oracle /// @param account The address of the account event NextValidatorOracle(uint256 index, address indexed account); /// @dev This event emits when rewards are processed for staking, indicating the amount and the number of shares. /// @param amount The total amount of rewards that have been processed for staking. /// @param sharesAmount The total number of shares associated with the processed staking rewards. event ProcessStakeRewards(uint256 indexed amount, uint256 indexed sharesAmount); /// @dev This event emits when a validator's stake has been processed. /// @param account The address of the account whose stake as a validator has been processed. /// @param amount The amount the account staked that has been processed. event ProcessStakeValidator(address indexed account, uint256 amount); /// @notice Emitted when Ether is received /// @param amount The amount of Ether received event ReceiveEther(uint256 indexed amount); /// @notice Emitted when a pool is removed /// @param pool The address of the pool event RemovePool(address indexed pool); /// @notice Emitted when a validator oracle is removed /// @param account The address of the account event RemoveValidatorOracle(address indexed account); /// @notice Emitted when the beacon balance is set /// @param amount The amount set for the beacon balance event SetBeaconBalance(uint256 indexed amount); /// @notice Emitted when a user's anti-fraud status is changed /// @param sender The address that is executing /// @param account The address of the account /// @param isListed The new anti-fraud status of the account (true if listed, false otherwise) event SetAntiFraudStatus(address indexed sender, address indexed account, bool isListed); /// @notice Emitted when the configuration is set /// @param config The configuration struct event SetConfig(Config indexed config); /// @notice Emitted when a fee is set /// @param feeType The type of fee being set /// @param value The value of the fee /// @param allocations The allocations for the fee event SetFee(FeeType indexed feeType, uint256 value, uint256[] allocations); /// @notice Emitted when a fee address is set /// @param role The role associated with the fee /// @param account The address of the account event SetFeeAddress(FeeRole indexed role, address indexed account); /// @notice Emitted when the router is set /// @param router The address of the router event SetRouter(address indexed router); /// @notice Emitted when the StakeTogether address is set /// @param stakeTogether The address of StakeTogether event SetStakeTogether(address indexed stakeTogether); /// @notice Emitted when the validator size is set /// @param newValidatorSize The new size for the validator event SetValidatorSize(uint256 indexed newValidatorSize); /// @notice Emitted when the withdraw balance is set /// @param amount The amount set for the withdraw balance event SetWithdrawBalance(uint256 indexed amount); /// @notice Emitted when the withdrawal credentials are set /// @param withdrawalCredentials The withdrawal credentials bytes event SetWithdrawalsCredentials(bytes indexed withdrawalCredentials); /// @notice Emitted when shares are transferred /// @param from The address transferring from /// @param to The address transferring to /// @param sharesAmount The amount of shares transferred event TransferShares(address indexed from, address indexed to, uint256 sharesAmount); /// @notice Emitted when delegations are updated /// @param account The address of the account /// @param delegations The delegation array event UpdateDelegations(address indexed account, Delegation[] delegations); /// @notice Emitted when a base withdrawal is made /// @param account The address withdrawing /// @param amount The withdrawal amount /// @param withdrawType The type of withdrawal /// @param pool The address of the pool event WithdrawBase( address indexed account, uint256 amount, WithdrawType withdrawType, address indexed pool ); /// @notice Emitted when the withdrawal limit is reached /// @param sender The address of the sender /// @param amount The amount withdrawn event WithdrawalsLimitWasReached(address indexed sender, uint256 amount, WithdrawType withdrawType); /// @notice Pauses the contract, preventing certain actions. /// @dev Only callable by the admin role. function pause() external; /// @notice Unpauses the contract, allowing actions to resume. /// @dev Only callable by the admin role. function unpause() external; /// @notice Receive function to accept incoming ETH transfers. receive() external payable; /// @notice Sets the configuration for the Stake Together Protocol. /// @dev Only callable by the admin role. /// @param _config Configuration settings to be applied. function setConfig(Config memory _config) external; /// @notice Returns the total supply of the pool (contract balance + beacon balance). /// @return Total supply value. function totalSupply() external view returns (uint256); /// @notice Calculates the shares amount by wei. /// @param _account The address of the account. /// @return Balance value of the given account. function balanceOf(address _account) external view returns (uint256); /// @notice Retrieves the current balance of the beacon. /// @dev This function returns the current stored value within the beacon. /// @return The balance held within the beacon in uint256 format. function beaconBalance() external view returns (uint256); /// @notice Retrieves the available balance for withdrawal. /// @dev This function returns the balance that is currently available for withdrawal. /// @return The available balance for withdrawal in uint256 format. function withdrawBalance() external view returns (uint256); /// @notice Calculates the wei amount by shares. /// @param _sharesAmount Amount of shares. /// @return Equivalent amount in wei. function weiByShares(uint256 _sharesAmount) external view returns (uint256); /// @notice Calculates the shares amount by wei. /// @param _amount Amount in wei. /// @return Equivalent amount in shares. function sharesByWei(uint256 _amount) external view returns (uint256); /// @notice Transfers an amount of wei to the specified address. /// @param _to The address to transfer to. /// @param _amount The amount to be transferred. /// @return True if the transfer was successful. function transfer(address _to, uint256 _amount) external returns (bool); /// @notice Transfers tokens from one address to another using an allowance mechanism. /// @param _from Address to transfer from. /// @param _to Address to transfer to. /// @param _amount Amount of tokens to transfer. /// @return A boolean value indicating whether the operation succeeded. function transferFrom(address _from, address _to, uint256 _amount) external returns (bool); /// @notice Returns the remaining number of tokens that an spender is allowed to spend on behalf of a token owner. /// @param _account Address of the token owner. /// @param _spender Address of the spender. /// @return A uint256 value representing the remaining number of tokens available for the spender. function allowance(address _account, address _spender) external view returns (uint256); /// @notice Sets the amount `_amount` as allowance of `_spender` over the caller's tokens. /// @param _spender Address of the spender. /// @param _amount Amount of allowance to be set. /// @return A boolean value indicating whether the operation succeeded. function approve(address _spender, uint256 _amount) external returns (bool); /// @notice Deposits into the pool with specific delegations. /// @param _pool the address of the pool. /// @param _referral The referral address. function depositPool(address _pool, bytes calldata _referral) external payable; /// @notice Deposits a donation to the specified address. /// @param _to The address to deposit to. /// @param _pool the address of the pool. /// @param _referral The referral address. function depositDonation(address _to, address _pool, bytes calldata _referral) external payable; /// @notice Withdraws from the pool with specific delegations and transfers the funds to the sender. /// @param _amount The amount to withdraw. /// @param _pool the address of the pool. function withdrawPool(uint256 _amount, address _pool) external; /// @notice Withdraws from the validators with specific delegations and mints tokens to the sender. /// @param _amount The amount to withdraw. /// @param _pool the address of the pool. function withdrawBeacon(uint256 _amount, address _pool) external; /// @notice Get the next withdraw block for account /// @param _account the address of the account. function getWithdrawBlock(address _account) external view returns (uint256); /// @notice Get the next withdraw beacon block for account /// @param _account the address of the account. function getWithdrawBeaconBlock(address _account) external view returns (uint256); /// @notice Adds an address to the anti-fraud list. /// @dev Callable only by accounts with the ANTI_FRAUD_SENTINEL_ROLE or ANTI_FRAUD_MANAGER_ROLE. /// Reverts if the provided address is the zero address or if the sender is not authorized. /// @param _account The address to be added to the anti-fraud list. function addToAntiFraud(address _account) external; /// @notice Removes an address from the anti-fraud list. /// @dev Callable only by accounts with the ANTI_FRAUD_MANAGER_ROLE. /// Reverts if the provided address is the zero address, not in the anti-fraud list, or if the sender is not authorized. /// @param _account The address to be removed from the anti-fraud list. function removeFromAntiFraud(address _account) external; /// @notice Check if an address is listed in the anti-fraud list. /// @param _account The address to be checked. /// @return true if the address is in the anti-fraud list, false otherwise. function isListedInAntiFraud(address _account) external view returns (bool); /// @notice Adds a permissionless pool with a specified address and listing status if feature enabled. /// @param _pool Address of the new pool. /// @param _listed True if the pool is listed. /// @param _social True if the pool is social. /// @param _index True if the pool is an index. function addPool(address _pool, bool _listed, bool _social, bool _index) external payable; /// @notice Removes a pool by its address. /// @param _pool The address of the pool to remove. function removePool(address _pool) external; /// @notice Updates delegations for the sender's address. /// @param _delegations The array of delegations to update. function updateDelegations(Delegation[] memory _delegations) external; /// @notice Adds a new validator oracle by its address. /// @param _account The address of the validator oracle to add. function addValidatorOracle(address _account) external; /// @notice Removes a validator oracle by its address. /// @param _account The address of the validator oracle to remove. function removeValidatorOracle(address _account) external; /// @notice Checks if an address is a validator oracle. /// @param _account The address to check. /// @return True if the address is a validator oracle, false otherwise. function isValidatorOracle(address _account) external view returns (bool); /// @notice Forces the selection of the next validator oracle. function forceNextValidatorOracle() external; /// @notice Sets the beacon balance to the specified amount. /// @param _amount The amount to set as the beacon balance. /// @dev Only the router address can call this function. function setBeaconBalance(uint256 _amount) external payable; /// @notice Sets the pending withdraw balance to the specified amount. /// @param _amount The amount to set as the pending withdraw balance. /// @dev Only the router address can call this function. function setWithdrawBalance(uint256 _amount) external payable; /// @notice Initiates a transfer to anticipate a validator's withdrawal. /// @dev Only a valid validator oracle can initiate this anticipation request. /// This function also checks the balance constraints before processing. function anticipateWithdrawBeacon() external; /// @notice Creates a new validator with the given parameters. /// @param _publicKey The public key of the validator. /// @param _signature The signature of the validator. /// @param _depositDataRoot The deposit data root for the validator. /// @dev Only a valid validator oracle can call this function. function addValidator( bytes calldata _publicKey, bytes calldata _signature, bytes32 _depositDataRoot ) external; /// @notice Function to claim rewards by transferring shares, accessible only by the airdrop fee address. /// @param _account Address to transfer the claimed rewards to. /// @param _sharesAmount Amount of shares to claim as rewards. function claimAirdrop(address _account, uint256 _sharesAmount) external; /// @notice Returns an array of fee roles. /// @return roles An array of FeeRole. function getFeesRoles() external pure returns (FeeRole[4] memory); /// @notice Sets the fee address for a given role. /// @param _role The role for which the address will be set. /// @param _address The address to set. /// @dev Only an admin can call this function. function setFeeAddress(FeeRole _role, address payable _address) external; /// @notice Gets the fee address for a given role. /// @param _role The role for which the address will be retrieved. /// @return The address associated with the given role. function getFeeAddress(FeeRole _role) external view returns (address); /// @notice Sets the fee for a given fee type. /// @param _feeType The type of fee to set. /// @param _value The value of the fee. /// @param _allocations The allocations for the fee. /// @dev Only an admin can call this function. function setFee(FeeType _feeType, uint256 _value, uint256[] calldata _allocations) external; /// @notice Process staking rewards and distributes the rewards based on shares. /// @param _sharesAmount The amount of shares related to the staking rewards. /// @dev Requires the caller to be the router contract. function processFeeRewards(uint256 _sharesAmount) external payable; }
// SPDX-FileCopyrightText: 2023 Stake Together Labs <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.22; /// @title Interface for Validators Withdrawals /// @notice A contract that represent the validator withdrawal functionality /// @custom:security-contact [email protected] interface IWithdrawals { /// @notice This error is thrown when use try withdraw before the beacon delay. error EarlyBeaconTransfer(); /// @notice Thrown if the operation is a FlashLoan. error FlashLoan(); /// @notice This error is thrown when the sender has insufficient STW balance to perform a transaction. error InsufficientStwBalance(); /// @notice This error is thrown when the contract has insufficient ETH balance to perform a transaction. error InsufficientEthBalance(); /// @notice Thrown if the listed in anti-fraud. error ListedInAntiFraud(); /// @notice This error is thrown when there is no extra amount of ETH available to transfer. error NoExtraAmountAvailable(); /// @notice This error is thrown when an action is attempted by an address other than the router. error OnlyRouter(); /// @notice This error is thrown when an action is attempted by an address other than the stakeTogether contract. error OnlyStakeTogether(); /// @notice This error is thrown when trying to set the router contract that has already been set. error RouterAlreadySet(); /// @notice This error is thrown when trying to set the stakeTogether address that has already been set. error StakeTogetherAlreadySet(); /// @notice Thrown if the shares amount being claimed is zero. error ZeroAmount(); /// @notice Thrown if the address trying to make a claim is the zero address. error ZeroAddress(); /// @notice Emitted when Ether is received /// @param amount The amount of Ether received event ReceiveEther(uint256 indexed amount); /// @notice Emitted when Ether is received from Router /// @param amount The amount of Ether received event ReceiveWithdrawEther(uint256 indexed amount); /// @notice Emitted when the Router address is set /// @param router The address of the StakeTogether contract event SetRouter(address indexed router); /// @notice Emitted when the StakeTogether address is set /// @param stakeTogether The address of the StakeTogether contract event SetStakeTogether(address indexed stakeTogether); /// @notice Emitted when a user withdraws funds /// @param user The address of the user who is withdrawing /// @param amount The amount being withdrawn event Withdraw(address indexed user, uint256 amount); /// @notice Initialization function for Withdrawals contract. function initialize() external; /// @notice Pauses withdrawals. /// @dev Only callable by the admin role. function pause() external; /// @notice Unpauses withdrawals. /// @dev Only callable by the admin role. function unpause() external; /// @notice Receive function to accept incoming ETH transfers. receive() external payable; /// @notice Allows the router to send ETH to the contract. /// @dev This function can only be called by the router. function receiveWithdrawEther() external payable; /// @notice Transfers any extra amount of ETH in the contract to the StakeTogether fee address. /// @dev Only callable by the admin role and requires that extra amount exists in the contract balance. function transferExtraAmount() external; /// @notice Sets the StakeTogether contract address. /// @param _stakeTogether The address of the new StakeTogether contract. /// @dev Only callable by the admin role. function setStakeTogether(address _stakeTogether) external; /// @notice Sets the Router contract address. /// @param _router The address of the router. /// @dev Only callable by the admin role. function setRouter(address _router) external; /// @notice Mints tokens to a specific address. /// @param _to Address to receive the minted tokens. /// @param _amount Amount of tokens to mint. /// @dev Only callable by the StakeTogether contract. function mint(address _to, uint256 _amount) external; /// @notice Withdraws the specified amount of ETH, burning tokens in exchange. /// @param _amount Amount of ETH to withdraw. /// @dev The caller must have a balance greater or equal to the amount, and the contract must have sufficient ETH balance. function withdraw(uint256 _amount) external; /// @notice Checks if the contract is ready to withdraw the specified amount. /// @param _amount Amount of ETH to check. /// @return A boolean indicating if the contract has sufficient balance to withdraw the specified amount. function isWithdrawReady(uint256 _amount) external view returns (bool); /// @notice Transfers an amount of wei to the specified address. /// @param _to The address to transfer to. /// @param _amount The amount to be transferred. /// @return True if the transfer was successful. function transfer(address _to, uint256 _amount) external returns (bool); /// @notice Transfers tokens from one address to another using an allowance mechanism. /// @param _from Address to transfer from. /// @param _to Address to transfer to. /// @param _amount Amount of tokens to transfer. /// @return A boolean value indicating whether the operation succeeded. function transferFrom(address _from, address _to, uint256 _amount) external returns (bool); }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"DepositLimitReached","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":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[],"name":"EarlyTransfer","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeatureDisabled","type":"error"},{"inputs":[],"name":"FlashLoan","type":"error"},{"inputs":[],"name":"InsufficientAccountBalance","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBeaconBalance","type":"error"},{"inputs":[],"name":"InsufficientPoolBalance","type":"error"},{"inputs":[],"name":"InsufficientShares","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentNonce","type":"uint256"}],"name":"InvalidAccountNonce","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"InvalidSize","type":"error"},{"inputs":[],"name":"InvalidSum","type":"error"},{"inputs":[],"name":"InvalidTotalPercentage","type":"error"},{"inputs":[],"name":"InvalidTotalSupply","type":"error"},{"inputs":[],"name":"InvalidValue","type":"error"},{"inputs":[],"name":"LessThanMinimumDeposit","type":"error"},{"inputs":[],"name":"LessThanMinimumWithdraw","type":"error"},{"inputs":[],"name":"ListedInAntiFraud","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"MaxDelegations","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotEnoughBalanceOnPool","type":"error"},{"inputs":[],"name":"NotEnoughPoolBalance","type":"error"},{"inputs":[],"name":"NotInAntiFraudList","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotIsCurrentValidatorOracle","type":"error"},{"inputs":[],"name":"OnlyAirdrop","type":"error"},{"inputs":[],"name":"OnlyRouter","type":"error"},{"inputs":[],"name":"OnlyValidatorOracle","type":"error"},{"inputs":[],"name":"PoolExists","type":"error"},{"inputs":[],"name":"PoolNotFound","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RouterAlreadyHaveBalance","type":"error"},{"inputs":[],"name":"ShouldAnticipateWithdraw","type":"error"},{"inputs":[],"name":"ShouldBeZeroLength","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"ValidatorExists","type":"error"},{"inputs":[],"name":"ValidatorOracleExists","type":"error"},{"inputs":[],"name":"ValidatorOracleNotFound","type":"error"},{"inputs":[],"name":"WithdrawFromPool","type":"error"},{"inputs":[],"name":"WithdrawZeroBalance","type":"error"},{"inputs":[],"name":"WithdrawalsPoolLimitReached","type":"error"},{"inputs":[],"name":"WithdrawalsValidatorLimitWasReached","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroSupply","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"bool","name":"listed","type":"bool"},{"indexed":false,"internalType":"bool","name":"social","type":"bool"},{"indexed":false,"internalType":"bool","name":"index","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AddPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"publicKey","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"withdrawalCredentials","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"depositDataRoot","type":"bytes32"}],"name":"AddValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddValidatorOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AnticipateWithdrawBeacon","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":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesAmount","type":"uint256"}],"name":"BurnShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"enum IStakeTogether.DepositType","name":"depositType","type":"uint8"},{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":true,"internalType":"bytes","name":"referral","type":"bytes"}],"name":"DepositBase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositLimitWasReached","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesAmount","type":"uint256"},{"indexed":true,"internalType":"enum IStakeTogether.FeeType","name":"feeType","type":"uint8"},{"indexed":true,"internalType":"enum IStakeTogether.FeeRole","name":"feeRole","type":"uint8"}],"name":"MintFeeShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesAmount","type":"uint256"}],"name":"MintShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"NextValidatorOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"sharesAmount","type":"uint256"}],"name":"ProcessStakeRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ProcessStakeValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReceiveEther","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"}],"name":"RemovePool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RemoveValidatorOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"isListed","type":"bool"}],"name":"SetAntiFraudStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SetBeaconBalance","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"blocksPerDay","type":"uint256"},{"internalType":"uint256","name":"depositLimit","type":"uint256"},{"internalType":"uint256","name":"maxDelegations","type":"uint256"},{"internalType":"uint256","name":"minDepositAmount","type":"uint256"},{"internalType":"uint256","name":"minWithdrawAmount","type":"uint256"},{"internalType":"uint256","name":"poolSize","type":"uint256"},{"internalType":"uint256","name":"validatorSize","type":"uint256"},{"internalType":"uint256","name":"withdrawalPoolLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawalValidatorLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawDelay","type":"uint256"},{"internalType":"uint256","name":"withdrawBeaconDelay","type":"uint256"},{"components":[{"internalType":"bool","name":"AddPool","type":"bool"},{"internalType":"bool","name":"Deposit","type":"bool"},{"internalType":"bool","name":"WithdrawPool","type":"bool"},{"internalType":"bool","name":"WithdrawBeacon","type":"bool"}],"internalType":"struct IStakeTogether.Feature","name":"feature","type":"tuple"}],"indexed":true,"internalType":"struct IStakeTogether.Config","name":"config","type":"tuple"}],"name":"SetConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum IStakeTogether.FeeType","name":"feeType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"allocations","type":"uint256[]"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum IStakeTogether.FeeRole","name":"role","type":"uint8"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"SetFeeAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"router","type":"address"}],"name":"SetRouter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeTogether","type":"address"}],"name":"SetStakeTogether","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"newValidatorSize","type":"uint256"}],"name":"SetValidatorSize","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SetWithdrawBalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"withdrawalCredentials","type":"bytes"}],"name":"SetWithdrawalsCredentials","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesAmount","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"indexed":false,"internalType":"struct IStakeTogether.Delegation[]","name":"delegations","type":"tuple[]"}],"name":"UpdateDelegations","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"enum IStakeTogether.WithdrawType","name":"withdrawType","type":"uint8"},{"indexed":true,"internalType":"address","name":"pool","type":"address"}],"name":"WithdrawBase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"enum IStakeTogether.WithdrawType","name":"withdrawType","type":"uint8"}],"name":"WithdrawalsLimitWasReached","type":"event"},{"inputs":[],"name":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ANTI_FRAUD_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ANTI_FRAUD_SENTINEL_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_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":"POOL_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VALIDATOR_ORACLE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VALIDATOR_ORACLE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VALIDATOR_ORACLE_SENTINEL_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"bool","name":"_listed","type":"bool"},{"internalType":"bool","name":"_social","type":"bool"},{"internalType":"bool","name":"_index","type":"bool"}],"name":"addPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addToAntiFraud","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_publicKey","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"bytes32","name":"_depositDataRoot","type":"bytes32"}],"name":"addValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addValidatorOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"airdrop","outputs":[{"internalType":"contract IAirdrop","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"anticipateWithdrawBeacon","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_amount","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":[],"name":"beaconBalance","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":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_sharesAmount","type":"uint256"}],"name":"claimAirdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"uint256","name":"blocksPerDay","type":"uint256"},{"internalType":"uint256","name":"depositLimit","type":"uint256"},{"internalType":"uint256","name":"maxDelegations","type":"uint256"},{"internalType":"uint256","name":"minDepositAmount","type":"uint256"},{"internalType":"uint256","name":"minWithdrawAmount","type":"uint256"},{"internalType":"uint256","name":"poolSize","type":"uint256"},{"internalType":"uint256","name":"validatorSize","type":"uint256"},{"internalType":"uint256","name":"withdrawalPoolLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawalValidatorLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawDelay","type":"uint256"},{"internalType":"uint256","name":"withdrawBeaconDelay","type":"uint256"},{"components":[{"internalType":"bool","name":"AddPool","type":"bool"},{"internalType":"bool","name":"Deposit","type":"bool"},{"internalType":"bool","name":"WithdrawPool","type":"bool"},{"internalType":"bool","name":"WithdrawBeacon","type":"bool"}],"internalType":"struct IStakeTogether.Feature","name":"feature","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentOracleIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"address","name":"_pool","type":"address"},{"internalType":"bytes","name":"_referral","type":"bytes"}],"name":"depositDonation","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"bytes","name":"_referral","type":"bytes"}],"name":"depositPool","outputs":[],"stateMutability":"payable","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":"forceNextValidatorOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IStakeTogether.FeeType","name":"_feeType","type":"uint8"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IStakeTogether.FeeRole","name":"_role","type":"uint8"}],"name":"getFeeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeesRoles","outputs":[{"internalType":"enum IStakeTogether.FeeRole[4]","name":"","type":"uint8[4]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getWithdrawBeaconBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getWithdrawBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initializeV3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isListedInAntiFraud","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isValidatorOracle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastResetBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pools","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sharesAmount","type":"uint256"}],"name":"processFeeRewards","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeFromAntiFraud","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"}],"name":"removePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeValidatorOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setBeaconBalance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"blocksPerDay","type":"uint256"},{"internalType":"uint256","name":"depositLimit","type":"uint256"},{"internalType":"uint256","name":"maxDelegations","type":"uint256"},{"internalType":"uint256","name":"minDepositAmount","type":"uint256"},{"internalType":"uint256","name":"minWithdrawAmount","type":"uint256"},{"internalType":"uint256","name":"poolSize","type":"uint256"},{"internalType":"uint256","name":"validatorSize","type":"uint256"},{"internalType":"uint256","name":"withdrawalPoolLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawalValidatorLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawDelay","type":"uint256"},{"internalType":"uint256","name":"withdrawBeaconDelay","type":"uint256"},{"components":[{"internalType":"bool","name":"AddPool","type":"bool"},{"internalType":"bool","name":"Deposit","type":"bool"},{"internalType":"bool","name":"WithdrawPool","type":"bool"},{"internalType":"bool","name":"WithdrawBeacon","type":"bool"}],"internalType":"struct IStakeTogether.Feature","name":"feature","type":"tuple"}],"internalType":"struct IStakeTogether.Config","name":"_config","type":"tuple"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IStakeTogether.FeeType","name":"_feeType","type":"uint8"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256[]","name":"_allocations","type":"uint256[]"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IStakeTogether.FeeRole","name":"_role","type":"uint8"},{"internalType":"address payable","name":"_address","type":"address"}],"name":"setFeeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setWithdrawBalance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"shares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sharesByWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDeposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalWithdrawnPool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalWithdrawnValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"percentage","type":"uint256"}],"internalType":"struct IStakeTogether.Delegation[]","name":"_delegations","type":"tuple[]"}],"name":"updateDelegations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"validators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sharesAmount","type":"uint256"}],"name":"weiByShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_pool","type":"address"}],"name":"withdrawBeacon","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_pool","type":"address"}],"name":"withdrawPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalCredentials","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawals","outputs":[{"internalType":"contract IWithdrawals","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a0604052306080523480156200001557600080fd5b506200002062000026565b620000da565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000775760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000d75780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051615a586200010460003960008181613bcc01528181613bf50152613d580152615a586000f3fe6080604052600436106104ae5760003560e01c806370a082311161026b578063a9059cbb1161014f578063d8531d60116100c1578063e2b99e6b11610085578063e2b99e6b14610fbf578063e4b9a59a14610fd5578063f4d3f04c14610ff5578063f72c0d8b14611029578063f887ea401461105d578063ff50abdc1461107d57600080fd5b8063d8531d6014610ef0578063d8e4956d14610f05578063da06a4ee14610f39578063db87e79b14610f59578063dd62ed3e14610f7957600080fd5b8063cb570f2611610113578063cb570f2614610e2b578063ce7c2ac214610e41578063d0e30db014610e6e578063d505accf14610e8e578063d547741f14610eae578063d72c3d1c14610ece57600080fd5b8063a9059cbb14610d64578063ad3cb1cc14610d84578063ade0e93e14610db5578063b767210e14610dd5578063c37187db14610df557600080fd5b80638456cb59116101e857806396f5a4ce116101ac57806396f5a4ce14610cb6578063975355d314610cd6578063a217fddf14610cf6578063a4063dbc14610d0b578063a7c2d8fd14610d3b578063a8d1f82214610d4e57600080fd5b80638456cb5914610c2457806384b0196e14610c39578063889a40fb14610c6157806391d1485414610c8157806395d89b4114610ca157600080fd5b806379502c551161022f57806379502c5514610aa457806379cc679014610bb15780637c3f186c14610bd15780637ecebe0014610bf1578063835cc19914610c1157600080fd5b806370a08231146109f957806372ddb3f214610a1957806372ee976e14610a3957806375b238fc14610a6f57806378c0918614610a9157600080fd5b80633a98ef391161039257806352d1902d1161030f57806364372ea5116102d357806364372ea5146109265780636b3b744f146109485780636b5e12ca146109685780636c36511a1461097e5780636c5a81b9146109b95780636cb7d29d146109d957600080fd5b806352d1902d1461088c57806354fd4d50146108a157806356d73568146108b75780635c975abb146108eb5780635fd8c7101461091057600080fd5b806346ad957b1161035657806346ad957b1461081b5780634cd79e0a1461082e5780634f1ef286146108435780634f9a4d2b14610856578063513dd7f01461087657600080fd5b80633a98ef391461079b5780633b7d0946146107b15780633f4ba83a146107d157806342966c68146107e6578063452b2b9e1461080657600080fd5b806323b872dd1161042b578063313ce567116103ef578063313ce567146106e15780633644e515146106fd57806336568abe146107125780633884d6351461073257806338e454b114610752578063391b0d2f1461076757600080fd5b806323b872dd1461064c57806323d4d1e51461066c578063248a9ca31461068e5780632f2ff15d146106ae578063301862c4146106ce57600080fd5b8063095ea7b311610472578063095ea7b3146105c45780630acbdb5f146105e457806310e908e71461060457806318160ddd146106245780631831d95f1461063957600080fd5b806301ff0e05146104e557806301ffc9a71461050757806306fdde031461053c578063079229e81461055e578063083132c41461059657600080fd5b366104e05760405134907fceeedae0890c8b65dd388797879b0ea414f47e1bb170734056b4004c4a7e181490600090a2005b600080fd5b3480156104f157600080fd5b50610505610500366004614bed565b611093565b005b34801561051357600080fd5b50610527610522366004614c60565b6112cc565b60405190151581526020015b60405180910390f35b34801561054857600080fd5b50610551611303565b6040516105339190614cda565b34801561056a57600080fd5b5061057e610579366004614cfa565b6113be565b6040516001600160a01b039091168152602001610533565b3480156105a257600080fd5b506105b66105b1366004614cfa565b611407565b604051908152602001610533565b3480156105d057600080fd5b506105276105df366004614d2c565b611447565b3480156105f057600080fd5b506105056105ff366004614d2c565b61145f565b34801561061057600080fd5b5061050561061f366004614de9565b6114ad565b34801561063057600080fd5b506105b6611613565b610505610647366004614ebe565b611635565b34801561065857600080fd5b50610527610667366004614f12565b61168f565b34801561067857600080fd5b506105b660008051602061594383398151915281565b34801561069a57600080fd5b506105b66106a9366004614f53565b611727565b3480156106ba57600080fd5b506105056106c9366004614f6c565b611749565b6105056106dc366004614f53565b61176b565b3480156106ed57600080fd5b5060405160128152602001610533565b34801561070957600080fd5b506105b66117eb565b34801561071e57600080fd5b5061050561072d366004614f6c565b6117f5565b34801561073e57600080fd5b5060015461057e906001600160a01b031681565b34801561075e57600080fd5b50610505611828565b34801561077357600080fd5b506105b67f4353b7b6368a0adaa5f872e5695b9055abd33653d52a39b1ef41543a0c1aac9a81565b3480156107a757600080fd5b506105b660155481565b3480156107bd57600080fd5b506105056107cc366004614f9c565b61185a565b3480156107dd57600080fd5b5061050561194e565b3480156107f257600080fd5b50610505610801366004614f53565b61196e565b34801561081257600080fd5b50610505611978565b610505610829366004614f53565b6119ec565b34801561083a57600080fd5b50610551611a30565b610505610851366004615028565b611abe565b34801561086257600080fd5b50610505610871366004615077565b611ad9565b34801561088257600080fd5b506105b6601d5481565b34801561089857600080fd5b506105b6611c9b565b3480156108ad57600080fd5b506105b660005481565b3480156108c357600080fd5b506105b67f6077685936c8169d09204a1d97db12e41713588c38e1d29a61867d3dcee98aff81565b3480156108f757600080fd5b506000805160206159e38339815191525460ff16610527565b34801561091c57600080fd5b506105b660075481565b34801561093257600080fd5b5061093b611cb8565b6040516105339190615118565b34801561095457600080fd5b506105b6610963366004614f53565b611cea565b34801561097457600080fd5b506105b6601a5481565b34801561098a57600080fd5b50610527610999366004615160565b805160208183018101805160228252928201919093012091525460ff1681565b3480156109c557600080fd5b506105276109d4366004614f9c565b611d00565b3480156109e557600080fd5b506105056109f4366004614f9c565b611d1e565b348015610a0557600080fd5b506105b6610a14366004614f9c565b611f12565b348015610a2557600080fd5b50610505610a3436600461519c565b611f34565b348015610a4557600080fd5b506105b6610a54366004614f9c565b6001600160a01b031660009081526019602052604090205490565b348015610a7b57600080fd5b506105b6600080516020615a0383398151915281565b610505610a9f366004614f53565b6120f2565b348015610ab057600080fd5b50600854600954600a54600b54600c54600d54600e54600f546010546011546012546040805160808101825260135460ff80821615158352610100820481161515602084015262010000820481161515938301939093526301000000900490911615156060820152610b2a9b9a999897969594939291908c565b604080519c8d526020808e019c909c528c81019a909a526060808d019990995260808c019790975260a08b019590955260c08a019390935260e0890191909152610100880152610120870152610140860152805115156101608601529283015115156101808501529082015115156101a0840152015115156101c08201526101e001610533565b348015610bbd57600080fd5b50610505610bcc366004614d2c565b61212e565b348015610bdd57600080fd5b50610527610bec366004614f9c565b612143565b348015610bfd57600080fd5b506105b6610c0c366004614f9c565b612181565b610505610c1f3660046151ca565b6121be565b348015610c3057600080fd5b50610505612213565b348015610c4557600080fd5b50610c4e612233565b604051610533979695949392919061522e565b348015610c6d57600080fd5b506105b6610c7c366004614f53565b6122e4565b348015610c8d57600080fd5b50610527610c9c366004614f6c565b6122fc565b348015610cad57600080fd5b50610551612334565b348015610cc257600080fd5b50610505610cd1366004614f6c565b612385565b348015610ce257600080fd5b50610505610cf1366004614f9c565b6124e9565b348015610d0257600080fd5b506105b6600081565b348015610d1757600080fd5b50610527610d26366004614f9c565b601e6020526000908152604090205460ff1681565b610505610d493660046152dc565b6125ec565b348015610d5a57600080fd5b506105b660065481565b348015610d7057600080fd5b50610527610d7f366004614d2c565b6127d0565b348015610d9057600080fd5b50610551604051806040016040528060058152602001640352e302e360dc1b81525081565b348015610dc157600080fd5b5060045461057e906001600160a01b031681565b348015610de157600080fd5b50610505610df0366004614f9c565b61282b565b348015610e0157600080fd5b506105b6610e10366004614f9c565b6001600160a01b031660009081526018602052604090205490565b348015610e3757600080fd5b506105b6601c5481565b348015610e4d57600080fd5b506105b6610e5c366004614f9c565b60146020526000908152604090205481565b348015610e7a57600080fd5b5060025461057e906001600160a01b031681565b348015610e9a57600080fd5b50610505610ea9366004615332565b612923565b348015610eba57600080fd5b50610505610ec9366004614f6c565b612a7c565b348015610eda57600080fd5b506105b66000805160206159a383398151915281565b348015610efc57600080fd5b50610505612a98565b348015610f1157600080fd5b506105b67f54f5fa3fbe05747e670128ef2b79b948460620ea3992e7fd9c4ff652cc82deb681565b348015610f4557600080fd5b50610505610f54366004614f6c565b612c59565b348015610f6557600080fd5b50610505610f74366004614f9c565b612d00565b348015610f8557600080fd5b506105b6610f943660046153a9565b6001600160a01b03918216600090815260166020908152604080832093909416825291909152205490565b348015610fcb57600080fd5b506105b660215481565b348015610fe157600080fd5b50610505610ff0366004615446565b612df8565b34801561100157600080fd5b506105b67f93350e56e77530c4c3adffe989496c648c85b1171c82068c5dec82bc9deb532f81565b34801561103557600080fd5b506105b67f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e381565b34801561106957600080fd5b5060035461057e906001600160a01b031681565b34801561108957600080fd5b506105b6601b5481565b61109b612f32565b6110a3612f7c565b6110ac33612143565b6110c95760405163e2bbd18560e01b815260040160405180910390fd5b601f602154815481106110de576110de6154e9565b6000918252602090912001546001600160a01b031633146111125760405163231432ef60e01b815260040160405180910390fd5b600d5447101561113557604051635c08952760e11b815260040160405180910390fd5b602285856040516111479291906154ff565b9081526040519081900360200190205460ff161561117857604051633f4dc7d360e11b815260040160405180910390fd5b6007546003546001600160a01b03163110156111a757604051630c86d86d60e31b815260040160405180910390fd5b6001602286866040516111bb9291906154ff565b908152604051908190036020019020805491151560ff199092169190911790556111e3612fad565b600e546006546111fb916111f691615525565b613032565b600e5460405133917fc297ac07d1b1234693dde6e235f4a2212aa5b4a22df77d916094dac3f2906ffd9161123c9190899089906005908a908a908a9061563f565b60405180910390a2600254600e546040516304512a2360e31b81526001600160a01b03909216916322895118919061128390899089906005908a908a908a90600401615695565b6000604051808303818588803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b50505050506112bd613065565b6112c5613119565b5050505050565b60006001600160e01b03198216637965db0b60e01b14806112fd57506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace005b905080600301805461133a90615561565b80601f016020809104026020016040519081016040528092919081815260200182805461136690615561565b80156113b35780601f10611388576101008083540402835291602001916113b3565b820191906000526020600020905b81548152906001019060200180831161139657829003601f168201915b505050505091505090565b6000602360008360038111156113d6576113d6615102565b60038111156113e7576113e7615102565b81526020810191909152604001600020546001600160a01b031692915050565b60006024600083600381111561141f5761141f615102565b600381111561143057611430615102565b815260208101919091526040016000205492915050565b6000611456338484600161313f565b50600192915050565b611467612f7c565b6001546001600160a01b0316331461149257604051635b82805d60e01b815260040160405180910390fd5b6001546114a9906001600160a01b0316838361320e565b5050565b33600090815260146020526040812054156115ae57600a54825111156114e65760405163105de61360e11b815260040160405180910390fd5b60005b825181101561158057601e6000848381518110611508576115086154e9565b602090810291909101810151516001600160a01b031682528101919091526040016000205460ff1661154d576040516301dbb3ff60e61b815260040160405180910390fd5b82818151811061155f5761155f6154e9565b602002602001015160200151826115769190615525565b91506001016114e9565b5080670de0b6b3a7640000146115a957604051630b8ad7f160e01b815260040160405180910390fd5b6115ce565b8151156115ce576040516360063e6960e01b815260040160405180910390fd5b336001600160a01b03167ff0dec0870aca14d1ad51321dee719a02707c5d5956a11f238491d3a44c7477928360405161160791906156e4565b60405180910390a25050565b6000600754600654476116269190615525565b611630919061573c565b905090565b61163d612f32565b33600090815260176020526040902054431161166c576040516304e4394960e11b815260040160405180910390fd5b611674612f7c565b611682336001858585613399565b61168a613119565b505050565b600061169a84611d00565b156116b857604051633a24938b60e21b815260040160405180910390fd5b6116c183611d00565b156116df57604051633a24938b60e21b815260040160405180910390fd5b6116e833611d00565b1561170657604051633a24938b60e21b815260040160405180910390fd5b6117118433846135a5565b61171c84848461360b565b5060015b9392505050565b60009081526000805160206159c3833981519152602052604090206001015490565b61175282611727565b61175b8161366a565b6117658383613674565b50505050565b611773612f32565b61177b612f7c565b6003546001600160a01b031633146117a657604051639e41bdd760e01b815260040160405180910390fd5b6117b36001826000613719565b604051819034907ffea5ecb74077e67f0a7c0d022852a4f7938afbc487b876038b8c87e330e8bad990600090a36117e8613119565b50565b6000611630613a72565b6001600160a01b038116331461181e5760405163334bd91960e11b815260040160405180910390fd5b61168a8282613a7c565b7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e36118528161366a565b506003600055565b336000908152601760205260409020544311611889576040516304e4394960e11b815260040160405180910390fd5b611891612f7c565b7f6077685936c8169d09204a1d97db12e41713588c38e1d29a61867d3dcee98aff6118bb8161366a565b6001600160a01b0382166000908152601e602052604090205460ff166118f4576040516301dbb3ff60e61b815260040160405180910390fd5b6001600160a01b0382166000818152601e60209081526040808320805460ff191690553383526017909152808220439055517f0719c8bc6522957e7735717af2894124fbc9096cf04b5bfaabcff515779087659190a25050565b600080516020615a038339815191526119668161366a565b6117e8613af8565b6117e83382613b58565b6119a27f4353b7b6368a0adaa5f872e5695b9055abd33653d52a39b1ef41543a0c1aac9a336122fc565b1580156119c457506119c26000805160206159a3833981519152336122fc565b155b156119e25760405163ea8e4eb560e01b815260040160405180910390fd5b6119ea612fad565b565b6119f4612f32565b6003546001600160a01b03163314611a1f57604051639e41bdd760e01b815260040160405180910390fd5b611a2881613b8e565b6117e8613119565b60058054611a3d90615561565b80601f0160208091040260200160405190810160405280929190818152602001828054611a6990615561565b8015611ab65780601f10611a8b57610100808354040283529160200191611ab6565b820191906000526020600020905b815481529060010190602001808311611a9957829003601f168201915b505050505081565b611ac6613bc1565b611acf82613c66565b6114a98282613c90565b600080516020615a03833981519152611af18161366a565b60048214611b125760405163251f56a160e21b815260040160405180910390fd5b6000805b83811015611be457848482818110611b3057611b306154e9565b9050602002013560246000896003811115611b4d57611b4d615102565b6003811115611b5e57611b5e615102565b81526020019081526020016000206001016000836003811115611b8357611b83615102565b6003811115611b9457611b94615102565b6003811115611ba557611ba5615102565b8152602081019190915260400160002055848482818110611bc857611bc86154e9565b9050602002013582611bda9190615525565b9150600101611b16565b5080670de0b6b3a764000014611c0d57604051630adc3ccb60e31b815260040160405180910390fd5b8460246000886003811115611c2457611c24615102565b6003811115611c3557611c35615102565b8152602081019190915260400160002055856003811115611c5857611c58615102565b7f5051fc6a7b31ea3fa7919ccc0c788f2108f610821b18b57408a3924eb76188e6868686604051611c8b9392919061574f565b60405180910390a2505050505050565b6000611ca5613d4d565b5060008051602061598383398151915290565b611cc0614b87565b60408051608081019091528060008152602001600181526020016002815260200160039052919050565b60006112fd82601554611cfb611613565b613d96565b6001600160a01b031660009081526025602052604090205460ff1690565b6000805160206159a3833981519152611d368161366a565b6001600160a01b03821660009081526020805260408120549003611d6d57604051630ae471df60e41b815260040160405180910390fd5b6001600160a01b0382166000908152602080526040812054611d919060019061573c565b601f54909150611da39060019061573c565b811015611e4b57601f805460009190611dbe9060019061573c565b81548110611dce57611dce6154e9565b600091825260209091200154601f80546001600160a01b039092169250829184908110611dfd57611dfd6154e9565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055611e31826001615525565b6001600160a01b0390911660009081526020805260409020555b601f805480611e5c57611e5c615790565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03851682528052604081205560215481148015611ebf57601f54602154611eb1906001615525565b611ebb91906157bc565b6021555b611ed760008051602061594383398151915285613a7c565b506040516001600160a01b038516907fb025ca7b24d2a1ec588bad96d467ad319b21cf169715b7dac04065c7fb51acbc90600090a250505050565b6001600160a01b0381166000908152601460205260408120546112fd906122e4565b600080516020615a03833981519152611f4c8161366a565b6001600160a01b038216611f735760405163d92e233d60e01b815260040160405180910390fd5b8160236000856003811115611f8a57611f8a615102565b6003811115611f9b57611f9b615102565b81526020810191909152604001600090812080546001600160a01b0319166001600160a01b039390931692909217909155836003811115611fde57611fde615102565b0361204d576001546001600160a01b03166023600085600381111561200557612005615102565b600381111561201657612016615102565b815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055506120a8565b816023600085600381111561206457612064615102565b600381111561207557612075615102565b815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b816001600160a01b03168360038111156120c4576120c4615102565b6040517f76f62d968bedb2d4fe6d9e87c8348e3d6a6c3fbe73e20884b75c73d230d11a6590600090a3505050565b6120fa612f32565b6003546001600160a01b0316331461212557604051639e41bdd760e01b815260040160405180910390fd5b611a2881613032565b6121398233836135a5565b6114a98282613b58565b600061215d600080516020615943833981519152836122fc565b80156112fd5750506001600160a01b03166000908152602080526040902054151590565b6001600160a01b03811660009081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb0060205260408120546112fd565b6121c6612f32565b3360009081526017602052604090205443116121f5576040516304e4394960e11b815260040160405180910390fd5b6121fd612f7c565b61220b846000858585613399565b611765613119565b600080516020615a0383398151915261222b8161366a565b6117e8613e5a565b60006060808280808381600080516020615963833981519152805490915015801561226057506001810154155b6122a95760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064015b60405180910390fd5b6122b1613ea3565b6122b9613ee2565b60408051600080825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b60006112fd826122f2611613565b6015546001613efa565b60009182526000805160206159c3833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace009161133a90615561565b61238d612f32565b3360009081526017602052604090205443116123bc576040516304e4394960e11b815260040160405180910390fd5b6123c4612f7c565b6013546301000000900460ff166123ee5760405163562fb04960e11b815260040160405180910390fd5b47821161240e5760405163ba8552c160e01b815260040160405180910390fd5b60065460075461241e9084615525565b111561243d576040516392c730c760e01b815260040160405180910390fd5b60125461244a9043615525565b3360009081526019602052604090205561246682600183613f4b565b61247c826007546124779190615525565b613b8e565b600480546040516340c10f1960e01b81523392810192909252602482018490526001600160a01b0316906340c10f1990604401600060405180830381600087803b1580156124c957600080fd5b505af11580156124dd573d6000803e3d6000fd5b505050506114a9613119565b6125137f93350e56e77530c4c3adffe989496c648c85b1171c82068c5dec82bc9deb532f336122fc565b15801561254757506125457f54f5fa3fbe05747e670128ef2b79b948460620ea3992e7fd9c4ff652cc82deb6336122fc565b155b156125655760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b03811661258c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038116600081815260256020908152604091829020805460ff19166001908117909155915191825233917fac3e318f4d8128b08cb4ed08640aee05f99325ff6838c9cf196cf392c7565e2a91015b60405180910390a350565b6125f4612f32565b6125fc612f7c565b33600090815260176020526040902054431161262b576040516304e4394960e11b815260040160405180910390fd5b6001600160a01b0384166126525760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0384166000908152601e602052604090205460ff161561268c57604051637a471e1360e11b815260040160405180910390fd5b6126b67f6077685936c8169d09204a1d97db12e41713588c38e1d29a61867d3dcee98aff336122fc565b15806126c25750600034115b1561273d5760135460ff166126ea5760405163562fb04960e11b815260040160405180910390fd5b600260005260246020527f47bb5529a97e2b401b32950f6360fbc9e3f4e70b887dc0f9b9ad1f7402ca11da54341461273557604051632a9ffab760e21b815260040160405180910390fd5b61273d6141c7565b6001600160a01b0384166000818152601e60209081526040808320805460ff19166001179055338352601790915290819020439055517feb848dd9e3c3dbe3da6da5c36e67f2e41778a42fcbb3a341ccdcbc61bffaf428906127c09086908690869034909315158452911515602084015215156040830152606082015260800190565b60405180910390a2611765613119565b60006127db33611d00565b156127f957604051633a24938b60e21b815260040160405180910390fd5b61280283611d00565b1561282057604051633a24938b60e21b815260040160405180910390fd5b61145633848461360b565b6128557f54f5fa3fbe05747e670128ef2b79b948460620ea3992e7fd9c4ff652cc82deb6336122fc565b6128725760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381166128995760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03811660009081526025602052604090205460ff166128d2576040516373300e5d60e11b815260040160405180910390fd5b6001600160a01b0381166000818152602560209081526040808320805460ff191690555191825233917fac3e318f4d8128b08cb4ed08640aee05f99325ff6838c9cf196cf392c7565e2a91016125e1565b834211156129475760405163313c898160e11b8152600481018590526024016122a0565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886129b38c6001600160a01b031660009081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000612a0e82614223565b90506000612a1e82878787614250565b9050896001600160a01b0316816001600160a01b031614612a65576040516325c0072360e11b81526001600160a01b0380831660048301528b1660248201526044016122a0565b612a708a8a8a61427e565b50505050505050505050565b612a8582611727565b612a8e8161366a565b6117658383613a7c565b612aa0612f32565b612aa8612f7c565b612ab133612143565b612ace5760405163e2bbd18560e01b815260040160405180910390fd5b601f60215481548110612ae357612ae36154e9565b6000918252602090912001546001600160a01b03163314612b175760405163231432ef60e01b815260040160405180910390fd5b600754600003612b3a57604051630dc748df60e11b815260040160405180910390fd5b6003546007546001600160a01b039091163190811115612b6d5760405163eb939ef360e01b815260040160405180910390fd5b600081600754612b7d919061573c565b905080471015612ba05760405163eee2a49b60e01b815260040160405180910390fd5b612bb1816006546111f69190615525565b60405181815233907faa0a55a65b848d4893316c409a99d531792f3c57684cda06f3caacbe363b25d19060200160405180910390a2600360009054906101000a90046001600160a01b03166001600160a01b031663d692e4e3826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612c3657600080fd5b505af1158015612c4a573d6000803e3d6000fd5b505050505050506119ea613119565b612c61612f32565b336000908152601760205260409020544311612c90576040516304e4394960e11b815260040160405180910390fd5b612c98612f7c565b60135462010000900460ff16612cc15760405163562fb04960e11b815260040160405180910390fd5b47821115612ce25760405163bc6072f160e01b815260040160405180910390fd5b612cee82600083613f4b565b612cf8338361428b565b6114a9613119565b6000805160206159a3833981519152612d188161366a565b6001600160a01b038216600090815260208052604090205415612d4e576040516375098d1760e01b815260040160405180910390fd5b601f80546001810182557fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d8070180546001600160a01b0319166001600160a01b0385169081179091559054600091825260208052604090912055612dbf60008051602061594383398151915283613674565b506040516001600160a01b038316907f9e24791803ca4403a42ed0ac802bafb55e327c452f7a01205b8655977bffcdb090600090a25050565b600080516020615a03833981519152612e108161366a565b600e5460a08301511015612e3757604051630ffd11ad60e01b815260040160405180910390fd5b8151600855602080830151600955604080840151600a55606080850151600b556080850151600c5560a0850151600d5560c0850151600e5560e0850151600f556101008086015160105561012086015160115561014086015160125561016086015180516013805496830151838701519390950151151563010000000263ff0000001993151562010000029390931663ffff00001995151590940261ff00199215159290921661ffff19909716969096171792909216171790915551612efe9083906157d0565b604051908190038120907f254354c73cfc0090ceaf2ea35d959ffed011e9eeeeb6e0e078f3f6dc8cb501cb90600090a25050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901612f7657604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6000805160206159e38339815191525460ff16156119ea5760405163d93c066560e01b815260040160405180910390fd5b601f54602154612fbe906001615525565b612fc891906157bc565b602181905550601f60215481548110612fe357612fe36154e9565b600091825260209182902001546021546040519081526001600160a01b03909116917fd577232dd9e50b968dfc0fdc01cd1a29fb367e9cea13608cf7134a9c24ce70d5910160405180910390a2565b600681905560405181907ffe6bd73b2487c4b7d5939ba1ba9c89f149f9010a73b175c07eff14441869483f90600090a250565b61306f60016113be565b6003600052602460209081527f8a6809e43cef135a96df89aa3c0800baae7c497913adf6156625c15a6f57cdf0546040519081526001600160a01b0392909216917f0ed8b6fdfe110a7f817805007b6d22859af5e490ca5e07a18fee7cb48b1a57e4910160405180910390a26119ea6130e860016113be565b600360005260246020527f8a6809e43cef135a96df89aa3c0800baae7c497913adf6156625c15a6f57cdf05461428b565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6001600160a01b0384166131665760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03831661318d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038085166000908152601660209081526040808320938716835292905220829055801561176557826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161320091815260200190565b60405180910390a350505050565b613216612f7c565b61321f83611d00565b1561323d57604051633a24938b60e21b815260040160405180910390fd5b61324682611d00565b1561326457604051633a24938b60e21b815260040160405180910390fd5b6001600160a01b03831661328b5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382166132b25760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0383166000908152601460205260409020548111156132eb57604051633999656760e01b815260040160405180910390fd5b6001600160a01b0383166000908152601460205260408120805483929061331390849061573c565b90915550506001600160a01b03821660009081526014602052604081208054839290613340908490615525565b92505081905550816001600160a01b0316836001600160a01b03167f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb8360405161338c91815260200190565b60405180910390a3505050565b601354610100900460ff166133c15760405163562fb04960e11b815260040160405180910390fd5b60006133cb611613565b116133e95760405163c16f3a9360e01b815260040160405180910390fd5b6001600160a01b03851660009081526025602052604090205460ff161561342357604051633a24938b60e21b815260040160405180910390fd5b600b543410156134465760405163663436a560e11b815260040160405180910390fd5b6001600160a01b0383166000908152601e602052604090205460ff1661347f576040516301dbb3ff60e61b815260040160405180910390fd5b613487614322565b34601b60008282546134999190615525565b909155505033600090815260176020526040902043908190556011546134be91615525565b33600090815260186020526040902055600954601b54111561353657846001600160a01b03167fa7ca73d163eac9a150c6c4afd1ff6cadedfdc85012b37aadd9039f54540a04c73460405161351591815260200190565b60405180910390a2604051632484557960e01b815260040160405180910390fd5b81816040516135469291906154ff565b6040518091039020836001600160a01b0316866001600160a01b03167fce5e8aa759525e99721a56b0c70d317638e2d6d80a440e4dd97c3af8267b4b0134886040516135939291906158ce565b60405180910390a46112c5853461434e565b6001600160a01b03808416600090815260166020908152604080832093861683529290522054600019811461176557818110156135f5576040516313be252b60e01b815260040160405180910390fd5b6117658484613604858561573c565b600161313f565b6001600160a01b03831661363557604051634b637e8f60e11b8152600060048201526024016122a0565b6001600160a01b03821661365f5760405163ec442f0560e01b8152600060048201526024016122a0565b61168a83838361436e565b6117e8813361445b565b60006000805160206159c383398151915261368f84846122fc565b61370f576000848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556136c53390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506112fd565b60009150506112fd565b613721614b87565b600061372b611cb8565b905060006024600087600381111561374557613745615102565b600381111561375657613756615102565b8152602001908152602001600020600001549050600061377f8683670de0b6b3a7640000613d96565b90506000805b6137916001600461573c565b8110156138bc5760006137b98683600481106137af576137af6154e9565b60200201516113be565b6001600160a01b0316036137e05760405163d92e233d60e01b815260040160405180910390fd5b6000602460008b60038111156137f8576137f8615102565b600381111561380957613809615102565b8152602001908152602001600020600101600087846004811061382e5761382e6154e9565b6020020151600381111561384457613844615102565b600381111561385557613855615102565b81526020019081526020016000205490506138798482670de0b6b3a7640000613d96565b87836004811061388b5761388b6154e9565b60200201528682600481106138a2576138a26154e9565b60200201516138b19084615525565b925050600101613785565b506138c7818861573c565b60608601526000808960038111156138e1576138e1615102565b146138f7576138f26001600461573c565b6138fa565b60045b905060005b81811015612a7057600087826004811061391b5761391b6154e9565b60200201511115613a6a5760008a600381111561393a5761393a615102565b14801561396e57506003868260048110613956576139566154e9565b6020020151600381111561396c5761396c615102565b145b156139985761399388888360048110613989576139896154e9565b6020020151614494565b613a6a565b6139c26139b08783600481106137af576137af6154e9565b888360048110613989576139896154e9565b8581600481106139d4576139d46154e9565b602002015160038111156139ea576139ea615102565b8a60038111156139fc576139fc615102565b613a118884600481106137af576137af6154e9565b6001600160a01b03167fd8d136691cb70fed9e96b70a3de7e6efdee8c468fd8398375be41720182defc98a8560048110613a4d57613a4d6154e9565b6020020151604051613a6191815260200190565b60405180910390a45b6001016138ff565b6000611630614592565b60006000805160206159c3833981519152613a9784846122fc565b1561370f576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506112fd565b613b00614606565b6000805160206159e3833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b6001600160a01b038216613b8257604051634b637e8f60e11b8152600060048201526024016122a0565b6114a98260008361436e565b600781905560405181907fec837734bfcb6c37153600ffa50a6123c7818f84e13c382a5f45b74308a5f04390600090a250565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480613c4857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613c3c600080516020615983833981519152546001600160a01b031690565b6001600160a01b031614155b156119ea5760405163703e46dd60e11b815260040160405180910390fd5b7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e36114a98161366a565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613cea575060408051601f3d908101601f19168201909252613ce7918101906158eb565b60015b613d1257604051634c9c8ce360e01b81526001600160a01b03831660048201526024016122a0565b6000805160206159838339815191528114613d4357604051632a87526960e21b8152600481018290526024016122a0565b61168a8383614636565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146119ea5760405163703e46dd60e11b815260040160405180910390fd5b6000838302816000198587098281108382030391505080600003613dcd57838281613dc357613dc36157a6565b0492505050611720565b808411613ded5760405163227bc15360e01b815260040160405180910390fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b613e62612f7c565b6000805160206159e3833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833613b3a565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060916000805160206159638339815191529161133a90615561565b60606000600080516020615963833981519152611329565b600080613f08868686613d96565b9050613f138361468c565b8015613f2f575060008480613f2a57613f2a6157a6565b868809115b15613f4257613f3f600182615525565b90505b95945050505050565b3360009081526025602052604090205460ff1615613f7c57604051633a24938b60e21b815260040160405180910390fd5b82600003613f9d57604051631f2a200560e01b815260040160405180910390fd5b613fa633611f12565b831115613fc657604051630b0888ab60e41b815260040160405180910390fd5b600c54831015613fe957604051631ec6b8b360e21b815260040160405180910390fd5b3360009081526018602052604090205443101561401957604051639fbfb9ab60e01b815260040160405180910390fd5b614021614322565b33600090815260176020526040812043905582600181111561404557614045615102565b036140ce5782601c600082825461405c9190615525565b9091555050600f54601c5411156140c957336001600160a01b03167fa80a491daef20bedd52d7c1fcee4a50bf43d4384594c75b7d3fa8260855654bd84846040516140a89291906158ce565b60405180910390a26040516371c4522160e01b815260040160405180910390fd5b61414d565b82601d60008282546140e09190615525565b9091555050601054601d54111561414d57336001600160a01b03167fa80a491daef20bedd52d7c1fcee4a50bf43d4384594c75b7d3fa8260855654bd848460405161412c9291906158ce565b60405180910390a2604051632299fde160e01b815260040160405180910390fd5b806001600160a01b0316336001600160a01b03167fc9374dd61d5f2babb5a5044b17c753e856de109d37ec23bdf7c67a18b9b6dda585856040516141929291906158ce565b60405180910390a33360008181526014602052604081205490916141bb918691611cfb90611f12565b905061176533826146b9565b6002600090815260246020527f47bb5529a97e2b401b32950f6360fbc9e3f4e70b887dc0f9b9ad1f7402ca11da546015549091906142149083908161420a611613565b611cfb919061573c565b90506114a96002826000613719565b60006112fd614230613a72565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080614262888888886147db565b92509250925061427282826148aa565b50909695505050505050565b61168a838383600161313f565b804710156142ae5760405163cd78605960e01b81523060048201526024016122a0565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146142fb576040519150601f19603f3d011682016040523d82523d6000602084013e614300565b606091505b505090508061168a57604051630a12f52160e11b815260040160405180910390fd5b600854601a546143329190615525565b4311156119ea576000601b819055601c819055601d5543601a55565b6000614360826015548461420a611613565b905061168a60008285613719565b614376612f32565b3360009081526017602052604090205443116143a5576040516304e4394960e11b815260040160405180910390fd5b6143ad612f7c565b336000908152601860205260409020544310156143dd57604051639fbfb9ab60e01b815260040160405180910390fd5b3360009081526017602052604081204390556143f882611cea565b905061440584848361320e565b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161444a91815260200190565b60405180910390a35061168a613119565b61446582826122fc565b6114a95760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044016122a0565b61449c612f7c565b6001600160a01b0382166144c35760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038216600090815260146020526040812080548392906144eb908490615525565b9250508190555080601560008282546145049190615525565b90915550506040518181526001600160a01b038316907fe0db2c42b942601357f9499d6f0520c824b2ce7513135a456b661d1d3e45de5e9060200160405180910390a26001600160a01b03821660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef61457d846122e4565b60405190815260200160405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6145bd614963565b6145c56149cd565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6000805160206159e38339815191525460ff166119ea57604051638dfc202b60e01b815260040160405180910390fd5b61463f82614a11565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156146845761168a8282614a76565b6114a9614ae3565b600060028260038111156146a2576146a2615102565b6146ac9190615904565b60ff166001149050919050565b6146c1612f7c565b6001600160a01b0382166146e85760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03821660009081526014602052604090205481111561472157604051633999656760e01b815260040160405180910390fd5b6001600160a01b0382166000908152601460205260408120805483929061474990849061573c565b925050819055508060156000828254614762919061573c565b90915550506040518181526001600160a01b038316907f5c482005cb92f4606eb4f7244f8978adb96c9dfff9ab5c5be326273f0610fe459060200160405180910390a260006001600160a01b0383167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef61457d846122e4565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561481657506000915060039050826148a0565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561486a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614896575060009250600191508290506148a0565b9250600091508190505b9450945094915050565b60008260038111156148be576148be615102565b036148c7575050565b60018260038111156148db576148db615102565b036148f95760405163f645eedf60e01b815260040160405180910390fd5b600282600381111561490d5761490d615102565b0361492e5760405163fce698f760e01b8152600481018290526024016122a0565b600382600381111561494257614942615102565b036114a9576040516335e2f38360e21b8152600481018290526024016122a0565b60006000805160206159638339815191528161497d613ea3565b80519091501561499557805160209091012092915050565b815480156149a4579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b6000600080516020615963833981519152816149e7613ee2565b8051909150156149ff57805160209091012092915050565b600182015480156149a4579392505050565b806001600160a01b03163b600003614a4757604051634c9c8ce360e01b81526001600160a01b03821660048201526024016122a0565b60008051602061598383398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051614a939190615926565b600060405180830381855af49150503d8060008114614ace576040519150601f19603f3d011682016040523d82523d6000602084013e614ad3565b606091505b5091509150613f42858383614b02565b34156119ea5760405163b398979f60e01b815260040160405180910390fd5b606082614b1757614b1282614b5e565b611720565b8151158015614b2e57506001600160a01b0384163b155b15614b5757604051639996b31560e01b81526001600160a01b03851660048201526024016122a0565b5080611720565b805115614b6e5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60405180608001604052806004906020820280368337509192915050565b60008083601f840112614bb757600080fd5b5081356001600160401b03811115614bce57600080fd5b602083019150836020828501011115614be657600080fd5b9250929050565b600080600080600060608688031215614c0557600080fd5b85356001600160401b0380821115614c1c57600080fd5b614c2889838a01614ba5565b90975095506020880135915080821115614c4157600080fd5b50614c4e88828901614ba5565b96999598509660400135949350505050565b600060208284031215614c7257600080fd5b81356001600160e01b03198116811461172057600080fd5b60005b83811015614ca5578181015183820152602001614c8d565b50506000910152565b60008151808452614cc6816020860160208601614c8a565b601f01601f19169290920160200192915050565b6020815260006117206020830184614cae565b600481106117e857600080fd5b600060208284031215614d0c57600080fd5b813561172081614ced565b6001600160a01b03811681146117e857600080fd5b60008060408385031215614d3f57600080fd5b8235614d4a81614d17565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715614d9057614d90614d58565b60405290565b60405161018081016001600160401b0381118282101715614d9057614d90614d58565b604051601f8201601f191681016001600160401b0381118282101715614de157614de1614d58565b604052919050565b60006020808385031215614dfc57600080fd5b82356001600160401b0380821115614e1357600080fd5b818501915085601f830112614e2757600080fd5b813581811115614e3957614e39614d58565b614e47848260051b01614db9565b818152848101925060069190911b830184019087821115614e6757600080fd5b928401925b81841015614eb35760408489031215614e855760008081fd5b614e8d614d6e565b8435614e9881614d17565b81528486013586820152835260409093019291840191614e6c565b979650505050505050565b600080600060408486031215614ed357600080fd5b8335614ede81614d17565b925060208401356001600160401b03811115614ef957600080fd5b614f0586828701614ba5565b9497909650939450505050565b600080600060608486031215614f2757600080fd5b8335614f3281614d17565b92506020840135614f4281614d17565b929592945050506040919091013590565b600060208284031215614f6557600080fd5b5035919050565b60008060408385031215614f7f57600080fd5b823591506020830135614f9181614d17565b809150509250929050565b600060208284031215614fae57600080fd5b813561172081614d17565b600082601f830112614fca57600080fd5b81356001600160401b03811115614fe357614fe3614d58565b614ff6601f8201601f1916602001614db9565b81815284602083860101111561500b57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561503b57600080fd5b823561504681614d17565b915060208301356001600160401b0381111561506157600080fd5b61506d85828601614fb9565b9150509250929050565b6000806000806060858703121561508d57600080fd5b843561509881614ced565b93506020850135925060408501356001600160401b03808211156150bb57600080fd5b818701915087601f8301126150cf57600080fd5b8135818111156150de57600080fd5b8860208260051b85010111156150f357600080fd5b95989497505060200194505050565b634e487b7160e01b600052602160045260246000fd5b60808101818360005b60048082106151305750615157565b825181811061514157615141615102565b8452506020928301929190910190600101615121565b50505092915050565b60006020828403121561517257600080fd5b81356001600160401b0381111561518857600080fd5b61519484828501614fb9565b949350505050565b600080604083850312156151af57600080fd5b82356151ba81614ced565b91506020830135614f9181614d17565b600080600080606085870312156151e057600080fd5b84356151eb81614d17565b935060208501356151fb81614d17565b925060408501356001600160401b0381111561521657600080fd5b61522287828801614ba5565b95989497509550505050565b60ff60f81b881681526000602060e0602084015261524f60e084018a614cae565b8381036040850152615261818a614cae565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b818110156152b557835183529284019291840191600101615299565b50909c9b505050505050505050505050565b803580151581146152d757600080fd5b919050565b600080600080608085870312156152f257600080fd5b84356152fd81614d17565b935061530b602086016152c7565b9250615319604086016152c7565b9150615327606086016152c7565b905092959194509250565b600080600080600080600060e0888a03121561534d57600080fd5b873561535881614d17565b9650602088013561536881614d17565b95506040880135945060608801359350608088013560ff8116811461538c57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156153bc57600080fd5b82356151ba81614d17565b6000608082840312156153d957600080fd5b604051608081018181106001600160401b03821117156153fb576153fb614d58565b60405290508061540a836152c7565b8152615418602084016152c7565b6020820152615429604084016152c7565b604082015261543a606084016152c7565b60608201525092915050565b60006101e0828403121561545957600080fd5b615461614d96565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152506101208084013581830152506101408084013581830152506101606154de858286016153c7565b908201529392505050565b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156112fd576112fd61550f565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600181811c9082168061557557607f821691505b60208210810361559557634e487b7160e01b600052602260045260246000fd5b50919050565b8054600090600181811c90808316806155b557607f831692505b602080841082036155d657634e487b7160e01b600052602260045260246000fd5b838852602088018280156155f1576001811461560757615632565b60ff198716825285151560051b82019750615632565b60008981526020902060005b8781101561562c57815484820152908601908401615613565b83019850505b5050505050505092915050565b87815260a06020820152600061565960a08301888a615538565b828103604084015261566b818861559b565b90508281036060840152615680818688615538565b91505082608083015298975050505050505050565b6080815260006156a960808301888a615538565b82810360208401526156bb818861559b565b905082810360408401526156d0818688615538565b915050826060830152979650505050505050565b602080825282518282018190526000919060409081850190868401855b8281101561572f57815180516001600160a01b03168552860151868501529284019290850190600101615701565b5091979650505050505050565b818103818111156112fd576112fd61550f565b838152604060208201819052810182905260006001600160fb1b0383111561577657600080fd5b8260051b8085606085013791909101606001949350505050565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000826157cb576157cb6157a6565b500690565b815181526158b461587e61587061586261585461584761583a61582d61582061581361580660208c0160208e0151815260200190565b60408d0151815260200190565b60608c0151815260200190565b60808b0151815260200190565b60a08a0151815260200190565b60c0890151815260200190565b60e0880151815260200190565b610100870151815260200190565b610120860151815260200190565b610140850151815260200190565b61016084015180511515825260208082015115159083015260408082015115159083015260609081015115159082015260800190565b506101e001919050565b600281106117e8576117e8615102565b828152604081016158de836158be565b8260208301529392505050565b6000602082840312156158fd57600080fd5b5051919050565b600060ff831680615917576159176157a6565b8060ff84160691505092915050565b60008251615938818460208701614c8a565b919091019291505056fe3b394600f9a9e5957a84f453f4142ea034b950b69711afc0c4ed772f1580df2ca16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbce06ea5fb1a9d8d613e08b8f50cba89eefef698ab183e9c58c5040c4ee526ab7102dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220ec7e4fc4d35ac2c9723826e651d929c7a4e694b690beae457d047deb9001c2f864736f6c63430008160033
Deployed Bytecode
0x6080604052600436106104ae5760003560e01c806370a082311161026b578063a9059cbb1161014f578063d8531d60116100c1578063e2b99e6b11610085578063e2b99e6b14610fbf578063e4b9a59a14610fd5578063f4d3f04c14610ff5578063f72c0d8b14611029578063f887ea401461105d578063ff50abdc1461107d57600080fd5b8063d8531d6014610ef0578063d8e4956d14610f05578063da06a4ee14610f39578063db87e79b14610f59578063dd62ed3e14610f7957600080fd5b8063cb570f2611610113578063cb570f2614610e2b578063ce7c2ac214610e41578063d0e30db014610e6e578063d505accf14610e8e578063d547741f14610eae578063d72c3d1c14610ece57600080fd5b8063a9059cbb14610d64578063ad3cb1cc14610d84578063ade0e93e14610db5578063b767210e14610dd5578063c37187db14610df557600080fd5b80638456cb59116101e857806396f5a4ce116101ac57806396f5a4ce14610cb6578063975355d314610cd6578063a217fddf14610cf6578063a4063dbc14610d0b578063a7c2d8fd14610d3b578063a8d1f82214610d4e57600080fd5b80638456cb5914610c2457806384b0196e14610c39578063889a40fb14610c6157806391d1485414610c8157806395d89b4114610ca157600080fd5b806379502c551161022f57806379502c5514610aa457806379cc679014610bb15780637c3f186c14610bd15780637ecebe0014610bf1578063835cc19914610c1157600080fd5b806370a08231146109f957806372ddb3f214610a1957806372ee976e14610a3957806375b238fc14610a6f57806378c0918614610a9157600080fd5b80633a98ef391161039257806352d1902d1161030f57806364372ea5116102d357806364372ea5146109265780636b3b744f146109485780636b5e12ca146109685780636c36511a1461097e5780636c5a81b9146109b95780636cb7d29d146109d957600080fd5b806352d1902d1461088c57806354fd4d50146108a157806356d73568146108b75780635c975abb146108eb5780635fd8c7101461091057600080fd5b806346ad957b1161035657806346ad957b1461081b5780634cd79e0a1461082e5780634f1ef286146108435780634f9a4d2b14610856578063513dd7f01461087657600080fd5b80633a98ef391461079b5780633b7d0946146107b15780633f4ba83a146107d157806342966c68146107e6578063452b2b9e1461080657600080fd5b806323b872dd1161042b578063313ce567116103ef578063313ce567146106e15780633644e515146106fd57806336568abe146107125780633884d6351461073257806338e454b114610752578063391b0d2f1461076757600080fd5b806323b872dd1461064c57806323d4d1e51461066c578063248a9ca31461068e5780632f2ff15d146106ae578063301862c4146106ce57600080fd5b8063095ea7b311610472578063095ea7b3146105c45780630acbdb5f146105e457806310e908e71461060457806318160ddd146106245780631831d95f1461063957600080fd5b806301ff0e05146104e557806301ffc9a71461050757806306fdde031461053c578063079229e81461055e578063083132c41461059657600080fd5b366104e05760405134907fceeedae0890c8b65dd388797879b0ea414f47e1bb170734056b4004c4a7e181490600090a2005b600080fd5b3480156104f157600080fd5b50610505610500366004614bed565b611093565b005b34801561051357600080fd5b50610527610522366004614c60565b6112cc565b60405190151581526020015b60405180910390f35b34801561054857600080fd5b50610551611303565b6040516105339190614cda565b34801561056a57600080fd5b5061057e610579366004614cfa565b6113be565b6040516001600160a01b039091168152602001610533565b3480156105a257600080fd5b506105b66105b1366004614cfa565b611407565b604051908152602001610533565b3480156105d057600080fd5b506105276105df366004614d2c565b611447565b3480156105f057600080fd5b506105056105ff366004614d2c565b61145f565b34801561061057600080fd5b5061050561061f366004614de9565b6114ad565b34801561063057600080fd5b506105b6611613565b610505610647366004614ebe565b611635565b34801561065857600080fd5b50610527610667366004614f12565b61168f565b34801561067857600080fd5b506105b660008051602061594383398151915281565b34801561069a57600080fd5b506105b66106a9366004614f53565b611727565b3480156106ba57600080fd5b506105056106c9366004614f6c565b611749565b6105056106dc366004614f53565b61176b565b3480156106ed57600080fd5b5060405160128152602001610533565b34801561070957600080fd5b506105b66117eb565b34801561071e57600080fd5b5061050561072d366004614f6c565b6117f5565b34801561073e57600080fd5b5060015461057e906001600160a01b031681565b34801561075e57600080fd5b50610505611828565b34801561077357600080fd5b506105b67f4353b7b6368a0adaa5f872e5695b9055abd33653d52a39b1ef41543a0c1aac9a81565b3480156107a757600080fd5b506105b660155481565b3480156107bd57600080fd5b506105056107cc366004614f9c565b61185a565b3480156107dd57600080fd5b5061050561194e565b3480156107f257600080fd5b50610505610801366004614f53565b61196e565b34801561081257600080fd5b50610505611978565b610505610829366004614f53565b6119ec565b34801561083a57600080fd5b50610551611a30565b610505610851366004615028565b611abe565b34801561086257600080fd5b50610505610871366004615077565b611ad9565b34801561088257600080fd5b506105b6601d5481565b34801561089857600080fd5b506105b6611c9b565b3480156108ad57600080fd5b506105b660005481565b3480156108c357600080fd5b506105b67f6077685936c8169d09204a1d97db12e41713588c38e1d29a61867d3dcee98aff81565b3480156108f757600080fd5b506000805160206159e38339815191525460ff16610527565b34801561091c57600080fd5b506105b660075481565b34801561093257600080fd5b5061093b611cb8565b6040516105339190615118565b34801561095457600080fd5b506105b6610963366004614f53565b611cea565b34801561097457600080fd5b506105b6601a5481565b34801561098a57600080fd5b50610527610999366004615160565b805160208183018101805160228252928201919093012091525460ff1681565b3480156109c557600080fd5b506105276109d4366004614f9c565b611d00565b3480156109e557600080fd5b506105056109f4366004614f9c565b611d1e565b348015610a0557600080fd5b506105b6610a14366004614f9c565b611f12565b348015610a2557600080fd5b50610505610a3436600461519c565b611f34565b348015610a4557600080fd5b506105b6610a54366004614f9c565b6001600160a01b031660009081526019602052604090205490565b348015610a7b57600080fd5b506105b6600080516020615a0383398151915281565b610505610a9f366004614f53565b6120f2565b348015610ab057600080fd5b50600854600954600a54600b54600c54600d54600e54600f546010546011546012546040805160808101825260135460ff80821615158352610100820481161515602084015262010000820481161515938301939093526301000000900490911615156060820152610b2a9b9a999897969594939291908c565b604080519c8d526020808e019c909c528c81019a909a526060808d019990995260808c019790975260a08b019590955260c08a019390935260e0890191909152610100880152610120870152610140860152805115156101608601529283015115156101808501529082015115156101a0840152015115156101c08201526101e001610533565b348015610bbd57600080fd5b50610505610bcc366004614d2c565b61212e565b348015610bdd57600080fd5b50610527610bec366004614f9c565b612143565b348015610bfd57600080fd5b506105b6610c0c366004614f9c565b612181565b610505610c1f3660046151ca565b6121be565b348015610c3057600080fd5b50610505612213565b348015610c4557600080fd5b50610c4e612233565b604051610533979695949392919061522e565b348015610c6d57600080fd5b506105b6610c7c366004614f53565b6122e4565b348015610c8d57600080fd5b50610527610c9c366004614f6c565b6122fc565b348015610cad57600080fd5b50610551612334565b348015610cc257600080fd5b50610505610cd1366004614f6c565b612385565b348015610ce257600080fd5b50610505610cf1366004614f9c565b6124e9565b348015610d0257600080fd5b506105b6600081565b348015610d1757600080fd5b50610527610d26366004614f9c565b601e6020526000908152604090205460ff1681565b610505610d493660046152dc565b6125ec565b348015610d5a57600080fd5b506105b660065481565b348015610d7057600080fd5b50610527610d7f366004614d2c565b6127d0565b348015610d9057600080fd5b50610551604051806040016040528060058152602001640352e302e360dc1b81525081565b348015610dc157600080fd5b5060045461057e906001600160a01b031681565b348015610de157600080fd5b50610505610df0366004614f9c565b61282b565b348015610e0157600080fd5b506105b6610e10366004614f9c565b6001600160a01b031660009081526018602052604090205490565b348015610e3757600080fd5b506105b6601c5481565b348015610e4d57600080fd5b506105b6610e5c366004614f9c565b60146020526000908152604090205481565b348015610e7a57600080fd5b5060025461057e906001600160a01b031681565b348015610e9a57600080fd5b50610505610ea9366004615332565b612923565b348015610eba57600080fd5b50610505610ec9366004614f6c565b612a7c565b348015610eda57600080fd5b506105b66000805160206159a383398151915281565b348015610efc57600080fd5b50610505612a98565b348015610f1157600080fd5b506105b67f54f5fa3fbe05747e670128ef2b79b948460620ea3992e7fd9c4ff652cc82deb681565b348015610f4557600080fd5b50610505610f54366004614f6c565b612c59565b348015610f6557600080fd5b50610505610f74366004614f9c565b612d00565b348015610f8557600080fd5b506105b6610f943660046153a9565b6001600160a01b03918216600090815260166020908152604080832093909416825291909152205490565b348015610fcb57600080fd5b506105b660215481565b348015610fe157600080fd5b50610505610ff0366004615446565b612df8565b34801561100157600080fd5b506105b67f93350e56e77530c4c3adffe989496c648c85b1171c82068c5dec82bc9deb532f81565b34801561103557600080fd5b506105b67f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e381565b34801561106957600080fd5b5060035461057e906001600160a01b031681565b34801561108957600080fd5b506105b6601b5481565b61109b612f32565b6110a3612f7c565b6110ac33612143565b6110c95760405163e2bbd18560e01b815260040160405180910390fd5b601f602154815481106110de576110de6154e9565b6000918252602090912001546001600160a01b031633146111125760405163231432ef60e01b815260040160405180910390fd5b600d5447101561113557604051635c08952760e11b815260040160405180910390fd5b602285856040516111479291906154ff565b9081526040519081900360200190205460ff161561117857604051633f4dc7d360e11b815260040160405180910390fd5b6007546003546001600160a01b03163110156111a757604051630c86d86d60e31b815260040160405180910390fd5b6001602286866040516111bb9291906154ff565b908152604051908190036020019020805491151560ff199092169190911790556111e3612fad565b600e546006546111fb916111f691615525565b613032565b600e5460405133917fc297ac07d1b1234693dde6e235f4a2212aa5b4a22df77d916094dac3f2906ffd9161123c9190899089906005908a908a908a9061563f565b60405180910390a2600254600e546040516304512a2360e31b81526001600160a01b03909216916322895118919061128390899089906005908a908a908a90600401615695565b6000604051808303818588803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b50505050506112bd613065565b6112c5613119565b5050505050565b60006001600160e01b03198216637965db0b60e01b14806112fd57506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060007f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace005b905080600301805461133a90615561565b80601f016020809104026020016040519081016040528092919081815260200182805461136690615561565b80156113b35780601f10611388576101008083540402835291602001916113b3565b820191906000526020600020905b81548152906001019060200180831161139657829003601f168201915b505050505091505090565b6000602360008360038111156113d6576113d6615102565b60038111156113e7576113e7615102565b81526020810191909152604001600020546001600160a01b031692915050565b60006024600083600381111561141f5761141f615102565b600381111561143057611430615102565b815260208101919091526040016000205492915050565b6000611456338484600161313f565b50600192915050565b611467612f7c565b6001546001600160a01b0316331461149257604051635b82805d60e01b815260040160405180910390fd5b6001546114a9906001600160a01b0316838361320e565b5050565b33600090815260146020526040812054156115ae57600a54825111156114e65760405163105de61360e11b815260040160405180910390fd5b60005b825181101561158057601e6000848381518110611508576115086154e9565b602090810291909101810151516001600160a01b031682528101919091526040016000205460ff1661154d576040516301dbb3ff60e61b815260040160405180910390fd5b82818151811061155f5761155f6154e9565b602002602001015160200151826115769190615525565b91506001016114e9565b5080670de0b6b3a7640000146115a957604051630b8ad7f160e01b815260040160405180910390fd5b6115ce565b8151156115ce576040516360063e6960e01b815260040160405180910390fd5b336001600160a01b03167ff0dec0870aca14d1ad51321dee719a02707c5d5956a11f238491d3a44c7477928360405161160791906156e4565b60405180910390a25050565b6000600754600654476116269190615525565b611630919061573c565b905090565b61163d612f32565b33600090815260176020526040902054431161166c576040516304e4394960e11b815260040160405180910390fd5b611674612f7c565b611682336001858585613399565b61168a613119565b505050565b600061169a84611d00565b156116b857604051633a24938b60e21b815260040160405180910390fd5b6116c183611d00565b156116df57604051633a24938b60e21b815260040160405180910390fd5b6116e833611d00565b1561170657604051633a24938b60e21b815260040160405180910390fd5b6117118433846135a5565b61171c84848461360b565b5060015b9392505050565b60009081526000805160206159c3833981519152602052604090206001015490565b61175282611727565b61175b8161366a565b6117658383613674565b50505050565b611773612f32565b61177b612f7c565b6003546001600160a01b031633146117a657604051639e41bdd760e01b815260040160405180910390fd5b6117b36001826000613719565b604051819034907ffea5ecb74077e67f0a7c0d022852a4f7938afbc487b876038b8c87e330e8bad990600090a36117e8613119565b50565b6000611630613a72565b6001600160a01b038116331461181e5760405163334bd91960e11b815260040160405180910390fd5b61168a8282613a7c565b7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e36118528161366a565b506003600055565b336000908152601760205260409020544311611889576040516304e4394960e11b815260040160405180910390fd5b611891612f7c565b7f6077685936c8169d09204a1d97db12e41713588c38e1d29a61867d3dcee98aff6118bb8161366a565b6001600160a01b0382166000908152601e602052604090205460ff166118f4576040516301dbb3ff60e61b815260040160405180910390fd5b6001600160a01b0382166000818152601e60209081526040808320805460ff191690553383526017909152808220439055517f0719c8bc6522957e7735717af2894124fbc9096cf04b5bfaabcff515779087659190a25050565b600080516020615a038339815191526119668161366a565b6117e8613af8565b6117e83382613b58565b6119a27f4353b7b6368a0adaa5f872e5695b9055abd33653d52a39b1ef41543a0c1aac9a336122fc565b1580156119c457506119c26000805160206159a3833981519152336122fc565b155b156119e25760405163ea8e4eb560e01b815260040160405180910390fd5b6119ea612fad565b565b6119f4612f32565b6003546001600160a01b03163314611a1f57604051639e41bdd760e01b815260040160405180910390fd5b611a2881613b8e565b6117e8613119565b60058054611a3d90615561565b80601f0160208091040260200160405190810160405280929190818152602001828054611a6990615561565b8015611ab65780601f10611a8b57610100808354040283529160200191611ab6565b820191906000526020600020905b815481529060010190602001808311611a9957829003601f168201915b505050505081565b611ac6613bc1565b611acf82613c66565b6114a98282613c90565b600080516020615a03833981519152611af18161366a565b60048214611b125760405163251f56a160e21b815260040160405180910390fd5b6000805b83811015611be457848482818110611b3057611b306154e9565b9050602002013560246000896003811115611b4d57611b4d615102565b6003811115611b5e57611b5e615102565b81526020019081526020016000206001016000836003811115611b8357611b83615102565b6003811115611b9457611b94615102565b6003811115611ba557611ba5615102565b8152602081019190915260400160002055848482818110611bc857611bc86154e9565b9050602002013582611bda9190615525565b9150600101611b16565b5080670de0b6b3a764000014611c0d57604051630adc3ccb60e31b815260040160405180910390fd5b8460246000886003811115611c2457611c24615102565b6003811115611c3557611c35615102565b8152602081019190915260400160002055856003811115611c5857611c58615102565b7f5051fc6a7b31ea3fa7919ccc0c788f2108f610821b18b57408a3924eb76188e6868686604051611c8b9392919061574f565b60405180910390a2505050505050565b6000611ca5613d4d565b5060008051602061598383398151915290565b611cc0614b87565b60408051608081019091528060008152602001600181526020016002815260200160039052919050565b60006112fd82601554611cfb611613565b613d96565b6001600160a01b031660009081526025602052604090205460ff1690565b6000805160206159a3833981519152611d368161366a565b6001600160a01b03821660009081526020805260408120549003611d6d57604051630ae471df60e41b815260040160405180910390fd5b6001600160a01b0382166000908152602080526040812054611d919060019061573c565b601f54909150611da39060019061573c565b811015611e4b57601f805460009190611dbe9060019061573c565b81548110611dce57611dce6154e9565b600091825260209091200154601f80546001600160a01b039092169250829184908110611dfd57611dfd6154e9565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055611e31826001615525565b6001600160a01b0390911660009081526020805260409020555b601f805480611e5c57611e5c615790565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03851682528052604081205560215481148015611ebf57601f54602154611eb1906001615525565b611ebb91906157bc565b6021555b611ed760008051602061594383398151915285613a7c565b506040516001600160a01b038516907fb025ca7b24d2a1ec588bad96d467ad319b21cf169715b7dac04065c7fb51acbc90600090a250505050565b6001600160a01b0381166000908152601460205260408120546112fd906122e4565b600080516020615a03833981519152611f4c8161366a565b6001600160a01b038216611f735760405163d92e233d60e01b815260040160405180910390fd5b8160236000856003811115611f8a57611f8a615102565b6003811115611f9b57611f9b615102565b81526020810191909152604001600090812080546001600160a01b0319166001600160a01b039390931692909217909155836003811115611fde57611fde615102565b0361204d576001546001600160a01b03166023600085600381111561200557612005615102565b600381111561201657612016615102565b815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055506120a8565b816023600085600381111561206457612064615102565b600381111561207557612075615102565b815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b816001600160a01b03168360038111156120c4576120c4615102565b6040517f76f62d968bedb2d4fe6d9e87c8348e3d6a6c3fbe73e20884b75c73d230d11a6590600090a3505050565b6120fa612f32565b6003546001600160a01b0316331461212557604051639e41bdd760e01b815260040160405180910390fd5b611a2881613032565b6121398233836135a5565b6114a98282613b58565b600061215d600080516020615943833981519152836122fc565b80156112fd5750506001600160a01b03166000908152602080526040902054151590565b6001600160a01b03811660009081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb0060205260408120546112fd565b6121c6612f32565b3360009081526017602052604090205443116121f5576040516304e4394960e11b815260040160405180910390fd5b6121fd612f7c565b61220b846000858585613399565b611765613119565b600080516020615a0383398151915261222b8161366a565b6117e8613e5a565b60006060808280808381600080516020615963833981519152805490915015801561226057506001810154155b6122a95760405162461bcd60e51b81526020600482015260156024820152741152540dcc4c8e88155b9a5b9a5d1a585b1a5e9959605a1b60448201526064015b60405180910390fd5b6122b1613ea3565b6122b9613ee2565b60408051600080825260208201909252600f60f81b9c939b5091995046985030975095509350915050565b60006112fd826122f2611613565b6015546001613efa565b60009182526000805160206159c3833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0480546060917f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace009161133a90615561565b61238d612f32565b3360009081526017602052604090205443116123bc576040516304e4394960e11b815260040160405180910390fd5b6123c4612f7c565b6013546301000000900460ff166123ee5760405163562fb04960e11b815260040160405180910390fd5b47821161240e5760405163ba8552c160e01b815260040160405180910390fd5b60065460075461241e9084615525565b111561243d576040516392c730c760e01b815260040160405180910390fd5b60125461244a9043615525565b3360009081526019602052604090205561246682600183613f4b565b61247c826007546124779190615525565b613b8e565b600480546040516340c10f1960e01b81523392810192909252602482018490526001600160a01b0316906340c10f1990604401600060405180830381600087803b1580156124c957600080fd5b505af11580156124dd573d6000803e3d6000fd5b505050506114a9613119565b6125137f93350e56e77530c4c3adffe989496c648c85b1171c82068c5dec82bc9deb532f336122fc565b15801561254757506125457f54f5fa3fbe05747e670128ef2b79b948460620ea3992e7fd9c4ff652cc82deb6336122fc565b155b156125655760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b03811661258c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038116600081815260256020908152604091829020805460ff19166001908117909155915191825233917fac3e318f4d8128b08cb4ed08640aee05f99325ff6838c9cf196cf392c7565e2a91015b60405180910390a350565b6125f4612f32565b6125fc612f7c565b33600090815260176020526040902054431161262b576040516304e4394960e11b815260040160405180910390fd5b6001600160a01b0384166126525760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0384166000908152601e602052604090205460ff161561268c57604051637a471e1360e11b815260040160405180910390fd5b6126b67f6077685936c8169d09204a1d97db12e41713588c38e1d29a61867d3dcee98aff336122fc565b15806126c25750600034115b1561273d5760135460ff166126ea5760405163562fb04960e11b815260040160405180910390fd5b600260005260246020527f47bb5529a97e2b401b32950f6360fbc9e3f4e70b887dc0f9b9ad1f7402ca11da54341461273557604051632a9ffab760e21b815260040160405180910390fd5b61273d6141c7565b6001600160a01b0384166000818152601e60209081526040808320805460ff19166001179055338352601790915290819020439055517feb848dd9e3c3dbe3da6da5c36e67f2e41778a42fcbb3a341ccdcbc61bffaf428906127c09086908690869034909315158452911515602084015215156040830152606082015260800190565b60405180910390a2611765613119565b60006127db33611d00565b156127f957604051633a24938b60e21b815260040160405180910390fd5b61280283611d00565b1561282057604051633a24938b60e21b815260040160405180910390fd5b61145633848461360b565b6128557f54f5fa3fbe05747e670128ef2b79b948460620ea3992e7fd9c4ff652cc82deb6336122fc565b6128725760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381166128995760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03811660009081526025602052604090205460ff166128d2576040516373300e5d60e11b815260040160405180910390fd5b6001600160a01b0381166000818152602560209081526040808320805460ff191690555191825233917fac3e318f4d8128b08cb4ed08640aee05f99325ff6838c9cf196cf392c7565e2a91016125e1565b834211156129475760405163313c898160e11b8152600481018590526024016122a0565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886129b38c6001600160a01b031660009081527f5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb006020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000612a0e82614223565b90506000612a1e82878787614250565b9050896001600160a01b0316816001600160a01b031614612a65576040516325c0072360e11b81526001600160a01b0380831660048301528b1660248201526044016122a0565b612a708a8a8a61427e565b50505050505050505050565b612a8582611727565b612a8e8161366a565b6117658383613a7c565b612aa0612f32565b612aa8612f7c565b612ab133612143565b612ace5760405163e2bbd18560e01b815260040160405180910390fd5b601f60215481548110612ae357612ae36154e9565b6000918252602090912001546001600160a01b03163314612b175760405163231432ef60e01b815260040160405180910390fd5b600754600003612b3a57604051630dc748df60e11b815260040160405180910390fd5b6003546007546001600160a01b039091163190811115612b6d5760405163eb939ef360e01b815260040160405180910390fd5b600081600754612b7d919061573c565b905080471015612ba05760405163eee2a49b60e01b815260040160405180910390fd5b612bb1816006546111f69190615525565b60405181815233907faa0a55a65b848d4893316c409a99d531792f3c57684cda06f3caacbe363b25d19060200160405180910390a2600360009054906101000a90046001600160a01b03166001600160a01b031663d692e4e3826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612c3657600080fd5b505af1158015612c4a573d6000803e3d6000fd5b505050505050506119ea613119565b612c61612f32565b336000908152601760205260409020544311612c90576040516304e4394960e11b815260040160405180910390fd5b612c98612f7c565b60135462010000900460ff16612cc15760405163562fb04960e11b815260040160405180910390fd5b47821115612ce25760405163bc6072f160e01b815260040160405180910390fd5b612cee82600083613f4b565b612cf8338361428b565b6114a9613119565b6000805160206159a3833981519152612d188161366a565b6001600160a01b038216600090815260208052604090205415612d4e576040516375098d1760e01b815260040160405180910390fd5b601f80546001810182557fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d8070180546001600160a01b0319166001600160a01b0385169081179091559054600091825260208052604090912055612dbf60008051602061594383398151915283613674565b506040516001600160a01b038316907f9e24791803ca4403a42ed0ac802bafb55e327c452f7a01205b8655977bffcdb090600090a25050565b600080516020615a03833981519152612e108161366a565b600e5460a08301511015612e3757604051630ffd11ad60e01b815260040160405180910390fd5b8151600855602080830151600955604080840151600a55606080850151600b556080850151600c5560a0850151600d5560c0850151600e5560e0850151600f556101008086015160105561012086015160115561014086015160125561016086015180516013805496830151838701519390950151151563010000000263ff0000001993151562010000029390931663ffff00001995151590940261ff00199215159290921661ffff19909716969096171792909216171790915551612efe9083906157d0565b604051908190038120907f254354c73cfc0090ceaf2ea35d959ffed011e9eeeeb6e0e078f3f6dc8cb501cb90600090a25050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901612f7657604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6000805160206159e38339815191525460ff16156119ea5760405163d93c066560e01b815260040160405180910390fd5b601f54602154612fbe906001615525565b612fc891906157bc565b602181905550601f60215481548110612fe357612fe36154e9565b600091825260209182902001546021546040519081526001600160a01b03909116917fd577232dd9e50b968dfc0fdc01cd1a29fb367e9cea13608cf7134a9c24ce70d5910160405180910390a2565b600681905560405181907ffe6bd73b2487c4b7d5939ba1ba9c89f149f9010a73b175c07eff14441869483f90600090a250565b61306f60016113be565b6003600052602460209081527f8a6809e43cef135a96df89aa3c0800baae7c497913adf6156625c15a6f57cdf0546040519081526001600160a01b0392909216917f0ed8b6fdfe110a7f817805007b6d22859af5e490ca5e07a18fee7cb48b1a57e4910160405180910390a26119ea6130e860016113be565b600360005260246020527f8a6809e43cef135a96df89aa3c0800baae7c497913adf6156625c15a6f57cdf05461428b565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6001600160a01b0384166131665760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03831661318d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038085166000908152601660209081526040808320938716835292905220829055801561176557826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161320091815260200190565b60405180910390a350505050565b613216612f7c565b61321f83611d00565b1561323d57604051633a24938b60e21b815260040160405180910390fd5b61324682611d00565b1561326457604051633a24938b60e21b815260040160405180910390fd5b6001600160a01b03831661328b5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382166132b25760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0383166000908152601460205260409020548111156132eb57604051633999656760e01b815260040160405180910390fd5b6001600160a01b0383166000908152601460205260408120805483929061331390849061573c565b90915550506001600160a01b03821660009081526014602052604081208054839290613340908490615525565b92505081905550816001600160a01b0316836001600160a01b03167f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb8360405161338c91815260200190565b60405180910390a3505050565b601354610100900460ff166133c15760405163562fb04960e11b815260040160405180910390fd5b60006133cb611613565b116133e95760405163c16f3a9360e01b815260040160405180910390fd5b6001600160a01b03851660009081526025602052604090205460ff161561342357604051633a24938b60e21b815260040160405180910390fd5b600b543410156134465760405163663436a560e11b815260040160405180910390fd5b6001600160a01b0383166000908152601e602052604090205460ff1661347f576040516301dbb3ff60e61b815260040160405180910390fd5b613487614322565b34601b60008282546134999190615525565b909155505033600090815260176020526040902043908190556011546134be91615525565b33600090815260186020526040902055600954601b54111561353657846001600160a01b03167fa7ca73d163eac9a150c6c4afd1ff6cadedfdc85012b37aadd9039f54540a04c73460405161351591815260200190565b60405180910390a2604051632484557960e01b815260040160405180910390fd5b81816040516135469291906154ff565b6040518091039020836001600160a01b0316866001600160a01b03167fce5e8aa759525e99721a56b0c70d317638e2d6d80a440e4dd97c3af8267b4b0134886040516135939291906158ce565b60405180910390a46112c5853461434e565b6001600160a01b03808416600090815260166020908152604080832093861683529290522054600019811461176557818110156135f5576040516313be252b60e01b815260040160405180910390fd5b6117658484613604858561573c565b600161313f565b6001600160a01b03831661363557604051634b637e8f60e11b8152600060048201526024016122a0565b6001600160a01b03821661365f5760405163ec442f0560e01b8152600060048201526024016122a0565b61168a83838361436e565b6117e8813361445b565b60006000805160206159c383398151915261368f84846122fc565b61370f576000848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556136c53390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506112fd565b60009150506112fd565b613721614b87565b600061372b611cb8565b905060006024600087600381111561374557613745615102565b600381111561375657613756615102565b8152602001908152602001600020600001549050600061377f8683670de0b6b3a7640000613d96565b90506000805b6137916001600461573c565b8110156138bc5760006137b98683600481106137af576137af6154e9565b60200201516113be565b6001600160a01b0316036137e05760405163d92e233d60e01b815260040160405180910390fd5b6000602460008b60038111156137f8576137f8615102565b600381111561380957613809615102565b8152602001908152602001600020600101600087846004811061382e5761382e6154e9565b6020020151600381111561384457613844615102565b600381111561385557613855615102565b81526020019081526020016000205490506138798482670de0b6b3a7640000613d96565b87836004811061388b5761388b6154e9565b60200201528682600481106138a2576138a26154e9565b60200201516138b19084615525565b925050600101613785565b506138c7818861573c565b60608601526000808960038111156138e1576138e1615102565b146138f7576138f26001600461573c565b6138fa565b60045b905060005b81811015612a7057600087826004811061391b5761391b6154e9565b60200201511115613a6a5760008a600381111561393a5761393a615102565b14801561396e57506003868260048110613956576139566154e9565b6020020151600381111561396c5761396c615102565b145b156139985761399388888360048110613989576139896154e9565b6020020151614494565b613a6a565b6139c26139b08783600481106137af576137af6154e9565b888360048110613989576139896154e9565b8581600481106139d4576139d46154e9565b602002015160038111156139ea576139ea615102565b8a60038111156139fc576139fc615102565b613a118884600481106137af576137af6154e9565b6001600160a01b03167fd8d136691cb70fed9e96b70a3de7e6efdee8c468fd8398375be41720182defc98a8560048110613a4d57613a4d6154e9565b6020020151604051613a6191815260200190565b60405180910390a45b6001016138ff565b6000611630614592565b60006000805160206159c3833981519152613a9784846122fc565b1561370f576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506112fd565b613b00614606565b6000805160206159e3833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b6001600160a01b038216613b8257604051634b637e8f60e11b8152600060048201526024016122a0565b6114a98260008361436e565b600781905560405181907fec837734bfcb6c37153600ffa50a6123c7818f84e13c382a5f45b74308a5f04390600090a250565b306001600160a01b037f000000000000000000000000945164b7fbc49c04cc5a4f04caa5699f7d2f0c60161480613c4857507f000000000000000000000000945164b7fbc49c04cc5a4f04caa5699f7d2f0c606001600160a01b0316613c3c600080516020615983833981519152546001600160a01b031690565b6001600160a01b031614155b156119ea5760405163703e46dd60e11b815260040160405180910390fd5b7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e36114a98161366a565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015613cea575060408051601f3d908101601f19168201909252613ce7918101906158eb565b60015b613d1257604051634c9c8ce360e01b81526001600160a01b03831660048201526024016122a0565b6000805160206159838339815191528114613d4357604051632a87526960e21b8152600481018290526024016122a0565b61168a8383614636565b306001600160a01b037f000000000000000000000000945164b7fbc49c04cc5a4f04caa5699f7d2f0c6016146119ea5760405163703e46dd60e11b815260040160405180910390fd5b6000838302816000198587098281108382030391505080600003613dcd57838281613dc357613dc36157a6565b0492505050611720565b808411613ded5760405163227bc15360e01b815260040160405180910390fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b613e62612f7c565b6000805160206159e3833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833613b3a565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060916000805160206159638339815191529161133a90615561565b60606000600080516020615963833981519152611329565b600080613f08868686613d96565b9050613f138361468c565b8015613f2f575060008480613f2a57613f2a6157a6565b868809115b15613f4257613f3f600182615525565b90505b95945050505050565b3360009081526025602052604090205460ff1615613f7c57604051633a24938b60e21b815260040160405180910390fd5b82600003613f9d57604051631f2a200560e01b815260040160405180910390fd5b613fa633611f12565b831115613fc657604051630b0888ab60e41b815260040160405180910390fd5b600c54831015613fe957604051631ec6b8b360e21b815260040160405180910390fd5b3360009081526018602052604090205443101561401957604051639fbfb9ab60e01b815260040160405180910390fd5b614021614322565b33600090815260176020526040812043905582600181111561404557614045615102565b036140ce5782601c600082825461405c9190615525565b9091555050600f54601c5411156140c957336001600160a01b03167fa80a491daef20bedd52d7c1fcee4a50bf43d4384594c75b7d3fa8260855654bd84846040516140a89291906158ce565b60405180910390a26040516371c4522160e01b815260040160405180910390fd5b61414d565b82601d60008282546140e09190615525565b9091555050601054601d54111561414d57336001600160a01b03167fa80a491daef20bedd52d7c1fcee4a50bf43d4384594c75b7d3fa8260855654bd848460405161412c9291906158ce565b60405180910390a2604051632299fde160e01b815260040160405180910390fd5b806001600160a01b0316336001600160a01b03167fc9374dd61d5f2babb5a5044b17c753e856de109d37ec23bdf7c67a18b9b6dda585856040516141929291906158ce565b60405180910390a33360008181526014602052604081205490916141bb918691611cfb90611f12565b905061176533826146b9565b6002600090815260246020527f47bb5529a97e2b401b32950f6360fbc9e3f4e70b887dc0f9b9ad1f7402ca11da546015549091906142149083908161420a611613565b611cfb919061573c565b90506114a96002826000613719565b60006112fd614230613a72565b8360405161190160f01b8152600281019290925260228201526042902090565b600080600080614262888888886147db565b92509250925061427282826148aa565b50909695505050505050565b61168a838383600161313f565b804710156142ae5760405163cd78605960e01b81523060048201526024016122a0565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146142fb576040519150601f19603f3d011682016040523d82523d6000602084013e614300565b606091505b505090508061168a57604051630a12f52160e11b815260040160405180910390fd5b600854601a546143329190615525565b4311156119ea576000601b819055601c819055601d5543601a55565b6000614360826015548461420a611613565b905061168a60008285613719565b614376612f32565b3360009081526017602052604090205443116143a5576040516304e4394960e11b815260040160405180910390fd5b6143ad612f7c565b336000908152601860205260409020544310156143dd57604051639fbfb9ab60e01b815260040160405180910390fd5b3360009081526017602052604081204390556143f882611cea565b905061440584848361320e565b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161444a91815260200190565b60405180910390a35061168a613119565b61446582826122fc565b6114a95760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044016122a0565b61449c612f7c565b6001600160a01b0382166144c35760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038216600090815260146020526040812080548392906144eb908490615525565b9250508190555080601560008282546145049190615525565b90915550506040518181526001600160a01b038316907fe0db2c42b942601357f9499d6f0520c824b2ce7513135a456b661d1d3e45de5e9060200160405180910390a26001600160a01b03821660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef61457d846122e4565b60405190815260200160405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6145bd614963565b6145c56149cd565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6000805160206159e38339815191525460ff166119ea57604051638dfc202b60e01b815260040160405180910390fd5b61463f82614a11565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156146845761168a8282614a76565b6114a9614ae3565b600060028260038111156146a2576146a2615102565b6146ac9190615904565b60ff166001149050919050565b6146c1612f7c565b6001600160a01b0382166146e85760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03821660009081526014602052604090205481111561472157604051633999656760e01b815260040160405180910390fd5b6001600160a01b0382166000908152601460205260408120805483929061474990849061573c565b925050819055508060156000828254614762919061573c565b90915550506040518181526001600160a01b038316907f5c482005cb92f4606eb4f7244f8978adb96c9dfff9ab5c5be326273f0610fe459060200160405180910390a260006001600160a01b0383167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef61457d846122e4565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561481657506000915060039050826148a0565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561486a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614896575060009250600191508290506148a0565b9250600091508190505b9450945094915050565b60008260038111156148be576148be615102565b036148c7575050565b60018260038111156148db576148db615102565b036148f95760405163f645eedf60e01b815260040160405180910390fd5b600282600381111561490d5761490d615102565b0361492e5760405163fce698f760e01b8152600481018290526024016122a0565b600382600381111561494257614942615102565b036114a9576040516335e2f38360e21b8152600481018290526024016122a0565b60006000805160206159638339815191528161497d613ea3565b80519091501561499557805160209091012092915050565b815480156149a4579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b6000600080516020615963833981519152816149e7613ee2565b8051909150156149ff57805160209091012092915050565b600182015480156149a4579392505050565b806001600160a01b03163b600003614a4757604051634c9c8ce360e01b81526001600160a01b03821660048201526024016122a0565b60008051602061598383398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051614a939190615926565b600060405180830381855af49150503d8060008114614ace576040519150601f19603f3d011682016040523d82523d6000602084013e614ad3565b606091505b5091509150613f42858383614b02565b34156119ea5760405163b398979f60e01b815260040160405180910390fd5b606082614b1757614b1282614b5e565b611720565b8151158015614b2e57506001600160a01b0384163b155b15614b5757604051639996b31560e01b81526001600160a01b03851660048201526024016122a0565b5080611720565b805115614b6e5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60405180608001604052806004906020820280368337509192915050565b60008083601f840112614bb757600080fd5b5081356001600160401b03811115614bce57600080fd5b602083019150836020828501011115614be657600080fd5b9250929050565b600080600080600060608688031215614c0557600080fd5b85356001600160401b0380821115614c1c57600080fd5b614c2889838a01614ba5565b90975095506020880135915080821115614c4157600080fd5b50614c4e88828901614ba5565b96999598509660400135949350505050565b600060208284031215614c7257600080fd5b81356001600160e01b03198116811461172057600080fd5b60005b83811015614ca5578181015183820152602001614c8d565b50506000910152565b60008151808452614cc6816020860160208601614c8a565b601f01601f19169290920160200192915050565b6020815260006117206020830184614cae565b600481106117e857600080fd5b600060208284031215614d0c57600080fd5b813561172081614ced565b6001600160a01b03811681146117e857600080fd5b60008060408385031215614d3f57600080fd5b8235614d4a81614d17565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715614d9057614d90614d58565b60405290565b60405161018081016001600160401b0381118282101715614d9057614d90614d58565b604051601f8201601f191681016001600160401b0381118282101715614de157614de1614d58565b604052919050565b60006020808385031215614dfc57600080fd5b82356001600160401b0380821115614e1357600080fd5b818501915085601f830112614e2757600080fd5b813581811115614e3957614e39614d58565b614e47848260051b01614db9565b818152848101925060069190911b830184019087821115614e6757600080fd5b928401925b81841015614eb35760408489031215614e855760008081fd5b614e8d614d6e565b8435614e9881614d17565b81528486013586820152835260409093019291840191614e6c565b979650505050505050565b600080600060408486031215614ed357600080fd5b8335614ede81614d17565b925060208401356001600160401b03811115614ef957600080fd5b614f0586828701614ba5565b9497909650939450505050565b600080600060608486031215614f2757600080fd5b8335614f3281614d17565b92506020840135614f4281614d17565b929592945050506040919091013590565b600060208284031215614f6557600080fd5b5035919050565b60008060408385031215614f7f57600080fd5b823591506020830135614f9181614d17565b809150509250929050565b600060208284031215614fae57600080fd5b813561172081614d17565b600082601f830112614fca57600080fd5b81356001600160401b03811115614fe357614fe3614d58565b614ff6601f8201601f1916602001614db9565b81815284602083860101111561500b57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561503b57600080fd5b823561504681614d17565b915060208301356001600160401b0381111561506157600080fd5b61506d85828601614fb9565b9150509250929050565b6000806000806060858703121561508d57600080fd5b843561509881614ced565b93506020850135925060408501356001600160401b03808211156150bb57600080fd5b818701915087601f8301126150cf57600080fd5b8135818111156150de57600080fd5b8860208260051b85010111156150f357600080fd5b95989497505060200194505050565b634e487b7160e01b600052602160045260246000fd5b60808101818360005b60048082106151305750615157565b825181811061514157615141615102565b8452506020928301929190910190600101615121565b50505092915050565b60006020828403121561517257600080fd5b81356001600160401b0381111561518857600080fd5b61519484828501614fb9565b949350505050565b600080604083850312156151af57600080fd5b82356151ba81614ced565b91506020830135614f9181614d17565b600080600080606085870312156151e057600080fd5b84356151eb81614d17565b935060208501356151fb81614d17565b925060408501356001600160401b0381111561521657600080fd5b61522287828801614ba5565b95989497509550505050565b60ff60f81b881681526000602060e0602084015261524f60e084018a614cae565b8381036040850152615261818a614cae565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b818110156152b557835183529284019291840191600101615299565b50909c9b505050505050505050505050565b803580151581146152d757600080fd5b919050565b600080600080608085870312156152f257600080fd5b84356152fd81614d17565b935061530b602086016152c7565b9250615319604086016152c7565b9150615327606086016152c7565b905092959194509250565b600080600080600080600060e0888a03121561534d57600080fd5b873561535881614d17565b9650602088013561536881614d17565b95506040880135945060608801359350608088013560ff8116811461538c57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156153bc57600080fd5b82356151ba81614d17565b6000608082840312156153d957600080fd5b604051608081018181106001600160401b03821117156153fb576153fb614d58565b60405290508061540a836152c7565b8152615418602084016152c7565b6020820152615429604084016152c7565b604082015261543a606084016152c7565b60608201525092915050565b60006101e0828403121561545957600080fd5b615461614d96565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152506101208084013581830152506101408084013581830152506101606154de858286016153c7565b908201529392505050565b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156112fd576112fd61550f565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600181811c9082168061557557607f821691505b60208210810361559557634e487b7160e01b600052602260045260246000fd5b50919050565b8054600090600181811c90808316806155b557607f831692505b602080841082036155d657634e487b7160e01b600052602260045260246000fd5b838852602088018280156155f1576001811461560757615632565b60ff198716825285151560051b82019750615632565b60008981526020902060005b8781101561562c57815484820152908601908401615613565b83019850505b5050505050505092915050565b87815260a06020820152600061565960a08301888a615538565b828103604084015261566b818861559b565b90508281036060840152615680818688615538565b91505082608083015298975050505050505050565b6080815260006156a960808301888a615538565b82810360208401526156bb818861559b565b905082810360408401526156d0818688615538565b915050826060830152979650505050505050565b602080825282518282018190526000919060409081850190868401855b8281101561572f57815180516001600160a01b03168552860151868501529284019290850190600101615701565b5091979650505050505050565b818103818111156112fd576112fd61550f565b838152604060208201819052810182905260006001600160fb1b0383111561577657600080fd5b8260051b8085606085013791909101606001949350505050565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000826157cb576157cb6157a6565b500690565b815181526158b461587e61587061586261585461584761583a61582d61582061581361580660208c0160208e0151815260200190565b60408d0151815260200190565b60608c0151815260200190565b60808b0151815260200190565b60a08a0151815260200190565b60c0890151815260200190565b60e0880151815260200190565b610100870151815260200190565b610120860151815260200190565b610140850151815260200190565b61016084015180511515825260208082015115159083015260408082015115159083015260609081015115159082015260800190565b506101e001919050565b600281106117e8576117e8615102565b828152604081016158de836158be565b8260208301529392505050565b6000602082840312156158fd57600080fd5b5051919050565b600060ff831680615917576159176157a6565b8060ff84160691505092915050565b60008251615938818460208701614c8a565b919091019291505056fe3b394600f9a9e5957a84f453f4142ea034b950b69711afc0c4ed772f1580df2ca16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbce06ea5fb1a9d8d613e08b8f50cba89eefef698ab183e9c58c5040c4ee526ab7102dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300a49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220ec7e4fc4d35ac2c9723826e651d929c7a4e694b690beae457d047deb9001c2f864736f6c63430008160033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.