Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Lido
Compiler Version
v0.4.24+commit.e67f0147
Optimization Enabled:
Yes with 200 runs
Other Settings:
constantinople EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2020 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ pragma solidity 0.4.24; import "@aragon/os/contracts/apps/AragonApp.sol"; import "@aragon/os/contracts/lib/math/SafeMath.sol"; import "@aragon/os/contracts/lib/math/SafeMath64.sol"; import "solidity-bytes-utils/contracts/BytesLib.sol"; import "./interfaces/ILido.sol"; import "./interfaces/INodeOperatorsRegistry.sol"; import "./interfaces/IDepositContract.sol"; import "./interfaces/ILidoExecutionLayerRewardsVault.sol"; import "./StETH.sol"; import "./lib/StakeLimitUtils.sol"; interface IERC721 { /// @notice Transfer ownership of an NFT /// @param _from The current owner of the NFT /// @param _to The new owner /// @param _tokenId The NFT to transfer function transferFrom(address _from, address _to, uint256 _tokenId) external payable; } /** * @title Liquid staking pool implementation * * Lido is an Ethereum 2.0 liquid staking protocol solving the problem of frozen staked Ethers * until transfers become available in Ethereum 2.0. * Whitepaper: https://lido.fi/static/Lido:Ethereum-Liquid-Staking.pdf * * NOTE: the code below assumes moderate amount of node operators, e.g. up to 200. * * Since balances of all token holders change when the amount of total pooled Ether * changes, this token cannot fully implement ERC20 standard: it only emits `Transfer` * events upon explicit transfer between holders. In contrast, when Lido oracle reports * rewards, no Transfer events are generated: doing so would require emitting an event * for each token holder and thus running an unbounded loop. * * At the moment withdrawals are not possible in the beacon chain and there's no workaround. * Pool will be upgraded to an actual implementation when withdrawals are enabled * (Phase 1.5 or 2 of Eth2 launch, likely late 2022 or 2023). */ contract Lido is ILido, StETH, AragonApp { using SafeMath for uint256; using UnstructuredStorage for bytes32; using StakeLimitUnstructuredStorage for bytes32; using StakeLimitUtils for StakeLimitState.Data; /// ACL bytes32 constant public PAUSE_ROLE = keccak256("PAUSE_ROLE"); bytes32 constant public RESUME_ROLE = keccak256("RESUME_ROLE"); bytes32 constant public STAKING_PAUSE_ROLE = keccak256("STAKING_PAUSE_ROLE"); bytes32 constant public STAKING_CONTROL_ROLE = keccak256("STAKING_CONTROL_ROLE"); bytes32 constant public MANAGE_FEE = keccak256("MANAGE_FEE"); bytes32 constant public MANAGE_WITHDRAWAL_KEY = keccak256("MANAGE_WITHDRAWAL_KEY"); bytes32 constant public MANAGE_PROTOCOL_CONTRACTS_ROLE = keccak256("MANAGE_PROTOCOL_CONTRACTS_ROLE"); bytes32 constant public BURN_ROLE = keccak256("BURN_ROLE"); bytes32 constant public DEPOSIT_ROLE = keccak256("DEPOSIT_ROLE"); bytes32 constant public SET_EL_REWARDS_VAULT_ROLE = keccak256("SET_EL_REWARDS_VAULT_ROLE"); bytes32 constant public SET_EL_REWARDS_WITHDRAWAL_LIMIT_ROLE = keccak256( "SET_EL_REWARDS_WITHDRAWAL_LIMIT_ROLE" ); uint256 constant public PUBKEY_LENGTH = 48; uint256 constant public WITHDRAWAL_CREDENTIALS_LENGTH = 32; uint256 constant public SIGNATURE_LENGTH = 96; uint256 constant public DEPOSIT_SIZE = 32 ether; uint256 internal constant DEPOSIT_AMOUNT_UNIT = 1000000000 wei; uint256 internal constant TOTAL_BASIS_POINTS = 10000; /// @dev default value for maximum number of Ethereum 2.0 validators registered in a single depositBufferedEther call uint256 internal constant DEFAULT_MAX_DEPOSITS_PER_CALL = 150; bytes32 internal constant FEE_POSITION = keccak256("lido.Lido.fee"); bytes32 internal constant TREASURY_FEE_POSITION = keccak256("lido.Lido.treasuryFee"); bytes32 internal constant INSURANCE_FEE_POSITION = keccak256("lido.Lido.insuranceFee"); bytes32 internal constant NODE_OPERATORS_FEE_POSITION = keccak256("lido.Lido.nodeOperatorsFee"); bytes32 internal constant DEPOSIT_CONTRACT_POSITION = keccak256("lido.Lido.depositContract"); bytes32 internal constant ORACLE_POSITION = keccak256("lido.Lido.oracle"); bytes32 internal constant NODE_OPERATORS_REGISTRY_POSITION = keccak256("lido.Lido.nodeOperatorsRegistry"); bytes32 internal constant TREASURY_POSITION = keccak256("lido.Lido.treasury"); bytes32 internal constant INSURANCE_FUND_POSITION = keccak256("lido.Lido.insuranceFund"); bytes32 internal constant EL_REWARDS_VAULT_POSITION = keccak256("lido.Lido.executionLayerRewardsVault"); /// @dev storage slot position of the staking rate limit structure bytes32 internal constant STAKING_STATE_POSITION = keccak256("lido.Lido.stakeLimit"); /// @dev amount of Ether (on the current Ethereum side) buffered on this smart contract balance bytes32 internal constant BUFFERED_ETHER_POSITION = keccak256("lido.Lido.bufferedEther"); /// @dev number of deposited validators (incrementing counter of deposit operations). bytes32 internal constant DEPOSITED_VALIDATORS_POSITION = keccak256("lido.Lido.depositedValidators"); /// @dev total amount of Beacon-side Ether (sum of all the balances of Lido validators) bytes32 internal constant BEACON_BALANCE_POSITION = keccak256("lido.Lido.beaconBalance"); /// @dev number of Lido's validators available in the Beacon state bytes32 internal constant BEACON_VALIDATORS_POSITION = keccak256("lido.Lido.beaconValidators"); /// @dev percent in basis points of total pooled ether allowed to withdraw from LidoExecutionLayerRewardsVault per LidoOracle report bytes32 internal constant EL_REWARDS_WITHDRAWAL_LIMIT_POSITION = keccak256("lido.Lido.ELRewardsWithdrawalLimit"); /// @dev Just a counter of total amount of execution layer rewards received by Lido contract /// Not used in the logic bytes32 internal constant TOTAL_EL_REWARDS_COLLECTED_POSITION = keccak256("lido.Lido.totalELRewardsCollected"); /// @dev Credentials which allows the DAO to withdraw Ether on the 2.0 side bytes32 internal constant WITHDRAWAL_CREDENTIALS_POSITION = keccak256("lido.Lido.withdrawalCredentials"); /** * @dev As AragonApp, Lido contract must be initialized with following variables: * @param _depositContract official ETH2 Deposit contract * @param _oracle oracle contract * @param _operators instance of Node Operators Registry * @param _treasury treasury contract * @param _insuranceFund insurance fund contract * NB: by default, staking and the whole Lido pool are in paused state */ function initialize( IDepositContract _depositContract, address _oracle, INodeOperatorsRegistry _operators, address _treasury, address _insuranceFund ) public onlyInit { NODE_OPERATORS_REGISTRY_POSITION.setStorageAddress(address(_operators)); DEPOSIT_CONTRACT_POSITION.setStorageAddress(address(_depositContract)); _setProtocolContracts(_oracle, _treasury, _insuranceFund); initialized(); } /** * @notice Stops accepting new Ether to the protocol * * @dev While accepting new Ether is stopped, calls to the `submit` function, * as well as to the default payable function, will revert. * * Emits `StakingPaused` event. */ function pauseStaking() external { _auth(STAKING_PAUSE_ROLE); _pauseStaking(); } /** * @notice Resumes accepting new Ether to the protocol (if `pauseStaking` was called previously) * NB: Staking could be rate-limited by imposing a limit on the stake amount * at each moment in time, see `setStakingLimit()` and `removeStakingLimit()` * * @dev Preserves staking limit if it was set previously * * Emits `StakingResumed` event */ function resumeStaking() external { _auth(STAKING_CONTROL_ROLE); _resumeStaking(); } /** * @notice Sets the staking rate limit * * ▲ Stake limit * │..... ..... ........ ... .... ... Stake limit = max * │ . . . . . . . . . * │ . . . . . . . . . * │ . . . . . * │──────────────────────────────────────────────────> Time * │ ^ ^ ^ ^^^ ^ ^ ^ ^^^ ^ Stake events * * @dev Reverts if: * - `_maxStakeLimit` == 0 * - `_maxStakeLimit` >= 2^96 * - `_maxStakeLimit` < `_stakeLimitIncreasePerBlock` * - `_maxStakeLimit` / `_stakeLimitIncreasePerBlock` >= 2^32 (only if `_stakeLimitIncreasePerBlock` != 0) * * Emits `StakingLimitSet` event * * @param _maxStakeLimit max stake limit value * @param _stakeLimitIncreasePerBlock stake limit increase per single block */ function setStakingLimit(uint256 _maxStakeLimit, uint256 _stakeLimitIncreasePerBlock) external { _auth(STAKING_CONTROL_ROLE); STAKING_STATE_POSITION.setStorageStakeLimitStruct( STAKING_STATE_POSITION.getStorageStakeLimitStruct().setStakingLimit( _maxStakeLimit, _stakeLimitIncreasePerBlock ) ); emit StakingLimitSet(_maxStakeLimit, _stakeLimitIncreasePerBlock); } /** * @notice Removes the staking rate limit * * Emits `StakingLimitRemoved` event */ function removeStakingLimit() external { _auth(STAKING_CONTROL_ROLE); STAKING_STATE_POSITION.setStorageStakeLimitStruct( STAKING_STATE_POSITION.getStorageStakeLimitStruct().removeStakingLimit() ); emit StakingLimitRemoved(); } /** * @notice Check staking state: whether it's paused or not */ function isStakingPaused() external view returns (bool) { return STAKING_STATE_POSITION.getStorageStakeLimitStruct().isStakingPaused(); } /** * @notice Returns how much Ether can be staked in the current block * @dev Special return values: * - 2^256 - 1 if staking is unlimited; * - 0 if staking is paused or if limit is exhausted. */ function getCurrentStakeLimit() public view returns (uint256) { return _getCurrentStakeLimit(STAKING_STATE_POSITION.getStorageStakeLimitStruct()); } /** * @notice Returns full info about current stake limit params and state * @dev Might be used for the advanced integration requests. * @return isStakingPaused staking pause state (equivalent to return of isStakingPaused()) * @return isStakingLimitSet whether the stake limit is set * @return currentStakeLimit current stake limit (equivalent to return of getCurrentStakeLimit()) * @return maxStakeLimit max stake limit * @return maxStakeLimitGrowthBlocks blocks needed to restore max stake limit from the fully exhausted state * @return prevStakeLimit previously reached stake limit * @return prevStakeBlockNumber previously seen block number */ function getStakeLimitFullInfo() external view returns ( bool isStakingPaused, bool isStakingLimitSet, uint256 currentStakeLimit, uint256 maxStakeLimit, uint256 maxStakeLimitGrowthBlocks, uint256 prevStakeLimit, uint256 prevStakeBlockNumber ) { StakeLimitState.Data memory stakeLimitData = STAKING_STATE_POSITION.getStorageStakeLimitStruct(); isStakingPaused = stakeLimitData.isStakingPaused(); isStakingLimitSet = stakeLimitData.isStakingLimitSet(); currentStakeLimit = _getCurrentStakeLimit(stakeLimitData); maxStakeLimit = stakeLimitData.maxStakeLimit; maxStakeLimitGrowthBlocks = stakeLimitData.maxStakeLimitGrowthBlocks; prevStakeLimit = stakeLimitData.prevStakeLimit; prevStakeBlockNumber = stakeLimitData.prevStakeBlockNumber; } /** * @notice Send funds to the pool * @dev Users are able to submit their funds by transacting to the fallback function. * Unlike vanilla Eth2.0 Deposit contract, accepting only 32-Ether transactions, Lido * accepts payments of any size. Submitted Ethers are stored in Buffer until someone calls * depositBufferedEther() and pushes them to the ETH2 Deposit contract. */ function() external payable { // protection against accidental submissions by calling non-existent function require(msg.data.length == 0, "NON_EMPTY_DATA"); _submit(0); } /** * @notice Send funds to the pool with optional _referral parameter * @dev This function is alternative way to submit funds. Supports optional referral address. * @return Amount of StETH shares generated */ function submit(address _referral) external payable returns (uint256) { return _submit(_referral); } /** * @notice A payable function for execution layer rewards. Can be called only by ExecutionLayerRewardsVault contract * @dev We need a dedicated function because funds received by the default payable function * are treated as a user deposit */ function receiveELRewards() external payable { require(msg.sender == EL_REWARDS_VAULT_POSITION.getStorageAddress()); TOTAL_EL_REWARDS_COLLECTED_POSITION.setStorageUint256( TOTAL_EL_REWARDS_COLLECTED_POSITION.getStorageUint256().add(msg.value)); emit ELRewardsReceived(msg.value); } /** * @notice Deposits buffered ethers to the official DepositContract. * @dev This function is separated from submit() to reduce the cost of sending funds. */ function depositBufferedEther() external { _auth(DEPOSIT_ROLE); return _depositBufferedEther(DEFAULT_MAX_DEPOSITS_PER_CALL); } /** * @notice Deposits buffered ethers to the official DepositContract, making no more than `_maxDeposits` deposit calls. * @dev This function is separated from submit() to reduce the cost of sending funds. */ function depositBufferedEther(uint256 _maxDeposits) external { _auth(DEPOSIT_ROLE); return _depositBufferedEther(_maxDeposits); } function burnShares(address _account, uint256 _sharesAmount) external authP(BURN_ROLE, arr(_account, _sharesAmount)) returns (uint256 newTotalShares) { return _burnShares(_account, _sharesAmount); } /** * @notice Stop pool routine operations */ function stop() external { _auth(PAUSE_ROLE); _stop(); _pauseStaking(); } /** * @notice Resume pool routine operations * @dev Staking should be resumed manually after this call using the desired limits */ function resume() external { _auth(RESUME_ROLE); _resume(); _resumeStaking(); } /** * @notice Set fee rate to `_feeBasisPoints` basis points. * The fees are accrued when: * - oracles report staking results (beacon chain balance increase) * - validators gain execution layer rewards (priority fees and MEV) * @param _feeBasisPoints Fee rate, in basis points */ function setFee(uint16 _feeBasisPoints) external { _auth(MANAGE_FEE); _setBPValue(FEE_POSITION, _feeBasisPoints); emit FeeSet(_feeBasisPoints); } /** * @notice Set fee distribution * @param _treasuryFeeBasisPoints basis points go to the treasury, * @param _insuranceFeeBasisPoints basis points go to the insurance fund, * @param _operatorsFeeBasisPoints basis points go to node operators. * @dev The sum has to be 10 000. */ function setFeeDistribution( uint16 _treasuryFeeBasisPoints, uint16 _insuranceFeeBasisPoints, uint16 _operatorsFeeBasisPoints ) external { _auth(MANAGE_FEE); require( TOTAL_BASIS_POINTS == uint256(_treasuryFeeBasisPoints) .add(uint256(_insuranceFeeBasisPoints)) .add(uint256(_operatorsFeeBasisPoints)), "FEES_DONT_ADD_UP" ); _setBPValue(TREASURY_FEE_POSITION, _treasuryFeeBasisPoints); _setBPValue(INSURANCE_FEE_POSITION, _insuranceFeeBasisPoints); _setBPValue(NODE_OPERATORS_FEE_POSITION, _operatorsFeeBasisPoints); emit FeeDistributionSet(_treasuryFeeBasisPoints, _insuranceFeeBasisPoints, _operatorsFeeBasisPoints); } /** * @notice Set Lido protocol contracts (oracle, treasury, insurance fund). * * @dev Oracle contract specified here is allowed to make * periodical updates of beacon stats * by calling pushBeacon. Treasury contract specified here is used * to accumulate the protocol treasury fee. Insurance fund contract * specified here is used to accumulate the protocol insurance fee. * * @param _oracle oracle contract * @param _treasury treasury contract * @param _insuranceFund insurance fund contract */ function setProtocolContracts( address _oracle, address _treasury, address _insuranceFund ) external { _auth(MANAGE_PROTOCOL_CONTRACTS_ROLE); _setProtocolContracts(_oracle, _treasury, _insuranceFund); } /** * @notice Set credentials to withdraw ETH on ETH 2.0 side after the phase 2 is launched to `_withdrawalCredentials` * @dev Note that setWithdrawalCredentials discards all unused signing keys as the signatures are invalidated. * @param _withdrawalCredentials withdrawal credentials field as defined in the Ethereum PoS consensus specs */ function setWithdrawalCredentials(bytes32 _withdrawalCredentials) external { _auth(MANAGE_WITHDRAWAL_KEY); WITHDRAWAL_CREDENTIALS_POSITION.setStorageBytes32(_withdrawalCredentials); getOperators().trimUnusedKeys(); emit WithdrawalCredentialsSet(_withdrawalCredentials); } /** * @dev Sets the address of LidoExecutionLayerRewardsVault contract * @param _executionLayerRewardsVault Execution layer rewards vault contract address */ function setELRewardsVault(address _executionLayerRewardsVault) external { _auth(SET_EL_REWARDS_VAULT_ROLE); EL_REWARDS_VAULT_POSITION.setStorageAddress(_executionLayerRewardsVault); emit ELRewardsVaultSet(_executionLayerRewardsVault); } /** * @dev Sets limit on amount of ETH to withdraw from execution layer rewards vault per LidoOracle report * @param _limitPoints limit in basis points to amount of ETH to withdraw per LidoOracle report */ function setELRewardsWithdrawalLimit(uint16 _limitPoints) external { _auth(SET_EL_REWARDS_WITHDRAWAL_LIMIT_ROLE); _setBPValue(EL_REWARDS_WITHDRAWAL_LIMIT_POSITION, _limitPoints); emit ELRewardsWithdrawalLimitSet(_limitPoints); } /** * @notice Updates beacon stats, collects rewards from LidoExecutionLayerRewardsVault and distributes all rewards if beacon balance increased * @dev periodically called by the Oracle contract * @param _beaconValidators number of Lido's keys in the beacon state * @param _beaconBalance summarized balance of Lido-controlled keys in wei */ function handleOracleReport(uint256 _beaconValidators, uint256 _beaconBalance) external whenNotStopped { require(msg.sender == getOracle(), "APP_AUTH_FAILED"); uint256 depositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256(); require(_beaconValidators <= depositedValidators, "REPORTED_MORE_DEPOSITED"); uint256 beaconValidators = BEACON_VALIDATORS_POSITION.getStorageUint256(); // Since the calculation of funds in the ingress queue is based on the number of validators // that are in a transient state (deposited but not seen on beacon yet), we can't decrease the previously // reported number (we'll be unable to figure out who is in the queue and count them). // See LIP-1 for details https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-1.md require(_beaconValidators >= beaconValidators, "REPORTED_LESS_VALIDATORS"); uint256 appearedValidators = _beaconValidators.sub(beaconValidators); // RewardBase is the amount of money that is not included in the reward calculation // Just appeared validators * 32 added to the previously reported beacon balance uint256 rewardBase = (appearedValidators.mul(DEPOSIT_SIZE)).add(BEACON_BALANCE_POSITION.getStorageUint256()); // Save the current beacon balance and validators to // calculate rewards on the next push BEACON_BALANCE_POSITION.setStorageUint256(_beaconBalance); BEACON_VALIDATORS_POSITION.setStorageUint256(_beaconValidators); // If LidoExecutionLayerRewardsVault address is not set just do as if there were no execution layer rewards at all // Otherwise withdraw all rewards and put them to the buffer // Thus, execution layer rewards are handled the same way as beacon rewards uint256 executionLayerRewards; address executionLayerRewardsVaultAddress = getELRewardsVault(); if (executionLayerRewardsVaultAddress != address(0)) { executionLayerRewards = ILidoExecutionLayerRewardsVault(executionLayerRewardsVaultAddress).withdrawRewards( (_getTotalPooledEther() * EL_REWARDS_WITHDRAWAL_LIMIT_POSITION.getStorageUint256()) / TOTAL_BASIS_POINTS ); if (executionLayerRewards != 0) { BUFFERED_ETHER_POSITION.setStorageUint256(_getBufferedEther().add(executionLayerRewards)); } } // Don’t mint/distribute any protocol fee on the non-profitable Lido oracle report // (when beacon chain balance delta is zero or negative). // See ADR #3 for details: https://research.lido.fi/t/rewards-distribution-after-the-merge-architecture-decision-record/1535 if (_beaconBalance > rewardBase) { uint256 rewards = _beaconBalance.sub(rewardBase); distributeFee(rewards.add(executionLayerRewards)); } } /** * @notice Send funds to recovery Vault. Overrides default AragonApp behaviour * @param _token Token to be sent to recovery vault */ function transferToVault(address _token) external { require(allowRecoverability(_token), "RECOVER_DISALLOWED"); address vault = getRecoveryVault(); require(vault != address(0), "RECOVER_VAULT_ZERO"); uint256 balance; if (_token == ETH) { balance = _getUnaccountedEther(); // Transfer replaced by call to prevent transfer gas amount issue require(vault.call.value(balance)(), "RECOVER_TRANSFER_FAILED"); } else { ERC20 token = ERC20(_token); balance = token.staticBalanceOf(this); // safeTransfer comes from overridden default implementation require(token.safeTransfer(vault, balance), "RECOVER_TOKEN_TRANSFER_FAILED"); } emit RecoverToVault(vault, _token, balance); } /** * @notice Returns staking rewards fee rate */ function getFee() public view returns (uint16 feeBasisPoints) { return uint16(FEE_POSITION.getStorageUint256()); } /** * @notice Returns fee distribution proportion */ function getFeeDistribution() public view returns ( uint16 treasuryFeeBasisPoints, uint16 insuranceFeeBasisPoints, uint16 operatorsFeeBasisPoints ) { treasuryFeeBasisPoints = uint16(TREASURY_FEE_POSITION.getStorageUint256()); insuranceFeeBasisPoints = uint16(INSURANCE_FEE_POSITION.getStorageUint256()); operatorsFeeBasisPoints = uint16(NODE_OPERATORS_FEE_POSITION.getStorageUint256()); } /** * @notice Returns current credentials to withdraw ETH on ETH 2.0 side after the phase 2 is launched */ function getWithdrawalCredentials() public view returns (bytes32) { return WITHDRAWAL_CREDENTIALS_POSITION.getStorageBytes32(); } /** * @notice Get the amount of Ether temporary buffered on this contract balance * @dev Buffered balance is kept on the contract from the moment the funds are received from user * until the moment they are actually sent to the official Deposit contract. * @return amount of buffered funds in wei */ function getBufferedEther() external view returns (uint256) { return _getBufferedEther(); } /** * @notice Get total amount of execution layer rewards collected to Lido contract * @dev Ether got through LidoExecutionLayerRewardsVault is kept on this contract's balance the same way * as other buffered Ether is kept (until it gets deposited) * @return amount of funds received as execution layer rewards (in wei) */ function getTotalELRewardsCollected() external view returns (uint256) { return TOTAL_EL_REWARDS_COLLECTED_POSITION.getStorageUint256(); } /** * @notice Get limit in basis points to amount of ETH to withdraw per LidoOracle report * @return limit in basis points to amount of ETH to withdraw per LidoOracle report */ function getELRewardsWithdrawalLimit() external view returns (uint256) { return EL_REWARDS_WITHDRAWAL_LIMIT_POSITION.getStorageUint256(); } /** * @notice Gets deposit contract handle */ function getDepositContract() public view returns (IDepositContract) { return IDepositContract(DEPOSIT_CONTRACT_POSITION.getStorageAddress()); } /** * @notice Gets authorized oracle address * @return address of oracle contract */ function getOracle() public view returns (address) { return ORACLE_POSITION.getStorageAddress(); } /** * @notice Gets node operators registry interface handle */ function getOperators() public view returns (INodeOperatorsRegistry) { return INodeOperatorsRegistry(NODE_OPERATORS_REGISTRY_POSITION.getStorageAddress()); } /** * @notice Returns the treasury address */ function getTreasury() public view returns (address) { return TREASURY_POSITION.getStorageAddress(); } /** * @notice Returns the insurance fund address */ function getInsuranceFund() public view returns (address) { return INSURANCE_FUND_POSITION.getStorageAddress(); } /** * @notice Returns the key values related to Beacon-side * @return depositedValidators - number of deposited validators * @return beaconValidators - number of Lido's validators visible in the Beacon state, reported by oracles * @return beaconBalance - total amount of Beacon-side Ether (sum of all the balances of Lido validators) */ function getBeaconStat() public view returns (uint256 depositedValidators, uint256 beaconValidators, uint256 beaconBalance) { depositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256(); beaconValidators = BEACON_VALIDATORS_POSITION.getStorageUint256(); beaconBalance = BEACON_BALANCE_POSITION.getStorageUint256(); } /** * @notice Returns address of the contract set as LidoExecutionLayerRewardsVault */ function getELRewardsVault() public view returns (address) { return EL_REWARDS_VAULT_POSITION.getStorageAddress(); } /** * @dev Internal function to set authorized oracle address * @param _oracle oracle contract */ function _setProtocolContracts(address _oracle, address _treasury, address _insuranceFund) internal { require(_oracle != address(0), "ORACLE_ZERO_ADDRESS"); require(_treasury != address(0), "TREASURY_ZERO_ADDRESS"); require(_insuranceFund != address(0), "INSURANCE_FUND_ZERO_ADDRESS"); ORACLE_POSITION.setStorageAddress(_oracle); TREASURY_POSITION.setStorageAddress(_treasury); INSURANCE_FUND_POSITION.setStorageAddress(_insuranceFund); emit ProtocolContactsSet(_oracle, _treasury, _insuranceFund); } /** * @dev Process user deposit, mints liquid tokens and increase the pool buffer * @param _referral address of referral. * @return amount of StETH shares generated */ function _submit(address _referral) internal returns (uint256) { require(msg.value != 0, "ZERO_DEPOSIT"); StakeLimitState.Data memory stakeLimitData = STAKING_STATE_POSITION.getStorageStakeLimitStruct(); require(!stakeLimitData.isStakingPaused(), "STAKING_PAUSED"); if (stakeLimitData.isStakingLimitSet()) { uint256 currentStakeLimit = stakeLimitData.calculateCurrentStakeLimit(); require(msg.value <= currentStakeLimit, "STAKE_LIMIT"); STAKING_STATE_POSITION.setStorageStakeLimitStruct( stakeLimitData.updatePrevStakeLimit(currentStakeLimit - msg.value) ); } uint256 sharesAmount = getSharesByPooledEth(msg.value); if (sharesAmount == 0) { // totalControlledEther is 0: either the first-ever deposit or complete slashing // assume that shares correspond to Ether 1-to-1 sharesAmount = msg.value; } _mintShares(msg.sender, sharesAmount); BUFFERED_ETHER_POSITION.setStorageUint256(_getBufferedEther().add(msg.value)); emit Submitted(msg.sender, msg.value, _referral); _emitTransferAfterMintingShares(msg.sender, sharesAmount); return sharesAmount; } /** * @dev Emits {Transfer} and {TransferShares} events where `from` is 0 address. Indicates mint events. */ function _emitTransferAfterMintingShares(address _to, uint256 _sharesAmount) internal { emit Transfer(address(0), _to, getPooledEthByShares(_sharesAmount)); emit TransferShares(address(0), _to, _sharesAmount); } /** * @dev Deposits buffered eth to the DepositContract and assigns chunked deposits to node operators */ function _depositBufferedEther(uint256 _maxDeposits) internal whenNotStopped { uint256 buffered = _getBufferedEther(); if (buffered >= DEPOSIT_SIZE) { uint256 unaccounted = _getUnaccountedEther(); uint256 numDeposits = buffered.div(DEPOSIT_SIZE); _markAsUnbuffered(_ETH2Deposit(numDeposits < _maxDeposits ? numDeposits : _maxDeposits)); assert(_getUnaccountedEther() == unaccounted); } } /** * @dev Performs deposits to the ETH 2.0 side * @param _numDeposits Number of deposits to perform * @return actually deposited Ether amount */ function _ETH2Deposit(uint256 _numDeposits) internal returns (uint256) { (bytes memory pubkeys, bytes memory signatures) = getOperators().assignNextSigningKeys(_numDeposits); if (pubkeys.length == 0) { return 0; } require(pubkeys.length.mod(PUBKEY_LENGTH) == 0, "REGISTRY_INCONSISTENT_PUBKEYS_LEN"); require(signatures.length.mod(SIGNATURE_LENGTH) == 0, "REGISTRY_INCONSISTENT_SIG_LEN"); uint256 numKeys = pubkeys.length.div(PUBKEY_LENGTH); require(numKeys == signatures.length.div(SIGNATURE_LENGTH), "REGISTRY_INCONSISTENT_SIG_COUNT"); for (uint256 i = 0; i < numKeys; ++i) { bytes memory pubkey = BytesLib.slice(pubkeys, i * PUBKEY_LENGTH, PUBKEY_LENGTH); bytes memory signature = BytesLib.slice(signatures, i * SIGNATURE_LENGTH, SIGNATURE_LENGTH); _stake(pubkey, signature); } DEPOSITED_VALIDATORS_POSITION.setStorageUint256( DEPOSITED_VALIDATORS_POSITION.getStorageUint256().add(numKeys) ); return numKeys.mul(DEPOSIT_SIZE); } /** * @dev Invokes a deposit call to the official Deposit contract * @param _pubkey Validator to stake for * @param _signature Signature of the deposit call */ function _stake(bytes memory _pubkey, bytes memory _signature) internal { bytes32 withdrawalCredentials = getWithdrawalCredentials(); require(withdrawalCredentials != 0, "EMPTY_WITHDRAWAL_CREDENTIALS"); uint256 value = DEPOSIT_SIZE; // The following computations and Merkle tree-ization will make official Deposit contract happy uint256 depositAmount = value.div(DEPOSIT_AMOUNT_UNIT); assert(depositAmount.mul(DEPOSIT_AMOUNT_UNIT) == value); // properly rounded // Compute deposit data root (`DepositData` hash tree root) according to deposit_contract.sol bytes32 pubkeyRoot = sha256(_pad64(_pubkey)); bytes32 signatureRoot = sha256( abi.encodePacked( sha256(BytesLib.slice(_signature, 0, 64)), sha256(_pad64(BytesLib.slice(_signature, 64, SIGNATURE_LENGTH.sub(64)))) ) ); bytes32 depositDataRoot = sha256( abi.encodePacked( sha256(abi.encodePacked(pubkeyRoot, withdrawalCredentials)), sha256(abi.encodePacked(_toLittleEndian64(depositAmount), signatureRoot)) ) ); uint256 targetBalance = address(this).balance.sub(value); getDepositContract().deposit.value(value)( _pubkey, abi.encodePacked(withdrawalCredentials), _signature, depositDataRoot); require(address(this).balance == targetBalance, "EXPECTING_DEPOSIT_TO_HAPPEN"); } /** * @dev Distributes fee portion of the rewards by minting and distributing corresponding amount of liquid tokens. * @param _totalRewards Total rewards accrued on the Ethereum 2.0 side in wei */ function distributeFee(uint256 _totalRewards) internal { // We need to take a defined percentage of the reported reward as a fee, and we do // this by minting new token shares and assigning them to the fee recipients (see // StETH docs for the explanation of the shares mechanics). The staking rewards fee // is defined in basis points (1 basis point is equal to 0.01%, 10000 (TOTAL_BASIS_POINTS) is 100%). // // Since we've increased totalPooledEther by _totalRewards (which is already // performed by the time this function is called), the combined cost of all holders' // shares has became _totalRewards StETH tokens more, effectively splitting the reward // between each token holder proportionally to their token share. // // Now we want to mint new shares to the fee recipient, so that the total cost of the // newly-minted shares exactly corresponds to the fee taken: // // shares2mint * newShareCost = (_totalRewards * feeBasis) / TOTAL_BASIS_POINTS // newShareCost = newTotalPooledEther / (prevTotalShares + shares2mint) // // which follows to: // // _totalRewards * feeBasis * prevTotalShares // shares2mint = -------------------------------------------------------------- // (newTotalPooledEther * TOTAL_BASIS_POINTS) - (feeBasis * _totalRewards) // // The effect is that the given percentage of the reward goes to the fee recipient, and // the rest of the reward is distributed between token holders proportionally to their // token shares. uint256 feeBasis = getFee(); uint256 shares2mint = ( _totalRewards.mul(feeBasis).mul(_getTotalShares()) .div( _getTotalPooledEther().mul(TOTAL_BASIS_POINTS) .sub(feeBasis.mul(_totalRewards)) ) ); // Mint the calculated amount of shares to this contract address. This will reduce the // balances of the holders, as if the fee was taken in parts from each of them. _mintShares(address(this), shares2mint); (,uint16 insuranceFeeBasisPoints, uint16 operatorsFeeBasisPoints) = getFeeDistribution(); uint256 toInsuranceFund = shares2mint.mul(insuranceFeeBasisPoints).div(TOTAL_BASIS_POINTS); address insuranceFund = getInsuranceFund(); _transferShares(address(this), insuranceFund, toInsuranceFund); _emitTransferAfterMintingShares(insuranceFund, toInsuranceFund); uint256 distributedToOperatorsShares = _distributeNodeOperatorsReward( shares2mint.mul(operatorsFeeBasisPoints).div(TOTAL_BASIS_POINTS) ); // Transfer the rest of the fee to treasury uint256 toTreasury = shares2mint.sub(toInsuranceFund).sub(distributedToOperatorsShares); address treasury = getTreasury(); _transferShares(address(this), treasury, toTreasury); _emitTransferAfterMintingShares(treasury, toTreasury); } /** * @dev Internal function to distribute reward to node operators * @param _sharesToDistribute amount of shares to distribute * @return actual amount of shares that was transferred to node operators as a reward */ function _distributeNodeOperatorsReward(uint256 _sharesToDistribute) internal returns (uint256 distributed) { (address[] memory recipients, uint256[] memory shares) = getOperators().getRewardsDistribution(_sharesToDistribute); assert(recipients.length == shares.length); distributed = 0; for (uint256 idx = 0; idx < recipients.length; ++idx) { _transferShares( address(this), recipients[idx], shares[idx] ); _emitTransferAfterMintingShares(recipients[idx], shares[idx]); distributed = distributed.add(shares[idx]); } } /** * @dev Records a deposit to the deposit_contract.deposit function * @param _amount Total amount deposited to the ETH 2.0 side */ function _markAsUnbuffered(uint256 _amount) internal { BUFFERED_ETHER_POSITION.setStorageUint256( BUFFERED_ETHER_POSITION.getStorageUint256().sub(_amount)); emit Unbuffered(_amount); } /** * @dev Write a value nominated in basis points */ function _setBPValue(bytes32 _slot, uint16 _value) internal { require(_value <= TOTAL_BASIS_POINTS, "VALUE_OVER_100_PERCENT"); _slot.setStorageUint256(uint256(_value)); } /** * @dev Gets the amount of Ether temporary buffered on this contract balance */ function _getBufferedEther() internal view returns (uint256) { uint256 buffered = BUFFERED_ETHER_POSITION.getStorageUint256(); assert(address(this).balance >= buffered); return buffered; } /** * @dev Gets unaccounted (excess) Ether on this contract balance */ function _getUnaccountedEther() internal view returns (uint256) { return address(this).balance.sub(_getBufferedEther()); } /** * @dev Calculates and returns the total base balance (multiple of 32) of validators in transient state, * i.e. submitted to the official Deposit contract but not yet visible in the beacon state. * @return transient balance in wei (1e-18 Ether) */ function _getTransientBalance() internal view returns (uint256) { uint256 depositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256(); uint256 beaconValidators = BEACON_VALIDATORS_POSITION.getStorageUint256(); // beaconValidators can never be less than deposited ones. assert(depositedValidators >= beaconValidators); return depositedValidators.sub(beaconValidators).mul(DEPOSIT_SIZE); } /** * @dev Gets the total amount of Ether controlled by the system * @return total balance in wei */ function _getTotalPooledEther() internal view returns (uint256) { return _getBufferedEther().add( BEACON_BALANCE_POSITION.getStorageUint256() ).add(_getTransientBalance()); } /** * @dev Padding memory array with zeroes up to 64 bytes on the right * @param _b Memory array of size 32 .. 64 */ function _pad64(bytes memory _b) internal pure returns (bytes memory) { assert(_b.length >= 32 && _b.length <= 64); if (64 == _b.length) return _b; bytes memory zero32 = new bytes(32); assembly { mstore(add(zero32, 0x20), 0) } if (32 == _b.length) return BytesLib.concat(_b, zero32); else return BytesLib.concat(_b, BytesLib.slice(zero32, 0, uint256(64).sub(_b.length))); } /** * @dev Converting value to little endian bytes and padding up to 32 bytes on the right * @param _value Number less than `2**64` for compatibility reasons */ function _toLittleEndian64(uint256 _value) internal pure returns (uint256 result) { result = 0; uint256 temp_value = _value; for (uint256 i = 0; i < 8; ++i) { result = (result << 8) | (temp_value & 0xFF); temp_value >>= 8; } assert(0 == temp_value); // fully converted result <<= (24 * 8); } function _pauseStaking() internal { STAKING_STATE_POSITION.setStorageStakeLimitStruct( STAKING_STATE_POSITION.getStorageStakeLimitStruct().setStakeLimitPauseState(true) ); emit StakingPaused(); } function _resumeStaking() internal { STAKING_STATE_POSITION.setStorageStakeLimitStruct( STAKING_STATE_POSITION.getStorageStakeLimitStruct().setStakeLimitPauseState(false) ); emit StakingResumed(); } function _getCurrentStakeLimit(StakeLimitState.Data memory _stakeLimitData) internal view returns(uint256) { if (_stakeLimitData.isStakingPaused()) { return 0; } if (!_stakeLimitData.isStakingLimitSet()) { return uint256(-1); } return _stakeLimitData.calculateCurrentStakeLimit(); } /** * @dev Size-efficient analog of the `auth(_role)` modifier * @param _role Permission name */ function _auth(bytes32 _role) internal view auth(_role) { // no-op } }
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./AppStorage.sol";
import "../acl/ACLSyntaxSugar.sol";
import "../common/Autopetrified.sol";
import "../common/ConversionHelpers.sol";
import "../common/ReentrancyGuard.sol";
import "../common/VaultRecoverable.sol";
import "../evmscript/EVMScriptRunner.sol";
// Contracts inheriting from AragonApp are, by default, immediately petrified upon deployment so
// that they can never be initialized.
// Unless overriden, this behaviour enforces those contracts to be usable only behind an AppProxy.
// ReentrancyGuard, EVMScriptRunner, and ACLSyntaxSugar are not directly used by this contract, but
// are included so that they are automatically usable by subclassing contracts
contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGuard, EVMScriptRunner, ACLSyntaxSugar {
string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED";
modifier auth(bytes32 _role) {
require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED);
_;
}
modifier authP(bytes32 _role, uint256[] _params) {
require(canPerform(msg.sender, _role, _params), ERROR_AUTH_FAILED);
_;
}
/**
* @dev Check whether an action can be performed by a sender for a particular role on this app
* @param _sender Sender of the call
* @param _role Role on this app
* @param _params Permission params for the role
* @return Boolean indicating whether the sender has the permissions to perform the action.
* Always returns false if the app hasn't been initialized yet.
*/
function canPerform(address _sender, bytes32 _role, uint256[] _params) public view returns (bool) {
if (!hasInitialized()) {
return false;
}
IKernel linkedKernel = kernel();
if (address(linkedKernel) == address(0)) {
return false;
}
return linkedKernel.hasPermission(
_sender,
address(this),
_role,
ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)
);
}
/**
* @dev Get the recovery vault for the app
* @return Recovery vault address for the app
*/
function getRecoveryVault() public view returns (address) {
// Funds recovery via a vault is only available when used with a kernel
return kernel().getRecoveryVault(); // if kernel is not set, it will revert
}
}// See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
// Adapted to use pragma ^0.4.24 and satisfy our linter rules
pragma solidity ^0.4.24;
/**
* @title SafeMath
* @dev Math operations with safety checks that revert on error
*/
library SafeMath {
string private constant ERROR_ADD_OVERFLOW = "MATH_ADD_OVERFLOW";
string private constant ERROR_SUB_UNDERFLOW = "MATH_SUB_UNDERFLOW";
string private constant ERROR_MUL_OVERFLOW = "MATH_MUL_OVERFLOW";
string private constant ERROR_DIV_ZERO = "MATH_DIV_ZERO";
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {
// 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-solidity/pull/522
if (_a == 0) {
return 0;
}
uint256 c = _a * _b;
require(c / _a == _b, ERROR_MUL_OVERFLOW);
return c;
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
require(_b <= _a, ERROR_SUB_UNDERFLOW);
uint256 c = _a - _b;
return c;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
uint256 c = _a + _b;
require(c >= _a, ERROR_ADD_OVERFLOW);
return c;
}
/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, ERROR_DIV_ZERO);
return a % b;
}
}// See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/d51e38758e1d985661534534d5c61e27bece5042/contracts/math/SafeMath.sol
// Adapted for uint64, pragma ^0.4.24, and satisfying our linter rules
// Also optimized the mul() implementation, see https://github.com/aragon/aragonOS/pull/417
pragma solidity ^0.4.24;
/**
* @title SafeMath64
* @dev Math operations for uint64 with safety checks that revert on error
*/
library SafeMath64 {
string private constant ERROR_ADD_OVERFLOW = "MATH64_ADD_OVERFLOW";
string private constant ERROR_SUB_UNDERFLOW = "MATH64_SUB_UNDERFLOW";
string private constant ERROR_MUL_OVERFLOW = "MATH64_MUL_OVERFLOW";
string private constant ERROR_DIV_ZERO = "MATH64_DIV_ZERO";
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint64 _a, uint64 _b) internal pure returns (uint64) {
uint256 c = uint256(_a) * uint256(_b);
require(c < 0x010000000000000000, ERROR_MUL_OVERFLOW); // 2**64 (less gas this way)
return uint64(c);
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint64 _a, uint64 _b) internal pure returns (uint64) {
require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
uint64 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint64 _a, uint64 _b) internal pure returns (uint64) {
require(_b <= _a, ERROR_SUB_UNDERFLOW);
uint64 c = _a - _b;
return c;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint64 _a, uint64 _b) internal pure returns (uint64) {
uint64 c = _a + _b;
require(c >= _a, ERROR_ADD_OVERFLOW);
return c;
}
/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint64 a, uint64 b) internal pure returns (uint64) {
require(b != 0, ERROR_DIV_ZERO);
return a % b;
}
}/* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity ^0.4.19; library BytesLib { function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes_slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes_slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes_slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes_slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes_slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes_slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice(bytes _bytes, uint _start, uint _length) internal pure returns (bytes) { require(_bytes.length >= (_start + _length)); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes _bytes, uint _start) internal pure returns (address) { require(_bytes.length >= (_start + 20)); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes _bytes, uint _start) internal pure returns (uint8) { require(_bytes.length >= (_start + 1)); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes _bytes, uint _start) internal pure returns (uint16) { require(_bytes.length >= (_start + 2)); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes _bytes, uint _start) internal pure returns (uint32) { require(_bytes.length >= (_start + 4)); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint(bytes _bytes, uint _start) internal pure returns (uint256) { require(_bytes.length >= (_start + 32)); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes _bytes, uint _start) internal pure returns (bytes32) { require(_bytes.length >= (_start + 32)); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes_slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes_slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-FileCopyrightText: 2020 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.24; /** * @title Liquid staking pool * * For the high-level description of the pool operation please refer to the paper. * Pool manages withdrawal keys and fees. It receives ether submitted by users on the ETH 1 side * and stakes it via the deposit_contract.sol contract. It doesn't hold ether on it's balance, * only a small portion (buffer) of it. * It also mints new tokens for rewards generated at the ETH 2.0 side. * * At the moment withdrawals are not possible in the beacon chain and there's no workaround. * Pool will be upgraded to an actual implementation when withdrawals are enabled * (Phase 1.5 or 2 of Eth2 launch, likely late 2022 or 2023). */ interface ILido { function totalSupply() external view returns (uint256); function getTotalShares() external view returns (uint256); /** * @notice Stop pool routine operations */ function stop() external; /** * @notice Resume pool routine operations */ function resume() external; /** * @notice Stops accepting new Ether to the protocol * * @dev While accepting new Ether is stopped, calls to the `submit` function, * as well as to the default payable function, will revert. * * Emits `StakingPaused` event. */ function pauseStaking() external; /** * @notice Resumes accepting new Ether to the protocol (if `pauseStaking` was called previously) * NB: Staking could be rate-limited by imposing a limit on the stake amount * at each moment in time, see `setStakingLimit()` and `removeStakingLimit()` * * @dev Preserves staking limit if it was set previously * * Emits `StakingResumed` event */ function resumeStaking() external; /** * @notice Sets the staking rate limit * * @dev Reverts if: * - `_maxStakeLimit` == 0 * - `_maxStakeLimit` >= 2^96 * - `_maxStakeLimit` < `_stakeLimitIncreasePerBlock` * - `_maxStakeLimit` / `_stakeLimitIncreasePerBlock` >= 2^32 (only if `_stakeLimitIncreasePerBlock` != 0) * * Emits `StakingLimitSet` event * * @param _maxStakeLimit max stake limit value * @param _stakeLimitIncreasePerBlock stake limit increase per single block */ function setStakingLimit(uint256 _maxStakeLimit, uint256 _stakeLimitIncreasePerBlock) external; /** * @notice Removes the staking rate limit * * Emits `StakingLimitRemoved` event */ function removeStakingLimit() external; /** * @notice Check staking state: whether it's paused or not */ function isStakingPaused() external view returns (bool); /** * @notice Returns how much Ether can be staked in the current block * @dev Special return values: * - 2^256 - 1 if staking is unlimited; * - 0 if staking is paused or if limit is exhausted. */ function getCurrentStakeLimit() external view returns (uint256); /** * @notice Returns full info about current stake limit params and state * @dev Might be used for the advanced integration requests. * @return isStakingPaused staking pause state (equivalent to return of isStakingPaused()) * @return isStakingLimitSet whether the stake limit is set * @return currentStakeLimit current stake limit (equivalent to return of getCurrentStakeLimit()) * @return maxStakeLimit max stake limit * @return maxStakeLimitGrowthBlocks blocks needed to restore max stake limit from the fully exhausted state * @return prevStakeLimit previously reached stake limit * @return prevStakeBlockNumber previously seen block number */ function getStakeLimitFullInfo() external view returns ( bool isStakingPaused, bool isStakingLimitSet, uint256 currentStakeLimit, uint256 maxStakeLimit, uint256 maxStakeLimitGrowthBlocks, uint256 prevStakeLimit, uint256 prevStakeBlockNumber ); event Stopped(); event Resumed(); event StakingPaused(); event StakingResumed(); event StakingLimitSet(uint256 maxStakeLimit, uint256 stakeLimitIncreasePerBlock); event StakingLimitRemoved(); /** * @notice Set Lido protocol contracts (oracle, treasury, insurance fund). * @param _oracle oracle contract * @param _treasury treasury contract * @param _insuranceFund insurance fund contract */ function setProtocolContracts( address _oracle, address _treasury, address _insuranceFund ) external; event ProtocolContactsSet(address oracle, address treasury, address insuranceFund); /** * @notice Set fee rate to `_feeBasisPoints` basis points. * The fees are accrued when: * - oracles report staking results (beacon chain balance increase) * - validators gain execution layer rewards (priority fees and MEV) * @param _feeBasisPoints Fee rate, in basis points */ function setFee(uint16 _feeBasisPoints) external; /** * @notice Set fee distribution * @param _treasuryFeeBasisPoints basis points go to the treasury, * @param _insuranceFeeBasisPoints basis points go to the insurance fund, * @param _operatorsFeeBasisPoints basis points go to node operators. * @dev The sum has to be 10 000. */ function setFeeDistribution( uint16 _treasuryFeeBasisPoints, uint16 _insuranceFeeBasisPoints, uint16 _operatorsFeeBasisPoints ) external; /** * @notice Returns staking rewards fee rate */ function getFee() external view returns (uint16 feeBasisPoints); /** * @notice Returns fee distribution proportion */ function getFeeDistribution() external view returns ( uint16 treasuryFeeBasisPoints, uint16 insuranceFeeBasisPoints, uint16 operatorsFeeBasisPoints ); event FeeSet(uint16 feeBasisPoints); event FeeDistributionSet(uint16 treasuryFeeBasisPoints, uint16 insuranceFeeBasisPoints, uint16 operatorsFeeBasisPoints); /** * @notice A payable function supposed to be called only by LidoExecutionLayerRewardsVault contract * @dev We need a dedicated function because funds received by the default payable function * are treated as a user deposit */ function receiveELRewards() external payable; // The amount of ETH withdrawn from LidoExecutionLayerRewardsVault contract to Lido contract event ELRewardsReceived(uint256 amount); /** * @dev Sets limit on amount of ETH to withdraw from execution layer rewards vault per LidoOracle report * @param _limitPoints limit in basis points to amount of ETH to withdraw per LidoOracle report */ function setELRewardsWithdrawalLimit(uint16 _limitPoints) external; // Percent in basis points of total pooled ether allowed to withdraw from LidoExecutionLayerRewardsVault per LidoOracle report event ELRewardsWithdrawalLimitSet(uint256 limitPoints); /** * @notice Set credentials to withdraw ETH on ETH 2.0 side after the phase 2 is launched to `_withdrawalCredentials` * @dev Note that setWithdrawalCredentials discards all unused signing keys as the signatures are invalidated. * @param _withdrawalCredentials withdrawal credentials field as defined in the Ethereum PoS consensus specs */ function setWithdrawalCredentials(bytes32 _withdrawalCredentials) external; /** * @notice Returns current credentials to withdraw ETH on ETH 2.0 side after the phase 2 is launched */ function getWithdrawalCredentials() external view returns (bytes); event WithdrawalCredentialsSet(bytes32 withdrawalCredentials); /** * @dev Sets the address of LidoExecutionLayerRewardsVault contract * @param _executionLayerRewardsVault Execution layer rewards vault contract address */ function setELRewardsVault(address _executionLayerRewardsVault) external; // The `executionLayerRewardsVault` was set as the execution layer rewards vault for Lido event ELRewardsVaultSet(address executionLayerRewardsVault); /** * @notice Ether on the ETH 2.0 side reported by the oracle * @param _epoch Epoch id * @param _eth2balance Balance in wei on the ETH 2.0 side */ function handleOracleReport(uint256 _epoch, uint256 _eth2balance) external; // User functions /** * @notice Adds eth to the pool * @return StETH Amount of StETH generated */ function submit(address _referral) external payable returns (uint256 StETH); // Records a deposit made by a user event Submitted(address indexed sender, uint256 amount, address referral); // The `amount` of ether was sent to the deposit_contract.deposit function event Unbuffered(uint256 amount); // Requested withdrawal of `etherAmount` to `pubkeyHash` on the ETH 2.0 side, `tokenAmount` burned by `sender`, // `sentFromBuffer` was sent on the current Ethereum side. event Withdrawal(address indexed sender, uint256 tokenAmount, uint256 sentFromBuffer, bytes32 indexed pubkeyHash, uint256 etherAmount); // Info functions /** * @notice Gets the amount of Ether controlled by the system */ function getTotalPooledEther() external view returns (uint256); /** * @notice Gets the amount of Ether temporary buffered on this contract balance */ function getBufferedEther() external view returns (uint256); /** * @notice Returns the key values related to Beacon-side * @return depositedValidators - number of deposited validators * @return beaconValidators - number of Lido's validators visible in the Beacon state, reported by oracles * @return beaconBalance - total amount of Beacon-side Ether (sum of all the balances of Lido validators) */ function getBeaconStat() external view returns (uint256 depositedValidators, uint256 beaconValidators, uint256 beaconBalance); }
// SPDX-FileCopyrightText: 2020 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.24; /** * @title Node Operator registry * * Node Operator registry manages signing keys and other node operator data. * It's also responsible for distributing rewards to node operators. */ interface INodeOperatorsRegistry { /** * @notice Add node operator named `name` with reward address `rewardAddress` and staking limit = 0 validators * @param _name Human-readable name * @param _rewardAddress Ethereum 1 address which receives stETH rewards for this operator * @return a unique key of the added operator */ function addNodeOperator(string _name, address _rewardAddress) external returns (uint256 id); /** * @notice `_active ? 'Enable' : 'Disable'` the node operator #`_id` */ function setNodeOperatorActive(uint256 _id, bool _active) external; /** * @notice Change human-readable name of the node operator #`_id` to `_name` */ function setNodeOperatorName(uint256 _id, string _name) external; /** * @notice Change reward address of the node operator #`_id` to `_rewardAddress` */ function setNodeOperatorRewardAddress(uint256 _id, address _rewardAddress) external; /** * @notice Set the maximum number of validators to stake for the node operator #`_id` to `_stakingLimit` */ function setNodeOperatorStakingLimit(uint256 _id, uint64 _stakingLimit) external; /** * @notice Report `_stoppedIncrement` more stopped validators of the node operator #`_id` */ function reportStoppedValidators(uint256 _id, uint64 _stoppedIncrement) external; /** * @notice Remove unused signing keys * @dev Function is used by the pool */ function trimUnusedKeys() external; /** * @notice Returns total number of node operators */ function getNodeOperatorsCount() external view returns (uint256); /** * @notice Returns number of active node operators */ function getActiveNodeOperatorsCount() external view returns (uint256); /** * @notice Returns the n-th node operator * @param _id Node Operator id * @param _fullInfo If true, name will be returned as well */ function getNodeOperator(uint256 _id, bool _fullInfo) external view returns ( bool active, string name, address rewardAddress, uint64 stakingLimit, uint64 stoppedValidators, uint64 totalSigningKeys, uint64 usedSigningKeys); /** * @notice Returns the rewards distribution proportional to the effective stake for each node operator. * @param _totalRewardShares Total amount of reward shares to distribute. */ function getRewardsDistribution(uint256 _totalRewardShares) external view returns ( address[] memory recipients, uint256[] memory shares ); event NodeOperatorAdded(uint256 id, string name, address rewardAddress, uint64 stakingLimit); event NodeOperatorActiveSet(uint256 indexed id, bool active); event NodeOperatorNameSet(uint256 indexed id, string name); event NodeOperatorRewardAddressSet(uint256 indexed id, address rewardAddress); event NodeOperatorStakingLimitSet(uint256 indexed id, uint64 stakingLimit); event NodeOperatorTotalStoppedValidatorsReported(uint256 indexed id, uint64 totalStopped); event NodeOperatorTotalKeysTrimmed(uint256 indexed id, uint64 totalKeysTrimmed); /** * @notice Selects and returns at most `_numKeys` signing keys (as well as the corresponding * signatures) from the set of active keys and marks the selected keys as used. * May only be called by the pool contract. * * @param _numKeys The number of keys to select. The actual number of selected keys may be less * due to the lack of active keys. */ function assignNextSigningKeys(uint256 _numKeys) external returns (bytes memory pubkeys, bytes memory signatures); /** * @notice Add `_quantity` validator signing keys to the keys of the node operator #`_operator_id`. Concatenated keys are: `_pubkeys` * @dev Along with each key the DAO has to provide a signatures for the * (pubkey, withdrawal_credentials, 32000000000) message. * Given that information, the contract'll be able to call * deposit_contract.deposit on-chain. * @param _operator_id Node Operator id * @param _quantity Number of signing keys provided * @param _pubkeys Several concatenated validator signing keys * @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages */ function addSigningKeys(uint256 _operator_id, uint256 _quantity, bytes _pubkeys, bytes _signatures) external; /** * @notice Add `_quantity` validator signing keys of operator #`_id` to the set of usable keys. Concatenated keys are: `_pubkeys`. Can be done by node operator in question by using the designated rewards address. * @dev Along with each key the DAO has to provide a signatures for the * (pubkey, withdrawal_credentials, 32000000000) message. * Given that information, the contract'll be able to call * deposit_contract.deposit on-chain. * @param _operator_id Node Operator id * @param _quantity Number of signing keys provided * @param _pubkeys Several concatenated validator signing keys * @param _signatures Several concatenated signatures for (pubkey, withdrawal_credentials, 32000000000) messages */ function addSigningKeysOperatorBH(uint256 _operator_id, uint256 _quantity, bytes _pubkeys, bytes _signatures) external; /** * @notice Removes a validator signing key #`_index` from the keys of the node operator #`_operator_id` * @param _operator_id Node Operator id * @param _index Index of the key, starting with 0 */ function removeSigningKey(uint256 _operator_id, uint256 _index) external; /** * @notice Removes a validator signing key #`_index` of operator #`_id` from the set of usable keys. Executed on behalf of Node Operator. * @param _operator_id Node Operator id * @param _index Index of the key, starting with 0 */ function removeSigningKeyOperatorBH(uint256 _operator_id, uint256 _index) external; /** * @notice Removes an #`_amount` of validator signing keys starting from #`_index` of operator #`_id` usable keys. Executed on behalf of DAO. * @param _operator_id Node Operator id * @param _index Index of the key, starting with 0 * @param _amount Number of keys to remove */ function removeSigningKeys(uint256 _operator_id, uint256 _index, uint256 _amount) external; /** * @notice Removes an #`_amount` of validator signing keys starting from #`_index` of operator #`_id` usable keys. Executed on behalf of Node Operator. * @param _operator_id Node Operator id * @param _index Index of the key, starting with 0 * @param _amount Number of keys to remove */ function removeSigningKeysOperatorBH(uint256 _operator_id, uint256 _index, uint256 _amount) external; /** * @notice Returns total number of signing keys of the node operator #`_operator_id` */ function getTotalSigningKeyCount(uint256 _operator_id) external view returns (uint256); /** * @notice Returns number of usable signing keys of the node operator #`_operator_id` */ function getUnusedSigningKeyCount(uint256 _operator_id) external view returns (uint256); /** * @notice Returns n-th signing key of the node operator #`_operator_id` * @param _operator_id Node Operator id * @param _index Index of the key, starting with 0 * @return key Key * @return depositSignature Signature needed for a deposit_contract.deposit call * @return used Flag indication if the key was used in the staking */ function getSigningKey(uint256 _operator_id, uint256 _index) external view returns (bytes key, bytes depositSignature, bool used); /** * @notice Returns a monotonically increasing counter that gets incremented when any of the following happens: * 1. a node operator's key(s) is added; * 2. a node operator's key(s) is removed; * 3. a node operator's approved keys limit is changed. * 4. a node operator was activated/deactivated. Activation or deactivation of node operator * might lead to usage of unvalidated keys in the assignNextSigningKeys method. */ function getKeysOpIndex() external view returns (uint256); event SigningKeyAdded(uint256 indexed operatorId, bytes pubkey); event SigningKeyRemoved(uint256 indexed operatorId, bytes pubkey); event KeysOpIndexSet(uint256 keysOpIndex); }
// SPDX-FileCopyrightText: 2020 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.24; /** * @title Deposit contract interface */ interface IDepositContract { /** * @notice Top-ups deposit of a validator on the ETH 2.0 side * @param pubkey Validator signing key * @param withdrawal_credentials Credentials that allows to withdraw funds * @param signature Signature of the request * @param deposit_data_root The deposits Merkle tree node, used as a checksum */ function deposit( bytes /* 48 */ pubkey, bytes /* 32 */ withdrawal_credentials, bytes /* 96 */ signature, bytes32 deposit_data_root ) external payable; }
// SPDX-FileCopyrightText: 2021 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.24; interface ILidoExecutionLayerRewardsVault { /** * @notice Withdraw all accumulated execution layer rewards to Lido contract * @param _maxAmount Max amount of ETH to withdraw * @return amount of funds received as execution layer rewards (in wei) */ function withdrawRewards(uint256 _maxAmount) external returns (uint256 amount); }
// SPDX-FileCopyrightText: 2020 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ pragma solidity 0.4.24; import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; import "@aragon/os/contracts/common/UnstructuredStorage.sol"; import "@aragon/os/contracts/lib/math/SafeMath.sol"; import "./lib/Pausable.sol"; /** * @title Interest-bearing ERC20-like token for Lido Liquid Stacking protocol. * * This contract is abstract. To make the contract deployable override the * `_getTotalPooledEther` function. `Lido.sol` contract inherits StETH and defines * the `_getTotalPooledEther` function. * * StETH balances are dynamic and represent the holder's share in the total amount * of Ether controlled by the protocol. Account shares aren't normalized, so the * contract also stores the sum of all shares to calculate each account's token balance * which equals to: * * shares[account] * _getTotalPooledEther() / _getTotalShares() * * For example, assume that we have: * * _getTotalPooledEther() -> 10 ETH * sharesOf(user1) -> 100 * sharesOf(user2) -> 400 * * Therefore: * * balanceOf(user1) -> 2 tokens which corresponds 2 ETH * balanceOf(user2) -> 8 tokens which corresponds 8 ETH * * Since balances of all token holders change when the amount of total pooled Ether * changes, this token cannot fully implement ERC20 standard: it only emits `Transfer` * events upon explicit transfer between holders. In contrast, when total amount of * pooled Ether increases, no `Transfer` events are generated: doing so would require * emitting an event for each token holder and thus running an unbounded loop. * * The token inherits from `Pausable` and uses `whenNotStopped` modifier for methods * which change `shares` or `allowances`. `_stop` and `_resume` functions are overridden * in `Lido.sol` and might be called by an account with the `PAUSE_ROLE` assigned by the * DAO. This is useful for emergency scenarios, e.g. a protocol bug, where one might want * to freeze all token transfers and approvals until the emergency is resolved. */ contract StETH is IERC20, Pausable { using SafeMath for uint256; using UnstructuredStorage for bytes32; /** * @dev StETH balances are dynamic and are calculated based on the accounts' shares * and the total amount of Ether controlled by the protocol. Account shares aren't * normalized, so the contract also stores the sum of all shares to calculate * each account's token balance which equals to: * * shares[account] * _getTotalPooledEther() / _getTotalShares() */ mapping (address => uint256) private shares; /** * @dev Allowances are nominated in tokens, not token shares. */ mapping (address => mapping (address => uint256)) private allowances; /** * @dev Storage position used for holding the total amount of shares in existence. * * The Lido protocol is built on top of Aragon and uses the Unstructured Storage pattern * for value types: * * https://blog.openzeppelin.com/upgradeability-using-unstructured-storage * https://blog.8bitzen.com/posts/20-02-2020-understanding-how-solidity-upgradeable-unstructured-proxies-work * * For reference types, conventional storage variables are used since it's non-trivial * and error-prone to implement reference-type unstructured storage using Solidity v0.4; * see https://github.com/lidofinance/lido-dao/issues/181#issuecomment-736098834 */ bytes32 internal constant TOTAL_SHARES_POSITION = keccak256("lido.StETH.totalShares"); /** * @notice An executed shares transfer from `sender` to `recipient`. * * @dev emitted in pair with an ERC20-defined `Transfer` event. */ event TransferShares( address indexed from, address indexed to, uint256 sharesValue ); /** * @notice An executed `burnShares` request * * @dev Reports simultaneously burnt shares amount * and corresponding stETH amount. * The stETH amount is calculated twice: before and after the burning incurred rebase. * * @param account holder of the burnt shares * @param preRebaseTokenAmount amount of stETH the burnt shares corresponded to before the burn * @param postRebaseTokenAmount amount of stETH the burnt shares corresponded to after the burn * @param sharesAmount amount of burnt shares */ event SharesBurnt( address indexed account, uint256 preRebaseTokenAmount, uint256 postRebaseTokenAmount, uint256 sharesAmount ); /** * @return the name of the token. */ function name() public pure returns (string) { return "Liquid staked Ether 2.0"; } /** * @return the symbol of the token, usually a shorter version of the * name. */ function symbol() public pure returns (string) { return "stETH"; } /** * @return the number of decimals for getting user representation of a token amount. */ function decimals() public pure returns (uint8) { return 18; } /** * @return the amount of tokens in existence. * * @dev Always equals to `_getTotalPooledEther()` since token amount * is pegged to the total amount of Ether controlled by the protocol. */ function totalSupply() public view returns (uint256) { return _getTotalPooledEther(); } /** * @return the entire amount of Ether controlled by the protocol. * * @dev The sum of all ETH balances in the protocol, equals to the total supply of stETH. */ function getTotalPooledEther() public view returns (uint256) { return _getTotalPooledEther(); } /** * @return the amount of tokens owned by the `_account`. * * @dev Balances are dynamic and equal the `_account`'s share in the amount of the * total Ether controlled by the protocol. See `sharesOf`. */ function balanceOf(address _account) public view returns (uint256) { return getPooledEthByShares(_sharesOf(_account)); } /** * @notice Moves `_amount` tokens from the caller's account to the `_recipient` account. * * @return a boolean value indicating whether the operation succeeded. * Emits a `Transfer` event. * Emits a `TransferShares` event. * * Requirements: * * - `_recipient` cannot be the zero address. * - the caller must have a balance of at least `_amount`. * - the contract must not be paused. * * @dev The `_amount` argument is the amount of tokens, not shares. */ function transfer(address _recipient, uint256 _amount) public returns (bool) { _transfer(msg.sender, _recipient, _amount); return true; } /** * @return the remaining number of tokens that `_spender` is allowed to spend * on behalf of `_owner` through `transferFrom`. This is zero by default. * * @dev This value changes when `approve` or `transferFrom` is called. */ function allowance(address _owner, address _spender) public view returns (uint256) { return allowances[_owner][_spender]; } /** * @notice Sets `_amount` as the allowance of `_spender` over the caller's tokens. * * @return a boolean value indicating whether the operation succeeded. * Emits an `Approval` event. * * Requirements: * * - `_spender` cannot be the zero address. * - the contract must not be paused. * * @dev The `_amount` argument is the amount of tokens, not shares. */ function approve(address _spender, uint256 _amount) public returns (bool) { _approve(msg.sender, _spender, _amount); return true; } /** * @notice Moves `_amount` tokens from `_sender` to `_recipient` using the * allowance mechanism. `_amount` is then deducted from the caller's * allowance. * * @return a boolean value indicating whether the operation succeeded. * * Emits a `Transfer` event. * Emits a `TransferShares` event. * Emits an `Approval` event indicating the updated allowance. * * Requirements: * * - `_sender` and `_recipient` cannot be the zero addresses. * - `_sender` must have a balance of at least `_amount`. * - the caller must have allowance for `_sender`'s tokens of at least `_amount`. * - the contract must not be paused. * * @dev The `_amount` argument is the amount of tokens, not shares. */ function transferFrom(address _sender, address _recipient, uint256 _amount) public returns (bool) { uint256 currentAllowance = allowances[_sender][msg.sender]; require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE"); _transfer(_sender, _recipient, _amount); _approve(_sender, msg.sender, currentAllowance.sub(_amount)); return true; } /** * @notice Atomically increases the allowance granted to `_spender` by the caller by `_addedValue`. * * This is an alternative to `approve` that can be used as a mitigation for * problems described in: * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42 * Emits an `Approval` event indicating the updated allowance. * * Requirements: * * - `_spender` cannot be the the zero address. * - the contract must not be paused. */ function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) { _approve(msg.sender, _spender, allowances[msg.sender][_spender].add(_addedValue)); return true; } /** * @notice Atomically decreases the allowance granted to `_spender` by the caller by `_subtractedValue`. * * This is an alternative to `approve` that can be used as a mitigation for * problems described in: * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42 * Emits an `Approval` event indicating the updated allowance. * * Requirements: * * - `_spender` cannot be the zero address. * - `_spender` must have allowance for the caller of at least `_subtractedValue`. * - the contract must not be paused. */ function decreaseAllowance(address _spender, uint256 _subtractedValue) public returns (bool) { uint256 currentAllowance = allowances[msg.sender][_spender]; require(currentAllowance >= _subtractedValue, "DECREASED_ALLOWANCE_BELOW_ZERO"); _approve(msg.sender, _spender, currentAllowance.sub(_subtractedValue)); return true; } /** * @return the total amount of shares in existence. * * @dev The sum of all accounts' shares can be an arbitrary number, therefore * it is necessary to store it in order to calculate each account's relative share. */ function getTotalShares() public view returns (uint256) { return _getTotalShares(); } /** * @return the amount of shares owned by `_account`. */ function sharesOf(address _account) public view returns (uint256) { return _sharesOf(_account); } /** * @return the amount of shares that corresponds to `_ethAmount` protocol-controlled Ether. */ function getSharesByPooledEth(uint256 _ethAmount) public view returns (uint256) { uint256 totalPooledEther = _getTotalPooledEther(); if (totalPooledEther == 0) { return 0; } else { return _ethAmount .mul(_getTotalShares()) .div(totalPooledEther); } } /** * @return the amount of Ether that corresponds to `_sharesAmount` token shares. */ function getPooledEthByShares(uint256 _sharesAmount) public view returns (uint256) { uint256 totalShares = _getTotalShares(); if (totalShares == 0) { return 0; } else { return _sharesAmount .mul(_getTotalPooledEther()) .div(totalShares); } } /** * @notice Moves `_sharesAmount` token shares from the caller's account to the `_recipient` account. * * @return amount of transferred tokens. * Emits a `TransferShares` event. * Emits a `Transfer` event. * * Requirements: * * - `_recipient` cannot be the zero address. * - the caller must have at least `_sharesAmount` shares. * - the contract must not be paused. * * @dev The `_sharesAmount` argument is the amount of shares, not tokens. */ function transferShares(address _recipient, uint256 _sharesAmount) public returns (uint256) { _transferShares(msg.sender, _recipient, _sharesAmount); emit TransferShares(msg.sender, _recipient, _sharesAmount); uint256 tokensAmount = getPooledEthByShares(_sharesAmount); emit Transfer(msg.sender, _recipient, tokensAmount); return tokensAmount; } /** * @return the total amount (in wei) of Ether controlled by the protocol. * @dev This is used for calculating tokens from shares and vice versa. * @dev This function is required to be implemented in a derived contract. */ function _getTotalPooledEther() internal view returns (uint256); /** * @notice Moves `_amount` tokens from `_sender` to `_recipient`. * Emits a `Transfer` event. * Emits a `TransferShares` event. */ function _transfer(address _sender, address _recipient, uint256 _amount) internal { uint256 _sharesToTransfer = getSharesByPooledEth(_amount); _transferShares(_sender, _recipient, _sharesToTransfer); emit Transfer(_sender, _recipient, _amount); emit TransferShares(_sender, _recipient, _sharesToTransfer); } /** * @notice Sets `_amount` as the allowance of `_spender` over the `_owner` s tokens. * * Emits an `Approval` event. * * Requirements: * * - `_owner` cannot be the zero address. * - `_spender` cannot be the zero address. * - the contract must not be paused. */ function _approve(address _owner, address _spender, uint256 _amount) internal whenNotStopped { require(_owner != address(0), "APPROVE_FROM_ZERO_ADDRESS"); require(_spender != address(0), "APPROVE_TO_ZERO_ADDRESS"); allowances[_owner][_spender] = _amount; emit Approval(_owner, _spender, _amount); } /** * @return the total amount of shares in existence. */ function _getTotalShares() internal view returns (uint256) { return TOTAL_SHARES_POSITION.getStorageUint256(); } /** * @return the amount of shares owned by `_account`. */ function _sharesOf(address _account) internal view returns (uint256) { return shares[_account]; } /** * @notice Moves `_sharesAmount` shares from `_sender` to `_recipient`. * * Requirements: * * - `_sender` cannot be the zero address. * - `_recipient` cannot be the zero address. * - `_sender` must hold at least `_sharesAmount` shares. * - the contract must not be paused. */ function _transferShares(address _sender, address _recipient, uint256 _sharesAmount) internal whenNotStopped { require(_sender != address(0), "TRANSFER_FROM_THE_ZERO_ADDRESS"); require(_recipient != address(0), "TRANSFER_TO_THE_ZERO_ADDRESS"); uint256 currentSenderShares = shares[_sender]; require(_sharesAmount <= currentSenderShares, "TRANSFER_AMOUNT_EXCEEDS_BALANCE"); shares[_sender] = currentSenderShares.sub(_sharesAmount); shares[_recipient] = shares[_recipient].add(_sharesAmount); } /** * @notice Creates `_sharesAmount` shares and assigns them to `_recipient`, increasing the total amount of shares. * @dev This doesn't increase the token total supply. * * Requirements: * * - `_recipient` cannot be the zero address. * - the contract must not be paused. */ function _mintShares(address _recipient, uint256 _sharesAmount) internal whenNotStopped returns (uint256 newTotalShares) { require(_recipient != address(0), "MINT_TO_THE_ZERO_ADDRESS"); newTotalShares = _getTotalShares().add(_sharesAmount); TOTAL_SHARES_POSITION.setStorageUint256(newTotalShares); shares[_recipient] = shares[_recipient].add(_sharesAmount); // Notice: we're not emitting a Transfer event from the zero address here since shares mint // works by taking the amount of tokens corresponding to the minted shares from all other // token holders, proportionally to their share. The total supply of the token doesn't change // as the result. This is equivalent to performing a send from each other token holder's // address to `address`, but we cannot reflect this as it would require sending an unbounded // number of events. } /** * @notice Destroys `_sharesAmount` shares from `_account`'s holdings, decreasing the total amount of shares. * @dev This doesn't decrease the token total supply. * * Requirements: * * - `_account` cannot be the zero address. * - `_account` must hold at least `_sharesAmount` shares. * - the contract must not be paused. */ function _burnShares(address _account, uint256 _sharesAmount) internal whenNotStopped returns (uint256 newTotalShares) { require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS"); uint256 accountShares = shares[_account]; require(_sharesAmount <= accountShares, "BURN_AMOUNT_EXCEEDS_BALANCE"); uint256 preRebaseTokenAmount = getPooledEthByShares(_sharesAmount); newTotalShares = _getTotalShares().sub(_sharesAmount); TOTAL_SHARES_POSITION.setStorageUint256(newTotalShares); shares[_account] = accountShares.sub(_sharesAmount); uint256 postRebaseTokenAmount = getPooledEthByShares(_sharesAmount); emit SharesBurnt(_account, preRebaseTokenAmount, postRebaseTokenAmount, _sharesAmount); // Notice: we're not emitting a Transfer event to the zero address here since shares burn // works by redistributing the amount of tokens corresponding to the burned shares between // all other token holders. The total supply of the token doesn't change as the result. // This is equivalent to performing a send from `address` to each other token holder address, // but we cannot reflect this as it would require sending an unbounded number of events. // We're emitting `SharesBurnt` event to provide an explicit rebase log record nonetheless. } }
// SPDX-FileCopyrightText: 2022 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ pragma solidity 0.4.24; import "@aragon/os/contracts/common/UnstructuredStorage.sol"; // // We need to pack four variables into the same 256bit-wide storage slot // to lower the costs per each staking request. // // As a result, slot's memory aligned as follows: // // MSB ------------------------------------------------------------------------------> LSB // 256____________160_________________________128_______________32_____________________ 0 // |_______________|___________________________|________________|_______________________| // | maxStakeLimit | maxStakeLimitGrowthBlocks | prevStakeLimit | prevStakeBlockNumber | // |<-- 96 bits -->|<---------- 32 bits ------>|<-- 96 bits --->|<----- 32 bits ------->| // // // NB: Internal representation conventions: // // - the `maxStakeLimitGrowthBlocks` field above represented as follows: // `maxStakeLimitGrowthBlocks` = `maxStakeLimit` / `stakeLimitIncreasePerBlock` // 32 bits 96 bits 96 bits // // // - the "staking paused" state is encoded by `prevStakeBlockNumber` being zero, // - the "staking unlimited" state is encoded by `maxStakeLimit` being zero and `prevStakeBlockNumber` being non-zero. // /** * @notice Library for the internal structs definitions * @dev solidity <0.6 doesn't support top-level structs * using the library to have a proper namespace */ library StakeLimitState { /** * @dev Internal representation struct (slot-wide) */ struct Data { uint32 prevStakeBlockNumber; uint96 prevStakeLimit; uint32 maxStakeLimitGrowthBlocks; uint96 maxStakeLimit; } } library StakeLimitUnstructuredStorage { using UnstructuredStorage for bytes32; /// @dev Storage offset for `maxStakeLimit` (bits) uint256 internal constant MAX_STAKE_LIMIT_OFFSET = 160; /// @dev Storage offset for `maxStakeLimitGrowthBlocks` (bits) uint256 internal constant MAX_STAKE_LIMIT_GROWTH_BLOCKS_OFFSET = 128; /// @dev Storage offset for `prevStakeLimit` (bits) uint256 internal constant PREV_STAKE_LIMIT_OFFSET = 32; /// @dev Storage offset for `prevStakeBlockNumber` (bits) uint256 internal constant PREV_STAKE_BLOCK_NUMBER_OFFSET = 0; /** * @dev Read stake limit state from the unstructured storage position * @param _position storage offset */ function getStorageStakeLimitStruct(bytes32 _position) internal view returns (StakeLimitState.Data memory stakeLimit) { uint256 slotValue = _position.getStorageUint256(); stakeLimit.prevStakeBlockNumber = uint32(slotValue >> PREV_STAKE_BLOCK_NUMBER_OFFSET); stakeLimit.prevStakeLimit = uint96(slotValue >> PREV_STAKE_LIMIT_OFFSET); stakeLimit.maxStakeLimitGrowthBlocks = uint32(slotValue >> MAX_STAKE_LIMIT_GROWTH_BLOCKS_OFFSET); stakeLimit.maxStakeLimit = uint96(slotValue >> MAX_STAKE_LIMIT_OFFSET); } /** * @dev Write stake limit state to the unstructured storage position * @param _position storage offset * @param _data stake limit state structure instance */ function setStorageStakeLimitStruct(bytes32 _position, StakeLimitState.Data memory _data) internal { _position.setStorageUint256( uint256(_data.prevStakeBlockNumber) << PREV_STAKE_BLOCK_NUMBER_OFFSET | uint256(_data.prevStakeLimit) << PREV_STAKE_LIMIT_OFFSET | uint256(_data.maxStakeLimitGrowthBlocks) << MAX_STAKE_LIMIT_GROWTH_BLOCKS_OFFSET | uint256(_data.maxStakeLimit) << MAX_STAKE_LIMIT_OFFSET ); } } /** * @notice Interface library with helper functions to deal with stake limit struct in a more high-level approach. */ library StakeLimitUtils { /** * @notice Calculate stake limit for the current block. */ function calculateCurrentStakeLimit(StakeLimitState.Data memory _data) internal view returns(uint256 limit) { uint256 stakeLimitIncPerBlock; if (_data.maxStakeLimitGrowthBlocks != 0) { stakeLimitIncPerBlock = _data.maxStakeLimit / _data.maxStakeLimitGrowthBlocks; } limit = _data.prevStakeLimit + ((block.number - _data.prevStakeBlockNumber) * stakeLimitIncPerBlock); if (limit > _data.maxStakeLimit) { limit = _data.maxStakeLimit; } } /** * @notice check if staking is on pause */ function isStakingPaused(StakeLimitState.Data memory _data) internal pure returns(bool) { return _data.prevStakeBlockNumber == 0; } /** * @notice check if staking limit is set (otherwise staking is unlimited) */ function isStakingLimitSet(StakeLimitState.Data memory _data) internal pure returns(bool) { return _data.maxStakeLimit != 0; } /** * @notice update stake limit repr with the desired limits * @dev input `_data` param is mutated and the func returns effectively the same pointer * @param _data stake limit state struct * @param _maxStakeLimit stake limit max value * @param _stakeLimitIncreasePerBlock stake limit increase (restoration) per block */ function setStakingLimit( StakeLimitState.Data memory _data, uint256 _maxStakeLimit, uint256 _stakeLimitIncreasePerBlock ) internal view returns (StakeLimitState.Data memory) { require(_maxStakeLimit != 0, "ZERO_MAX_STAKE_LIMIT"); require(_maxStakeLimit <= uint96(-1), "TOO_LARGE_MAX_STAKE_LIMIT"); require(_maxStakeLimit >= _stakeLimitIncreasePerBlock, "TOO_LARGE_LIMIT_INCREASE"); require( (_stakeLimitIncreasePerBlock == 0) || (_maxStakeLimit / _stakeLimitIncreasePerBlock <= uint32(-1)), "TOO_SMALL_LIMIT_INCREASE" ); // if staking was paused or unlimited previously, // or new limit is lower than previous, then // reset prev stake limit to the new max stake limit if ((_data.maxStakeLimit == 0) || (_maxStakeLimit < _data.prevStakeLimit)) { _data.prevStakeLimit = uint96(_maxStakeLimit); } _data.maxStakeLimitGrowthBlocks = _stakeLimitIncreasePerBlock != 0 ? uint32(_maxStakeLimit / _stakeLimitIncreasePerBlock) : 0; _data.maxStakeLimit = uint96(_maxStakeLimit); if (_data.prevStakeBlockNumber != 0) { _data.prevStakeBlockNumber = uint32(block.number); } return _data; } /** * @notice update stake limit repr to remove the limit * @dev input `_data` param is mutated and the func returns effectively the same pointer * @param _data stake limit state struct */ function removeStakingLimit( StakeLimitState.Data memory _data ) internal view returns (StakeLimitState.Data memory) { _data.maxStakeLimit = 0; return _data; } /** * @notice update stake limit repr after submitting user's eth * @dev input `_data` param is mutated and the func returns effectively the same pointer * @param _data stake limit state struct * @param _newPrevStakeLimit new value for the `prevStakeLimit` field */ function updatePrevStakeLimit( StakeLimitState.Data memory _data, uint256 _newPrevStakeLimit ) internal view returns (StakeLimitState.Data memory) { assert(_newPrevStakeLimit <= uint96(-1)); assert(_data.prevStakeBlockNumber != 0); _data.prevStakeLimit = uint96(_newPrevStakeLimit); _data.prevStakeBlockNumber = uint32(block.number); return _data; } /** * @notice set stake limit pause state (on or off) * @dev input `_data` param is mutated and the func returns effectively the same pointer * @param _data stake limit state struct * @param _isPaused pause state flag */ function setStakeLimitPauseState( StakeLimitState.Data memory _data, bool _isPaused ) internal view returns (StakeLimitState.Data memory) { _data.prevStakeBlockNumber = uint32(_isPaused ? 0 : block.number); return _data; } }
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../common/UnstructuredStorage.sol";
import "../kernel/IKernel.sol";
contract AppStorage {
using UnstructuredStorage for bytes32;
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
*/
bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
function kernel() public view returns (IKernel) {
return IKernel(KERNEL_POSITION.getStorageAddress());
}
function appId() public view returns (bytes32) {
return APP_ID_POSITION.getStorageBytes32();
}
function setKernel(IKernel _kernel) internal {
KERNEL_POSITION.setStorageAddress(address(_kernel));
}
function setAppId(bytes32 _appId) internal {
APP_ID_POSITION.setStorageBytes32(_appId);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract ACLSyntaxSugar {
function arr() internal pure returns (uint256[]) {
return new uint256[](0);
}
function arr(bytes32 _a) internal pure returns (uint256[] r) {
return arr(uint256(_a));
}
function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a) internal pure returns (uint256[] r) {
return arr(uint256(_a));
}
function arr(address _a, address _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), _b, _c);
}
function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
return arr(uint256(_a), _b, _c, _d);
}
function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), _c, _d, _e);
}
function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), uint256(_c));
}
function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), uint256(_c));
}
function arr(uint256 _a) internal pure returns (uint256[] r) {
r = new uint256[](1);
r[0] = _a;
}
function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
r = new uint256[](2);
r[0] = _a;
r[1] = _b;
}
function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
r = new uint256[](3);
r[0] = _a;
r[1] = _b;
r[2] = _c;
}
function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
r = new uint256[](4);
r[0] = _a;
r[1] = _b;
r[2] = _c;
r[3] = _d;
}
function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
r = new uint256[](5);
r[0] = _a;
r[1] = _b;
r[2] = _c;
r[3] = _d;
r[4] = _e;
}
}
contract ACLHelpers {
function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
return uint8(_x >> (8 * 30));
}
function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
return uint8(_x >> (8 * 31));
}
function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
a = uint32(_x);
b = uint32(_x >> (8 * 4));
c = uint32(_x >> (8 * 8));
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Petrifiable.sol";
contract Autopetrified is Petrifiable {
constructor() public {
// Immediately petrify base (non-proxy) instances of inherited contracts on deploy.
// This renders them uninitializable (and unusable without a proxy).
petrify();
}
}pragma solidity ^0.4.24;
library ConversionHelpers {
string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
// Force cast the uint256[] into a bytes array, by overwriting its length
// Note that the bytes array doesn't need to be initialized as we immediately overwrite it
// with the input and a new length. The input becomes invalid from this point forward.
uint256 byteLength = _input.length * 32;
assembly {
output := _input
mstore(output, byteLength)
}
}
function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
// Force cast the bytes array into a uint256[], by overwriting its length
// Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
// with the input and a new length. The input becomes invalid from this point forward.
uint256 intsLength = _input.length / 32;
require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
assembly {
output := _input
mstore(output, intsLength)
}
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../common/UnstructuredStorage.sol";
contract ReentrancyGuard {
using UnstructuredStorage for bytes32;
/* Hardcoded constants to save gas
bytes32 internal constant REENTRANCY_MUTEX_POSITION = keccak256("aragonOS.reentrancyGuard.mutex");
*/
bytes32 private constant REENTRANCY_MUTEX_POSITION = 0xe855346402235fdd185c890e68d2c4ecad599b88587635ee285bce2fda58dacb;
string private constant ERROR_REENTRANT = "REENTRANCY_REENTRANT_CALL";
modifier nonReentrant() {
// Ensure mutex is unlocked
require(!REENTRANCY_MUTEX_POSITION.getStorageBool(), ERROR_REENTRANT);
// Lock mutex before function call
REENTRANCY_MUTEX_POSITION.setStorageBool(true);
// Perform function call
_;
// Unlock mutex after function call
REENTRANCY_MUTEX_POSITION.setStorageBool(false);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../lib/token/ERC20.sol";
import "./EtherTokenConstant.sol";
import "./IsContract.sol";
import "./IVaultRecoverable.sol";
import "./SafeERC20.sol";
contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
using SafeERC20 for ERC20;
string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
/**
* @notice Send funds to recovery Vault. This contract should never receive funds,
* but in case it does, this function allows one to recover them.
* @param _token Token balance to be sent to recovery vault.
*/
function transferToVault(address _token) external {
require(allowRecoverability(_token), ERROR_DISALLOWED);
address vault = getRecoveryVault();
require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
uint256 balance;
if (_token == ETH) {
balance = address(this).balance;
vault.transfer(balance);
} else {
ERC20 token = ERC20(_token);
balance = token.staticBalanceOf(this);
require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
}
emit RecoverToVault(vault, _token, balance);
}
/**
* @dev By default deriving from AragonApp makes it recoverable
* @param token Token address that would be recovered
* @return bool whether the app allows the recovery
*/
function allowRecoverability(address token) public view returns (bool) {
return true;
}
// Cast non-implemented interface to be public so we can use it internally
function getRecoveryVault() public view returns (address);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./IEVMScriptExecutor.sol";
import "./IEVMScriptRegistry.sol";
import "../apps/AppStorage.sol";
import "../kernel/KernelConstants.sol";
import "../common/Initializable.sol";
contract EVMScriptRunner is AppStorage, Initializable, EVMScriptRegistryConstants, KernelNamespaceConstants {
string private constant ERROR_EXECUTOR_UNAVAILABLE = "EVMRUN_EXECUTOR_UNAVAILABLE";
string private constant ERROR_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED";
/* This is manually crafted in assembly
string private constant ERROR_EXECUTOR_INVALID_RETURN = "EVMRUN_EXECUTOR_INVALID_RETURN";
*/
event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData);
function getEVMScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) {
return IEVMScriptExecutor(getEVMScriptRegistry().getScriptExecutor(_script));
}
function getEVMScriptRegistry() public view returns (IEVMScriptRegistry) {
address registryAddr = kernel().getApp(KERNEL_APP_ADDR_NAMESPACE, EVMSCRIPT_REGISTRY_APP_ID);
return IEVMScriptRegistry(registryAddr);
}
function runScript(bytes _script, bytes _input, address[] _blacklist)
internal
isInitialized
protectState
returns (bytes)
{
IEVMScriptExecutor executor = getEVMScriptExecutor(_script);
require(address(executor) != address(0), ERROR_EXECUTOR_UNAVAILABLE);
bytes4 sig = executor.execScript.selector;
bytes memory data = abi.encodeWithSelector(sig, _script, _input, _blacklist);
bytes memory output;
assembly {
let success := delegatecall(
gas, // forward all gas
executor, // address
add(data, 0x20), // calldata start
mload(data), // calldata length
0, // don't write output (we'll handle this ourselves)
0 // don't write output
)
output := mload(0x40) // free mem ptr get
switch success
case 0 {
// If the call errored, forward its full error data
returndatacopy(output, 0, returndatasize)
revert(output, returndatasize)
}
default {
switch gt(returndatasize, 0x3f)
case 0 {
// Need at least 0x40 bytes returned for properly ABI-encoded bytes values,
// revert with "EVMRUN_EXECUTOR_INVALID_RETURN"
// See remix: doing a `revert("EVMRUN_EXECUTOR_INVALID_RETURN")` always results in
// this memory layout
mstore(output, 0x08c379a000000000000000000000000000000000000000000000000000000000) // error identifier
mstore(add(output, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset
mstore(add(output, 0x24), 0x000000000000000000000000000000000000000000000000000000000000001e) // reason length
mstore(add(output, 0x44), 0x45564d52554e5f4558454355544f525f494e56414c49445f52455455524e0000) // reason
revert(output, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error)
}
default {
// Copy result
//
// Needs to perform an ABI decode for the expected `bytes` return type of
// `executor.execScript()` as solidity will automatically ABI encode the returned bytes as:
// [ position of the first dynamic length return value = 0x20 (32 bytes) ]
// [ output length (32 bytes) ]
// [ output content (N bytes) ]
//
// Perform the ABI decode by ignoring the first 32 bytes of the return data
let copysize := sub(returndatasize, 0x20)
returndatacopy(output, 0x20, copysize)
mstore(0x40, add(output, copysize)) // free mem ptr set
}
}
}
emit ScriptResult(address(executor), _script, _input, output);
return output;
}
modifier protectState {
address preKernel = address(kernel());
bytes32 preAppId = appId();
_; // exec
require(address(kernel()) == preKernel, ERROR_PROTECTED_STATE_MODIFIED);
require(appId() == preAppId, ERROR_PROTECTED_STATE_MODIFIED);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
library UnstructuredStorage {
function getStorageBool(bytes32 position) internal view returns (bool data) {
assembly { data := sload(position) }
}
function getStorageAddress(bytes32 position) internal view returns (address data) {
assembly { data := sload(position) }
}
function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
assembly { data := sload(position) }
}
function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
assembly { data := sload(position) }
}
function setStorageBool(bytes32 position, bool data) internal {
assembly { sstore(position, data) }
}
function setStorageAddress(bytes32 position, address data) internal {
assembly { sstore(position, data) }
}
function setStorageBytes32(bytes32 position, bytes32 data) internal {
assembly { sstore(position, data) }
}
function setStorageUint256(bytes32 position, uint256 data) internal {
assembly { sstore(position, data) }
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../acl/IACL.sol";
import "../common/IVaultRecoverable.sol";
interface IKernelEvents {
event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
}
// This should be an interface, but interfaces can't inherit yet :(
contract IKernel is IKernelEvents, IVaultRecoverable {
function acl() public view returns (IACL);
function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
function setApp(bytes32 namespace, bytes32 appId, address app) public;
function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IACL {
function initialize(address permissionsCreator) external;
// TODO: this should be external
// See https://github.com/ethereum/solidity/issues/4832
function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IVaultRecoverable {
event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
function transferToVault(address token) external;
function allowRecoverability(address token) external view returns (bool);
function getRecoveryVault() external view returns (address);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Initializable.sol";
contract Petrifiable is Initializable {
// Use block UINT256_MAX (which should be never) as the initializable date
uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
function isPetrified() public view returns (bool) {
return getInitializationBlock() == PETRIFIED_BLOCK;
}
/**
* @dev Function to be called by top level contract to prevent being initialized.
* Useful for freezing base contracts when they're used behind proxies.
*/
function petrify() internal onlyInit {
initializedAt(PETRIFIED_BLOCK);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./TimeHelpers.sol";
import "./UnstructuredStorage.sol";
contract Initializable is TimeHelpers {
using UnstructuredStorage for bytes32;
// keccak256("aragonOS.initializable.initializationBlock")
bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
modifier onlyInit {
require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
_;
}
modifier isInitialized {
require(hasInitialized(), ERROR_NOT_INITIALIZED);
_;
}
/**
* @return Block number in which the contract was initialized
*/
function getInitializationBlock() public view returns (uint256) {
return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
}
/**
* @return Whether the contract has been initialized by the time of the current block
*/
function hasInitialized() public view returns (bool) {
uint256 initializationBlock = getInitializationBlock();
return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
}
/**
* @dev Function to be called by top level contract after initialization has finished.
*/
function initialized() internal onlyInit {
INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
}
/**
* @dev Function to be called by top level contract after initialization to enable the contract
* at a future block number rather than immediately.
*/
function initializedAt(uint256 _blockNumber) internal onlyInit {
INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Uint256Helpers.sol";
contract TimeHelpers {
using Uint256Helpers for uint256;
/**
* @dev Returns the current block number.
* Using a function rather than `block.number` allows us to easily mock the block number in
* tests.
*/
function getBlockNumber() internal view returns (uint256) {
return block.number;
}
/**
* @dev Returns the current block number, converted to uint64.
* Using a function rather than `block.number` allows us to easily mock the block number in
* tests.
*/
function getBlockNumber64() internal view returns (uint64) {
return getBlockNumber().toUint64();
}
/**
* @dev Returns the current timestamp.
* Using a function rather than `block.timestamp` allows us to easily mock it in
* tests.
*/
function getTimestamp() internal view returns (uint256) {
return block.timestamp; // solium-disable-line security/no-block-members
}
/**
* @dev Returns the current timestamp, converted to uint64.
* Using a function rather than `block.timestamp` allows us to easily mock it in
* tests.
*/
function getTimestamp64() internal view returns (uint64) {
return getTimestamp().toUint64();
}
}pragma solidity ^0.4.24;
library Uint256Helpers {
uint256 private constant MAX_UINT64 = uint64(-1);
string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
function toUint64(uint256 a) internal pure returns (uint64) {
require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
return uint64(a);
}
}// See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
pragma solidity ^0.4.24;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function allowance(address _owner, address _spender)
public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
function approve(address _spender, uint256 _value)
public returns (bool);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
event Transfer(
address indexed from,
address indexed to,
uint256 value
);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
// aragonOS and aragon-apps rely on address(0) to denote native ETH, in
// contracts where both tokens and ETH are accepted
contract EtherTokenConstant {
address internal constant ETH = address(0);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract IsContract {
/*
* NOTE: this should NEVER be used for authentication
* (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
*
* This is only intended to be used as a sanity check that an address is actually a contract,
* RATHER THAN an address not being a contract.
*/
function isContract(address _target) internal view returns (bool) {
if (_target == address(0)) {
return false;
}
uint256 size;
assembly { size := extcodesize(_target) }
return size > 0;
}
}// Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
// and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
pragma solidity ^0.4.24;
import "../lib/token/ERC20.sol";
library SafeERC20 {
// Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
// https://github.com/ethereum/solidity/issues/3544
bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
private
returns (bool)
{
bool ret;
assembly {
let ptr := mload(0x40) // free memory pointer
let success := call(
gas, // forward all gas
_addr, // address
0, // no value
add(_calldata, 0x20), // calldata start
mload(_calldata), // calldata length
ptr, // write output over free memory
0x20 // uint256 return
)
if gt(success, 0) {
// Check number of bytes returned from last function call
switch returndatasize
// No bytes returned: assume success
case 0 {
ret := 1
}
// 32 bytes returned: check if non-zero
case 0x20 {
// Only return success if returned data was true
// Already have output in ptr
ret := eq(mload(ptr), 1)
}
// Not sure what was returned: don't mark as success
default { }
}
}
return ret;
}
function staticInvoke(address _addr, bytes memory _calldata)
private
view
returns (bool, uint256)
{
bool success;
uint256 ret;
assembly {
let ptr := mload(0x40) // free memory pointer
success := staticcall(
gas, // forward all gas
_addr, // address
add(_calldata, 0x20), // calldata start
mload(_calldata), // calldata length
ptr, // write output over free memory
0x20 // uint256 return
)
if gt(success, 0) {
ret := mload(ptr)
}
}
return (success, ret);
}
/**
* @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
bytes memory transferCallData = abi.encodeWithSelector(
TRANSFER_SELECTOR,
_to,
_amount
);
return invokeAndCheckSuccess(_token, transferCallData);
}
/**
* @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
bytes memory transferFromCallData = abi.encodeWithSelector(
_token.transferFrom.selector,
_from,
_to,
_amount
);
return invokeAndCheckSuccess(_token, transferFromCallData);
}
/**
* @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
bytes memory approveCallData = abi.encodeWithSelector(
_token.approve.selector,
_spender,
_amount
);
return invokeAndCheckSuccess(_token, approveCallData);
}
/**
* @dev Static call into ERC20.balanceOf().
* Reverts if the call fails for some reason (should never fail).
*/
function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
bytes memory balanceOfCallData = abi.encodeWithSelector(
_token.balanceOf.selector,
_owner
);
(bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
require(success, ERROR_TOKEN_BALANCE_REVERTED);
return tokenBalance;
}
/**
* @dev Static call into ERC20.allowance().
* Reverts if the call fails for some reason (should never fail).
*/
function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
bytes memory allowanceCallData = abi.encodeWithSelector(
_token.allowance.selector,
_owner,
_spender
);
(bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
return allowance;
}
/**
* @dev Static call into ERC20.totalSupply().
* Reverts if the call fails for some reason (should never fail).
*/
function staticTotalSupply(ERC20 _token) internal view returns (uint256) {
bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector);
(bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData);
require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
return totalSupply;
}
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IEVMScriptExecutor {
function execScript(bytes script, bytes input, address[] blacklist) external returns (bytes);
function executorType() external pure returns (bytes32);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./IEVMScriptExecutor.sol";
contract EVMScriptRegistryConstants {
/* Hardcoded constants to save gas
bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = apmNamehash("evmreg");
*/
bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = 0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61;
}
interface IEVMScriptRegistry {
function addScriptExecutor(IEVMScriptExecutor executor) external returns (uint id);
function disableScriptExecutor(uint256 executorId) external;
// TODO: this should be external
// See https://github.com/ethereum/solidity/issues/4832
function getScriptExecutor(bytes script) public view returns (IEVMScriptExecutor);
}/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract KernelAppIds {
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
*/
bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
}
contract KernelNamespaceConstants {
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
*/
bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
}pragma solidity ^0.4.24;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender)
external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value)
external returns (bool);
function transferFrom(address from, address to, uint256 value)
external returns (bool);
event Transfer(
address indexed from,
address indexed to,
uint256 value
);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}// SPDX-FileCopyrightText: 2020 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.24; import "@aragon/os/contracts/common/UnstructuredStorage.sol"; contract Pausable { using UnstructuredStorage for bytes32; event Stopped(); event Resumed(); bytes32 internal constant ACTIVE_FLAG_POSITION = keccak256("lido.Pausable.activeFlag"); modifier whenNotStopped() { require(ACTIVE_FLAG_POSITION.getStorageBool(), "CONTRACT_IS_STOPPED"); _; } modifier whenStopped() { require(!ACTIVE_FLAG_POSITION.getStorageBool(), "CONTRACT_IS_ACTIVE"); _; } function isStopped() external view returns (bool) { return !ACTIVE_FLAG_POSITION.getStorageBool(); } function _stop() internal whenNotStopped { ACTIVE_FLAG_POSITION.setStorageBool(false); emit Stopped(); } function _resume() internal whenStopped { ACTIVE_FLAG_POSITION.setStorageBool(true); emit Resumed(); } }
{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "constantinople",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"hasInitialized","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_CONTROL_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_depositContract","type":"address"},{"name":"_oracle","type":"address"},{"name":"_operators","type":"address"},{"name":"_treasury","type":"address"},{"name":"_insuranceFund","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getInsuranceFund","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_ethAmount","type":"uint256"}],"name":"getSharesByPooledEth","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStakingPaused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getOperators","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_script","type":"bytes"}],"name":"getEVMScriptExecutor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxStakeLimit","type":"uint256"},{"name":"_stakeLimitIncreasePerBlock","type":"uint256"}],"name":"setStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"RESUME_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getRecoveryVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DEPOSIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DEPOSIT_SIZE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTreasury","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isStopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_WITHDRAWAL_KEY","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getELRewardsWithdrawalLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SIGNATURE_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_limitPoints","type":"uint16"}],"name":"setELRewardsWithdrawalLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_beaconValidators","type":"uint256"},{"name":"_beaconBalance","type":"uint256"}],"name":"handleOracleReport","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getStakeLimitFullInfo","outputs":[{"name":"isStakingPaused","type":"bool"},{"name":"isStakingLimitSet","type":"bool"},{"name":"currentStakeLimit","type":"uint256"},{"name":"maxStakeLimit","type":"uint256"},{"name":"maxStakeLimitGrowthBlocks","type":"uint256"},{"name":"prevStakeLimit","type":"uint256"},{"name":"prevStakeBlockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_EL_REWARDS_WITHDRAWAL_LIMIT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getELRewardsVault","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resumeStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeDistribution","outputs":[{"name":"treasuryFeeBasisPoints","type":"uint16"},{"name":"insuranceFeeBasisPoints","type":"uint16"},{"name":"operatorsFeeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_executionLayerRewardsVault","type":"address"}],"name":"setELRewardsVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"}],"name":"allowRecoverability","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_PROTOCOL_CONTRACTS_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getOracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitializationBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_treasuryFeeBasisPoints","type":"uint16"},{"name":"_insuranceFeeBasisPoints","type":"uint16"},{"name":"_operatorsFeeBasisPoints","type":"uint16"}],"name":"setFeeDistribution","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_feeBasisPoints","type":"uint16"}],"name":"setFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDeposits","type":"uint256"}],"name":"depositBufferedEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"MANAGE_FEE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"}],"name":"transferToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_sender","type":"address"},{"name":"_role","type":"bytes32"},{"name":"_params","type":"uint256[]"}],"name":"canPerform","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_referral","type":"address"}],"name":"submit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"WITHDRAWAL_CREDENTIALS_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getEVMScriptRegistry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PUBKEY_LENGTH","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SET_EL_REWARDS_VAULT_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getDepositContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeaconStat","outputs":[{"name":"depositedValidators","type":"uint256"},{"name":"beaconValidators","type":"uint256"},{"name":"beaconBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"removeStakingLimit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"BURN_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getFee","outputs":[{"name":"feeBasisPoints","type":"uint16"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"kernel","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isPetrified","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_oracle","type":"address"},{"name":"_treasury","type":"address"},{"name":"_insuranceFund","type":"address"}],"name":"setProtocolContracts","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_withdrawalCredentials","type":"bytes32"}],"name":"setWithdrawalCredentials","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"depositBufferedEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_account","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"burnShares","outputs":[{"name":"newTotalShares","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pauseStaking","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getTotalELRewardsCollected","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"executor","type":"address"},{"indexed":false,"name":"script","type":"bytes"},{"indexed":false,"name":"input","type":"bytes"},{"indexed":false,"name":"returnData","type":"bytes"}],"name":"ScriptResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"vault","type":"address"},{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"RecoverToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"sharesValue","type":"uint256"}],"name":"TransferShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"preRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"postRebaseTokenAmount","type":"uint256"},{"indexed":false,"name":"sharesAmount","type":"uint256"}],"name":"SharesBurnt","type":"event"},{"anonymous":false,"inputs":[],"name":"Stopped","type":"event"},{"anonymous":false,"inputs":[],"name":"Resumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxStakeLimit","type":"uint256"},{"indexed":false,"name":"stakeLimitIncreasePerBlock","type":"uint256"}],"name":"StakingLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingLimitRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oracle","type":"address"},{"indexed":false,"name":"treasury","type":"address"},{"indexed":false,"name":"insuranceFund","type":"address"}],"name":"ProtocolContactsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"feeBasisPoints","type":"uint16"}],"name":"FeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"treasuryFeeBasisPoints","type":"uint16"},{"indexed":false,"name":"insuranceFeeBasisPoints","type":"uint16"},{"indexed":false,"name":"operatorsFeeBasisPoints","type":"uint16"}],"name":"FeeDistributionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"limitPoints","type":"uint256"}],"name":"ELRewardsWithdrawalLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"withdrawalCredentials","type":"bytes32"}],"name":"WithdrawalCredentialsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"executionLayerRewardsVault","type":"address"}],"name":"ELRewardsVaultSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"referral","type":"address"}],"name":"Submitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Unbuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"tokenAmount","type":"uint256"},{"indexed":false,"name":"sentFromBuffer","type":"uint256"},{"indexed":true,"name":"pubkeyHash","type":"bytes32"},{"indexed":false,"name":"etherAmount","type":"uint256"}],"name":"Withdrawal","type":"event"}]Contract Creation Code
6080604052620000146200001a60201b60201c565b62000231565b6200002a6200011c60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901562000106576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620000ca578181015183820152602001620000b0565b50505050905090810190601f168015620000f85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506200011a6000196200014f60201b60201c565b565b60006200014a6000805160206200616283398151915260001b600019166200022960201b62003e6f1760201c565b905090565b6200015f6200011c60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015620001fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252838181518152602001915080519060200190808383600083811015620000ca578181015183820152602001620000b0565b506200022660008051602062006162833981519152826200022d602090811b6200362617901c565b50565b5490565b9055565b615f2180620002416000396000f30060806040526004361061037e5760003560e01c63ffffffff168063046f7da2146103e157806306fdde03146103f857806307da68f5146104825780630803fac014610497578063095ea7b3146104c0578063136dd43c146104e45780631459457a1461050b578063158626f71461054457806318160ddd14610575578063192084511461058a5780631ea7ca89146105a257806323b872dd146105b757806327a099d8146105e15780632914b9bd146105f65780632cb5f7841461064f5780632de03aa11461066a578063313ce5671461067f57806332f0a3b5146106aa578063353efdcf146106bf57806336bf3325146106d457806337cfdaca14610575578063389ed267146106e957806339509351146106fe5780633b19e84a146107225780633f683b6a14610737578063435721da1461074c57806347b714e0146107615780634ad509b21461077657806352b3af931461077e578063540bc5ea1461079357806356396715146107a8578063609c4c6c146107bd57806363c2eb53146107d257806364f9991a146107ee578063665b4b0b146108095780636bb98ad314610858578063706aa30d1461086d57806370a08231146108825780637475f913146108a3578063752f77f1146108b85780637a28fb88146108f35780637e4193c61461090b5780637e7db6e11461092c5780637f6fdac71461094d57806380afdea814610962578063833b1fce146109775780638b3dd7491461098c5780638cef3612146109a15780638e005553146109c95780638fcb4e5b146109e557806390adc83b14610a0957806395d89b4114610a215780639aaa2d1514610a365780639d4941d814610a4b578063a1658fad14610a6c578063a1903eab14610ad3578063a30448c014610ae7578063a457c2d714610afc578063a479e50814610b20578063a4d55d1d14610b35578063a6426f5f14610b4a578063a9059cbb14610b5f578063ab94276a14610b83578063ae2e353814610b98578063b3320d9a14610bcb578063b930908f14610be0578063ced72f8714610bf5578063d4aae0c414610c21578063d5002f2e14610c36578063dd62ed3e14610c4b578063de4796ed14610c72578063e73f452914610c87578063e97ee8cc14610cb4578063eb85262f14610ccc578063ecc1dcfb14610ce1578063ee7a7c0414610cf6578063f5eb42dc14610d1a578063f999c50614610d3b578063fa64ebac14610d50575b36156103d4576040805160e560020a62461bcd02815260206004820152600e60248201527f4e4f4e5f454d5054595f44415441000000000000000000000000000000000000604482015290519081900360640190fd5b6103de6000610d65565b50005b3480156103ed57600080fd5b506103f6610fd5565b005b34801561040457600080fd5b5061040d611022565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561044757818101518382015260200161042f565b50505050905090810190601f1680156104745780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561048e57600080fd5b506103f6611059565b3480156104a357600080fd5b506104ac6110a4565b604080519115158252519081900360200190f35b3480156104cc57600080fd5b506104ac600160a060020a03600435166024356110cd565b3480156104f057600080fd5b506104f96110e3565b60408051918252519081900360200190f35b34801561051757600080fd5b506103f6600160a060020a0360043581169060243581169060443581169060643581169060843516611106565b34801561055057600080fd5b5061055961126e565b60408051600160a060020a039092168252519081900360200190f35b34801561058157600080fd5b506104f96112b1565b34801561059657600080fd5b506104f96004356112bb565b3480156105ae57600080fd5b506104ac611309565b3480156105c357600080fd5b506104ac600160a060020a036004358116906024351660443561133e565b3480156105ed57600080fd5b50610559611412565b34801561060257600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526105599436949293602493928401919081908401838280828437509497506114509650505050505050565b34801561065b57600080fd5b506103f6600435602435611535565b34801561067657600080fd5b506104f96115df565b34801561068b57600080fd5b50610694611614565b6040805160ff9092168252519081900360200190f35b3480156106b657600080fd5b50610559611619565b3480156106cb57600080fd5b506104f961168e565b3480156106e057600080fd5b506104f96116c3565b3480156106f557600080fd5b506104f96116d0565b34801561070a57600080fd5b506104ac600160a060020a0360043516602435611705565b34801561072e57600080fd5b50610559611741565b34801561074357600080fd5b506104ac61177f565b34801561075857600080fd5b506104f96117b1565b34801561076d57600080fd5b506104f96117e6565b6103f66117f0565b34801561078a57600080fd5b506104f9611969565b34801561079f57600080fd5b506104f96119cd565b3480156107b457600080fd5b506104f96119d2565b3480156107c957600080fd5b506104f9611a10565b3480156107de57600080fd5b506103f661ffff60043516611a45565b3480156107fa57600080fd5b506103f6600435602435611b42565b34801561081557600080fd5b5061081e611f42565b6040805197151588529515156020880152868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b34801561086457600080fd5b506104f9611fe5565b34801561087957600080fd5b50610559612040565b34801561088e57600080fd5b506104f9600160a060020a03600435166120a4565b3480156108af57600080fd5b506103f66120bd565b3480156108c457600080fd5b506108cd6120e6565b6040805161ffff9485168152928416602084015292168183015290519081900360600190f35b3480156108ff57600080fd5b506104f96004356121ab565b34801561091757600080fd5b506103f6600160a060020a03600435166121d7565b34801561093857600080fd5b506104ac600160a060020a03600435166122b9565b34801561095957600080fd5b506104f96122bf565b34801561096e57600080fd5b506104f96122f4565b34801561098357600080fd5b5061055961231f565b34801561099857600080fd5b506104f961235d565b3480156109ad57600080fd5b506103f661ffff60043581169060243581169060443516612388565b3480156109d557600080fd5b506103f661ffff6004351661253d565b3480156109f157600080fd5b506104f9600160a060020a03600435166024356125ee565b348015610a1557600080fd5b506103f6600435612694565b348015610a2d57600080fd5b5061040d6126db565b348015610a4257600080fd5b506104f9612712565b348015610a5757600080fd5b506103f6600160a060020a0360043516612747565b348015610a7857600080fd5b5060408051602060046044358181013583810280860185019096528085526104ac958335600160a060020a03169560248035963696956064959394920192918291850190849080828437509497506129879650505050505050565b6104f9600160a060020a0360043516612ad2565b348015610af357600080fd5b506104f9612add565b348015610b0857600080fd5b506104ac600160a060020a0360043516602435612ae2565b348015610b2c57600080fd5b50610559612b7d565b348015610b4157600080fd5b506104f9612c64565b348015610b5657600080fd5b506104f9612c69565b348015610b6b57600080fd5b506104ac600160a060020a0360043516602435612c9e565b348015610b8f57600080fd5b50610559612cab565b348015610ba457600080fd5b50610bad612ce9565b60408051938452602084019290925282820152519081900360600190f35b348015610bd757600080fd5b506103f6612d71565b348015610bec57600080fd5b506104f9612dfb565b348015610c0157600080fd5b50610c0a612e30565b6040805161ffff9092168252519081900360200190f35b348015610c2d57600080fd5b50610559612e6e565b348015610c4257600080fd5b506104f9612e99565b348015610c5757600080fd5b506104f9600160a060020a0360043581169060243516612ea3565b348015610c7e57600080fd5b506104ac612ece565b348015610c9357600080fd5b506103f6600160a060020a0360043581169060243581169060443516612ee1565b348015610cc057600080fd5b506103f6600435612f2c565b348015610cd857600080fd5b506104f961303a565b348015610ced57600080fd5b506103f661306f565b348015610d0257600080fd5b506104f9600160a060020a03600435166024356130b4565b348015610d2657600080fd5b506104f9600160a060020a0360043516613198565b348015610d4757600080fd5b506103f66131a3565b348015610d5c57600080fd5b506104f96131de565b6000610d6f615dee565b600080341515610dc9576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f4445504f5349540000000000000000000000000000000000000000604482015290519081900360640190fd5b60408051600080516020615e1683398151915281529051908190036014019020610df290613242565b9250610dfd83613295565b15610e52576040805160e560020a62461bcd02815260206004820152600e60248201527f5354414b494e475f504155534544000000000000000000000000000000000000604482015290519081900360640190fd5b610e5b836132a0565b15610f0457610e69836132b2565b915034821015610ec3576040805160e560020a62461bcd02815260206004820152600b60248201527f5354414b455f4c494d4954000000000000000000000000000000000000000000604482015290519081900360640190fd5b610f04610ed88434850363ffffffff61333d16565b60408051600080516020615e16833981519152815290519081900360140190209063ffffffff61338116565b610f0d346112bb565b9050801515610f195750345b610f2333826133e0565b50610f7d610f3f34610f3361354b565b9063ffffffff61359816565b604080517f6c69646f2e4c69646f2e62756666657265644574686572000000000000000000815290519081900360170190209063ffffffff61362616565b60408051348152600160a060020a0387166020820152815133927f96a25c8ce0baabc1fdefd93e9ed25d8e092a3332f3aa9a41722b5697231d1d1a928290030190a2610fc9338261362a565b8093505b505050919050565b604080517f524553554d455f524f4c450000000000000000000000000000000000000000008152905190819003600b019020611010906136b6565b611018613773565b61102061384d565b565b60408051808201909152601781527f4c6971756964207374616b656420457468657220322e30000000000000000000602082015290565b604080517f50415553455f524f4c45000000000000000000000000000000000000000000008152905190819003600a019020611094906136b6565b61109c6138b8565b611020613981565b6000806110af61235d565b905080158015906110c75750806110c46139e0565b10155b91505090565b60006110da3384846139e4565b50600192915050565b60408051600080516020615eb68339815191528152905190819003601401902081565b61110e61235d565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156111cf5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561119457818101518382015260200161117c565b50505050905090810190601f1680156111c15780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50604080517f6c69646f2e4c69646f2e6e6f64654f70657261746f72735265676973747279008152905190819003601f019020611212908463ffffffff61362616565b604080517f6c69646f2e4c69646f2e6465706f736974436f6e74726163740000000000000081529051908190036019019020611254908663ffffffff61362616565b61125f848383613b73565b611267613da9565b5050505050565b604080517f6c69646f2e4c69646f2e696e737572616e636546756e64000000000000000000815290519081900360170190206000906112ac90613e6f565b905090565b60006112ac613e73565b6000806112c6613e73565b90508015156112d85760009150611303565b611300816112f46112e7613eb5565b869063ffffffff613ef316565b9063ffffffff613f9e16565b91505b50919050565b60408051600080516020615e16833981519152815290519081900360140190206000906112ac9061133990613242565b613295565b600160a060020a0383166000908152600160209081526040808320338452909152812054828110156113e0576040805160e560020a62461bcd02815260206004820152602160248201527f5452414e534645525f414d4f554e545f455843454544535f414c4c4f57414e4360448201527f4500000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6113eb85858561403e565b6114058533611400848763ffffffff6140f216565b6139e4565b600191505b509392505050565b604080517f6c69646f2e4c69646f2e6e6f64654f70657261746f72735265676973747279008152905190819003601f0190206000906112ac90613e6f565b600061145a612b7d565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156114b557818101518382015260200161149d565b50505050905090810190601f1680156114e25780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050506040513d602081101561152b57600080fd5b505190505b919050565b60408051600080516020615eb68339815191528152905190819003601401902061155e906136b6565b60408051600080516020615e16833981519152815290519081900360140190206115a090610ed8908490849061159390613242565b919063ffffffff61418616565b604080518381526020810183905281517fce9fddf6179affa1ea7bf36d80a6bf0284e0f3b91f4b2fa6eea2af923e7fac2d929181900390910190a15050565b604080517f524553554d455f524f4c450000000000000000000000000000000000000000008152905190819003600b01902081565b601290565b6000611623612e6e565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561165d57600080fd5b505af1158015611671573d6000803e3d6000fd5b505050506040513d602081101561168757600080fd5b5051905090565b604080517f4445504f5349545f524f4c4500000000000000000000000000000000000000008152905190819003600c01902081565b6801bc16d674ec80000081565b604080517f50415553455f524f4c45000000000000000000000000000000000000000000008152905190819003600a01902081565b336000818152600160209081526040808320600160a060020a038716845290915281205490916110da918590611400908663ffffffff61359816565b604080517f6c69646f2e4c69646f2e74726561737572790000000000000000000000000000815290519081900360120190206000906112ac90613e6f565b60408051600080516020615e56833981519152815290519081900360180190206000906117ab90613e6f565b15905090565b604080517f4d414e4147455f5749544844524157414c5f4b455900000000000000000000008152905190819003601501902081565b60006112ac61354b565b604080517f6c69646f2e4c69646f2e657865637574696f6e4c61796572526577617264735681527f61756c74000000000000000000000000000000000000000000000000000000006020820152905190819003602401902061185190613e6f565b600160a060020a0316331461186557600080fd5b604080517f6c69646f2e4c69646f2e746f74616c454c52657761726473436f6c6c6563746581527f640000000000000000000000000000000000000000000000000000000000000060208201529051908190036021019020611934906118d0903490610f3390613e6f565b604080517f6c69646f2e4c69646f2e746f74616c454c52657761726473436f6c6c6563746581527f6400000000000000000000000000000000000000000000000000000000000000602082015290519081900360210190209063ffffffff61362616565b6040805134815290517fd27f9b0c98bdee27044afa149eadcd2047d6399cb6613a45c5b87e6aca76e6b59181900360200190a1565b604080517f6c69646f2e4c69646f2e454c526577617264735769746864726177616c4c696d81527f6974000000000000000000000000000000000000000000000000000000000000602082015290519081900360220190206000906112ac90613e6f565b606081565b604080517f6c69646f2e4c69646f2e7769746864726177616c43726564656e7469616c73008152905190819003601f0190206000906112ac90613e6f565b60408051600080516020615e16833981519152815290519081900360140190206000906112ac90611a4090613242565b61439e565b604080517f5345545f454c5f524557415244535f5749544844524157414c5f4c494d49545f81527f524f4c450000000000000000000000000000000000000000000000000000000060208201529051908190036024019020611aa6906136b6565b604080517f6c69646f2e4c69646f2e454c526577617264735769746864726177616c4c696d81527f697400000000000000000000000000000000000000000000000000000000000060208201529051908190036022019020611b0890826143d7565b6040805161ffff8316815290517f166eb213129ab51688433b859b5a206403ee174774a1430f8ffb83af316161f69181900360200190a150565b6000806000806000806000611b7d6040518080600080516020615e568339815191528152506018019050604051809103902060001916613e6f565b1515611bc1576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b611bc961231f565b600160a060020a03163314611c28576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b60408051600080516020615e768339815191528152905190819003601d019020611c5190613e6f565b965086891115611cab576040805160e560020a62461bcd02815260206004820152601760248201527f5245504f525445445f4d4f52455f4445504f5349544544000000000000000000604482015290519081900360640190fd5b60408051600080516020615ed68339815191528152905190819003601a019020611cd490613e6f565b955085891015611d2e576040805160e560020a62461bcd02815260206004820152601860248201527f5245504f525445445f4c4553535f56414c494441544f52530000000000000000604482015290519081900360640190fd5b611d3e898763ffffffff6140f216565b60408051600080516020615e3683398151915281529051908190036017019020909550611d8790611d6e90613e6f565b610f33876801bc16d674ec80000063ffffffff613ef316565b60408051600080516020615e3683398151915281529051908190036017019020909450611dba908963ffffffff61362616565b60408051600080516020615ed68339815191528152905190819003601a019020611dea908a63ffffffff61362616565b611df2612040565b9150600160a060020a03821615611f0557604080517f6c69646f2e4c69646f2e454c526577617264735769746864726177616c4c696d81527f697400000000000000000000000000000000000000000000000000000000000060208201529051908190036022019020600160a060020a03831690639342c8f49061271090611e7990613e6f565b611e81613e73565b02811515611e8b57fe5b046040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611ec257600080fd5b505af1158015611ed6573d6000803e3d6000fd5b505050506040513d6020811015611eec57600080fd5b505192508215611f0557611f05610f3f84610f3361354b565b83881115611f3757611f1d888563ffffffff6140f216565b9050611f37611f32828563ffffffff61359816565b614449565b505050505050505050565b6000806000806000806000611f55615dee565b60408051600080516020615e1683398151915281529051908190036014019020611f7e90613242565b9050611f8981613295565b9750611f94816132a0565b9650611f9f8161439e565b955080606001516001606060020a03169450806040015163ffffffff16935080602001516001606060020a03169250806000015163ffffffff1691505090919293949596565b604080517f5345545f454c5f524557415244535f5749544844524157414c5f4c494d49545f81527f524f4c45000000000000000000000000000000000000000000000000000000006020820152905190819003602401902081565b604080517f6c69646f2e4c69646f2e657865637574696f6e4c61796572526577617264735681527f61756c7400000000000000000000000000000000000000000000000000000000602082015290519081900360240190206000906112ac90613e6f565b60006120b76120b283614578565b6121ab565b92915050565b60408051600080516020615eb683398151915281529051908190036014019020611018906136b6565b604080517f6c69646f2e4c69646f2e74726561737572794665650000000000000000000000815290519081900360150190206000908190819061212890613e6f565b604080517f6c69646f2e4c69646f2e696e737572616e6365466565000000000000000000008152905190819003601601902090935061216690613e6f565b604080517f6c69646f2e4c69646f2e6e6f64654f70657261746f72734665650000000000008152905190819003601a0190209092506121a490613e6f565b9050909192565b6000806121b6613eb5565b90508015156121c85760009150611303565b611300816112f46112e7613e73565b604080517f5345545f454c5f524557415244535f5641554c545f524f4c450000000000000081529051908190036019019020612212906136b6565b604080517f6c69646f2e4c69646f2e657865637574696f6e4c61796572526577617264735681527f61756c74000000000000000000000000000000000000000000000000000000006020820152905190819003602401902061227a908263ffffffff61362616565b60408051600160a060020a038316815290517f8e2d01c4cfaa88fa4d772d37e4d068deda4342bf4ef6dc4b0cf3e868be5ebb409181900360200190a150565b50600190565b604080517f4d414e4147455f50524f544f434f4c5f434f4e5452414354535f524f4c4500008152905190819003601e01902081565b60006112ac7fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b613e6f565b604080517f6c69646f2e4c69646f2e6f7261636c6500000000000000000000000000000000815290519081900360100190206000906112ac90613e6f565b60006112ac7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e613e6f565b604080517f4d414e4147455f464545000000000000000000000000000000000000000000008152905190819003600a0190206123c3906136b6565b6123e68161ffff16610f338461ffff168661ffff1661359890919063ffffffff16565b6127101461243e576040805160e560020a62461bcd02815260206004820152601060248201527f464545535f444f4e545f4144445f555000000000000000000000000000000000604482015290519081900360640190fd5b604080517f6c69646f2e4c69646f2e747265617375727946656500000000000000000000008152905190819003601501902061247a90846143d7565b604080517f6c69646f2e4c69646f2e696e737572616e636546656500000000000000000000815290519081900360160190206124b690836143d7565b604080517f6c69646f2e4c69646f2e6e6f64654f70657261746f72734665650000000000008152905190819003601a0190206124f290826143d7565b6040805161ffff8086168252808516602083015283168183015290517f034529db1bba3830b8877e116871f19c5b96ef86c739f2a05668c860c84668989181900360600190a1505050565b604080517f4d414e4147455f464545000000000000000000000000000000000000000000008152905190819003600a019020612578906136b6565b604080517f6c69646f2e4c69646f2e666565000000000000000000000000000000000000008152905190819003600d0190206125b490826143d7565b6040805161ffff8316815290517faab062e3faf62b6c9a0f8e62af66e0310e27127a8c871a67be7dd4d93de6da539181900360200190a150565b6000806125fc338585614593565b604080518481529051600160a060020a0386169133917f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb9181900360200190a3612645836121ab565b604080518281529051919250600160a060020a0386169133917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a38091505b5092915050565b604080517f4445504f5349545f524f4c4500000000000000000000000000000000000000008152905190819003600c0190206126cf906136b6565b6126d88161479c565b50565b60408051808201909152600581527f7374455448000000000000000000000000000000000000000000000000000000602082015290565b604080517f4d414e4147455f464545000000000000000000000000000000000000000000008152905190819003600a01902081565b6000806000612755846122b9565b15156127ab576040805160e560020a62461bcd02815260206004820152601260248201527f5245434f5645525f444953414c4c4f5745440000000000000000000000000000604482015290519081900360640190fd5b6127b3611619565b9250600160a060020a0383161515612815576040805160e560020a62461bcd02815260206004820152601260248201527f5245434f5645525f5641554c545f5a45524f0000000000000000000000000000604482015290519081900360640190fd5b600160a060020a03841615156128a95761282d614884565b915082600160a060020a03168260405160006040518083038185875af19250505015156128a4576040805160e560020a62461bcd02815260206004820152601760248201527f5245434f5645525f5452414e534645525f4641494c4544000000000000000000604482015290519081900360640190fd5b612936565b50826128c4600160a060020a0382163063ffffffff61489f16565b91506128e0600160a060020a038216848463ffffffff6149b416565b1515612936576040805160e560020a62461bcd02815260206004820152601d60248201527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c4544000000604482015290519081900360640190fd5b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b6000806129926110a4565b15156129a1576000915061140a565b6129a9612e6e565b9050600160a060020a03811615156129c4576000915061140a565b80600160a060020a031663fdef91068630876129df88614a36565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015612a4e578181015183820152602001612a36565b50505050905090810190601f168015612a7b5780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015612a9d57600080fd5b505af1158015612ab1573d6000803e3d6000fd5b505050506040513d6020811015612ac757600080fd5b505195945050505050565b60006120b782610d65565b602081565b336000908152600160209081526040808320600160a060020a038616845290915281205482811015612b5e576040805160e560020a62461bcd02815260206004820152601e60248201527f4445435245415345445f414c4c4f57414e43455f42454c4f575f5a45524f0000604482015290519081900360640190fd5b612b733385611400848763ffffffff6140f216565b5060019392505050565b600080612b88612e6e565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b158015612c3257600080fd5b505af1158015612c46573d6000803e3d6000fd5b505050506040513d6020811015612c5c57600080fd5b505192915050565b603081565b604080517f5345545f454c5f524557415244535f5641554c545f524f4c45000000000000008152905190819003601901902081565b60006110da33848461403e565b604080517f6c69646f2e4c69646f2e6465706f736974436f6e747261637400000000000000815290519081900360190190206000906112ac90613e6f565b60408051600080516020615e768339815191528152905190819003601d01902060009081908190612d1990613e6f565b60408051600080516020615ed68339815191528152905190819003601a019020909350612d4590613e6f565b60408051600080516020615e36833981519152815290519081900360170190209092506121a490613e6f565b60408051600080516020615eb683398151915281529051908190036014019020612d9a906136b6565b60408051600080516020615e1683398151915281529051908190036014019020612dd090610ed890612dcb90613242565b614a40565b6040517f9b2a687c198898fcc32a33bbc610d478f177a73ab7352023e6cc1de5bf12a3df90600090a1565b604080517f4255524e5f524f4c4500000000000000000000000000000000000000000000008152905190819003600901902081565b604080517f6c69646f2e4c69646f2e666565000000000000000000000000000000000000008152905190819003600d0190206000906112ac90613e6f565b60006112ac7f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b613e6f565b60006112ac613eb5565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b6000600019612edb61235d565b14905090565b604080517f4d414e4147455f50524f544f434f4c5f434f4e5452414354535f524f4c4500008152905190819003601e019020612f1c906136b6565b612f27838383613b73565b505050565b604080517f4d414e4147455f5749544844524157414c5f4b4559000000000000000000000081529051908190036015019020612f67906136b6565b604080517f6c69646f2e4c69646f2e7769746864726177616c43726564656e7469616c73008152905190819003601f019020612fa9908263ffffffff61362616565b612fb1611412565b600160a060020a031663f778021e6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612feb57600080fd5b505af1158015612fff573d6000803e3d6000fd5b50506040805184815290517f13eb80e900aa05a2696d50d5de33ef631c73493c4921da233b17335ff6b7b1149350908190036020019150a150565b604080517f5354414b494e475f50415553455f524f4c4500000000000000000000000000008152905190819003601201902081565b604080517f4445504f5349545f524f4c4500000000000000000000000000000000000000008152905190819003600c0190206130aa906136b6565b611020609661479c565b604080517f4255524e5f524f4c450000000000000000000000000000000000000000000000815290519081900360090190206000906130f38484614a53565b6130fe338383612987565b60408051808201909152600f81527f4150505f415554485f4641494c4544000000000000000000000000000000000060208201529015156131845760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b5061318f8585614a6f565b95945050505050565b60006120b782614578565b604080517f5354414b494e475f50415553455f524f4c4500000000000000000000000000008152905190819003601201902061109c906136b6565b604080517f6c69646f2e4c69646f2e746f74616c454c52657761726473436f6c6c6563746581527f6400000000000000000000000000000000000000000000000000000000000000602082015290519081900360210190206000906112ac90613e6f565b61324a615dee565b600061325583613e6f565b63ffffffff600082901c811684526001606060020a03602083811c821690860152608083901c909116604085015260a09190911c16606083015250919050565b5163ffffffff161590565b606001516001606060020a0316151590565b6040810151600090819063ffffffff16156132f657826040015163ffffffff1683606001516001606060020a03168115156132e957fe5b046001606060020a031690505b80836000015163ffffffff1643030283602001516001606060020a031601915082606001516001606060020a0316821115611303575050606001516001606060020a031690565b613345615dee565b6001606060020a0382111561335657fe5b825163ffffffff16151561336657fe5b506001606060020a031660208201524363ffffffff16815290565b6133dc60a082606001516001606060020a0316901b6080836040015163ffffffff16901b602084602001516001606060020a0316901b6000856000015163ffffffff16901b171717836000191661362690919063ffffffff16565b5050565b60408051600080516020615e568339815191528152905190819003601801902060009061340c90613e6f565b1515613450576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b600160a060020a03831615156134b0576040805160e560020a62461bcd02815260206004820152601860248201527f4d494e545f544f5f5448455f5a45524f5f414444524553530000000000000000604482015290519081900360640190fd5b6134bc82610f33613eb5565b604080517f6c69646f2e53744554482e746f74616c5368617265730000000000000000000081529051908190036016019020909150613501908263ffffffff61362616565b600160a060020a03831660009081526020819052604090205461352a908363ffffffff61359816565b600160a060020a039093166000908152602081905260409020929092555090565b604080517f6c69646f2e4c69646f2e6275666665726564457468657200000000000000000081529051908190036017019020600090819061358b90613e6f565b9050303181111561153057fe5b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f570000000000000000000000000000006020820152600090838301908482101561140a5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b9055565b600160a060020a03821660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef613660846121ab565b60408051918252519081900360200190a3604080518281529051600160a060020a038416916000917f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb9181900360200190a35050565b806136ed338260006040519080825280602002602001820160405280156136e7578160200160208202803883390190505b50612987565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515612f275760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b60408051600080516020615e568339815191528152905190819003601801902061379c90613e6f565b156137f1576040805160e560020a62461bcd02815260206004820152601260248201527f434f4e54524143545f49535f4143544956450000000000000000000000000000604482015290519081900360640190fd5b60408051600080516020615e568339815191528152905190819003601801902061382290600163ffffffff61362616565b6040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f990600090a1565b60408051600080516020615e168339815191528152905190819003601401902061388d90610ed89060009061388190613242565b9063ffffffff614c9d16565b6040517fedaeeae9aed70c4545d3ab0065713261c9cee8d6cf5c8b07f52f0a65fd91efda90600090a1565b60408051600080516020615e56833981519152815290519081900360180190206138e190613e6f565b1515613925576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b60408051600080516020615e568339815191528152905190819003601801902061395690600063ffffffff61362616565b6040517f7acc84e34091ae817647a4c49116f5cc07f319078ba80f8f5fde37ea7e25cbd690600090a1565b60408051600080516020615e16833981519152815290519081900360140190206139b590610ed89060019061388190613242565b6040517f26d1807b479eaba249c1214b82e4b65bbb0cc73ee8a17901324b1ef1b5904e4990600090a1565b4390565b60408051600080516020615e5683398151915281529051908190036018019020613a0d90613e6f565b1515613a51576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b600160a060020a0383161515613ab1576040805160e560020a62461bcd02815260206004820152601960248201527f415050524f56455f46524f4d5f5a45524f5f4144445245535300000000000000604482015290519081900360640190fd5b600160a060020a0382161515613b11576040805160e560020a62461bcd02815260206004820152601760248201527f415050524f56455f544f5f5a45524f5f41444452455353000000000000000000604482015290519081900360640190fd5b600160a060020a03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600160a060020a0383161515613bd3576040805160e560020a62461bcd02815260206004820152601360248201527f4f5241434c455f5a45524f5f4144445245535300000000000000000000000000604482015290519081900360640190fd5b600160a060020a0382161515613c33576040805160e560020a62461bcd02815260206004820152601560248201527f54524541535552595f5a45524f5f414444524553530000000000000000000000604482015290519081900360640190fd5b600160a060020a0381161515613c93576040805160e560020a62461bcd02815260206004820152601b60248201527f494e535552414e43455f46554e445f5a45524f5f414444524553530000000000604482015290519081900360640190fd5b604080517f6c69646f2e4c69646f2e6f7261636c650000000000000000000000000000000081529051908190036010019020613cd5908463ffffffff61362616565b604080517f6c69646f2e4c69646f2e7472656173757279000000000000000000000000000081529051908190036012019020613d17908363ffffffff61362616565b604080517f6c69646f2e4c69646f2e696e737572616e636546756e6400000000000000000081529051908190036017019020613d59908263ffffffff61362616565b60408051600160a060020a038086168252808516602083015283168183015290517f7df55cbe17c0cf85c9c23753c046f686eeb4c6b2ce13182943d215e92afc565a9181900360600190a1505050565b613db161235d565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015613e365760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b50611020613e426139e0565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61362616565b5490565b60006112ac613e80614cc2565b60408051600080516020615e3683398151915281529051908190036017019020610f3390613ead90613e6f565b610f3361354b565b604080517f6c69646f2e53744554482e746f74616c53686172657300000000000000000000815290519081900360160190206000906112ac90613e6f565b600080831515613f06576000915061268d565b50828202828482811515613f1657fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f570000000000000000000000000000006020820152929190041461140a5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b60408051808201909152600d81527f4d4154485f4449565f5a45524f00000000000000000000000000000000000000602082015260009081908184116140295760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b50828481151561403557fe5b04949350505050565b6000614049826112bb565b9050614056848483614593565b82600160a060020a031684600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a382600160a060020a031684600160a060020a03167f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb836040518082815260200191505060405180910390a350505050565b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f570000000000000000000000000000602082015260009081908484111561417e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b505050900390565b61418e615dee565b8215156141e5576040805160e560020a62461bcd02815260206004820152601460248201527f5a45524f5f4d41585f5354414b455f4c494d4954000000000000000000000000604482015290519081900360640190fd5b6001606060020a03831115614244576040805160e560020a62461bcd02815260206004820152601960248201527f544f4f5f4c415247455f4d41585f5354414b455f4c494d495400000000000000604482015290519081900360640190fd5b8183101561429c576040805160e560020a62461bcd02815260206004820152601860248201527f544f4f5f4c415247455f4c494d49545f494e4352454153450000000000000000604482015290519081900360640190fd5b8115806142b8575063ffffffff82848115156142b457fe5b0411155b151561430e576040805160e560020a62461bcd02815260206004820152601860248201527f544f4f5f534d414c4c5f4c494d49545f494e4352454153450000000000000000604482015290519081900360640190fd5b60608401516001606060020a03161580614334575083602001516001606060020a031683105b15614349576001606060020a03831660208501525b811515614357576000614364565b818381151561436257fe5b045b63ffffffff90811660408601526001606060020a0384166060860152845116156143925763ffffffff431684525b509192915050565b5490565b60006143a982613295565b156143b657506000611530565b6143bf826132a0565b15156143ce5750600019611530565b6120b7826132b2565b61271061ffff82161115614435576040805160e560020a62461bcd02815260206004820152601660248201527f56414c55455f4f5645525f3130305f50455243454e5400000000000000000000604482015290519081900360640190fd5b6133dc8261ffff831663ffffffff61362616565b600080600080600080600080600061445f612e30565b61ffff1698506144bc6144a161447b8b8d63ffffffff613ef316565b614495612710614489613e73565b9063ffffffff613ef316565b9063ffffffff6140f216565b6112f46144ac613eb5565b6144898e8e63ffffffff613ef316565b97506144c830896133e0565b506144d16120e6565b90985096506144f290506127106112f48a61ffff8b1663ffffffff613ef316565b94506144fc61126e565b9350614509308587614593565b614513848661362a565b6145356145306127106112f48b61ffff8b1663ffffffff613ef316565b614d4e565b925061454b836144958a8863ffffffff6140f216565b9150614555611741565b9050614562308284614593565b61456c818361362a565b50505050505050505050565b600160a060020a031660009081526020819052604090205490565b60408051600080516020615e56833981519152815290519081900360180190206000906145bf90613e6f565b1515614603576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b600160a060020a0384161515614663576040805160e560020a62461bcd02815260206004820152601e60248201527f5452414e534645525f46524f4d5f5448455f5a45524f5f414444524553530000604482015290519081900360640190fd5b600160a060020a03831615156146c3576040805160e560020a62461bcd02815260206004820152601c60248201527f5452414e534645525f544f5f5448455f5a45524f5f4144445245535300000000604482015290519081900360640190fd5b50600160a060020a03831660009081526020819052604090205480821115614735576040805160e560020a62461bcd02815260206004820152601f60248201527f5452414e534645525f414d4f554e545f455843454544535f42414c414e434500604482015290519081900360640190fd5b614745818363ffffffff6140f216565b600160a060020a03808616600090815260208190526040808220939093559085168152205461477a908363ffffffff61359816565b600160a060020a03909316600090815260208190526040902092909255505050565b60408051600080516020615e5683398151915281529051908190036018019020600090819081906147cc90613e6f565b1515614810576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b61481861354b565b92506801bc16d674ec800000831061487e57614832614884565b915061484d836801bc16d674ec80000063ffffffff613f9e16565b905061486e6148698583106148625785614864565b825b614f3f565b6152be565b81614877614884565b1461487e57fe5b50505050565b60006112ac61489161354b565b30319063ffffffff6140f216565b60408051600160a060020a0383166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a0823100000000000000000000000000000000000000000000000000000000179052600090818061491f8684615339565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f524556455254454400000000602082015291935091508215156149aa5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b5095945050505050565b60408051600160a060020a038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905260009061318f858261536a565b8051602002815290565b614a48615dee565b506000606082015290565b6060614a6883600160a060020a0316836153b8565b9392505050565b60408051600080516020615e5683398151915281529051908190036018019020600090819081908190614aa190613e6f565b1515614ae5576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b600160a060020a0386161515614b45576040805160e560020a62461bcd02815260206004820152601a60248201527f4255524e5f46524f4d5f5448455f5a45524f5f41444452455353000000000000604482015290519081900360640190fd5b600160a060020a038616600090815260208190526040902054925082851115614bb8576040805160e560020a62461bcd02815260206004820152601b60248201527f4255524e5f414d4f554e545f455843454544535f42414c414e43450000000000604482015290519081900360640190fd5b614bc1856121ab565b9150614bcf85614495613eb5565b604080517f6c69646f2e53744554482e746f74616c5368617265730000000000000000000081529051908190036016019020909450614c14908563ffffffff61362616565b614c24838663ffffffff6140f216565b600160a060020a038716600090815260208190526040902055614c46856121ab565b60408051848152602081018390528082018890529051919250600160a060020a038816917f8b2a1e1ad5e0578c3dd82494156e985dade827a87c573b5c1c7716a32162ad649181900360600190a250505092915050565b614ca5615dee565b81614cb05743614cb3565b60005b63ffffffff1683525090919050565b60408051600080516020615e768339815191528152905190819003601d01902060009081908190614cf290613e6f565b60408051600080516020615ed68339815191528152905190819003601a019020909250614d1e90613e6f565b905080821015614d2a57fe5b614d476801bc16d674ec800000614489848463ffffffff6140f216565b9250505090565b60006060806000614d5d611412565b600160a060020a03166362dcfda1866040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015614da257600080fd5b505af1158015614db6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015614ddf57600080fd5b810190808051640100000000811115614df757600080fd5b82016020810184811115614e0a57600080fd5b8151856020820283011164010000000082111715614e2757600080fd5b50509291906020018051640100000000811115614e4357600080fd5b82016020810184811115614e5657600080fd5b8151856020820283011164010000000082111715614e7357600080fd5b50509291905050509250925081518351141515614e8c57fe5b5060009250825b8251811015610fcd57614ed5308483815181101515614eae57fe5b906020019060200201518484815181101515614ec657fe5b90602001906020020151614593565b614f0d8382815181101515614ee657fe5b906020019060200201518383815181101515614efe57fe5b9060200190602002015161362a565b614f358282815181101515614f1e57fe5b60209081029091010151859063ffffffff61359816565b9350600101614e93565b6000606080600080606080614f52611412565b600160a060020a03166341bc716f896040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015614f9757600080fd5b505af1158015614fab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015614fd457600080fd5b810190808051640100000000811115614fec57600080fd5b82016020810184811115614fff57600080fd5b815164010000000081118282018710171561501957600080fd5b5050929190602001805164010000000081111561503557600080fd5b8201602081018481111561504857600080fd5b815164010000000081118282018710171561506257600080fd5b50508451949a5098505050901515905061507f57600096506152b3565b855161509290603063ffffffff61541316565b1561510d576040805160e560020a62461bcd02815260206004820152602160248201527f52454749535452595f494e434f4e53495354454e545f5055424b4559535f4c4560448201527f4e00000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b845161512090606063ffffffff61541316565b15615175576040805160e560020a62461bcd02815260206004820152601d60248201527f52454749535452595f494e434f4e53495354454e545f5349475f4c454e000000604482015290519081900360640190fd5b855161518890603063ffffffff613f9e16565b855190945061519e90606063ffffffff613f9e16565b84146151f4576040805160e560020a62461bcd02815260206004820152601f60248201527f52454749535452595f494e434f4e53495354454e545f5349475f434f554e5400604482015290519081900360640190fd5b600092505b8383101561523857615210866030850260306154b0565b9150615221856060850260606154b0565b905061522d8282615531565b8260010192506151f9565b60408051600080516020615e768339815191528152905190819003601d0190206152979061526b908690610f3390613e6f565b60408051600080516020615e768339815191528152905190819003601d0190209063ffffffff61362616565b6152b0846801bc16d674ec80000063ffffffff613ef316565b96505b505050505050919050565b604080517f6c69646f2e4c69646f2e627566666572656445746865720000000000000000008152905190819003601701902061530390610f3f90839061449590613e6f565b6040805182815290517f76a397bea5768d4fca97ef47792796e35f98dc81b16c1de84e28a818e1f971089181900360200190a150565b6000806000806040516020818751602089018a5afa9250600083111561535e57805191505b50909590945092505050565b6000806040516020818551602087016000895af160008111156153ae573d801561539b57602081146153a4576153ac565b600193506153ac565b600183511493505b505b5090949350505050565b6040805160028082526060808301845292602083019080388339019050509050828160008151811015156153e857fe5b60209081029091010152805182908290600190811061540357fe5b6020908102909101015292915050565b60408051808201909152600d81527f4d4154485f4449565f5a45524f00000000000000000000000000000000000000602082015260009082151561549c5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b5081838115156154a857fe5b069392505050565b6060808284018551101515156154c557600080fd5b821580156154de57604051915060208201604052615528565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156155175780518352602092830192016154ff565b5050858452601f01601f1916604052505b50949350505050565b60008060008060008060006155446119d2565b965086151561559d576040805160e560020a62461bcd02815260206004820152601c60248201527f454d5054595f5749544844524157414c5f43524544454e5449414c5300000000604482015290519081900360640190fd5b6801bc16d674ec80000095506155bd86633b9aca0063ffffffff613f9e16565b9450856155d486633b9aca0063ffffffff613ef316565b146155db57fe5b60026155e68a615cab565b6040518082805190602001908083835b602083106156155780518252601f1990920191602091820191016155f6565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015615656573d6000803e3d6000fd5b5050506040513d602081101561566b57600080fd5b5051935060028061567f8a600060406154b0565b6040518082805190602001908083835b602083106156ae5780518252601f19909201916020918201910161568f565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af11580156156ef573d6000803e3d6000fd5b5050506040513d602081101561570457600080fd5b5051600261572c6157278c604061572260608263ffffffff6140f216565b6154b0565b615cab565b6040518082805190602001908083835b6020831061575b5780518252601f19909201916020918201910161573c565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af115801561579c573d6000803e3d6000fd5b5050506040513d60208110156157b157600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b602083106158075780518252601f1990920191602091820191016157e8565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015615848573d6000803e3d6000fd5b5050506040513d602081101561585d57600080fd5b50516040805160208181018890528183018b905282518083038401815260609092019283905281519396506002938493918291908401908083835b602083106158b75780518252601f199092019160209182019101615898565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af11580156158f8573d6000803e3d6000fd5b5050506040513d602081101561590d57600080fd5b5051600261591a88615d3b565b60408051602080820193909352808201899052815180820383018152606090910191829052805190928291908401908083835b6020831061596c5780518252601f19909201916020918201910161594d565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af11580156159ad573d6000803e3d6000fd5b5050506040513d60208110156159c257600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310615a185780518252601f1990920191602091820191016159f9565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015615a59573d6000803e3d6000fd5b5050506040513d6020811015615a6e57600080fd5b50519150615a8330318763ffffffff6140f216565b9050615a8d612cab565b600160a060020a03166322895118878b8a6040516020018082600019166000191681526020019150506040516020818303038152906040528c876040518663ffffffff1660e01b8152600401808060200180602001806020018560001916600019168152602001848103845288818151815260200191508051906020019080838360005b83811015615b29578181015183820152602001615b11565b50505050905090810190601f168015615b565780820380516001836020036101000a031916815260200191505b50848103835287518152875160209182019189019080838360005b83811015615b89578181015183820152602001615b71565b50505050905090810190601f168015615bb65780820380516001836020036101000a031916815260200191505b50848103825286518152865160209182019188019080838360005b83811015615be9578181015183820152602001615bd1565b50505050905090810190601f168015615c165780820380516001836020036101000a031916815260200191505b509750505050505050506000604051808303818588803b158015615c3957600080fd5b505af1158015615c4d573d6000803e3d6000fd5b50505050303182149050611f37576040805160e560020a62461bcd02815260206004820152601b60248201527f455850454354494e475f4445504f5349545f544f5f48415050454e0000000000604482015290519081900360640190fd5b6060806020835110158015615cc257506040835111155b1515615cca57fe5b825160401415615cdc57829150611303565b604080516020808252818301909252908082016104008038833901905050905060006020820152825160201415615d17576113008382615d73565b61130083615d36836000615722885160406140f290919063ffffffff16565b615d73565b600081815b6008811015615d6157600892831b60ff831617929190911c90600101615d40565b8115615d6957fe5b505060c01b919050565b6060806040519050835180825260208201818101602087015b81831015615da4578051835260209283019201615d8c565b50855184518101855292509050808201602086015b81831015615dd1578051835260209283019201615db9565b509551919091011594909401601f01601f19166040529392505050565b6040805160808101825260008082526020820181905291810182905260608101919091529056006c69646f2e4c69646f2e7374616b654c696d69740000000000000000000000006c69646f2e4c69646f2e626561636f6e42616c616e63650000000000000000006c69646f2e5061757361626c652e616374697665466c616700000000000000006c69646f2e4c69646f2e6465706f736974656456616c696461746f7273000000434f4e54524143545f49535f53544f50504544000000000000000000000000005354414b494e475f434f4e54524f4c5f524f4c450000000000000000000000006c69646f2e4c69646f2e626561636f6e56616c696461746f7273000000000000a165627a7a72305820867169b33ec290e89306c6decc0cd36d3cdb1bcb3e523992dceb5e117c92b8a90029ebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e
Deployed Bytecode
0x60806040526004361061037e5760003560e01c63ffffffff168063046f7da2146103e157806306fdde03146103f857806307da68f5146104825780630803fac014610497578063095ea7b3146104c0578063136dd43c146104e45780631459457a1461050b578063158626f71461054457806318160ddd14610575578063192084511461058a5780631ea7ca89146105a257806323b872dd146105b757806327a099d8146105e15780632914b9bd146105f65780632cb5f7841461064f5780632de03aa11461066a578063313ce5671461067f57806332f0a3b5146106aa578063353efdcf146106bf57806336bf3325146106d457806337cfdaca14610575578063389ed267146106e957806339509351146106fe5780633b19e84a146107225780633f683b6a14610737578063435721da1461074c57806347b714e0146107615780634ad509b21461077657806352b3af931461077e578063540bc5ea1461079357806356396715146107a8578063609c4c6c146107bd57806363c2eb53146107d257806364f9991a146107ee578063665b4b0b146108095780636bb98ad314610858578063706aa30d1461086d57806370a08231146108825780637475f913146108a3578063752f77f1146108b85780637a28fb88146108f35780637e4193c61461090b5780637e7db6e11461092c5780637f6fdac71461094d57806380afdea814610962578063833b1fce146109775780638b3dd7491461098c5780638cef3612146109a15780638e005553146109c95780638fcb4e5b146109e557806390adc83b14610a0957806395d89b4114610a215780639aaa2d1514610a365780639d4941d814610a4b578063a1658fad14610a6c578063a1903eab14610ad3578063a30448c014610ae7578063a457c2d714610afc578063a479e50814610b20578063a4d55d1d14610b35578063a6426f5f14610b4a578063a9059cbb14610b5f578063ab94276a14610b83578063ae2e353814610b98578063b3320d9a14610bcb578063b930908f14610be0578063ced72f8714610bf5578063d4aae0c414610c21578063d5002f2e14610c36578063dd62ed3e14610c4b578063de4796ed14610c72578063e73f452914610c87578063e97ee8cc14610cb4578063eb85262f14610ccc578063ecc1dcfb14610ce1578063ee7a7c0414610cf6578063f5eb42dc14610d1a578063f999c50614610d3b578063fa64ebac14610d50575b36156103d4576040805160e560020a62461bcd02815260206004820152600e60248201527f4e4f4e5f454d5054595f44415441000000000000000000000000000000000000604482015290519081900360640190fd5b6103de6000610d65565b50005b3480156103ed57600080fd5b506103f6610fd5565b005b34801561040457600080fd5b5061040d611022565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561044757818101518382015260200161042f565b50505050905090810190601f1680156104745780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561048e57600080fd5b506103f6611059565b3480156104a357600080fd5b506104ac6110a4565b604080519115158252519081900360200190f35b3480156104cc57600080fd5b506104ac600160a060020a03600435166024356110cd565b3480156104f057600080fd5b506104f96110e3565b60408051918252519081900360200190f35b34801561051757600080fd5b506103f6600160a060020a0360043581169060243581169060443581169060643581169060843516611106565b34801561055057600080fd5b5061055961126e565b60408051600160a060020a039092168252519081900360200190f35b34801561058157600080fd5b506104f96112b1565b34801561059657600080fd5b506104f96004356112bb565b3480156105ae57600080fd5b506104ac611309565b3480156105c357600080fd5b506104ac600160a060020a036004358116906024351660443561133e565b3480156105ed57600080fd5b50610559611412565b34801561060257600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526105599436949293602493928401919081908401838280828437509497506114509650505050505050565b34801561065b57600080fd5b506103f6600435602435611535565b34801561067657600080fd5b506104f96115df565b34801561068b57600080fd5b50610694611614565b6040805160ff9092168252519081900360200190f35b3480156106b657600080fd5b50610559611619565b3480156106cb57600080fd5b506104f961168e565b3480156106e057600080fd5b506104f96116c3565b3480156106f557600080fd5b506104f96116d0565b34801561070a57600080fd5b506104ac600160a060020a0360043516602435611705565b34801561072e57600080fd5b50610559611741565b34801561074357600080fd5b506104ac61177f565b34801561075857600080fd5b506104f96117b1565b34801561076d57600080fd5b506104f96117e6565b6103f66117f0565b34801561078a57600080fd5b506104f9611969565b34801561079f57600080fd5b506104f96119cd565b3480156107b457600080fd5b506104f96119d2565b3480156107c957600080fd5b506104f9611a10565b3480156107de57600080fd5b506103f661ffff60043516611a45565b3480156107fa57600080fd5b506103f6600435602435611b42565b34801561081557600080fd5b5061081e611f42565b6040805197151588529515156020880152868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b34801561086457600080fd5b506104f9611fe5565b34801561087957600080fd5b50610559612040565b34801561088e57600080fd5b506104f9600160a060020a03600435166120a4565b3480156108af57600080fd5b506103f66120bd565b3480156108c457600080fd5b506108cd6120e6565b6040805161ffff9485168152928416602084015292168183015290519081900360600190f35b3480156108ff57600080fd5b506104f96004356121ab565b34801561091757600080fd5b506103f6600160a060020a03600435166121d7565b34801561093857600080fd5b506104ac600160a060020a03600435166122b9565b34801561095957600080fd5b506104f96122bf565b34801561096e57600080fd5b506104f96122f4565b34801561098357600080fd5b5061055961231f565b34801561099857600080fd5b506104f961235d565b3480156109ad57600080fd5b506103f661ffff60043581169060243581169060443516612388565b3480156109d557600080fd5b506103f661ffff6004351661253d565b3480156109f157600080fd5b506104f9600160a060020a03600435166024356125ee565b348015610a1557600080fd5b506103f6600435612694565b348015610a2d57600080fd5b5061040d6126db565b348015610a4257600080fd5b506104f9612712565b348015610a5757600080fd5b506103f6600160a060020a0360043516612747565b348015610a7857600080fd5b5060408051602060046044358181013583810280860185019096528085526104ac958335600160a060020a03169560248035963696956064959394920192918291850190849080828437509497506129879650505050505050565b6104f9600160a060020a0360043516612ad2565b348015610af357600080fd5b506104f9612add565b348015610b0857600080fd5b506104ac600160a060020a0360043516602435612ae2565b348015610b2c57600080fd5b50610559612b7d565b348015610b4157600080fd5b506104f9612c64565b348015610b5657600080fd5b506104f9612c69565b348015610b6b57600080fd5b506104ac600160a060020a0360043516602435612c9e565b348015610b8f57600080fd5b50610559612cab565b348015610ba457600080fd5b50610bad612ce9565b60408051938452602084019290925282820152519081900360600190f35b348015610bd757600080fd5b506103f6612d71565b348015610bec57600080fd5b506104f9612dfb565b348015610c0157600080fd5b50610c0a612e30565b6040805161ffff9092168252519081900360200190f35b348015610c2d57600080fd5b50610559612e6e565b348015610c4257600080fd5b506104f9612e99565b348015610c5757600080fd5b506104f9600160a060020a0360043581169060243516612ea3565b348015610c7e57600080fd5b506104ac612ece565b348015610c9357600080fd5b506103f6600160a060020a0360043581169060243581169060443516612ee1565b348015610cc057600080fd5b506103f6600435612f2c565b348015610cd857600080fd5b506104f961303a565b348015610ced57600080fd5b506103f661306f565b348015610d0257600080fd5b506104f9600160a060020a03600435166024356130b4565b348015610d2657600080fd5b506104f9600160a060020a0360043516613198565b348015610d4757600080fd5b506103f66131a3565b348015610d5c57600080fd5b506104f96131de565b6000610d6f615dee565b600080341515610dc9576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f4445504f5349540000000000000000000000000000000000000000604482015290519081900360640190fd5b60408051600080516020615e1683398151915281529051908190036014019020610df290613242565b9250610dfd83613295565b15610e52576040805160e560020a62461bcd02815260206004820152600e60248201527f5354414b494e475f504155534544000000000000000000000000000000000000604482015290519081900360640190fd5b610e5b836132a0565b15610f0457610e69836132b2565b915034821015610ec3576040805160e560020a62461bcd02815260206004820152600b60248201527f5354414b455f4c494d4954000000000000000000000000000000000000000000604482015290519081900360640190fd5b610f04610ed88434850363ffffffff61333d16565b60408051600080516020615e16833981519152815290519081900360140190209063ffffffff61338116565b610f0d346112bb565b9050801515610f195750345b610f2333826133e0565b50610f7d610f3f34610f3361354b565b9063ffffffff61359816565b604080517f6c69646f2e4c69646f2e62756666657265644574686572000000000000000000815290519081900360170190209063ffffffff61362616565b60408051348152600160a060020a0387166020820152815133927f96a25c8ce0baabc1fdefd93e9ed25d8e092a3332f3aa9a41722b5697231d1d1a928290030190a2610fc9338261362a565b8093505b505050919050565b604080517f524553554d455f524f4c450000000000000000000000000000000000000000008152905190819003600b019020611010906136b6565b611018613773565b61102061384d565b565b60408051808201909152601781527f4c6971756964207374616b656420457468657220322e30000000000000000000602082015290565b604080517f50415553455f524f4c45000000000000000000000000000000000000000000008152905190819003600a019020611094906136b6565b61109c6138b8565b611020613981565b6000806110af61235d565b905080158015906110c75750806110c46139e0565b10155b91505090565b60006110da3384846139e4565b50600192915050565b60408051600080516020615eb68339815191528152905190819003601401902081565b61110e61235d565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156111cf5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561119457818101518382015260200161117c565b50505050905090810190601f1680156111c15780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50604080517f6c69646f2e4c69646f2e6e6f64654f70657261746f72735265676973747279008152905190819003601f019020611212908463ffffffff61362616565b604080517f6c69646f2e4c69646f2e6465706f736974436f6e74726163740000000000000081529051908190036019019020611254908663ffffffff61362616565b61125f848383613b73565b611267613da9565b5050505050565b604080517f6c69646f2e4c69646f2e696e737572616e636546756e64000000000000000000815290519081900360170190206000906112ac90613e6f565b905090565b60006112ac613e73565b6000806112c6613e73565b90508015156112d85760009150611303565b611300816112f46112e7613eb5565b869063ffffffff613ef316565b9063ffffffff613f9e16565b91505b50919050565b60408051600080516020615e16833981519152815290519081900360140190206000906112ac9061133990613242565b613295565b600160a060020a0383166000908152600160209081526040808320338452909152812054828110156113e0576040805160e560020a62461bcd02815260206004820152602160248201527f5452414e534645525f414d4f554e545f455843454544535f414c4c4f57414e4360448201527f4500000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6113eb85858561403e565b6114058533611400848763ffffffff6140f216565b6139e4565b600191505b509392505050565b604080517f6c69646f2e4c69646f2e6e6f64654f70657261746f72735265676973747279008152905190819003601f0190206000906112ac90613e6f565b600061145a612b7d565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156114b557818101518382015260200161149d565b50505050905090810190601f1680156114e25780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561150157600080fd5b505af1158015611515573d6000803e3d6000fd5b505050506040513d602081101561152b57600080fd5b505190505b919050565b60408051600080516020615eb68339815191528152905190819003601401902061155e906136b6565b60408051600080516020615e16833981519152815290519081900360140190206115a090610ed8908490849061159390613242565b919063ffffffff61418616565b604080518381526020810183905281517fce9fddf6179affa1ea7bf36d80a6bf0284e0f3b91f4b2fa6eea2af923e7fac2d929181900390910190a15050565b604080517f524553554d455f524f4c450000000000000000000000000000000000000000008152905190819003600b01902081565b601290565b6000611623612e6e565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561165d57600080fd5b505af1158015611671573d6000803e3d6000fd5b505050506040513d602081101561168757600080fd5b5051905090565b604080517f4445504f5349545f524f4c4500000000000000000000000000000000000000008152905190819003600c01902081565b6801bc16d674ec80000081565b604080517f50415553455f524f4c45000000000000000000000000000000000000000000008152905190819003600a01902081565b336000818152600160209081526040808320600160a060020a038716845290915281205490916110da918590611400908663ffffffff61359816565b604080517f6c69646f2e4c69646f2e74726561737572790000000000000000000000000000815290519081900360120190206000906112ac90613e6f565b60408051600080516020615e56833981519152815290519081900360180190206000906117ab90613e6f565b15905090565b604080517f4d414e4147455f5749544844524157414c5f4b455900000000000000000000008152905190819003601501902081565b60006112ac61354b565b604080517f6c69646f2e4c69646f2e657865637574696f6e4c61796572526577617264735681527f61756c74000000000000000000000000000000000000000000000000000000006020820152905190819003602401902061185190613e6f565b600160a060020a0316331461186557600080fd5b604080517f6c69646f2e4c69646f2e746f74616c454c52657761726473436f6c6c6563746581527f640000000000000000000000000000000000000000000000000000000000000060208201529051908190036021019020611934906118d0903490610f3390613e6f565b604080517f6c69646f2e4c69646f2e746f74616c454c52657761726473436f6c6c6563746581527f6400000000000000000000000000000000000000000000000000000000000000602082015290519081900360210190209063ffffffff61362616565b6040805134815290517fd27f9b0c98bdee27044afa149eadcd2047d6399cb6613a45c5b87e6aca76e6b59181900360200190a1565b604080517f6c69646f2e4c69646f2e454c526577617264735769746864726177616c4c696d81527f6974000000000000000000000000000000000000000000000000000000000000602082015290519081900360220190206000906112ac90613e6f565b606081565b604080517f6c69646f2e4c69646f2e7769746864726177616c43726564656e7469616c73008152905190819003601f0190206000906112ac90613e6f565b60408051600080516020615e16833981519152815290519081900360140190206000906112ac90611a4090613242565b61439e565b604080517f5345545f454c5f524557415244535f5749544844524157414c5f4c494d49545f81527f524f4c450000000000000000000000000000000000000000000000000000000060208201529051908190036024019020611aa6906136b6565b604080517f6c69646f2e4c69646f2e454c526577617264735769746864726177616c4c696d81527f697400000000000000000000000000000000000000000000000000000000000060208201529051908190036022019020611b0890826143d7565b6040805161ffff8316815290517f166eb213129ab51688433b859b5a206403ee174774a1430f8ffb83af316161f69181900360200190a150565b6000806000806000806000611b7d6040518080600080516020615e568339815191528152506018019050604051809103902060001916613e6f565b1515611bc1576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b611bc961231f565b600160a060020a03163314611c28576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b60408051600080516020615e768339815191528152905190819003601d019020611c5190613e6f565b965086891115611cab576040805160e560020a62461bcd02815260206004820152601760248201527f5245504f525445445f4d4f52455f4445504f5349544544000000000000000000604482015290519081900360640190fd5b60408051600080516020615ed68339815191528152905190819003601a019020611cd490613e6f565b955085891015611d2e576040805160e560020a62461bcd02815260206004820152601860248201527f5245504f525445445f4c4553535f56414c494441544f52530000000000000000604482015290519081900360640190fd5b611d3e898763ffffffff6140f216565b60408051600080516020615e3683398151915281529051908190036017019020909550611d8790611d6e90613e6f565b610f33876801bc16d674ec80000063ffffffff613ef316565b60408051600080516020615e3683398151915281529051908190036017019020909450611dba908963ffffffff61362616565b60408051600080516020615ed68339815191528152905190819003601a019020611dea908a63ffffffff61362616565b611df2612040565b9150600160a060020a03821615611f0557604080517f6c69646f2e4c69646f2e454c526577617264735769746864726177616c4c696d81527f697400000000000000000000000000000000000000000000000000000000000060208201529051908190036022019020600160a060020a03831690639342c8f49061271090611e7990613e6f565b611e81613e73565b02811515611e8b57fe5b046040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015611ec257600080fd5b505af1158015611ed6573d6000803e3d6000fd5b505050506040513d6020811015611eec57600080fd5b505192508215611f0557611f05610f3f84610f3361354b565b83881115611f3757611f1d888563ffffffff6140f216565b9050611f37611f32828563ffffffff61359816565b614449565b505050505050505050565b6000806000806000806000611f55615dee565b60408051600080516020615e1683398151915281529051908190036014019020611f7e90613242565b9050611f8981613295565b9750611f94816132a0565b9650611f9f8161439e565b955080606001516001606060020a03169450806040015163ffffffff16935080602001516001606060020a03169250806000015163ffffffff1691505090919293949596565b604080517f5345545f454c5f524557415244535f5749544844524157414c5f4c494d49545f81527f524f4c45000000000000000000000000000000000000000000000000000000006020820152905190819003602401902081565b604080517f6c69646f2e4c69646f2e657865637574696f6e4c61796572526577617264735681527f61756c7400000000000000000000000000000000000000000000000000000000602082015290519081900360240190206000906112ac90613e6f565b60006120b76120b283614578565b6121ab565b92915050565b60408051600080516020615eb683398151915281529051908190036014019020611018906136b6565b604080517f6c69646f2e4c69646f2e74726561737572794665650000000000000000000000815290519081900360150190206000908190819061212890613e6f565b604080517f6c69646f2e4c69646f2e696e737572616e6365466565000000000000000000008152905190819003601601902090935061216690613e6f565b604080517f6c69646f2e4c69646f2e6e6f64654f70657261746f72734665650000000000008152905190819003601a0190209092506121a490613e6f565b9050909192565b6000806121b6613eb5565b90508015156121c85760009150611303565b611300816112f46112e7613e73565b604080517f5345545f454c5f524557415244535f5641554c545f524f4c450000000000000081529051908190036019019020612212906136b6565b604080517f6c69646f2e4c69646f2e657865637574696f6e4c61796572526577617264735681527f61756c74000000000000000000000000000000000000000000000000000000006020820152905190819003602401902061227a908263ffffffff61362616565b60408051600160a060020a038316815290517f8e2d01c4cfaa88fa4d772d37e4d068deda4342bf4ef6dc4b0cf3e868be5ebb409181900360200190a150565b50600190565b604080517f4d414e4147455f50524f544f434f4c5f434f4e5452414354535f524f4c4500008152905190819003601e01902081565b60006112ac7fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b613e6f565b604080517f6c69646f2e4c69646f2e6f7261636c6500000000000000000000000000000000815290519081900360100190206000906112ac90613e6f565b60006112ac7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e613e6f565b604080517f4d414e4147455f464545000000000000000000000000000000000000000000008152905190819003600a0190206123c3906136b6565b6123e68161ffff16610f338461ffff168661ffff1661359890919063ffffffff16565b6127101461243e576040805160e560020a62461bcd02815260206004820152601060248201527f464545535f444f4e545f4144445f555000000000000000000000000000000000604482015290519081900360640190fd5b604080517f6c69646f2e4c69646f2e747265617375727946656500000000000000000000008152905190819003601501902061247a90846143d7565b604080517f6c69646f2e4c69646f2e696e737572616e636546656500000000000000000000815290519081900360160190206124b690836143d7565b604080517f6c69646f2e4c69646f2e6e6f64654f70657261746f72734665650000000000008152905190819003601a0190206124f290826143d7565b6040805161ffff8086168252808516602083015283168183015290517f034529db1bba3830b8877e116871f19c5b96ef86c739f2a05668c860c84668989181900360600190a1505050565b604080517f4d414e4147455f464545000000000000000000000000000000000000000000008152905190819003600a019020612578906136b6565b604080517f6c69646f2e4c69646f2e666565000000000000000000000000000000000000008152905190819003600d0190206125b490826143d7565b6040805161ffff8316815290517faab062e3faf62b6c9a0f8e62af66e0310e27127a8c871a67be7dd4d93de6da539181900360200190a150565b6000806125fc338585614593565b604080518481529051600160a060020a0386169133917f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb9181900360200190a3612645836121ab565b604080518281529051919250600160a060020a0386169133917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a38091505b5092915050565b604080517f4445504f5349545f524f4c4500000000000000000000000000000000000000008152905190819003600c0190206126cf906136b6565b6126d88161479c565b50565b60408051808201909152600581527f7374455448000000000000000000000000000000000000000000000000000000602082015290565b604080517f4d414e4147455f464545000000000000000000000000000000000000000000008152905190819003600a01902081565b6000806000612755846122b9565b15156127ab576040805160e560020a62461bcd02815260206004820152601260248201527f5245434f5645525f444953414c4c4f5745440000000000000000000000000000604482015290519081900360640190fd5b6127b3611619565b9250600160a060020a0383161515612815576040805160e560020a62461bcd02815260206004820152601260248201527f5245434f5645525f5641554c545f5a45524f0000000000000000000000000000604482015290519081900360640190fd5b600160a060020a03841615156128a95761282d614884565b915082600160a060020a03168260405160006040518083038185875af19250505015156128a4576040805160e560020a62461bcd02815260206004820152601760248201527f5245434f5645525f5452414e534645525f4641494c4544000000000000000000604482015290519081900360640190fd5b612936565b50826128c4600160a060020a0382163063ffffffff61489f16565b91506128e0600160a060020a038216848463ffffffff6149b416565b1515612936576040805160e560020a62461bcd02815260206004820152601d60248201527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c4544000000604482015290519081900360640190fd5b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b6000806129926110a4565b15156129a1576000915061140a565b6129a9612e6e565b9050600160a060020a03811615156129c4576000915061140a565b80600160a060020a031663fdef91068630876129df88614a36565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015612a4e578181015183820152602001612a36565b50505050905090810190601f168015612a7b5780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015612a9d57600080fd5b505af1158015612ab1573d6000803e3d6000fd5b505050506040513d6020811015612ac757600080fd5b505195945050505050565b60006120b782610d65565b602081565b336000908152600160209081526040808320600160a060020a038616845290915281205482811015612b5e576040805160e560020a62461bcd02815260206004820152601e60248201527f4445435245415345445f414c4c4f57414e43455f42454c4f575f5a45524f0000604482015290519081900360640190fd5b612b733385611400848763ffffffff6140f216565b5060019392505050565b600080612b88612e6e565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b158015612c3257600080fd5b505af1158015612c46573d6000803e3d6000fd5b505050506040513d6020811015612c5c57600080fd5b505192915050565b603081565b604080517f5345545f454c5f524557415244535f5641554c545f524f4c45000000000000008152905190819003601901902081565b60006110da33848461403e565b604080517f6c69646f2e4c69646f2e6465706f736974436f6e747261637400000000000000815290519081900360190190206000906112ac90613e6f565b60408051600080516020615e768339815191528152905190819003601d01902060009081908190612d1990613e6f565b60408051600080516020615ed68339815191528152905190819003601a019020909350612d4590613e6f565b60408051600080516020615e36833981519152815290519081900360170190209092506121a490613e6f565b60408051600080516020615eb683398151915281529051908190036014019020612d9a906136b6565b60408051600080516020615e1683398151915281529051908190036014019020612dd090610ed890612dcb90613242565b614a40565b6040517f9b2a687c198898fcc32a33bbc610d478f177a73ab7352023e6cc1de5bf12a3df90600090a1565b604080517f4255524e5f524f4c4500000000000000000000000000000000000000000000008152905190819003600901902081565b604080517f6c69646f2e4c69646f2e666565000000000000000000000000000000000000008152905190819003600d0190206000906112ac90613e6f565b60006112ac7f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b613e6f565b60006112ac613eb5565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b6000600019612edb61235d565b14905090565b604080517f4d414e4147455f50524f544f434f4c5f434f4e5452414354535f524f4c4500008152905190819003601e019020612f1c906136b6565b612f27838383613b73565b505050565b604080517f4d414e4147455f5749544844524157414c5f4b4559000000000000000000000081529051908190036015019020612f67906136b6565b604080517f6c69646f2e4c69646f2e7769746864726177616c43726564656e7469616c73008152905190819003601f019020612fa9908263ffffffff61362616565b612fb1611412565b600160a060020a031663f778021e6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612feb57600080fd5b505af1158015612fff573d6000803e3d6000fd5b50506040805184815290517f13eb80e900aa05a2696d50d5de33ef631c73493c4921da233b17335ff6b7b1149350908190036020019150a150565b604080517f5354414b494e475f50415553455f524f4c4500000000000000000000000000008152905190819003601201902081565b604080517f4445504f5349545f524f4c4500000000000000000000000000000000000000008152905190819003600c0190206130aa906136b6565b611020609661479c565b604080517f4255524e5f524f4c450000000000000000000000000000000000000000000000815290519081900360090190206000906130f38484614a53565b6130fe338383612987565b60408051808201909152600f81527f4150505f415554485f4641494c4544000000000000000000000000000000000060208201529015156131845760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b5061318f8585614a6f565b95945050505050565b60006120b782614578565b604080517f5354414b494e475f50415553455f524f4c4500000000000000000000000000008152905190819003601201902061109c906136b6565b604080517f6c69646f2e4c69646f2e746f74616c454c52657761726473436f6c6c6563746581527f6400000000000000000000000000000000000000000000000000000000000000602082015290519081900360210190206000906112ac90613e6f565b61324a615dee565b600061325583613e6f565b63ffffffff600082901c811684526001606060020a03602083811c821690860152608083901c909116604085015260a09190911c16606083015250919050565b5163ffffffff161590565b606001516001606060020a0316151590565b6040810151600090819063ffffffff16156132f657826040015163ffffffff1683606001516001606060020a03168115156132e957fe5b046001606060020a031690505b80836000015163ffffffff1643030283602001516001606060020a031601915082606001516001606060020a0316821115611303575050606001516001606060020a031690565b613345615dee565b6001606060020a0382111561335657fe5b825163ffffffff16151561336657fe5b506001606060020a031660208201524363ffffffff16815290565b6133dc60a082606001516001606060020a0316901b6080836040015163ffffffff16901b602084602001516001606060020a0316901b6000856000015163ffffffff16901b171717836000191661362690919063ffffffff16565b5050565b60408051600080516020615e568339815191528152905190819003601801902060009061340c90613e6f565b1515613450576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b600160a060020a03831615156134b0576040805160e560020a62461bcd02815260206004820152601860248201527f4d494e545f544f5f5448455f5a45524f5f414444524553530000000000000000604482015290519081900360640190fd5b6134bc82610f33613eb5565b604080517f6c69646f2e53744554482e746f74616c5368617265730000000000000000000081529051908190036016019020909150613501908263ffffffff61362616565b600160a060020a03831660009081526020819052604090205461352a908363ffffffff61359816565b600160a060020a039093166000908152602081905260409020929092555090565b604080517f6c69646f2e4c69646f2e6275666665726564457468657200000000000000000081529051908190036017019020600090819061358b90613e6f565b9050303181111561153057fe5b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f570000000000000000000000000000006020820152600090838301908482101561140a5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b9055565b600160a060020a03821660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef613660846121ab565b60408051918252519081900360200190a3604080518281529051600160a060020a038416916000917f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb9181900360200190a35050565b806136ed338260006040519080825280602002602001820160405280156136e7578160200160208202803883390190505b50612987565b60408051808201909152600f81527f4150505f415554485f4641494c454400000000000000000000000000000000006020820152901515612f275760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b60408051600080516020615e568339815191528152905190819003601801902061379c90613e6f565b156137f1576040805160e560020a62461bcd02815260206004820152601260248201527f434f4e54524143545f49535f4143544956450000000000000000000000000000604482015290519081900360640190fd5b60408051600080516020615e568339815191528152905190819003601801902061382290600163ffffffff61362616565b6040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f990600090a1565b60408051600080516020615e168339815191528152905190819003601401902061388d90610ed89060009061388190613242565b9063ffffffff614c9d16565b6040517fedaeeae9aed70c4545d3ab0065713261c9cee8d6cf5c8b07f52f0a65fd91efda90600090a1565b60408051600080516020615e56833981519152815290519081900360180190206138e190613e6f565b1515613925576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b60408051600080516020615e568339815191528152905190819003601801902061395690600063ffffffff61362616565b6040517f7acc84e34091ae817647a4c49116f5cc07f319078ba80f8f5fde37ea7e25cbd690600090a1565b60408051600080516020615e16833981519152815290519081900360140190206139b590610ed89060019061388190613242565b6040517f26d1807b479eaba249c1214b82e4b65bbb0cc73ee8a17901324b1ef1b5904e4990600090a1565b4390565b60408051600080516020615e5683398151915281529051908190036018019020613a0d90613e6f565b1515613a51576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b600160a060020a0383161515613ab1576040805160e560020a62461bcd02815260206004820152601960248201527f415050524f56455f46524f4d5f5a45524f5f4144445245535300000000000000604482015290519081900360640190fd5b600160a060020a0382161515613b11576040805160e560020a62461bcd02815260206004820152601760248201527f415050524f56455f544f5f5a45524f5f41444452455353000000000000000000604482015290519081900360640190fd5b600160a060020a03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600160a060020a0383161515613bd3576040805160e560020a62461bcd02815260206004820152601360248201527f4f5241434c455f5a45524f5f4144445245535300000000000000000000000000604482015290519081900360640190fd5b600160a060020a0382161515613c33576040805160e560020a62461bcd02815260206004820152601560248201527f54524541535552595f5a45524f5f414444524553530000000000000000000000604482015290519081900360640190fd5b600160a060020a0381161515613c93576040805160e560020a62461bcd02815260206004820152601b60248201527f494e535552414e43455f46554e445f5a45524f5f414444524553530000000000604482015290519081900360640190fd5b604080517f6c69646f2e4c69646f2e6f7261636c650000000000000000000000000000000081529051908190036010019020613cd5908463ffffffff61362616565b604080517f6c69646f2e4c69646f2e7472656173757279000000000000000000000000000081529051908190036012019020613d17908363ffffffff61362616565b604080517f6c69646f2e4c69646f2e696e737572616e636546756e6400000000000000000081529051908190036017019020613d59908263ffffffff61362616565b60408051600160a060020a038086168252808516602083015283168183015290517f7df55cbe17c0cf85c9c23753c046f686eeb4c6b2ce13182943d215e92afc565a9181900360600190a1505050565b613db161235d565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015613e365760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b50611020613e426139e0565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61362616565b5490565b60006112ac613e80614cc2565b60408051600080516020615e3683398151915281529051908190036017019020610f3390613ead90613e6f565b610f3361354b565b604080517f6c69646f2e53744554482e746f74616c53686172657300000000000000000000815290519081900360160190206000906112ac90613e6f565b600080831515613f06576000915061268d565b50828202828482811515613f1657fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f570000000000000000000000000000006020820152929190041461140a5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b60408051808201909152600d81527f4d4154485f4449565f5a45524f00000000000000000000000000000000000000602082015260009081908184116140295760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b50828481151561403557fe5b04949350505050565b6000614049826112bb565b9050614056848483614593565b82600160a060020a031684600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a382600160a060020a031684600160a060020a03167f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb836040518082815260200191505060405180910390a350505050565b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f570000000000000000000000000000602082015260009081908484111561417e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b505050900390565b61418e615dee565b8215156141e5576040805160e560020a62461bcd02815260206004820152601460248201527f5a45524f5f4d41585f5354414b455f4c494d4954000000000000000000000000604482015290519081900360640190fd5b6001606060020a03831115614244576040805160e560020a62461bcd02815260206004820152601960248201527f544f4f5f4c415247455f4d41585f5354414b455f4c494d495400000000000000604482015290519081900360640190fd5b8183101561429c576040805160e560020a62461bcd02815260206004820152601860248201527f544f4f5f4c415247455f4c494d49545f494e4352454153450000000000000000604482015290519081900360640190fd5b8115806142b8575063ffffffff82848115156142b457fe5b0411155b151561430e576040805160e560020a62461bcd02815260206004820152601860248201527f544f4f5f534d414c4c5f4c494d49545f494e4352454153450000000000000000604482015290519081900360640190fd5b60608401516001606060020a03161580614334575083602001516001606060020a031683105b15614349576001606060020a03831660208501525b811515614357576000614364565b818381151561436257fe5b045b63ffffffff90811660408601526001606060020a0384166060860152845116156143925763ffffffff431684525b509192915050565b5490565b60006143a982613295565b156143b657506000611530565b6143bf826132a0565b15156143ce5750600019611530565b6120b7826132b2565b61271061ffff82161115614435576040805160e560020a62461bcd02815260206004820152601660248201527f56414c55455f4f5645525f3130305f50455243454e5400000000000000000000604482015290519081900360640190fd5b6133dc8261ffff831663ffffffff61362616565b600080600080600080600080600061445f612e30565b61ffff1698506144bc6144a161447b8b8d63ffffffff613ef316565b614495612710614489613e73565b9063ffffffff613ef316565b9063ffffffff6140f216565b6112f46144ac613eb5565b6144898e8e63ffffffff613ef316565b97506144c830896133e0565b506144d16120e6565b90985096506144f290506127106112f48a61ffff8b1663ffffffff613ef316565b94506144fc61126e565b9350614509308587614593565b614513848661362a565b6145356145306127106112f48b61ffff8b1663ffffffff613ef316565b614d4e565b925061454b836144958a8863ffffffff6140f216565b9150614555611741565b9050614562308284614593565b61456c818361362a565b50505050505050505050565b600160a060020a031660009081526020819052604090205490565b60408051600080516020615e56833981519152815290519081900360180190206000906145bf90613e6f565b1515614603576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b600160a060020a0384161515614663576040805160e560020a62461bcd02815260206004820152601e60248201527f5452414e534645525f46524f4d5f5448455f5a45524f5f414444524553530000604482015290519081900360640190fd5b600160a060020a03831615156146c3576040805160e560020a62461bcd02815260206004820152601c60248201527f5452414e534645525f544f5f5448455f5a45524f5f4144445245535300000000604482015290519081900360640190fd5b50600160a060020a03831660009081526020819052604090205480821115614735576040805160e560020a62461bcd02815260206004820152601f60248201527f5452414e534645525f414d4f554e545f455843454544535f42414c414e434500604482015290519081900360640190fd5b614745818363ffffffff6140f216565b600160a060020a03808616600090815260208190526040808220939093559085168152205461477a908363ffffffff61359816565b600160a060020a03909316600090815260208190526040902092909255505050565b60408051600080516020615e5683398151915281529051908190036018019020600090819081906147cc90613e6f565b1515614810576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b61481861354b565b92506801bc16d674ec800000831061487e57614832614884565b915061484d836801bc16d674ec80000063ffffffff613f9e16565b905061486e6148698583106148625785614864565b825b614f3f565b6152be565b81614877614884565b1461487e57fe5b50505050565b60006112ac61489161354b565b30319063ffffffff6140f216565b60408051600160a060020a0383166024808301919091528251808303909101815260449091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a0823100000000000000000000000000000000000000000000000000000000179052600090818061491f8684615339565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f524556455254454400000000602082015291935091508215156149aa5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b5095945050505050565b60408051600160a060020a038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905260009061318f858261536a565b8051602002815290565b614a48615dee565b506000606082015290565b6060614a6883600160a060020a0316836153b8565b9392505050565b60408051600080516020615e5683398151915281529051908190036018019020600090819081908190614aa190613e6f565b1515614ae5576040805160e560020a62461bcd0281526020600482015260136024820152600080516020615e96833981519152604482015290519081900360640190fd5b600160a060020a0386161515614b45576040805160e560020a62461bcd02815260206004820152601a60248201527f4255524e5f46524f4d5f5448455f5a45524f5f41444452455353000000000000604482015290519081900360640190fd5b600160a060020a038616600090815260208190526040902054925082851115614bb8576040805160e560020a62461bcd02815260206004820152601b60248201527f4255524e5f414d4f554e545f455843454544535f42414c414e43450000000000604482015290519081900360640190fd5b614bc1856121ab565b9150614bcf85614495613eb5565b604080517f6c69646f2e53744554482e746f74616c5368617265730000000000000000000081529051908190036016019020909450614c14908563ffffffff61362616565b614c24838663ffffffff6140f216565b600160a060020a038716600090815260208190526040902055614c46856121ab565b60408051848152602081018390528082018890529051919250600160a060020a038816917f8b2a1e1ad5e0578c3dd82494156e985dade827a87c573b5c1c7716a32162ad649181900360600190a250505092915050565b614ca5615dee565b81614cb05743614cb3565b60005b63ffffffff1683525090919050565b60408051600080516020615e768339815191528152905190819003601d01902060009081908190614cf290613e6f565b60408051600080516020615ed68339815191528152905190819003601a019020909250614d1e90613e6f565b905080821015614d2a57fe5b614d476801bc16d674ec800000614489848463ffffffff6140f216565b9250505090565b60006060806000614d5d611412565b600160a060020a03166362dcfda1866040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015614da257600080fd5b505af1158015614db6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015614ddf57600080fd5b810190808051640100000000811115614df757600080fd5b82016020810184811115614e0a57600080fd5b8151856020820283011164010000000082111715614e2757600080fd5b50509291906020018051640100000000811115614e4357600080fd5b82016020810184811115614e5657600080fd5b8151856020820283011164010000000082111715614e7357600080fd5b50509291905050509250925081518351141515614e8c57fe5b5060009250825b8251811015610fcd57614ed5308483815181101515614eae57fe5b906020019060200201518484815181101515614ec657fe5b90602001906020020151614593565b614f0d8382815181101515614ee657fe5b906020019060200201518383815181101515614efe57fe5b9060200190602002015161362a565b614f358282815181101515614f1e57fe5b60209081029091010151859063ffffffff61359816565b9350600101614e93565b6000606080600080606080614f52611412565b600160a060020a03166341bc716f896040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015614f9757600080fd5b505af1158015614fab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015614fd457600080fd5b810190808051640100000000811115614fec57600080fd5b82016020810184811115614fff57600080fd5b815164010000000081118282018710171561501957600080fd5b5050929190602001805164010000000081111561503557600080fd5b8201602081018481111561504857600080fd5b815164010000000081118282018710171561506257600080fd5b50508451949a5098505050901515905061507f57600096506152b3565b855161509290603063ffffffff61541316565b1561510d576040805160e560020a62461bcd02815260206004820152602160248201527f52454749535452595f494e434f4e53495354454e545f5055424b4559535f4c4560448201527f4e00000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b845161512090606063ffffffff61541316565b15615175576040805160e560020a62461bcd02815260206004820152601d60248201527f52454749535452595f494e434f4e53495354454e545f5349475f4c454e000000604482015290519081900360640190fd5b855161518890603063ffffffff613f9e16565b855190945061519e90606063ffffffff613f9e16565b84146151f4576040805160e560020a62461bcd02815260206004820152601f60248201527f52454749535452595f494e434f4e53495354454e545f5349475f434f554e5400604482015290519081900360640190fd5b600092505b8383101561523857615210866030850260306154b0565b9150615221856060850260606154b0565b905061522d8282615531565b8260010192506151f9565b60408051600080516020615e768339815191528152905190819003601d0190206152979061526b908690610f3390613e6f565b60408051600080516020615e768339815191528152905190819003601d0190209063ffffffff61362616565b6152b0846801bc16d674ec80000063ffffffff613ef316565b96505b505050505050919050565b604080517f6c69646f2e4c69646f2e627566666572656445746865720000000000000000008152905190819003601701902061530390610f3f90839061449590613e6f565b6040805182815290517f76a397bea5768d4fca97ef47792796e35f98dc81b16c1de84e28a818e1f971089181900360200190a150565b6000806000806040516020818751602089018a5afa9250600083111561535e57805191505b50909590945092505050565b6000806040516020818551602087016000895af160008111156153ae573d801561539b57602081146153a4576153ac565b600193506153ac565b600183511493505b505b5090949350505050565b6040805160028082526060808301845292602083019080388339019050509050828160008151811015156153e857fe5b60209081029091010152805182908290600190811061540357fe5b6020908102909101015292915050565b60408051808201909152600d81527f4d4154485f4449565f5a45524f00000000000000000000000000000000000000602082015260009082151561549c5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561119457818101518382015260200161117c565b5081838115156154a857fe5b069392505050565b6060808284018551101515156154c557600080fd5b821580156154de57604051915060208201604052615528565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156155175780518352602092830192016154ff565b5050858452601f01601f1916604052505b50949350505050565b60008060008060008060006155446119d2565b965086151561559d576040805160e560020a62461bcd02815260206004820152601c60248201527f454d5054595f5749544844524157414c5f43524544454e5449414c5300000000604482015290519081900360640190fd5b6801bc16d674ec80000095506155bd86633b9aca0063ffffffff613f9e16565b9450856155d486633b9aca0063ffffffff613ef316565b146155db57fe5b60026155e68a615cab565b6040518082805190602001908083835b602083106156155780518252601f1990920191602091820191016155f6565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015615656573d6000803e3d6000fd5b5050506040513d602081101561566b57600080fd5b5051935060028061567f8a600060406154b0565b6040518082805190602001908083835b602083106156ae5780518252601f19909201916020918201910161568f565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af11580156156ef573d6000803e3d6000fd5b5050506040513d602081101561570457600080fd5b5051600261572c6157278c604061572260608263ffffffff6140f216565b6154b0565b615cab565b6040518082805190602001908083835b6020831061575b5780518252601f19909201916020918201910161573c565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af115801561579c573d6000803e3d6000fd5b5050506040513d60208110156157b157600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b602083106158075780518252601f1990920191602091820191016157e8565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015615848573d6000803e3d6000fd5b5050506040513d602081101561585d57600080fd5b50516040805160208181018890528183018b905282518083038401815260609092019283905281519396506002938493918291908401908083835b602083106158b75780518252601f199092019160209182019101615898565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af11580156158f8573d6000803e3d6000fd5b5050506040513d602081101561590d57600080fd5b5051600261591a88615d3b565b60408051602080820193909352808201899052815180820383018152606090910191829052805190928291908401908083835b6020831061596c5780518252601f19909201916020918201910161594d565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af11580156159ad573d6000803e3d6000fd5b5050506040513d60208110156159c257600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310615a185780518252601f1990920191602091820191016159f9565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015615a59573d6000803e3d6000fd5b5050506040513d6020811015615a6e57600080fd5b50519150615a8330318763ffffffff6140f216565b9050615a8d612cab565b600160a060020a03166322895118878b8a6040516020018082600019166000191681526020019150506040516020818303038152906040528c876040518663ffffffff1660e01b8152600401808060200180602001806020018560001916600019168152602001848103845288818151815260200191508051906020019080838360005b83811015615b29578181015183820152602001615b11565b50505050905090810190601f168015615b565780820380516001836020036101000a031916815260200191505b50848103835287518152875160209182019189019080838360005b83811015615b89578181015183820152602001615b71565b50505050905090810190601f168015615bb65780820380516001836020036101000a031916815260200191505b50848103825286518152865160209182019188019080838360005b83811015615be9578181015183820152602001615bd1565b50505050905090810190601f168015615c165780820380516001836020036101000a031916815260200191505b509750505050505050506000604051808303818588803b158015615c3957600080fd5b505af1158015615c4d573d6000803e3d6000fd5b50505050303182149050611f37576040805160e560020a62461bcd02815260206004820152601b60248201527f455850454354494e475f4445504f5349545f544f5f48415050454e0000000000604482015290519081900360640190fd5b6060806020835110158015615cc257506040835111155b1515615cca57fe5b825160401415615cdc57829150611303565b604080516020808252818301909252908082016104008038833901905050905060006020820152825160201415615d17576113008382615d73565b61130083615d36836000615722885160406140f290919063ffffffff16565b615d73565b600081815b6008811015615d6157600892831b60ff831617929190911c90600101615d40565b8115615d6957fe5b505060c01b919050565b6060806040519050835180825260208201818101602087015b81831015615da4578051835260209283019201615d8c565b50855184518101855292509050808201602086015b81831015615dd1578051835260209283019201615db9565b509551919091011594909401601f01601f19166040529392505050565b6040805160808101825260008082526020820181905291810182905260608101919091529056006c69646f2e4c69646f2e7374616b654c696d69740000000000000000000000006c69646f2e4c69646f2e626561636f6e42616c616e63650000000000000000006c69646f2e5061757361626c652e616374697665466c616700000000000000006c69646f2e4c69646f2e6465706f736974656456616c696461746f7273000000434f4e54524143545f49535f53544f50504544000000000000000000000000005354414b494e475f434f4e54524f4c5f524f4c450000000000000000000000006c69646f2e4c69646f2e626561636f6e56616c696461746f7273000000000000a165627a7a72305820867169b33ec290e89306c6decc0cd36d3cdb1bcb3e523992dceb5e117c92b8a90029
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.