Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
Amount
|
||
|---|---|---|---|---|---|---|---|
| Emit Token Rebas... | 745586 | 203 days ago | 0 ETH | ||||
| Collect Rewards ... | 745586 | 203 days ago | 0 ETH | ||||
| Mint Shares | 745586 | 203 days ago | 0 ETH | ||||
| Mint Shares | 745586 | 203 days ago | 0 ETH | ||||
| Process Cl State... | 745586 | 203 days ago | 0 ETH | ||||
| Get External Eth... | 745586 | 203 days ago | 0 ETH | ||||
| Get External Sha... | 745586 | 203 days ago | 0 ETH | ||||
| Get Total Shares | 745586 | 203 days ago | 0 ETH | ||||
| Get Total Pooled... | 745586 | 203 days ago | 0 ETH | ||||
| Get Beacon Stat | 745586 | 203 days ago | 0 ETH | ||||
| Emit Token Rebas... | 745235 | 203 days ago | 0 ETH | ||||
| Collect Rewards ... | 745235 | 203 days ago | 0 ETH | ||||
| Mint Shares | 745235 | 203 days ago | 0 ETH | ||||
| Mint Shares | 745235 | 203 days ago | 0 ETH | ||||
| Process Cl State... | 745235 | 203 days ago | 0 ETH | ||||
| Get External Eth... | 745235 | 203 days ago | 0 ETH | ||||
| Get External Sha... | 745235 | 203 days ago | 0 ETH | ||||
| Get Total Shares | 745235 | 203 days ago | 0 ETH | ||||
| Get Total Pooled... | 745235 | 203 days ago | 0 ETH | ||||
| Get Beacon Stat | 745235 | 203 days ago | 0 ETH | ||||
| Emit Token Rebas... | 744520 | 203 days ago | 0 ETH | ||||
| Collect Rewards ... | 744520 | 203 days ago | 0 ETH | ||||
| Mint Shares | 744520 | 203 days ago | 0 ETH | ||||
| Mint Shares | 744520 | 203 days ago | 0 ETH | ||||
| Process Cl State... | 744520 | 203 days ago | 0 ETH |
Loading...
Loading
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: 2025 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ pragma solidity 0.4.24; import {AragonApp, UnstructuredStorage} from "@aragon/os/contracts/apps/AragonApp.sol"; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {ILidoLocator} from "../common/interfaces/ILidoLocator.sol"; import {StakeLimitUtils, StakeLimitUnstructuredStorage, StakeLimitState} from "./lib/StakeLimitUtils.sol"; import {Math256} from "../common/lib/Math256.sol"; import {StETHPermit} from "./StETHPermit.sol"; import {Versioned} from "./utils/Versioned.sol"; interface IStakingRouter { function deposit(uint256 _depositsCount, uint256 _stakingModuleId, bytes _depositCalldata) external payable; function getStakingModuleMaxDepositsCount( uint256 _stakingModuleId, uint256 _maxDepositsValue ) external view returns (uint256); function getTotalFeeE4Precision() external view returns (uint16 totalFee); function TOTAL_BASIS_POINTS() external view returns (uint256); function getWithdrawalCredentials() external view returns (bytes32); function getStakingFeeAggregateDistributionE4Precision() external view returns (uint16 modulesFee, uint16 treasuryFee); } interface IWithdrawalQueue { function unfinalizedStETH() external view returns (uint256); function isBunkerModeActive() external view returns (bool); function finalize(uint256 _lastIdToFinalize, uint256 _maxShareRate) external payable; } interface ILidoExecutionLayerRewardsVault { function withdrawRewards(uint256 _maxAmount) external returns (uint256 amount); } interface IWithdrawalVault { function withdrawWithdrawals(uint256 _amount) external; } /** * @title Liquid staking pool implementation * * Lido is an Ethereum liquid staking protocol solving the problem of frozen staked ether on the Consensus Layer * being unavailable for transfers and DeFi on the Execution Layer. * * 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 the Lido oracle reports * rewards, no `Transfer` events are emitted: doing so would require an event for each token holder * and thus running an unbounded loop. * * ######### STRUCTURED STORAGE ######### * NB: The order of inheritance must preserve the structured storage layout of the previous versions. * * @dev Lido is derived from `StETHPermit` that has a structured storage: * SLOT 0: mapping (address => uint256) private shares (`StETH`) * SLOT 1: mapping (address => mapping (address => uint256)) private allowances (`StETH`) * SLOT 2: mapping(address => uint256) internal noncesByAddress (`StETHPermit`) * * `Versioned` and `AragonApp` both don't have the pre-allocated structured storage. */ contract Lido is Versioned, StETHPermit, AragonApp { using SafeMath for uint256; using UnstructuredStorage for bytes32; using StakeLimitUnstructuredStorage for bytes32; using StakeLimitUtils for StakeLimitState.Data; /// ACL bytes32 public constant PAUSE_ROLE = 0x139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d; // keccak256("PAUSE_ROLE"); bytes32 public constant RESUME_ROLE = 0x2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c7; // keccak256("RESUME_ROLE"); bytes32 public constant STAKING_PAUSE_ROLE = 0x84ea57490227bc2be925c684e2a367071d69890b629590198f4125a018eb1de8; // keccak256("STAKING_PAUSE_ROLE") bytes32 public constant STAKING_CONTROL_ROLE = 0xa42eee1333c0758ba72be38e728b6dadb32ea767de5b4ddbaea1dae85b1b051f; // keccak256("STAKING_CONTROL_ROLE") bytes32 public constant UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE = 0xe6dc5d79630c61871e99d341ad72c5a052bed2fc8c79e5a4480a7cd31117576c; // keccak256("UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE") uint256 private constant DEPOSIT_SIZE = 32 ether; uint256 internal constant TOTAL_BASIS_POINTS = 10000; /// @dev storage slot position for the Lido protocol contracts locator bytes32 internal constant LIDO_LOCATOR_POSITION = 0x9ef78dff90f100ea94042bd00ccb978430524befc391d3e510b5f55ff3166df7; // keccak256("lido.Lido.lidoLocator") /// @dev storage slot position of the staking rate limit structure bytes32 internal constant STAKING_STATE_POSITION = 0xa3678de4a579be090bed1177e0a24f77cc29d181ac22fd7688aca344d8938015; // 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 = 0xed310af23f61f96daefbcd140b306c0bdbf8c178398299741687b90e794772b0; // keccak256("lido.Lido.bufferedEther"); /// @dev number of deposited validators (incrementing counter of deposit operations). bytes32 internal constant DEPOSITED_VALIDATORS_POSITION = 0xe6e35175eb53fc006520a2a9c3e9711a7c00de6ff2c32dd31df8c5a24cac1b5c; // keccak256("lido.Lido.depositedValidators"); /// @dev total amount of ether on Consensus Layer (sum of all the balances of Lido validators) // "beacon" in the `keccak256()` parameter is staying here for compatibility reason bytes32 internal constant CL_BALANCE_POSITION = 0xa66d35f054e68143c18f32c990ed5cb972bb68a68f500cd2dd3a16bbf3686483; // keccak256("lido.Lido.beaconBalance"); /// @dev number of Lido's validators available in the Consensus Layer state // "beacon" in the `keccak256()` parameter is staying here for compatibility reason bytes32 internal constant CL_VALIDATORS_POSITION = 0x9f70001d82b6ef54e9d3725b46581c3eb9ee3aa02b941b6aa54d678a9ca35b10; // keccak256("lido.Lido.beaconValidators"); /// @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 = 0xafe016039542d12eec0183bb0b1ffc2ca45b027126a494672fba4154ee77facb; // keccak256("lido.Lido.totalELRewardsCollected"); /// @dev amount of stETH shares backed by external ether sources bytes32 internal constant EXTERNAL_SHARES_POSITION = 0x2ab18be87d6c30f8dc2a29c9950ab4796c891232dbcc6a95a6b44b9f8aad9352; // keccak256("lido.Lido.externalShares"); /// @dev maximum allowed ratio of external shares to total shares in basis points bytes32 internal constant MAX_EXTERNAL_RATIO_POSITION = 0xf243b7ab6a2698a3d0a16e54fb43706d25b46e82d0a92f60e7e1a4aa86c30e1f; // keccak256("lido.Lido.maxExternalRatioBP") // Staking was paused (don't accept user's ether submits) event StakingPaused(); // Staking was resumed (accept user's ether submits) event StakingResumed(); // Staking limit was set (rate limits user's submits) event StakingLimitSet(uint256 maxStakeLimit, uint256 stakeLimitIncreasePerBlock); // Staking limit was removed event StakingLimitRemoved(); // Emitted when validators number delivered by the oracle event CLValidatorsUpdated(uint256 indexed reportTimestamp, uint256 preCLValidators, uint256 postCLValidators); // Emitted when var at `DEPOSITED_VALIDATORS_POSITION` changed event DepositedValidatorsChanged(uint256 depositedValidators); // Emitted when oracle accounting report processed // @dev `preCLBalance` is the balance of the validators on previous report // plus the amount of ether that was deposited to the deposit contract since then event ETHDistributed( uint256 indexed reportTimestamp, uint256 preCLBalance, // actually its preCLBalance + deposits due to compatibility reasons uint256 postCLBalance, uint256 withdrawalsWithdrawn, uint256 executionLayerRewardsWithdrawn, uint256 postBufferedEther ); // Emitted when token is rebased (total supply and/or total shares were changed) event TokenRebased( uint256 indexed reportTimestamp, uint256 timeElapsed, uint256 preTotalShares, uint256 preTotalEther, uint256 postTotalShares, uint256 postTotalEther, uint256 sharesMintedAsFees ); // Lido locator set event LidoLocatorSet(address lidoLocator); // The amount of ETH withdrawn from LidoExecutionLayerRewardsVault to Lido event ELRewardsReceived(uint256 amount); // The amount of ETH withdrawn from WithdrawalVault to Lido event WithdrawalsReceived(uint256 amount); // 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); // Internal share rate updated event InternalShareRateUpdated( uint256 indexed reportTimestamp, uint256 postInternalShares, uint256 postInternalEther, uint256 sharesMintedAsFees ); // External shares minted for receiver event ExternalSharesMinted(address indexed receiver, uint256 amountOfShares, uint256 amountOfStETH); // External shares burned for account event ExternalSharesBurned(address indexed account, uint256 amountOfShares, uint256 stethAmount); // Maximum ratio of external shares to total shares in basis points set event MaxExternalRatioBPSet(uint256 maxExternalRatioBP); // External ether transferred to buffer event ExternalEtherTransferredToBuffer(uint256 amount); /** * @dev As AragonApp, Lido contract must be initialized with following variables: * NB: by default, staking and the whole Lido pool are in paused state * * The contract's balance must be non-zero to allow initial holder bootstrap. * * @param _lidoLocator lido locator contract * @param _eip712StETH eip712 helper contract for StETH */ function initialize(address _lidoLocator, address _eip712StETH) public payable onlyInit { _bootstrapInitialHolder(); // stone in the elevator LIDO_LOCATOR_POSITION.setStorageAddress(_lidoLocator); emit LidoLocatorSet(_lidoLocator); _initializeEIP712StETH(_eip712StETH); // set infinite allowance for burner from withdrawal queue // to burn finalized requests' shares _approve(ILidoLocator(_lidoLocator).withdrawalQueue(), ILidoLocator(_lidoLocator).burner(), INFINITE_ALLOWANCE); _initialize_v3(); initialized(); } /** * @notice A function to finalize upgrade to v3 (from v2). Can be called only once * * For more details see https://github.com/lidofinance/lido-improvement-proposals/blob/develop/LIPS/lip-10.md */ function finalizeUpgrade_v3() external { require(hasInitialized(), "NOT_INITIALIZED"); _checkContractVersion(2); _initialize_v3(); } /** * initializer for the Lido version "3" */ function _initialize_v3() internal { _setContractVersion(3); } /** * @notice Stop 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. */ function pauseStaking() external { _auth(STAKING_PAUSE_ROLE); _pauseStaking(); } /** * @notice Resume 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 */ function resumeStaking() external { _auth(STAKING_CONTROL_ROLE); require(hasInitialized(), "NOT_INITIALIZED"); _resumeStaking(); } /** * @notice Set 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) * * @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 Remove the staking rate limit */ 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(); } /** * @return the maximum amount of ether that 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) { return _getCurrentStakeLimit(STAKING_STATE_POSITION.getStorageStakeLimitStruct()); } /** * @notice Get the 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; } /** * @return the maximum allowed external shares ratio as basis points of total shares [0-10000] */ function getMaxExternalRatioBP() external view returns (uint256) { return MAX_EXTERNAL_RATIO_POSITION.getStorageUint256(); } /** * @notice Set the maximum allowed external shares ratio as basis points of total shares * @param _maxExternalRatioBP The maximum ratio in basis points [0-10000] */ function setMaxExternalRatioBP(uint256 _maxExternalRatioBP) external { _auth(STAKING_CONTROL_ROLE); require(_maxExternalRatioBP <= TOTAL_BASIS_POINTS, "INVALID_MAX_EXTERNAL_RATIO"); MAX_EXTERNAL_RATIO_POSITION.setStorageUint256(_maxExternalRatioBP); emit MaxExternalRatioBPSet(_maxExternalRatioBP); } /** * @notice Send funds to the pool and mint StETH to the `msg.sender` address * @dev Users are able to submit their funds by sending ether to the contract address * Unlike vanilla Ethereum Deposit contract, accepting only 32-Ether transactions, Lido * accepts payments of any size. Submitted ether is stored in the buffer until someone calls * deposit() and pushes it to the Ethereum Deposit contract. */ // solhint-disable-next-line no-complex-fallback 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 the optional `_referral` parameter and mint StETH to the `msg.sender` address * @param _referral optional referral address * @return Amount of StETH shares minted */ 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` * @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 == getLidoLocator().elRewardsVault()); TOTAL_EL_REWARDS_COLLECTED_POSITION.setStorageUint256(getTotalELRewardsCollected().add(msg.value)); emit ELRewardsReceived(msg.value); } /** * @notice A payable function for withdrawals acquisition. Can be called only by `WithdrawalVault` * @dev We need a dedicated function because funds received by the default payable function * are treated as a user deposit */ function receiveWithdrawals() external payable { require(msg.sender == getLidoLocator().withdrawalVault()); emit WithdrawalsReceived(msg.value); } /** * @notice Stop pool routine operations */ function stop() external { _auth(PAUSE_ROLE); _stop(); _pauseStaking(); } /** * @notice Resume pool routine operations * @dev Staking is resumed after this call using the previously set limits (if any) */ function resume() external { _auth(RESUME_ROLE); _resume(); _resumeStaking(); } /** * @notice Unsafely change the deposited validators counter * * The method unsafely changes deposited validator counter. * Can be required when onboarding external validators to Lido * (i.e., had deposited before and rotated their type-0x00 withdrawal credentials to Lido) * * @param _newDepositedValidators new value * * TODO: remove this with maxEB-friendly accounting */ function unsafeChangeDepositedValidators(uint256 _newDepositedValidators) external { _auth(UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE); DEPOSITED_VALIDATORS_POSITION.setStorageUint256(_newDepositedValidators); emit DepositedValidatorsChanged(_newDepositedValidators); } /** * @return the amount of ether temporarily 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 or used to fulfill withdrawal requests */ function getBufferedEther() external view returns (uint256) { return _getBufferedEther(); } /** * @return the amount of ether held by external sources to back external shares */ function getExternalEther() external view returns (uint256) { return _getExternalEther(_getInternalEther()); } /** * @return the total amount of shares backed by external ether sources */ function getExternalShares() external view returns (uint256) { return EXTERNAL_SHARES_POSITION.getStorageUint256(); } /** * @return the maximum amount of external shares that can be minted under the current external ratio limit */ function getMaxMintableExternalShares() external view returns (uint256) { return _getMaxMintableExternalShares(); } /** * @return the total amount of Execution Layer rewards collected to the Lido contract * @dev ether received through LidoExecutionLayerRewardsVault is kept on this contract's balance the same way * as other buffered ether is kept (until it gets deposited or withdrawn) */ function getTotalELRewardsCollected() public view returns (uint256) { return TOTAL_EL_REWARDS_COLLECTED_POSITION.getStorageUint256(); } /** * @return the Lido Locator address */ function getLidoLocator() public view returns (ILidoLocator) { return ILidoLocator(LIDO_LOCATOR_POSITION.getStorageAddress()); } /** * @notice Get the key values related to the Consensus Layer side of the contract. * @return depositedValidators - number of deposited validators from Lido contract side * @return beaconValidators - number of Lido validators visible on Consensus Layer, reported by oracle * @return beaconBalance - total amount of ether on the Consensus Layer side (sum of all the balances of Lido validators) */ function getBeaconStat() external view returns (uint256 depositedValidators, uint256 beaconValidators, uint256 beaconBalance) { depositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256(); beaconValidators = CL_VALIDATORS_POSITION.getStorageUint256(); beaconBalance = CL_BALANCE_POSITION.getStorageUint256(); } /** * @notice Check that Lido allows depositing buffered ether to the Consensus Layer * @dev Depends on the bunker mode and protocol pause state */ function canDeposit() public view returns (bool) { return !_withdrawalQueue().isBunkerModeActive() && !isStopped(); } /** * @return the amount of ether in the buffer that can be deposited to the Consensus Layer * @dev Takes into account unfinalized stETH required by WithdrawalQueue */ function getDepositableEther() public view returns (uint256) { uint256 bufferedEther = _getBufferedEther(); uint256 withdrawalReserve = _withdrawalQueue().unfinalizedStETH(); return bufferedEther > withdrawalReserve ? bufferedEther - withdrawalReserve : 0; } /** * @notice Invoke a deposit call to the Staking Router contract and update buffered counters * @param _maxDepositsCount max deposits count * @param _stakingModuleId id of the staking module to be deposited * @param _depositCalldata module calldata */ function deposit(uint256 _maxDepositsCount, uint256 _stakingModuleId, bytes _depositCalldata) external { ILidoLocator locator = getLidoLocator(); require(msg.sender == locator.depositSecurityModule(), "APP_AUTH_DSM_FAILED"); require(canDeposit(), "CAN_NOT_DEPOSIT"); IStakingRouter stakingRouter = IStakingRouter(locator.stakingRouter()); uint256 depositsCount = Math256.min( _maxDepositsCount, stakingRouter.getStakingModuleMaxDepositsCount(_stakingModuleId, getDepositableEther()) ); uint256 depositsValue; if (depositsCount > 0) { depositsValue = depositsCount.mul(DEPOSIT_SIZE); /// @dev firstly update the local state of the contract to prevent a reentrancy attack, /// even if the StakingRouter is a trusted contract. BUFFERED_ETHER_POSITION.setStorageUint256(_getBufferedEther().sub(depositsValue)); emit Unbuffered(depositsValue); uint256 newDepositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256().add(depositsCount); DEPOSITED_VALIDATORS_POSITION.setStorageUint256(newDepositedValidators); emit DepositedValidatorsChanged(newDepositedValidators); } /// @dev transfer ether to StakingRouter and make a deposit at the same time. All the ether /// sent to StakingRouter is counted as deposited. If StakingRouter can't deposit all /// passed ether it MUST revert the whole transaction (never happens in normal circumstances) stakingRouter.deposit.value(depositsValue)(depositsCount, _stakingModuleId, _depositCalldata); } /** * @notice Mint stETH shares * @param _recipient recipient of the shares * @param _amountOfShares amount of shares to mint * @dev can be called only by accounting */ function mintShares(address _recipient, uint256 _amountOfShares) public { _auth(getLidoLocator().accounting()); _whenNotStopped(); _mintShares(_recipient, _amountOfShares); // emit event after minting shares because we are always having the net new ether under the hood // for vaults we have new locked ether and for fees we have a part of rewards _emitTransferAfterMintingShares(_recipient, _amountOfShares); } /** * @notice Burn stETH shares from the `msg.sender` address * @param _amountOfShares amount of shares to burn * @dev can be called only by burner */ function burnShares(uint256 _amountOfShares) public { _auth(getLidoLocator().burner()); _whenNotStopped(); _burnShares(msg.sender, _amountOfShares); // historically there is no events for this kind of burning // TODO: should burn events be emitted here? // maybe TransferShare for cover burn and all events for withdrawal burn } /** * @notice Mint shares backed by external ether sources * @param _recipient Address to receive the minted shares * @param _amountOfShares Amount of shares to mint * @dev Can be called only by VaultHub * NB: Reverts if the the external balance limit is exceeded. */ function mintExternalShares(address _recipient, uint256 _amountOfShares) external { require(_recipient != address(0), "MINT_RECEIVER_ZERO_ADDRESS"); require(_amountOfShares != 0, "MINT_ZERO_AMOUNT_OF_SHARES"); _auth(getLidoLocator().vaultHub()); _whenNotStopped(); uint256 newExternalShares = EXTERNAL_SHARES_POSITION.getStorageUint256().add(_amountOfShares); uint256 maxMintableExternalShares = _getMaxMintableExternalShares(); require(newExternalShares <= maxMintableExternalShares, "EXTERNAL_BALANCE_LIMIT_EXCEEDED"); EXTERNAL_SHARES_POSITION.setStorageUint256(newExternalShares); _mintShares(_recipient, _amountOfShares); // emit event after minting shares because we are always having the net new ether under the hood // for vaults we have new locked ether and for fees we have a part of rewards _emitTransferAfterMintingShares(_recipient, _amountOfShares); emit ExternalSharesMinted(_recipient, _amountOfShares, getPooledEthByShares(_amountOfShares)); } /** * @notice Burn external shares from the `msg.sender` address * @param _amountOfShares Amount of shares to burn */ function burnExternalShares(uint256 _amountOfShares) external { require(_amountOfShares != 0, "BURN_ZERO_AMOUNT_OF_SHARES"); _auth(getLidoLocator().vaultHub()); _whenNotStopped(); uint256 externalShares = EXTERNAL_SHARES_POSITION.getStorageUint256(); if (externalShares < _amountOfShares) revert("EXT_SHARES_TOO_SMALL"); EXTERNAL_SHARES_POSITION.setStorageUint256(externalShares - _amountOfShares); _burnShares(msg.sender, _amountOfShares); uint256 stethAmount = getPooledEthByShares(_amountOfShares); _emitTransferEvents(msg.sender, address(0), stethAmount, _amountOfShares); emit ExternalSharesBurned(msg.sender, _amountOfShares, stethAmount); } /** * @notice Transfer ether to the buffer decreasing the number of external shares in the same time * @dev it's an equivalent of using `submit` and then `burnExternalShares` * but without any limits or pauses * * - msg.value is transferred to the buffer */ function rebalanceExternalEtherToInternal() external payable { require(msg.value != 0, "ZERO_VALUE"); _auth(getLidoLocator().vaultHub()); _whenNotStopped(); uint256 shares = getSharesByPooledEth(msg.value); uint256 externalShares = EXTERNAL_SHARES_POSITION.getStorageUint256(); if (externalShares < shares) revert("EXT_SHARES_TOO_SMALL"); // here the external balance is decreased (totalShares remains the same) EXTERNAL_SHARES_POSITION.setStorageUint256(externalShares - shares); // here the buffer is increased _setBufferedEther(_getBufferedEther().add(msg.value)); // the result can be a smallish rebase like 1-2 wei per tx // but it's not worth then using submit for it, // so invariants are the same emit ExternalEtherTransferredToBuffer(msg.value); } /** * @notice Process CL related state changes as a part of the report processing * @dev All data validation was done by Accounting and OracleReportSanityChecker * @param _reportTimestamp timestamp of the report * @param _preClValidators number of validators in the previous CL state (for event compatibility) * @param _reportClValidators number of validators in the current CL state * @param _reportClBalance total balance of the current CL state */ function processClStateUpdate( uint256 _reportTimestamp, uint256 _preClValidators, uint256 _reportClValidators, uint256 _reportClBalance ) external { _whenNotStopped(); _auth(getLidoLocator().accounting()); // Save the current CL balance and validators to // calculate rewards on the next rebase CL_VALIDATORS_POSITION.setStorageUint256(_reportClValidators); CL_BALANCE_POSITION.setStorageUint256(_reportClBalance); emit CLValidatorsUpdated(_reportTimestamp, _preClValidators, _reportClValidators); // cl balance change are logged in ETHDistributed event later } /** * @notice Process withdrawals and collect rewards as a part of the report processing * @dev All data validation was done by Accounting and OracleReportSanityChecker * @param _reportTimestamp timestamp of the report * @param _reportClBalance total balance of validators reported by the oracle * @param _principalCLBalance total balance of validators in the previous report and deposits made since then * @param _withdrawalsToWithdraw amount of withdrawals to collect from WithdrawalsVault * @param _elRewardsToWithdraw amount of EL rewards to collect from ELRewardsVault * @param _lastWithdrawalRequestToFinalize last withdrawal request ID to finalize * @param _withdrawalsShareRate share rate used to fulfill withdrawal requests * @param _etherToLockOnWithdrawalQueue amount of ETH to lock on the WithdrawalQueue to fulfill withdrawal requests */ function collectRewardsAndProcessWithdrawals( uint256 _reportTimestamp, uint256 _reportClBalance, uint256 _principalCLBalance, uint256 _withdrawalsToWithdraw, uint256 _elRewardsToWithdraw, uint256 _lastWithdrawalRequestToFinalize, uint256 _withdrawalsShareRate, uint256 _etherToLockOnWithdrawalQueue ) external { _whenNotStopped(); ILidoLocator locator = getLidoLocator(); _auth(locator.accounting()); // withdraw execution layer rewards and put them to the buffer if (_elRewardsToWithdraw > 0) { ILidoExecutionLayerRewardsVault(locator.elRewardsVault()).withdrawRewards(_elRewardsToWithdraw); } // withdraw withdrawals and put them to the buffer if (_withdrawalsToWithdraw > 0) { IWithdrawalVault(locator.withdrawalVault()).withdrawWithdrawals(_withdrawalsToWithdraw); } // finalize withdrawals (send ether, assign shares for burning) if (_etherToLockOnWithdrawalQueue > 0) { IWithdrawalQueue(locator.withdrawalQueue()).finalize.value(_etherToLockOnWithdrawalQueue)( _lastWithdrawalRequestToFinalize, _withdrawalsShareRate ); } uint256 postBufferedEther = _getBufferedEther() .add(_elRewardsToWithdraw) // Collected from ELVault .add(_withdrawalsToWithdraw) // Collected from WithdrawalVault .sub(_etherToLockOnWithdrawalQueue); // Sent to WithdrawalQueue _setBufferedEther(postBufferedEther); emit ETHDistributed( _reportTimestamp, _principalCLBalance, _reportClBalance, _withdrawalsToWithdraw, _elRewardsToWithdraw, postBufferedEther ); } /** * @notice Emit the `TokenRebase` event * @dev It's here for back compatibility reasons */ function emitTokenRebase( uint256 _reportTimestamp, uint256 _timeElapsed, uint256 _preTotalShares, uint256 _preTotalEther, uint256 _postTotalShares, uint256 _postTotalEther, uint256 _postInternalShares, uint256 _postInternalEther, uint256 _sharesMintedAsFees ) external { _auth(getLidoLocator().accounting()); emit TokenRebased( _reportTimestamp, _timeElapsed, _preTotalShares, _preTotalEther, _postTotalShares, _postTotalEther, _sharesMintedAsFees ); emit InternalShareRateUpdated(_reportTimestamp, _postInternalShares, _postInternalEther, _sharesMintedAsFees); } //////////////////////////////////////////////////////////////////////////// ////////////////////// DEPRECATED PUBLIC METHODS /////////////////////////// //////////////////////////////////////////////////////////////////////////// /** * @notice DEPRECATED: Returns current withdrawal credentials of deposited validators * @dev DEPRECATED: use StakingRouter.getWithdrawalCredentials() instead */ function getWithdrawalCredentials() external view returns (bytes32) { return _stakingRouter().getWithdrawalCredentials(); } /** * @notice DEPRECATED: Returns the treasury address * @dev DEPRECATED: use LidoLocator.treasury() */ function getTreasury() external view returns (address) { return getLidoLocator().treasury(); } /** * @notice DEPRECATED: Returns current staking rewards fee rate * @dev DEPRECATED: Now fees information is stored in StakingRouter and * with higher precision. Use StakingRouter.getStakingFeeAggregateDistribution() instead. * @return totalFee total rewards fee in 1e4 precision (10000 is 100%). The value might be * inaccurate because the actual value is truncated here to 1e4 precision. */ function getFee() external view returns (uint16 totalFee) { totalFee = _stakingRouter().getTotalFeeE4Precision(); } /** * @notice DEPRECATED: Returns current fee distribution, values relative to the total fee (getFee()) * @dev DEPRECATED: Now fees information is stored in StakingRouter and * with higher precision. Use StakingRouter.getStakingFeeAggregateDistribution() instead. * @return treasuryFeeBasisPoints return treasury fee in TOTAL_BASIS_POINTS (10000 is 100% fee) precision * @return insuranceFeeBasisPoints always returns 0 because the capability to send fees to * insurance from Lido contract is removed. * @return operatorsFeeBasisPoints return total fee for all operators of all staking modules in * TOTAL_BASIS_POINTS (10000 is 100% fee) precision. * Previously returned total fee of all node operators of NodeOperatorsRegistry (Curated staking module now) * The value might be inaccurate because the actual value is truncated here to 1e4 precision. */ function getFeeDistribution() external view returns (uint16 treasuryFeeBasisPoints, uint16 insuranceFeeBasisPoints, uint16 operatorsFeeBasisPoints) { IStakingRouter stakingRouter = _stakingRouter(); uint256 totalBasisPoints = stakingRouter.TOTAL_BASIS_POINTS(); uint256 totalFee = stakingRouter.getTotalFeeE4Precision(); (uint256 treasuryFeeBasisPointsAbs, uint256 operatorsFeeBasisPointsAbs) = stakingRouter .getStakingFeeAggregateDistributionE4Precision(); insuranceFeeBasisPoints = 0; // explicitly set to zero treasuryFeeBasisPoints = uint16((treasuryFeeBasisPointsAbs * totalBasisPoints) / totalFee); operatorsFeeBasisPoints = uint16((operatorsFeeBasisPointsAbs * totalBasisPoints) / totalFee); } /** * @notice Overrides default AragonApp behavior to disallow recovery. */ function transferToVault(address /* _token */) external { revert("NOT_SUPPORTED"); } /// @dev Process user deposit, mint liquid tokens and increase the pool buffer /// @param _referral address of referral. /// @return amount of StETH shares minted function _submit(address _referral) internal returns (uint256) { require(msg.value != 0, "ZERO_DEPOSIT"); StakeLimitState.Data memory stakeLimitData = STAKING_STATE_POSITION.getStorageStakeLimitStruct(); // There is an invariant that protocol pause also implies staking pause. // Thus, no need to check protocol pause explicitly. 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); _mintShares(msg.sender, sharesAmount); _setBufferedEther(_getBufferedEther().add(msg.value)); emit Submitted(msg.sender, msg.value, _referral); _emitTransferAfterMintingShares(msg.sender, sharesAmount); return sharesAmount; } /// @dev Get the amount of ether temporary buffered on this contract balance function _getBufferedEther() internal view returns (uint256) { return BUFFERED_ETHER_POSITION.getStorageUint256(); } /// @dev Set the amount of ether temporary buffered on this contract balance function _setBufferedEther(uint256 _newBufferedEther) internal { BUFFERED_ETHER_POSITION.setStorageUint256(_newBufferedEther); } /// @dev Calculate and return 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 CL state. /// @return transient ether in wei (1e-18 Ether) function _getTransientEther() internal view returns (uint256) { uint256 depositedValidators = DEPOSITED_VALIDATORS_POSITION.getStorageUint256(); uint256 clValidators = CL_VALIDATORS_POSITION.getStorageUint256(); // clValidators can never be less than deposited ones. assert(depositedValidators >= clValidators); return (depositedValidators - clValidators).mul(DEPOSIT_SIZE); } /// @dev Get the total amount of ether controlled by the protocol internally /// (buffered + CL balance of StakingRouter controlled validators + transient) function _getInternalEther() internal view returns (uint256) { return _getBufferedEther() .add(CL_BALANCE_POSITION.getStorageUint256()) .add(_getTransientEther()); } /// @dev Calculate the amount of ether controlled by external entities function _getExternalEther(uint256 _internalEther) internal view returns (uint256) { uint256 externalShares = EXTERNAL_SHARES_POSITION.getStorageUint256(); uint256 internalShares = _getTotalShares() - externalShares; return externalShares.mul(_internalEther).div(internalShares); } /// @dev Get the total amount of ether controlled by the protocol and external entities /// @return total balance in wei function _getTotalPooledEther() internal view returns (uint256) { uint256 internalEther = _getInternalEther(); return internalEther.add(_getExternalEther(internalEther)); } /// @dev the numerator (in ether) of the share rate for StETH conversion between shares and ether and vice versa. /// using the numerator and denominator different from totalShares and totalPooledEther allows to: /// - avoid double precision loss on additional division on external ether calculations /// - optimize gas cost of conversions between shares and ether function _getShareRateNumerator() internal view returns (uint256) { return _getInternalEther(); } /// @dev the denominator (in shares) of the share rate for StETH conversion between shares and ether and vice versa. function _getShareRateDenominator() internal view returns (uint256) { uint256 externalShares = EXTERNAL_SHARES_POSITION.getStorageUint256(); uint256 internalShares = _getTotalShares() - externalShares; // never 0 because of the stone in the elevator return internalShares; } /// @notice Calculate the maximum amount of external shares that can be minted while maintaining /// maximum allowed external ratio limits /// @return Maximum amount of external shares that can be minted /// @dev This function enforces the ratio between external and total shares to stay below a limit. /// The limit is defined by some maxRatioBP out of totalBP. /// /// The calculation ensures: (externalShares + x) / (totalShares + x) <= maxRatioBP / totalBP /// Which gives formula: x <= (totalShares * maxRatioBP - externalShares * totalBP) / (totalBP - maxRatioBP) /// /// Special cases: /// - Returns 0 if maxBP is 0 (external minting is disabled) or external shares already exceed the limit /// - Returns 2^256-1 if maxBP is 100% (external minting is unlimited) function _getMaxMintableExternalShares() internal view returns (uint256) { uint256 maxRatioBP = MAX_EXTERNAL_RATIO_POSITION.getStorageUint256(); if (maxRatioBP == 0) return 0; if (maxRatioBP == TOTAL_BASIS_POINTS) return uint256(-1); uint256 externalShares = EXTERNAL_SHARES_POSITION.getStorageUint256(); uint256 totalShares = _getTotalShares(); if (totalShares.mul(maxRatioBP) <= externalShares.mul(TOTAL_BASIS_POINTS)) return 0; return (totalShares.mul(maxRatioBP) - externalShares.mul(TOTAL_BASIS_POINTS)).div( TOTAL_BASIS_POINTS - maxRatioBP ); } 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 Bytecode size-efficient analog of the `auth(_role)` modifier /// @param _role Permission name function _auth(bytes32 _role) internal view { require(canPerform(msg.sender, _role, new uint256[](0)), "APP_AUTH_FAILED"); } /// @dev simple address-based auth function _auth(address _address) internal view { require(msg.sender == _address, "APP_AUTH_FAILED"); } function _stakingRouter() internal view returns (IStakingRouter) { return IStakingRouter(getLidoLocator().stakingRouter()); } function _withdrawalQueue() internal view returns (IWithdrawalQueue) { return IWithdrawalQueue(getLidoLocator().withdrawalQueue()); } /// @notice Mints shares on behalf of 0xdead address, /// the shares amount is equal to the contract's balance. /// /// Allows to get rid of zero checks for `totalShares` and `totalPooledEther` /// and overcome corner cases. /// /// NB: reverts if the current contract's balance is zero. /// /// @dev must be invoked before using the token function _bootstrapInitialHolder() internal { uint256 balance = address(this).balance; assert(balance != 0); if (_getTotalShares() == 0) { // if protocol is empty, bootstrap it with the contract's balance // address(0xdead) is a holder for initial shares _setBufferedEther(balance); // emitting `Submitted` before Transfer events to preserve events order in tx emit Submitted(INITIAL_TOKEN_HOLDER, balance, 0); _mintInitialShares(balance); } } }
/*
* 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;
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;
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;
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
}
}/*
* 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;
// 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;
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;
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;
}
}/*
* 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 "../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);
}
}// 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;
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);
}
}/*
* 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 "../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;
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;
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;
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;
}// 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/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-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ pragma solidity 0.4.24; import {UnstructuredStorage} from "@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; // block number of the previous stake submit uint96 prevStakeLimit; // limit value (<= `maxStakeLimit`) obtained on the previous stake submit uint32 maxStakeLimitGrowthBlocks; // limit regeneration speed expressed in blocks uint96 maxStakeLimit; // maximum limit value } } 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. * @dev using `_constGasMin` to make gas consumption independent of the current block number */ function calculateCurrentStakeLimit(StakeLimitState.Data memory _data) internal view returns(uint256 limit) { uint256 stakeLimitIncPerBlock; if (_data.maxStakeLimitGrowthBlocks != 0) { stakeLimitIncPerBlock = _data.maxStakeLimit / _data.maxStakeLimitGrowthBlocks; } uint256 blocksPassed = block.number - _data.prevStakeBlockNumber; uint256 projectedLimit = _data.prevStakeLimit + blocksPassed * stakeLimitIncPerBlock; limit = _constGasMin( projectedLimit, _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" ); // reset prev stake limit to the new max stake limit if if ( // staking was paused or _data.prevStakeBlockNumber == 0 || // staking was unlimited or _data.maxStakeLimit == 0 || // new maximum limit value is lower than the value obtained on the previous stake submit _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 pure 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; } /** * @notice find a minimum of two numbers with a constant gas consumption * @dev doesn't use branching logic inside * @param _lhs left hand side value * @param _rhs right hand side value */ function _constGasMin(uint256 _lhs, uint256 _rhs) internal pure returns (uint256 min) { uint256 lhsIsLess; assembly { lhsIsLess := lt(_lhs, _rhs) // lhsIsLess = (_lhs < _rhs) ? 1 : 0 } min = (_lhs * lhsIsLess) + (_rhs * (1 - lhsIsLess)); } }
// SPDX-FileCopyrightText: 2025 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ pragma solidity 0.4.24; import {IERC20} from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; import {UnstructuredStorage} from "@aragon/os/contracts/common/UnstructuredStorage.sol"; import {SafeMath} from "@aragon/os/contracts/lib/math/SafeMath.sol"; import {Pausable} from "./utils/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; address constant internal INITIAL_TOKEN_HOLDER = 0xdead; uint256 constant internal INFINITE_ALLOWANCE = ~uint256(0); /** * @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 * * keccak256("lido.StETH.totalShares") */ bytes32 internal constant TOTAL_SHARES_POSITION = 0xe3b4b636e601189b5f4c6742edf2538ac12bb61ed03e6da26949d69838fa447e; /** * @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() external pure returns (string) { return "Liquid staked Ether 2.0"; } /** * @return the symbol of the token, usually a shorter version of the * name. */ function symbol() external pure returns (string) { return "stETH"; } /** * @return the number of decimals for getting user representation of a token amount. */ function decimals() external 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() external 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() external 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) external 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 or the stETH contract itself. * - 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) external 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) external view returns (uint256) { return allowances[_owner][_spender]; } /** * @notice Sets `_amount` as the allowance of `_spender` over the caller's tokens. * * @dev allowance can be set to "infinity" (INFINITE_ALLOWANCE). * In this case allowance is not to be spent on transfer, that can save some gas. * * @return a boolean value indicating whether the operation succeeded. * Emits an `Approval` event. * * Requirements: * * - `_spender` cannot be the zero address. * * @dev The `_amount` argument is the amount of tokens, not shares. */ function approve(address _spender, uint256 _amount) external 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 if it's not infinite. * * @return a boolean value indicating whether the operation succeeded. * * Emits a `Transfer` event. * Emits a `TransferShares` event. * Emits an `Approval` event if the allowance is updated. * * Requirements: * * - `_sender` cannot be the zero address. * - `_recipient` cannot be the zero address or the stETH contract itself. * - `_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) external returns (bool) { _spendAllowance(_sender, msg.sender, _amount); _transfer(_sender, _recipient, _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/b709eae01d1da91902d06ace340df6b324e6f049/contracts/token/ERC20/IERC20.sol#L57 * Emits an `Approval` event indicating the updated allowance. * * Requirements: * * - `_spender` cannot be the the zero address. */ function increaseAllowance(address _spender, uint256 _addedValue) external 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/b709eae01d1da91902d06ace340df6b324e6f049/contracts/token/ERC20/IERC20.sol#L57 * 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`. */ function decreaseAllowance(address _spender, uint256 _subtractedValue) external returns (bool) { uint256 currentAllowance = allowances[msg.sender][_spender]; require(currentAllowance >= _subtractedValue, "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() external view returns (uint256) { return _getTotalShares(); } /** * @return the amount of shares owned by `_account`. */ function sharesOf(address _account) external 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) { return _ethAmount .mul(_getShareRateDenominator()) // denominator in shares .div(_getShareRateNumerator()); // numerator in ether } /** * @return the amount of ether that corresponds to `_sharesAmount` token shares. */ function getPooledEthByShares(uint256 _sharesAmount) public view returns (uint256) { return _sharesAmount .mul(_getShareRateNumerator()) // numerator in ether .div(_getShareRateDenominator()); // denominator in shares } /** * @return the amount of ether that corresponds to `_sharesAmount` token shares. * @dev The result is rounded up. So, * for `shareRate >= 0.5`, `getSharesByPooledEth(getPooledEthBySharesRoundUp(1))` will be 1. */ function getPooledEthBySharesRoundUp(uint256 _sharesAmount) public view returns (uint256 etherAmount) { uint256 numeratorInEther = _getShareRateNumerator(); uint256 denominatorInShares = _getShareRateDenominator(); etherAmount = _sharesAmount .mul(numeratorInEther) .div(denominatorInShares); if (_sharesAmount.mul(numeratorInEther) != etherAmount.mul(denominatorInShares)) { ++etherAmount; } } /** * @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 or the stETH contract itself. * - 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) external returns (uint256) { _transferShares(msg.sender, _recipient, _sharesAmount); uint256 tokensAmount = getPooledEthByShares(_sharesAmount); _emitTransferEvents(msg.sender, _recipient, tokensAmount, _sharesAmount); return tokensAmount; } /** * @notice Moves `_sharesAmount` token shares from the `_sender` account to the `_recipient` account. * * @return amount of transferred tokens. * Emits a `TransferShares` event. * Emits a `Transfer` event. * * Requirements: * * - `_sender` and `_recipient` cannot be the zero addresses. * - `_sender` must have at least `_sharesAmount` shares. * - the caller must have allowance for `_sender`'s tokens of at least `getPooledEthByShares(_sharesAmount)`. * - the contract must not be paused. * * @dev The `_sharesAmount` argument is the amount of shares, not tokens. */ function transferSharesFrom( address _sender, address _recipient, uint256 _sharesAmount ) external returns (uint256) { uint256 tokensAmount = getPooledEthByShares(_sharesAmount); _spendAllowance(_sender, msg.sender, tokensAmount); _transferShares(_sender, _recipient, _sharesAmount); _emitTransferEvents(_sender, _recipient, tokensAmount, _sharesAmount); 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); /** * @return the numerator of the protocol's share rate (in ether). * @dev used to convert shares to tokens and vice versa. */ function _getShareRateNumerator() internal view returns (uint256) { return _getTotalPooledEther(); } /** * @return the denominator of the protocol's share rate (in shares). * @dev used to convert shares to tokens and vice versa. */ function _getShareRateDenominator() internal view returns (uint256) { return _getTotalShares(); } /** * @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); _emitTransferEvents(_sender, _recipient, _amount, _sharesToTransfer); } /** * @notice Sets `_amount` as the allowance of `_spender` over the `_owner` s tokens. * * Emits an `Approval` event. * * NB: the method can be invoked even if the protocol paused. * * Requirements: * * - `_owner` cannot be the zero address. * - `_spender` cannot be the zero address. */ function _approve(address _owner, address _spender, uint256 _amount) internal { require(_owner != address(0), "APPROVE_FROM_ZERO_ADDR"); require(_spender != address(0), "APPROVE_TO_ZERO_ADDR"); allowances[_owner][_spender] = _amount; emit Approval(_owner, _spender, _amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address _owner, address _spender, uint256 _amount) internal { uint256 currentAllowance = allowances[_owner][_spender]; if (currentAllowance != INFINITE_ALLOWANCE) { require(currentAllowance >= _amount, "ALLOWANCE_EXCEEDED"); _approve(_owner, _spender, currentAllowance - _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 or the `stETH` token contract itself * - `_sender` must hold at least `_sharesAmount` shares. * - the contract must not be paused. */ function _transferShares(address _sender, address _recipient, uint256 _sharesAmount) internal { require(_sender != address(0), "TRANSFER_FROM_ZERO_ADDR"); require(_recipient != address(0), "TRANSFER_TO_ZERO_ADDR"); require(_recipient != address(this), "TRANSFER_TO_STETH_CONTRACT"); _whenNotStopped(); uint256 currentSenderShares = shares[_sender]; require(_sharesAmount <= currentSenderShares, "BALANCE_EXCEEDED"); 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. * * NB: The method doesn't check protocol pause relying on the external enforcement. * * Requirements: * * - `_recipient` cannot be the zero address. * - the contract must not be paused. */ function _mintShares(address _recipient, uint256 _sharesAmount) internal returns (uint256 newTotalShares) { require(_recipient != address(0), "MINT_TO_ZERO_ADDR"); 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 returns (uint256 newTotalShares) { require(_account != address(0), "BURN_FROM_ZERO_ADDR"); uint256 accountShares = shares[_account]; require(_sharesAmount <= accountShares, "BALANCE_EXCEEDED"); 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. } /** * @dev Emits {Transfer} and {TransferShares} events */ function _emitTransferEvents(address _from, address _to, uint256 _tokenAmount, uint256 _sharesAmount) internal { emit Transfer(_from, _to, _tokenAmount); emit TransferShares(_from, _to, _sharesAmount); } /** * @dev Emits {Transfer} and {TransferShares} events where `from` is 0 address. Indicates mint events. */ function _emitTransferAfterMintingShares(address _to, uint256 _sharesAmount) internal { _emitTransferEvents(address(0), _to, getPooledEthByShares(_sharesAmount), _sharesAmount); } /** * @dev Mints shares to INITIAL_TOKEN_HOLDER */ function _mintInitialShares(uint256 _sharesAmount) internal { _mintShares(INITIAL_TOKEN_HOLDER, _sharesAmount); _emitTransferAfterMintingShares(INITIAL_TOKEN_HOLDER, _sharesAmount); } }
// SPDX-FileCopyrightText: 2023 OpenZeppelin, Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 /* See contracts/COMPILERS.md */ pragma solidity 0.4.24; import {UnstructuredStorage} from "@aragon/os/contracts/common/UnstructuredStorage.sol"; import {SignatureUtils} from "../common/lib/SignatureUtils.sol"; import {IEIP712StETH} from "../common/interfaces/IEIP712StETH.sol"; import {StETH} from "./StETH.sol"; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold ether at all. */ interface IERC2612 { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); } contract StETHPermit is IERC2612, StETH { using UnstructuredStorage for bytes32; /** * @dev Service event for initialization */ event EIP712StETHInitialized(address eip712StETH); /** * @dev Nonces for ERC-2612 (Permit) */ mapping(address => uint256) internal noncesByAddress; /** * @dev Storage position used for the EIP712 message utils contract * * keccak256("lido.StETHPermit.eip712StETH") */ bytes32 internal constant EIP712_STETH_POSITION = 0x42b2d95e1ce15ce63bf9a8d9f6312cf44b23415c977ffa3b884333422af8941c; /** * @dev Typehash constant for ERC-2612 (Permit) * * keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)") */ bytes32 internal constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). */ function permit( address _owner, address _spender, uint256 _value, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external { require(block.timestamp <= _deadline, "DEADLINE_EXPIRED"); bytes32 structHash = keccak256( abi.encode(PERMIT_TYPEHASH, _owner, _spender, _value, _useNonce(_owner), _deadline) ); bytes32 hash = IEIP712StETH(getEIP712StETH()).hashTypedDataV4(address(this), structHash); require(SignatureUtils.isValidSignature(_owner, hash, _v, _r, _s), "INVALID_SIGNATURE"); _approve(_owner, _spender, _value); } /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256) { return noncesByAddress[owner]; } /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32) { return IEIP712StETH(getEIP712StETH()).domainSeparatorV4(address(this)); } /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. * * NB: comparing to the full-fledged ERC-5267 version: * - `salt` and `extensions` are unused * - `flags` is hex"0f" or 01111b * * @dev using shortened returns to reduce a bytecode size */ function eip712Domain() external view returns ( string memory name, string memory version, uint256 chainId, address verifyingContract ) { return IEIP712StETH(getEIP712StETH()).eip712Domain(address(this)); } /** * @dev "Consume a nonce": return the current value and increment. */ function _useNonce(address _owner) internal returns (uint256 current) { current = noncesByAddress[_owner]; noncesByAddress[_owner] = current.add(1); } /** * @dev Initialize EIP712 message utils contract for stETH */ function _initializeEIP712StETH(address _eip712StETH) internal { require(_eip712StETH != address(0), "ZERO_EIP712STETH"); require(getEIP712StETH() == address(0), "EIP712STETH_ALREADY_SET"); EIP712_STETH_POSITION.setStorageAddress(_eip712StETH); emit EIP712StETHInitialized(_eip712StETH); } /** * @dev Get EIP712 message utils contract */ function getEIP712StETH() public view returns (address) { return EIP712_STETH_POSITION.getStorageAddress(); } }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.24; import {UnstructuredStorage} from "@aragon/os/contracts/common/UnstructuredStorage.sol"; contract Pausable { using UnstructuredStorage for bytes32; event Stopped(); event Resumed(); // keccak256("lido.Pausable.activeFlag") bytes32 internal constant ACTIVE_FLAG_POSITION = 0x644132c4ddd5bb6f0655d5fe2870dcec7870e6be4758890f366b83441f9fdece; function _whenNotStopped() internal view { require(ACTIVE_FLAG_POSITION.getStorageBool(), "CONTRACT_IS_STOPPED"); } function _whenStopped() internal view { require(!ACTIVE_FLAG_POSITION.getStorageBool(), "CONTRACT_IS_ACTIVE"); } function isStopped() public 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(); } }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.24; import "@aragon/os/contracts/common/UnstructuredStorage.sol"; /** * @title Adapted code of /contracts/0.8.9/utils/Versioned.sol * * This contract contains only core part of original Versioned.sol * to reduce contract size */ contract Versioned { using UnstructuredStorage for bytes32; event ContractVersionSet(uint256 version); /// @dev Storage slot: uint256 version /// Version of the initialized contract storage. /// The version stored in CONTRACT_VERSION_POSITION equals to: /// - 0 right after the deployment, before an initializer is invoked (and only at that moment); /// - N after calling initialize(), where N is the initially deployed contract version; /// - N after upgrading contract by calling finalizeUpgrade_vN(). bytes32 internal constant CONTRACT_VERSION_POSITION = 0x4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a6; // keccak256("lido.Versioned.contractVersion"); uint256 internal constant PETRIFIED_VERSION_MARK = uint256(-1); constructor() public { // lock version in the implementation's storage to prevent initialization CONTRACT_VERSION_POSITION.setStorageUint256(PETRIFIED_VERSION_MARK); } /// @notice Returns the current contract version. function getContractVersion() public view returns (uint256) { return CONTRACT_VERSION_POSITION.getStorageUint256(); } function _checkContractVersion(uint256 version) internal view { require(version == getContractVersion(), "UNEXPECTED_CONTRACT_VERSION"); } function _setContractVersion(uint256 version) internal { CONTRACT_VERSION_POSITION.setStorageUint256(version); emit ContractVersionSet(version); } }
// SPDX-FileCopyrightText: 2023 OpenZeppelin, Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 // See contracts/COMPILERS.md // solhint-disable-next-line pragma solidity >=0.4.24 <0.9.0; /** * @dev Helper interface of EIP712 StETH-dedicated helper. * * Has an access to the CHAIN_ID opcode and relies on immutables internally * Both are unavailable for Solidity 0.4.24. */ interface IEIP712StETH { /** * @dev Returns the domain separator for the current chain. */ function domainSeparatorV4(address _stETH) external view returns (bytes32); /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function hashTypedDataV4(address _stETH, bytes32 _structHash) external view returns (bytes32); /** * @dev returns the fields and values that describe the domain separator * used by stETH for EIP-712 signature. */ function eip712Domain(address _stETH) external view returns ( string memory name, string memory version, uint256 chainId, address verifyingContract ); }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: GPL-3.0 // See contracts/COMPILERS.md // solhint-disable-next-line lido/fixed-compiler-version pragma solidity >=0.4.24 <0.9.0; interface ILidoLocator { function accountingOracle() external view returns(address); function depositSecurityModule() external view returns(address); function elRewardsVault() external view returns(address); function lido() external view returns(address); function oracleReportSanityChecker() external view returns(address); function burner() external view returns(address); function stakingRouter() external view returns(address); function treasury() external view returns(address); function validatorsExitBusOracle() external view returns(address); function withdrawalQueue() external view returns(address); function withdrawalVault() external view returns(address); function postTokenRebaseReceiver() external view returns(address); function oracleDaemonConfig() external view returns(address); function accounting() external view returns (address); function predepositGuarantee() external view returns (address); function wstETH() external view returns (address); function vaultHub() external view returns (address); function operatorGrid() external view returns (address); /// @notice Returns core Lido protocol component addresses in a single call /// @dev This function provides a gas-efficient way to fetch multiple component addresses in a single call function coreComponents() external view returns( address elRewardsVault, address oracleReportSanityChecker, address stakingRouter, address treasury, address withdrawalQueue, address withdrawalVault ); /// @notice Returns addresses of components involved in processing oracle reports in the Lido contract /// @dev This function provides a gas-efficient way to fetch multiple component addresses in a single call function oracleReportComponents() external view returns( address accountingOracle, address oracleReportSanityChecker, address burner, address withdrawalQueue, address postTokenRebaseReceiver, address stakingRouter, address vaultHub ); }
// SPDX-License-Identifier: MIT
// Extracted from:
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/cryptography/ECDSA.sol#L53
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/541e821/contracts/utils/cryptography/ECDSA.sol#L112
/* See contracts/COMPILERS.md */
// solhint-disable-next-line
pragma solidity >=0.4.24 <0.9.0;
library ECDSA {
/**
* @dev Returns the address that signed a hashed message (`hash`).
* This address can then be used for verification purposes.
* Receives the `v`, `r` and `s` signature fields separately.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address)
{
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value");
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "ECDSA: invalid signature");
return signer;
}
/**
* @dev Overload of `recover` that receives the `r` and `vs` short-signature fields separately.
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
bytes32 s;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
return recover(hash, v, r, s);
}
}// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: MIT // Copied from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/0457042d93d9dfd760dbaa06a4d2f1216fdbe297/contracts/utils/math/Math.sol // See contracts/COMPILERS.md // solhint-disable-next-line pragma solidity >=0.4.24 <0.9.0; library Math256 { /// @dev Returns the largest of two numbers. function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /// @dev Returns the smallest of two numbers. function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /// @dev Returns the largest of two numbers. function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /// @dev Returns the smallest of two numbers. function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /// @dev Returns the ceiling of the division of two numbers. /// /// This differs from standard division with `/` in that it rounds up instead /// of rounding down. function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /// @dev Returns absolute difference of two numbers. function absDiff(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a - b : b - a; } }
// SPDX-FileCopyrightText: 2023 Lido <[email protected]> // SPDX-License-Identifier: MIT /* See contracts/COMPILERS.md */ // solhint-disable-next-line lido/fixed-compiler-version pragma solidity >=0.4.24 <0.9.0; import {ECDSA} from "./ECDSA.sol"; library SignatureUtils { /** * @dev The selector of the ERC1271's `isValidSignature(bytes32 hash, bytes signature)` function, * serving at the same time as the magic value that the function should return upon success. * * See https://eips.ethereum.org/EIPS/eip-1271. * * bytes4(keccak256("isValidSignature(bytes32,bytes)") */ bytes4 internal constant ERC1271_IS_VALID_SIGNATURE_SELECTOR = 0x1626ba7e; /** * @dev Checks signature validity. * * If the signer address doesn't contain any code, assumes that the address is externally owned * and the signature is a ECDSA signature generated using its private key. Otherwise, issues a * static call to the signer address to check the signature validity using the ERC-1271 standard. */ function isValidSignature( address signer, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s ) internal view returns (bool) { if (_hasCode(signer)) { bytes memory sig = abi.encodePacked(r, s, v); // Solidity <0.5 generates a regular CALL instruction even if the function being called // is marked as `view`, and the only way to perform a STATICCALL is to use assembly bytes memory data = abi.encodeWithSelector(ERC1271_IS_VALID_SIGNATURE_SELECTOR, msgHash, sig); bytes32 retval; /// @solidity memory-safe-assembly assembly { // allocate memory for storing the return value let outDataOffset := mload(0x40) mstore(0x40, add(outDataOffset, 32)) // issue a static call and load the result if the call succeeded let success := staticcall(gas(), signer, add(data, 32), mload(data), outDataOffset, 32) if and(eq(success, 1), eq(returndatasize(), 32)) { retval := mload(outDataOffset) } } return retval == bytes32(ERC1271_IS_VALID_SIGNATURE_SELECTOR); } else { return ECDSA.recover(msgHash, v, r, s) == signer; } } function _hasCode(address addr) internal view returns (bool) { uint256 size; /// @solidity memory-safe-assembly assembly { size := extcodesize(addr) } return size > 0; } }
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
);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "constantinople",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthBySharesRoundUp","outputs":[{"name":"etherAmount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amountOfShares","type":"uint256"}],"name":"mintExternalShares","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":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":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_timeElapsed","type":"uint256"},{"name":"_preTotalShares","type":"uint256"},{"name":"_preTotalEther","type":"uint256"},{"name":"_postTotalShares","type":"uint256"},{"name":"_postTotalEther","type":"uint256"},{"name":"_postInternalShares","type":"uint256"},{"name":"_postInternalEther","type":"uint256"},{"name":"_sharesMintedAsFees","type":"uint256"}],"name":"emitTokenRebase","outputs":[],"payable":false,"stateMutability":"nonpayable","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":"_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":"DOMAIN_SEPARATOR","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPooledEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDepositedValidators","type":"uint256"}],"name":"unsafeChangeDepositedValidators","outputs":[],"payable":false,"stateMutability":"nonpayable","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":"getBufferedEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lidoLocator","type":"address"},{"name":"_eip712StETH","type":"address"}],"name":"initialize","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"receiveELRewards","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amountOfShares","type":"uint256"}],"name":"mintShares","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawalCredentials","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_preClValidators","type":"uint256"},{"name":"_reportClValidators","type":"uint256"},{"name":"_reportClBalance","type":"uint256"}],"name":"processClStateUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentStakeLimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getExternalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","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":false,"inputs":[],"name":"finalizeUpgrade_v3","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"},{"name":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferSharesFrom","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","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":"_amountOfShares","type":"uint256"}],"name":"burnExternalShares","outputs":[],"payable":false,"stateMutability":"nonpayable","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":false,"inputs":[],"name":"receiveWithdrawals","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_sharesAmount","type":"uint256"}],"name":"getPooledEthByShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","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":"owner","type":"address"}],"name":"nonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"rebalanceExternalEtherToInternal","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"appId","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"eip712Domain","outputs":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amountOfShares","type":"uint256"}],"name":"burnShares","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getMaxMintableExternalShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getContractVersion","outputs":[{"name":"","type":"uint256"}],"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":"_recipient","type":"address"},{"name":"_sharesAmount","type":"uint256"}],"name":"transferShares","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_reportTimestamp","type":"uint256"},{"name":"_reportClBalance","type":"uint256"},{"name":"_principalCLBalance","type":"uint256"},{"name":"_withdrawalsToWithdraw","type":"uint256"},{"name":"_elRewardsToWithdraw","type":"uint256"},{"name":"_lastWithdrawalRequestToFinalize","type":"uint256"},{"name":"_withdrawalsShareRate","type":"uint256"},{"name":"_etherToLockOnWithdrawalQueue","type":"uint256"}],"name":"collectRewardsAndProcessWithdrawals","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":"getEIP712StETH","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMaxExternalRatioBP","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"","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":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":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maxDepositsCount","type":"uint256"},{"name":"_stakingModuleId","type":"uint256"},{"name":"_depositCalldata","type":"bytes"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE","outputs":[{"name":"","type":"bytes32"}],"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":"getFee","outputs":[{"name":"totalFee","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":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_deadline","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","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":true,"inputs":[],"name":"getExternalEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getLidoLocator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"STAKING_PAUSE_ROLE","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getDepositableEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_maxExternalRatioBP","type":"uint256"}],"name":"setMaxExternalRatioBP","outputs":[],"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":[],"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":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLValidators","type":"uint256"},{"indexed":false,"name":"postCLValidators","type":"uint256"}],"name":"CLValidatorsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"depositedValidators","type":"uint256"}],"name":"DepositedValidatorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"preCLBalance","type":"uint256"},{"indexed":false,"name":"postCLBalance","type":"uint256"},{"indexed":false,"name":"withdrawalsWithdrawn","type":"uint256"},{"indexed":false,"name":"executionLayerRewardsWithdrawn","type":"uint256"},{"indexed":false,"name":"postBufferedEther","type":"uint256"}],"name":"ETHDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"timeElapsed","type":"uint256"},{"indexed":false,"name":"preTotalShares","type":"uint256"},{"indexed":false,"name":"preTotalEther","type":"uint256"},{"indexed":false,"name":"postTotalShares","type":"uint256"},{"indexed":false,"name":"postTotalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"TokenRebased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"lidoLocator","type":"address"}],"name":"LidoLocatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ELRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"WithdrawalsReceived","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":"reportTimestamp","type":"uint256"},{"indexed":false,"name":"postInternalShares","type":"uint256"},{"indexed":false,"name":"postInternalEther","type":"uint256"},{"indexed":false,"name":"sharesMintedAsFees","type":"uint256"}],"name":"InternalShareRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"receiver","type":"address"},{"indexed":false,"name":"amountOfShares","type":"uint256"},{"indexed":false,"name":"amountOfStETH","type":"uint256"}],"name":"ExternalSharesMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"amountOfShares","type":"uint256"},{"indexed":false,"name":"stethAmount","type":"uint256"}],"name":"ExternalSharesBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"maxExternalRatioBP","type":"uint256"}],"name":"MaxExternalRatioBPSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"ExternalEtherTransferredToBuffer","type":"event"},{"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":false,"name":"eip712StETH","type":"address"}],"name":"EIP712StETHInitialized","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":[{"indexed":false,"name":"version","type":"uint256"}],"name":"ContractVersionSet","type":"event"}]Contract Creation Code
60806040526200003e7f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a660001962000054602090811b6200415b17901c565b6200004e6200005860201b60201c565b6200026b565b9055565b620000686200015a60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901562000144576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101562000108578181015183820152602001620000ee565b50505050905090810190601f168015620001365780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50620001586000196200018d60201b60201c565b565b6000620001886000805160206200580a83398151915260001b600019166200026760201b6200406d1760201c565b905090565b6200019d6200015a60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156200023c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360008381101562000108578181015183820152602001620000ee565b50620002646000805160206200580a8339815191528262000054602090811b6200415b17901c565b50565b5490565b61558f806200027b6000396000f3006080604052600436106103945760003560e01c63ffffffff1680630103349c146103f7578063046f7da21461042157806306f187a41461043857806306fdde031461045c57806307da68f5146104e65780630803fac0146104fb578063095ea7b314610524578063136dd43c1461054857806318160ddd1461055d57806319208451146105725780631b2500971461058a5780631ea7ca89146105bb57806323b872dd146105d05780632914b9bd146105fa5780632cb5f7841461066f5780632de03aa11461068a578063313ce5671461069f57806332f0a3b5146106ca5780633644e515146106df57806337cfdaca1461055d57806338998624146106f4578063389ed2671461070c57806339509351146107215780633b19e84a146107455780633f683b6a1461075a57806347b714e01461076f578063485cc955146107845780634ad509b21461079e578063528c198a146107a657806356396715146107ca578063603540cd146107df578063609c4c6c1461080057806363021d8b14610815578063665b4b0b1461082a5780636d395b7e146108795780636d7804591461088e57806370a08231146108b857806372e62e56146108d95780637475f913146108f1578063752f77f11461090657806378ffcfe2146109415780637a28fb88146109495780637e7db6e1146109615780637ecebe00146109825780637f2d491e146109a357806380afdea8146109ab57806384b0196e146109c0578063853c637d14610ac85780638831f09e14610ae05780638aa1043514610af55780638b3dd74914610b0a5780638fcb4e5b14610b1f5780639271e3e614610b4357806395d89b4114610b705780639861f8e514610b855780639ca5a3d014610b9a5780639d4941d814610baf578063a1658fad14610bd0578063a1903eab14610c37578063a457c2d714610c4b578063a479e50814610c6f578063a9059cbb14610c84578063aa0b7db714610ca8578063ad1394e914610cd0578063ae2e353814610ce5578063b3320d9a14610d18578063ced72f8714610d2d578063d4aae0c414610d59578063d5002f2e14610d6e578063d505accf14610d83578063dd62ed3e14610dbc578063de4796ed14610de3578063e16a906514610df8578063e654ff1714610e0d578063e78a587514610e22578063eb85262f14610e37578063f2cfa87d14610e4c578063f352e17e14610e61578063f5eb42dc14610e79578063f999c50614610e9a578063fa64ebac14610eaf575b36156103ea576040805160e560020a62461bcd02815260206004820152600e60248201527f4e4f4e5f454d5054595f44415441000000000000000000000000000000000000604482015290519081900360640190fd5b6103f46000610ec4565b50005b34801561040357600080fd5b5061040f6004356110ca565b60408051918252519081900360200190f35b34801561042d57600080fd5b50610436611138565b005b34801561044457600080fd5b50610436600160a060020a0360043516602435611173565b34801561046857600080fd5b506104716113b0565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104ab578181015183820152602001610493565b50505050905090810190601f1680156104d85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104f257600080fd5b506104366113e7565b34801561050757600080fd5b50610510611420565b604080519115158252519081900360200190f35b34801561053057600080fd5b50610510600160a060020a0360043516602435611449565b34801561055457600080fd5b5061040f61145f565b34801561056957600080fd5b5061040f611471565b34801561057e57600080fd5b5061040f600435611480565b34801561059657600080fd5b5061043660043560243560443560643560843560a43560c43560e435610104356114ad565b3480156105c757600080fd5b50610510611598565b3480156105dc57600080fd5b50610510600160a060020a03600435811690602435166044356115b9565b34801561060657600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526106539436949293602493928401919081908401838280828437509497506115db9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b34801561067b57600080fd5b506104366004356024356116be565b34801561069657600080fd5b5061040f611740565b3480156106ab57600080fd5b506106b4611764565b6040805160ff9092168252519081900360200190f35b3480156106d657600080fd5b50610653611769565b3480156106eb57600080fd5b5061040f6117de565b34801561070057600080fd5b5061043660043561183f565b34801561071857600080fd5b5061040f6118bc565b34801561072d57600080fd5b50610510600160a060020a03600435166024356118e0565b34801561075157600080fd5b50610653611921565b34801561076657600080fd5b50610510611965565b34801561077b57600080fd5b5061040f611984565b610436600160a060020a036004358116906024351661198e565b610436611be2565b3480156107b257600080fd5b50610436600160a060020a0360043516602435611cd5565b3480156107d657600080fd5b5061040f611cfd565b3480156107eb57600080fd5b50610436600435602435604435606435611d41565b34801561080c57600080fd5b5061040f611df4565b34801561082157600080fd5b5061040f611e15565b34801561083657600080fd5b5061083f611e2e565b6040805197151588529515156020880152868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b34801561088557600080fd5b50610436611ebf565b34801561089a57600080fd5b5061040f600160a060020a0360043581169060243516604435611f2f565b3480156108c457600080fd5b5061040f600160a060020a0360043516611f6b565b3480156108e557600080fd5b50610436600435611f7e565b3480156108fd57600080fd5b506104366120de565b34801561091257600080fd5b5061091b612153565b6040805161ffff9485168152928416602084015292168183015290519081900360600190f35b610436612328565b34801561095557600080fd5b5061040f6004356123df565b34801561096d57600080fd5b50610510600160a060020a03600435166123f7565b34801561098e57600080fd5b5061040f600160a060020a03600435166123fd565b610436612418565b3480156109b757600080fd5b5061040f612567565b3480156109cc57600080fd5b506109d5612592565b60408051908101839052600160a060020a038216606082015260808082528551908201528451819060208083019160a084019189019080838360005b83811015610a29578181015183820152602001610a11565b50505050905090810190601f168015610a565780820380516001836020036101000a031916815260200191505b50838103825286518152865160209182019188019080838360005b83811015610a89578181015183820152602001610a71565b50505050905090810190601f168015610ab65780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390f35b348015610ad457600080fd5b506104366004356126e1565b348015610aec57600080fd5b5061040f612738565b348015610b0157600080fd5b5061040f612742565b348015610b1657600080fd5b5061040f61276d565b348015610b2b57600080fd5b5061040f600160a060020a0360043516602435612798565b348015610b4f57600080fd5b5061043660043560243560443560643560843560a43560c43560e4356127c8565b348015610b7c57600080fd5b50610471612b85565b348015610b9157600080fd5b50610653612bbc565b348015610ba657600080fd5b5061040f612be7565b348015610bbb57600080fd5b50610436600160a060020a0360043516612c12565b348015610bdc57600080fd5b506040805160206004604435818101358381028086018501909652808552610510958335600160a060020a0316956024803596369695606495939492019291829185019084908082843750949750612c629650505050505050565b61040f600160a060020a0360043516612dad565b348015610c5757600080fd5b50610510600160a060020a0360043516602435612db8565b348015610c7b57600080fd5b50610653612e49565b348015610c9057600080fd5b50610510600160a060020a0360043516602435612efe565b348015610cb457600080fd5b5061043660048035906024803591604435918201910135612f0b565b348015610cdc57600080fd5b5061040f6132cc565b348015610cf157600080fd5b50610cfa6132f0565b60408051938452602084019290925282820152519081900360600190f35b348015610d2457600080fd5b50610436613368565b348015610d3957600080fd5b50610d426133cc565b6040805161ffff9092168252519081900360200190f35b348015610d6557600080fd5b50610653613410565b348015610d7a57600080fd5b5061040f61343b565b348015610d8f57600080fd5b50610436600160a060020a036004358116906024351660443560643560ff6084351660a43560c435613445565b348015610dc857600080fd5b5061040f600160a060020a0360043581169060243516613690565b348015610def57600080fd5b506105106136bb565b348015610e0457600080fd5b5061040f6136ce565b348015610e1957600080fd5b506106536136e0565b348015610e2e57600080fd5b5061051061370b565b348015610e4357600080fd5b5061040f61378b565b348015610e5857600080fd5b5061040f6137af565b348015610e6d57600080fd5b50610436600435613847565b348015610e8557600080fd5b5061040f600160a060020a036004351661391e565b348015610ea657600080fd5b50610436613929565b348015610ebb57600080fd5b5061040f613952565b6000610ece61549c565b600080341515610f28576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f4445504f5349540000000000000000000000000000000000000000604482015290519081900360640190fd5b610f3f60008051602061554483398151915261397d565b9250610f4a836139d0565b15610f9f576040805160e560020a62461bcd02815260206004820152600e60248201527f5354414b494e475f504155534544000000000000000000000000000000000000604482015290519081900360640190fd5b610fa8836139db565b1561104057610fb6836139ed565b915034821015611010576040805160e560020a62461bcd02815260206004820152600b60248201527f5354414b455f4c494d4954000000000000000000000000000000000000000000604482015290519081900360640190fd5b6110406110258434850363ffffffff613a7916565b6000805160206155448339815191529063ffffffff613abd16565b61104934611480565b90506110553382613b18565b5061107661107134611065613c02565b9063ffffffff613c2d16565b613cbb565b60408051348152600160a060020a0387166020820152815133927f96a25c8ce0baabc1fdefd93e9ed25d8e092a3332f3aa9a41722b5697231d1d1a928290030190a26110c23382613cee565b949350505050565b60008060006110d7613d03565b91506110e1613d0d565b9050611103816110f7868563ffffffff613d3b16565b9063ffffffff613de616565b9250611115838263ffffffff613d3b16565b611125858463ffffffff613d3b16565b14611131578260010192505b5050919050565b6111617f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c7613e86565b611169613ef8565b611171613f4a565b565b600080600160a060020a03841615156111d6576040805160e560020a62461bcd02815260206004820152601a60248201527f4d494e545f52454345495645525f5a45524f5f41444452455353000000000000604482015290519081900360640190fd5b82151561122d576040805160e560020a62461bcd02815260206004820152601a60248201527f4d494e545f5a45524f5f414d4f554e545f4f465f534841524553000000000000604482015290519081900360640190fd5b6112a36112386136e0565b600160a060020a0316636dd6e80b6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d602081101561129c57600080fd5b5051613fa0565b6112ab614000565b6112c6836110656000805160206154c483398151915261406d565b91506112d0614071565b90508082111561132a576040805160e560020a62461bcd02815260206004820152601f60248201527f45585445524e414c5f42414c414e43455f4c494d49545f455843454544454400604482015290519081900360640190fd5b6113486000805160206154c48339815191528363ffffffff61415b16565b6113528484613b18565b5061135d8484613cee565b83600160a060020a03167f18d933acf4b4ff66716a65b6485fa7184fe79acdd568c3b0804a598a0d63a52d84611392866123df565b6040805192835260208301919091528051918290030190a250505050565b60408051808201909152601781527f4c6971756964207374616b656420457468657220322e30000000000000000000602082015290565b6114107f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d613e86565b61141861415f565b6111716141b1565b60008061142b61276d565b905080158015906114435750806114406141fb565b10155b91505090565b60006114563384846141ff565b50600192915050565b60008051602061552483398151915281565b600061147b614321565b905090565b60006114a561148d613d03565b6110f7611498613d0d565b859063ffffffff613d3b16565b90505b919050565b6114f26114b86136e0565b600160a060020a0316639624e83e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b6040805189815260208101899052808201889052606081018790526080810186905260a0810183905290518a917fff08c3ef606d198e316ef5b822193c489965899eb4e3c248cea1a4626c3eda50919081900360c00190a2604080518481526020810184905280820183905290518a917faf00d86be4cd299db16aa59803992e174fa88b67d81a0c7dd0148f9a75606a8d919081900360600190a2505050505050505050565b600061147b6115b460008051602061554483398151915261397d565b6139d0565b60006115c6843384614347565b6115d18484846143e1565b5060019392505050565b60006115e5612e49565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611640578181015183820152602001611628565b50505050905090810190601f16801561166d5780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561168c57600080fd5b505af11580156116a0573d6000803e3d6000fd5b505050506040513d60208110156116b657600080fd5b505192915050565b6116d5600080516020615524833981519152613e86565b61170161102583836116f460008051602061554483398151915261397d565b919063ffffffff61440516565b604080518381526020810183905281517fce9fddf6179affa1ea7bf36d80a6bf0284e0f3b91f4b2fa6eea2af923e7fac2d929181900390910190a15050565b7f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c781565b601290565b6000611773613410565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b505af11580156117c1573d6000803e3d6000fd5b505050506040513d60208110156117d757600080fd5b5051905090565b60006117e8612bbc565b600160a060020a031663b8f120b3306040518263ffffffff1660e01b81526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156117ad57600080fd5b6118687fe6dc5d79630c61871e99d341ad72c5a052bed2fc8c79e5a4480a7cd31117576c613e86565b6118866000805160206155048339815191528263ffffffff61415b16565b6040805182815290517fe0aacfc334457703148118055ec794ac17654c6f918d29638ba3b18003cee5ff9181900360200190a150565b7f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d81565b336000818152600160209081526040808320600160a060020a0387168452909152812054909161145691859061191c908663ffffffff613c2d16565b6141ff565b600061192b6136e0565b600160a060020a03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b600061197e6000805160206154e483398151915261406d565b15905090565b600061147b613c02565b61199661276d565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015611a575760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611a1c578181015183820152602001611a04565b50505050905090810190601f168015611a495780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50611a60614629565b611a907f9ef78dff90f100ea94042bd00ccb978430524befc391d3e510b5f55ff3166df78363ffffffff61415b16565b60408051600160a060020a038416815290517f61f9416d3c29deb4e424342445a2b132738430becd9fa275e11297c90668b22e9181900360200190a1611ad581614690565b611bce82600160a060020a03166337d5fe996040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611b1357600080fd5b505af1158015611b27573d6000803e3d6000fd5b505050506040513d6020811015611b3d57600080fd5b5051604080517f27810b6e0000000000000000000000000000000000000000000000000000000081529051600160a060020a038616916327810b6e9160048083019260209291908290030181600087803b158015611b9a57600080fd5b505af1158015611bae573d6000803e3d6000fd5b505050506040513d6020811015611bc457600080fd5b50516000196141ff565b611bd66147c7565b611bde6147d1565b5050565b611bea6136e0565b600160a060020a031663e441d25f6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611c2457600080fd5b505af1158015611c38573d6000803e3d6000fd5b505050506040513d6020811015611c4e57600080fd5b5051600160a060020a03163314611c6457600080fd5b611ca0611c7334611065613952565b7fafe016039542d12eec0183bb0b1ffc2ca45b027126a494672fba4154ee77facb9063ffffffff61415b16565b6040805134815290517fd27f9b0c98bdee27044afa149eadcd2047d6399cb6613a45c5b87e6aca76e6b59181900360200190a1565b611ce06114b86136e0565b611ce8614000565b611cf28282613b18565b50611bde8282613cee565b6000611d07614897565b600160a060020a031663563967156040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b611d49614000565b611d546114b86136e0565b611d847f9f70001d82b6ef54e9d3725b46581c3eb9ee3aa02b941b6aa54d678a9ca35b108363ffffffff61415b16565b611db47fa66d35f054e68143c18f32c990ed5cb972bb68a68f500cd2dd3a16bbf36864838263ffffffff61415b16565b6040805184815260208101849052815186927f1252331d4f3ee8a9f0a3484c4c2fb059c70a047b5dc5482a3ee6415f742d9f2e928290030190a250505050565b600061147b611e1060008051602061554483398151915261397d565b6148db565b600061147b6000805160206154c483398151915261406d565b6000806000806000806000611e4161549c565b611e5860008051602061554483398151915261397d565b9050611e63816139d0565b9750611e6e816139db565b9650611e79816148db565b955080606001516001606060020a03169450806040015163ffffffff16935080602001516001606060020a03169250806000015163ffffffff1691505090919293949596565b611ec7611420565b1515611f1d576040805160e560020a62461bcd02815260206004820152600f60248201527f4e4f545f494e495449414c495a45440000000000000000000000000000000000604482015290519081900360640190fd5b611f276002614914565b6111716147c7565b600080611f3b836123df565b9050611f48853383614347565b611f53858585614972565b611f5f85858386614b76565b8091505b509392505050565b60006114a5611f7983614c12565b6123df565b600080821515611fd8576040805160e560020a62461bcd02815260206004820152601a60248201527f4255524e5f5a45524f5f414d4f554e545f4f465f534841524553000000000000604482015290519081900360640190fd5b611fe36112386136e0565b611feb614000565b6120026000805160206154c483398151915261406d565b91508282101561205c576040805160e560020a62461bcd02815260206004820152601460248201527f4558545f5348415245535f544f4f5f534d414c4c000000000000000000000000604482015290519081900360640190fd5b61207c6000805160206154c483398151915284840363ffffffff61415b16565b6120863384614c2d565b50612090836123df565b905061209f3360008386614b76565b6040805184815260208101839052815133927f6e0564ed75135eb2e178547662a366099055c2bec707c550a1ecc51502019b3c928290030190a2505050565b6120f5600080516020615524833981519152613e86565b6120fd611420565b1515611169576040805160e560020a62461bcd02815260206004820152600f60248201527f4e4f545f494e495449414c495a45440000000000000000000000000000000000604482015290519081900360640190fd5b600080600080600080600080612167614897565b945084600160a060020a031663271662ec6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156121a457600080fd5b505af11580156121b8573d6000803e3d6000fd5b505050506040513d60208110156121ce57600080fd5b5051604080517f9fbb7bae0000000000000000000000000000000000000000000000000000000081529051919550600160a060020a03871691639fbb7bae916004808201926020929091908290030181600087803b15801561222f57600080fd5b505af1158015612243573d6000803e3d6000fd5b505050506040513d602081101561225957600080fd5b5051604080517fefcdcc0e000000000000000000000000000000000000000000000000000000008152815161ffff9093169550600160a060020a0388169263efcdcc0e926004808401939192918290030181600087803b1580156122bc57600080fd5b505af11580156122d0573d6000803e3d6000fd5b505050506040513d60408110156122e657600080fd5b5080516020909101516000985061ffff91821693501690508284830281151561230b57fe5b0497508284820281151561231b57fe5b0495505050505050909192565b6123306136e0565b600160a060020a03166369d421486040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561236a57600080fd5b505af115801561237e573d6000803e3d6000fd5b505050506040513d602081101561239457600080fd5b5051600160a060020a031633146123aa57600080fd5b6040805134815290517f6e5086f7e1ab04bd826e77faae35b1bcfe31bd144623361a40ea4af51670b1c39181900360200190a1565b60006114a56123ec613d0d565b6110f7611498613d03565b50600190565b600160a060020a031660009081526002602052604090205490565b600080341515612472576040805160e560020a62461bcd02815260206004820152600a60248201527f5a45524f5f56414c554500000000000000000000000000000000000000000000604482015290519081900360640190fd5b61247d6112386136e0565b612485614000565b61248e34611480565b91506124a76000805160206154c483398151915261406d565b905081811015612501576040805160e560020a62461bcd02815260206004820152601460248201527f4558545f5348415245535f544f4f5f534d414c4c000000000000000000000000604482015290519081900360640190fd5b6125216000805160206154c483398151915283830363ffffffff61415b16565b61253061107134611065613c02565b6040805134815290517f4ee34277c93491eeca655ad5c42ae1c193a5719e1c8837df9058af7696817cce9181900360200190a15050565b600061147b7fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b61406d565b6060806000806125a0612bbc565b600160a060020a031663f4409319306040518263ffffffff1660e01b81526004018082600160a060020a0316600160a060020a03168152602001915050600060405180830381600087803b1580156125f757600080fd5b505af115801561260b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052608081101561263457600080fd5b81019080805164010000000081111561264c57600080fd5b8201602081018481111561265f57600080fd5b815164010000000081118282018710171561267957600080fd5b5050929190602001805164010000000081111561269557600080fd5b820160208101848111156126a857600080fd5b81516401000000008111828201871017156126c257600080fd5b5050602082015160409092015194985096509450919250505090919293565b6127266126ec6136e0565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b61272e614000565b611bde3382614c2d565b600061147b614071565b600061147b7f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a661406d565b600061147b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e61406d565b6000806127a6338585614972565b6127af836123df565b90506127bd33858386614b76565b8091505b5092915050565b6000806127d3614000565b6127db6136e0565b915061281b82600160a060020a0316639624e83e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b600086111561291c5781600160a060020a031663e441d25f6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561285f57600080fd5b505af1158015612873573d6000803e3d6000fd5b505050506040513d602081101561288957600080fd5b5051604080517f9342c8f4000000000000000000000000000000000000000000000000000000008152600481018990529051600160a060020a0390921691639342c8f4916024808201926020929091908290030181600087803b1580156128ef57600080fd5b505af1158015612903573d6000803e3d6000fd5b505050506040513d602081101561291957600080fd5b50505b6000871115612a085781600160a060020a03166369d421486040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561296057600080fd5b505af1158015612974573d6000803e3d6000fd5b505050506040513d602081101561298a57600080fd5b5051604080517f3194528a000000000000000000000000000000000000000000000000000000008152600481018a90529051600160a060020a0390921691633194528a9160248082019260009290919082900301818387803b1580156129ef57600080fd5b505af1158015612a03573d6000803e3d6000fd5b505050505b6000831115612afd5781600160a060020a03166337d5fe996040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612a4c57600080fd5b505af1158015612a60573d6000803e3d6000fd5b505050506040513d6020811015612a7657600080fd5b5051604080517fb6013cef00000000000000000000000000000000000000000000000000000000815260048101889052602481018790529051600160a060020a039092169163b6013cef918691604480830192600092919082900301818588803b158015612ae357600080fd5b505af1158015612af7573d6000803e3d6000fd5b50505050505b612b1d83612b11896110658a611065613c02565b9063ffffffff614dd716565b9050612b2881613cbb565b60408051898152602081018b9052808201899052606081018890526080810183905290518b917f92dd3cb149a1eebd51fd8c2a3653fd96f30c4ac01d4f850fc16d46abd6c3e92f919081900360a00190a250505050505050505050565b60408051808201909152600581527f7374455448000000000000000000000000000000000000000000000000000000602082015290565b600061147b7f42b2d95e1ce15ce63bf9a8d9f6312cf44b23415c977ffa3b884333422af8941c61406d565b600061147b7ff243b7ab6a2698a3d0a16e54fb43706d25b46e82d0a92f60e7e1a4aa86c30e1f61406d565b6040805160e560020a62461bcd02815260206004820152600d60248201527f4e4f545f535550504f5254454400000000000000000000000000000000000000604482015290519081900360640190fd5b600080612c6d611420565b1515612c7c5760009150611f63565b612c84613410565b9050600160a060020a0381161515612c9f5760009150611f63565b80600160a060020a031663fdef9106863087612cba88614e6b565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015612d29578181015183820152602001612d11565b50505050905090810190601f168015612d565780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015612d7857600080fd5b505af1158015612d8c573d6000803e3d6000fd5b505050506040513d6020811015612da257600080fd5b505195945050505050565b60006114a582610ec4565b336000908152600160209081526040808320600160a060020a038616845290915281205482811015612e34576040805160e560020a62461bcd02815260206004820152601460248201527f414c4c4f57414e43455f42454c4f575f5a45524f000000000000000000000000604482015290519081900360640190fd5b6115d1338561191c848763ffffffff614dd716565b600080612e54613410565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b15801561168c57600080fd5b60006114563384846143e1565b6000806000806000612f1b6136e0565b945084600160a060020a031663472c17766040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612f5857600080fd5b505af1158015612f6c573d6000803e3d6000fd5b505050506040513d6020811015612f8257600080fd5b5051600160a060020a03163314612fe3576040805160e560020a62461bcd02815260206004820152601360248201527f4150505f415554485f44534d5f4641494c454400000000000000000000000000604482015290519081900360640190fd5b612feb61370b565b1515613041576040805160e560020a62461bcd02815260206004820152600f60248201527f43414e5f4e4f545f4445504f5349540000000000000000000000000000000000604482015290519081900360640190fd5b84600160a060020a031663ef6c064c6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561307c57600080fd5b505af1158015613090573d6000803e3d6000fd5b505050506040513d60208110156130a657600080fd5b5051935061313489600160a060020a0386166319c64b798b6130c66137af565b6040518363ffffffff1660e01b81526004018083815260200182815260200192505050602060405180830381600087803b15801561310357600080fd5b505af1158015613117573d6000803e3d6000fd5b505050506040513d602081101561312d57600080fd5b5051614e75565b9250600083111561323857613158836801bc16d674ec80000063ffffffff613d3b16565b915061319661316983612b11613c02565b7fed310af23f61f96daefbcd140b306c0bdbf8c178398299741687b90e794772b09063ffffffff61415b16565b6040805183815290517f76a397bea5768d4fca97ef47792796e35f98dc81b16c1de84e28a818e1f971089181900360200190a16131e48361106560008051602061550483398151915261406d565b90506132046000805160206155048339815191528263ffffffff61415b16565b6040805182815290517fe0aacfc334457703148118055ec794ac17654c6f918d29638ba3b18003cee5ff9181900360200190a15b83600160a060020a031663aa0b7db783858b8b8b6040518663ffffffff1660e01b8152600401808581526020018481526020018060200182810382528484828181526020019250808284378201915050955050505050506000604051808303818588803b1580156132a857600080fd5b505af11580156132bc573d6000803e3d6000fd5b5050505050505050505050505050565b7fe6dc5d79630c61871e99d341ad72c5a052bed2fc8c79e5a4480a7cd31117576c81565b6000808061330b60008051602061550483398151915261406d565b92506133367f9f70001d82b6ef54e9d3725b46581c3eb9ee3aa02b941b6aa54d678a9ca35b1061406d565b91506133617fa66d35f054e68143c18f32c990ed5cb972bb68a68f500cd2dd3a16bbf368648361406d565b9050909192565b61337f600080516020615524833981519152613e86565b6133a161102561339c60008051602061554483398151915261397d565b614e8d565b6040517f9b2a687c198898fcc32a33bbc610d478f177a73ab7352023e6cc1de5bf12a3df90600090a1565b60006133d6614897565b600160a060020a0316639fbb7bae6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b600061147b7f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b61406d565b600061147b614ea0565b600080428610156134a0576040805160e560020a62461bcd02815260206004820152601060248201527f444541444c494e455f4558504952454400000000000000000000000000000000604482015290519081900360640190fd5b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98989896134cd83614ecb565b60408051602080820197909752600160a060020a0395861681830152939094166060840152608083019190915260a082015260c08082018a90528251808303909101815260e090910191829052805190928291908401908083835b602083106135475780518252601f199092019160209182019101613528565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020915061357e612bbc565b604080517f804e5eb3000000000000000000000000000000000000000000000000000000008152306004820152602481018590529051600160a060020a03929092169163804e5eb3916044808201926020929091908290030181600087803b1580156135e957600080fd5b505af11580156135fd573d6000803e3d6000fd5b505050506040513d602081101561361357600080fd5b505190506136248982878787614f15565b151561367a576040805160e560020a62461bcd02815260206004820152601160248201527f494e56414c49445f5349474e4154555245000000000000000000000000000000604482015290519081900360640190fd5b6136858989896141ff565b505050505050505050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b60006000196136c861276d565b14905090565b600061147b6136db6150da565b61511b565b600061147b7f9ef78dff90f100ea94042bd00ccb978430524befc391d3e510b5f55ff3166df761406d565b6000613715615158565b600160a060020a0316632b95b7816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561374f57600080fd5b505af1158015613763573d6000803e3d6000fd5b505050506040513d602081101561377957600080fd5b505115801561147b575061197e611965565b7f84ea57490227bc2be925c684e2a367071d69890b629590198f4125a018eb1de881565b60008060006137bc613c02565b91506137c6615158565b600160a060020a031663d0fb84e86040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561380057600080fd5b505af1158015613814573d6000803e3d6000fd5b505050506040513d602081101561382a57600080fd5b5051905080821161383c576000613840565b8082035b9250505090565b61385e600080516020615524833981519152613e86565b6127108111156138b8576040805160e560020a62461bcd02815260206004820152601a60248201527f494e56414c49445f4d41585f45585445524e414c5f524154494f000000000000604482015290519081900360640190fd5b6138e87ff243b7ab6a2698a3d0a16e54fb43706d25b46e82d0a92f60e7e1a4aa86c30e1f8263ffffffff61415b16565b6040805182815290517f13c514ee70ee403f89bdf5ab83908edba92a77e3a61e19b774670c0a2cb2d7e69181900360200190a150565b60006114a582614c12565b6114187f84ea57490227bc2be925c684e2a367071d69890b629590198f4125a018eb1de8613e86565b600061147b7fafe016039542d12eec0183bb0b1ffc2ca45b027126a494672fba4154ee77facb61406d565b61398561549c565b60006139908361406d565b63ffffffff600082901c811684526001606060020a03602083811c821690860152608083901c909116604085015260a09190911c16606083015250919050565b5163ffffffff161590565b606001516001606060020a0316151590565b600080600080846040015163ffffffff166000141515613a3657846040015163ffffffff1685606001516001606060020a0316811515613a2957fe5b046001606060020a031692505b846000015163ffffffff164303915082820285602001516001606060020a0316019050613a708186606001516001606060020a031661519c565b95945050505050565b613a8161549c565b6001606060020a03821115613a9257fe5b825163ffffffff161515613aa257fe5b506001606060020a031660208201524363ffffffff16815290565b611bde60a082606001516001606060020a0316901b6080836040015163ffffffff16901b602084602001516001606060020a0316901b6000856000015163ffffffff16901b171717836000191661415b90919063ffffffff16565b6000600160a060020a0383161515613b7a576040805160e560020a62461bcd02815260206004820152601160248201527f4d494e545f544f5f5a45524f5f41444452000000000000000000000000000000604482015290519081900360640190fd5b613b8682611065614ea0565b9050613bb87fe3b4b636e601189b5f4c6742edf2538ac12bb61ed03e6da26949d69838fa447e8263ffffffff61415b16565b600160a060020a038316600090815260208190526040902054613be1908363ffffffff613c2d16565b600160a060020a039093166000908152602081905260409020929092555090565b600061147b7fed310af23f61f96daefbcd140b306c0bdbf8c178398299741687b90e794772b061406d565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f5700000000000000000000000000000060208201526000908383019084821015611f635760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b613ceb7fed310af23f61f96daefbcd140b306c0bdbf8c178398299741687b90e794772b08263ffffffff61415b16565b50565b611bde600083613cfd846123df565b84614b76565b600061147b6150da565b60008080613d286000805160206154c483398151915261406d565b915081613d33614ea0565b039392505050565b600080831515613d4e57600091506127c1565b50828202828482811515613d5e57fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f5700000000000000000000000000000060208201529291900414611f635760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b60408051808201909152600d81527f4d4154485f4449565f5a45524f0000000000000000000000000000000000000060208201526000908190818411613e715760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b508284811515613e7d57fe5b04949350505050565b604080516000815260208101909152613ea29033908390612c62565b1515613ceb576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b613f006151ad565b613f1f6000805160206154e4833981519152600163ffffffff61415b16565b6040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f990600090a1565b613f756110256000613f6960008051602061554483398151915261397d565b9063ffffffff61521916565b6040517fedaeeae9aed70c4545d3ab0065713261c9cee8d6cf5c8b07f52f0a65fd91efda90600090a1565b33600160a060020a03821614613ceb576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b6140176000805160206154e483398151915261406d565b1515611171576040805160e560020a62461bcd02815260206004820152601360248201527f434f4e54524143545f49535f53544f5050454400000000000000000000000000604482015290519081900360640190fd5b5490565b600080808061409f7ff243b7ab6a2698a3d0a16e54fb43706d25b46e82d0a92f60e7e1a4aa86c30e1f61406d565b92508215156140b15760009350614155565b6127108314156140c5576000199350614155565b6140dc6000805160206154c483398151915261406d565b91506140e6614ea0565b90506140fa8261271063ffffffff613d3b16565b61410a828563ffffffff613d3b16565b116141185760009350614155565b614152836127100361413561271085613d3b90919063ffffffff16565b614145848763ffffffff613d3b16565b039063ffffffff613de616565b93505b50505090565b9055565b614167614000565b6141866000805160206154e4833981519152600063ffffffff61415b16565b6040517f7acc84e34091ae817647a4c49116f5cc07f319078ba80f8f5fde37ea7e25cbd690600090a1565b6141d06110256001613f6960008051602061554483398151915261397d565b6040517f26d1807b479eaba249c1214b82e4b65bbb0cc73ee8a17901324b1ef1b5904e4990600090a1565b4390565b600160a060020a038316151561425f576040805160e560020a62461bcd02815260206004820152601660248201527f415050524f56455f46524f4d5f5a45524f5f4144445200000000000000000000604482015290519081900360640190fd5b600160a060020a03821615156142bf576040805160e560020a62461bcd02815260206004820152601460248201527f415050524f56455f544f5f5a45524f5f41444452000000000000000000000000604482015290519081900360640190fd5b600160a060020a03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b60008061432c6150da565b905061144361433a8261511b565b829063ffffffff613c2d16565b600160a060020a0380841660009081526001602090815260408083209386168352929052205460001981146143db57818110156143ce576040805160e560020a62461bcd02815260206004820152601260248201527f414c4c4f57414e43455f45584345454445440000000000000000000000000000604482015290519081900360640190fd5b6143db84848484036141ff565b50505050565b60006143ec82611480565b90506143f9848483614972565b6143db84848484614b76565b61440d61549c565b821515614464576040805160e560020a62461bcd02815260206004820152601460248201527f5a45524f5f4d41585f5354414b455f4c494d4954000000000000000000000000604482015290519081900360640190fd5b6001606060020a038311156144c3576040805160e560020a62461bcd02815260206004820152601960248201527f544f4f5f4c415247455f4d41585f5354414b455f4c494d495400000000000000604482015290519081900360640190fd5b8183101561451b576040805160e560020a62461bcd02815260206004820152601860248201527f544f4f5f4c415247455f4c494d49545f494e4352454153450000000000000000604482015290519081900360640190fd5b811580614537575063ffffffff828481151561453357fe5b0411155b151561458d576040805160e560020a62461bcd02815260206004820152601860248201527f544f4f5f534d414c4c5f4c494d49545f494e4352454153450000000000000000604482015290519081900360640190fd5b835163ffffffff1615806145ac575060608401516001606060020a0316155b806145c3575083602001516001606060020a031683105b156145d8576001606060020a03831660208501525b8115156145e65760006145f3565b81838115156145f157fe5b045b63ffffffff90811660408601526001606060020a0384166060860152845116156146215763ffffffff431684525b509192915050565b303180151561463457fe5b61463c614ea0565b1515613ceb5761464b81613cbb565b6040805182815260006020820152815161dead927f96a25c8ce0baabc1fdefd93e9ed25d8e092a3332f3aa9a41722b5697231d1d1a928290030190a2613ceb8161523e565b600160a060020a03811615156146f0576040805160e560020a62461bcd02815260206004820152601060248201527f5a45524f5f454950373132535445544800000000000000000000000000000000604482015290519081900360640190fd5b60006146fa612bbc565b600160a060020a031614614758576040805160e560020a62461bcd02815260206004820152601760248201527f45495037313253544554485f414c52454144595f534554000000000000000000604482015290519081900360640190fd5b6147887f42b2d95e1ce15ce63bf9a8d9f6312cf44b23415c977ffa3b884333422af8941c8263ffffffff61415b16565b60408051600160a060020a038316815290517fb80a5409082a3729c9fc139f8b41192c40e85252752df2c07caebd613086ca839181900360200190a150565b6111716003615257565b6147d961276d565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901561485e5760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b5061117161486a6141fb565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61415b16565b60006148a16136e0565b600160a060020a031663ef6c064c6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b60006148e6826139d0565b156148f3575060006114a8565b6148fc826139db565b151561490b57506000196114a8565b6114a5826139ed565b61491c612742565b8114613ceb576040805160e560020a62461bcd02815260206004820152601b60248201527f554e45585045435445445f434f4e54524143545f56455253494f4e0000000000604482015290519081900360640190fd5b6000600160a060020a03841615156149d4576040805160e560020a62461bcd02815260206004820152601760248201527f5452414e534645525f46524f4d5f5a45524f5f41444452000000000000000000604482015290519081900360640190fd5b600160a060020a0383161515614a34576040805160e560020a62461bcd02815260206004820152601560248201527f5452414e534645525f544f5f5a45524f5f414444520000000000000000000000604482015290519081900360640190fd5b600160a060020a038316301415614a95576040805160e560020a62461bcd02815260206004820152601a60248201527f5452414e534645525f544f5f53544554485f434f4e5452414354000000000000604482015290519081900360640190fd5b614a9d614000565b50600160a060020a03831660009081526020819052604090205480821115614b0f576040805160e560020a62461bcd02815260206004820152601060248201527f42414c414e43455f455843454544454400000000000000000000000000000000604482015290519081900360640190fd5b614b1f818363ffffffff614dd716565b600160a060020a038086166000908152602081905260408082209390935590851681522054614b54908363ffffffff613c2d16565b600160a060020a03909316600090815260208190526040902092909255505050565b82600160a060020a031684600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a382600160a060020a031684600160a060020a03167f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb836040518082815260200191505060405180910390a350505050565b600160a060020a031660009081526020819052604090205490565b6000808080600160a060020a0386161515614c92576040805160e560020a62461bcd02815260206004820152601360248201527f4255524e5f46524f4d5f5a45524f5f4144445200000000000000000000000000604482015290519081900360640190fd5b600160a060020a038616600090815260208190526040902054925082851115614d05576040805160e560020a62461bcd02815260206004820152601060248201527f42414c414e43455f455843454544454400000000000000000000000000000000604482015290519081900360640190fd5b614d0e856123df565b9150614d1c85612b11614ea0565b9350614d4e7fe3b4b636e601189b5f4c6742edf2538ac12bb61ed03e6da26949d69838fa447e8563ffffffff61415b16565b614d5e838663ffffffff614dd716565b600160a060020a038716600090815260208190526040902055614d80856123df565b60408051848152602081018390528082018890529051919250600160a060020a038816917f8b2a1e1ad5e0578c3dd82494156e985dade827a87c573b5c1c7716a32162ad649181900360600190a250505092915050565b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f5700000000000000000000000000006020820152600090819084841115614e635760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b505050900390565b8051602002815290565b6000818310614e845781614e86565b825b9392505050565b614e9561549c565b506000606082015290565b600061147b7fe3b4b636e601189b5f4c6742edf2538ac12bb61ed03e6da26949d69838fa447e61406d565b600160a060020a038116600090815260026020526040902054614ef581600163ffffffff613c2d16565b600160a060020a0390921660009081526002602052604090209190915590565b60006060806000614f25896152bd565b156150ab5760408051602080820189905281830188905260ff8a1660f81b606083015282516041818403018152606183018452608583018c815260a58401948552815160c585015281519197507f1626ba7e00000000000000000000000000000000000000000000000000000000948d9489949293919260e5909101919085019080838360005b83811015614fc4578181015183820152602001614fac565b50505050905090810190601f168015614ff15780820380516001836020036101000a031916815260200191505b509350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509150604051602081016040526020818451602086018d5afa60203d1460018214161561507f57815192505b50507f1626ba7e00000000000000000000000000000000000000000000000000000000811493506150ce565b88600160a060020a03166150c1898989896152c5565b600160a060020a03161493505b50505095945050505050565b600061147b6150e761542f565b6110656151137fa66d35f054e68143c18f32c990ed5cb972bb68a68f500cd2dd3a16bbf368648361406d565b611065613c02565b600080806151366000805160206154c483398151915261406d565b915081615141614ea0565b0390506110c2816110f7848763ffffffff613d3b16565b60006151626136e0565b600160a060020a03166337d5fe996040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b808210918202600192909203020190565b6151c46000805160206154e483398151915261406d565b15611171576040805160e560020a62461bcd02815260206004820152601260248201527f434f4e54524143545f49535f4143544956450000000000000000000000000000604482015290519081900360640190fd5b61522161549c565b8161522c574361522f565b60005b63ffffffff1683525090919050565b61524a61dead82613b18565b50613ceb61dead82613cee565b6152877f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a68263ffffffff61415b16565b6040805182815290517ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9181900360200190a150565b6000903b1190565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083821c1115615368576040805160e560020a62461bcd02815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60408051600080825260208083018085528a905260ff8916838501526060830188905260808301879052925160019360a0808501949193601f19840193928390039091019190865af11580156153c2573d6000803e3d6000fd5b5050604051601f190151915050600160a060020a0381161515613a70576040805160e560020a62461bcd02815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015290519081900360640190fd5b6000808061544a60008051602061550483398151915261406d565b91506154757f9f70001d82b6ef54e9d3725b46581c3eb9ee3aa02b941b6aa54d678a9ca35b1061406d565b90508082101561548157fe5b6138408183036801bc16d674ec80000063ffffffff613d3b16565b6040805160808101825260008082526020820181905291810182905260608101919091529056002ab18be87d6c30f8dc2a29c9950ab4796c891232dbcc6a95a6b44b9f8aad9352644132c4ddd5bb6f0655d5fe2870dcec7870e6be4758890f366b83441f9fdecee6e35175eb53fc006520a2a9c3e9711a7c00de6ff2c32dd31df8c5a24cac1b5ca42eee1333c0758ba72be38e728b6dadb32ea767de5b4ddbaea1dae85b1b051fa3678de4a579be090bed1177e0a24f77cc29d181ac22fd7688aca344d8938015a165627a7a72305820cba81952eb2d87bb7df06feb3eee19feb853e3fa0b509bb5be460ebbf9044f6a0029ebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e
Deployed Bytecode
0x6080604052600436106103945760003560e01c63ffffffff1680630103349c146103f7578063046f7da21461042157806306f187a41461043857806306fdde031461045c57806307da68f5146104e65780630803fac0146104fb578063095ea7b314610524578063136dd43c1461054857806318160ddd1461055d57806319208451146105725780631b2500971461058a5780631ea7ca89146105bb57806323b872dd146105d05780632914b9bd146105fa5780632cb5f7841461066f5780632de03aa11461068a578063313ce5671461069f57806332f0a3b5146106ca5780633644e515146106df57806337cfdaca1461055d57806338998624146106f4578063389ed2671461070c57806339509351146107215780633b19e84a146107455780633f683b6a1461075a57806347b714e01461076f578063485cc955146107845780634ad509b21461079e578063528c198a146107a657806356396715146107ca578063603540cd146107df578063609c4c6c1461080057806363021d8b14610815578063665b4b0b1461082a5780636d395b7e146108795780636d7804591461088e57806370a08231146108b857806372e62e56146108d95780637475f913146108f1578063752f77f11461090657806378ffcfe2146109415780637a28fb88146109495780637e7db6e1146109615780637ecebe00146109825780637f2d491e146109a357806380afdea8146109ab57806384b0196e146109c0578063853c637d14610ac85780638831f09e14610ae05780638aa1043514610af55780638b3dd74914610b0a5780638fcb4e5b14610b1f5780639271e3e614610b4357806395d89b4114610b705780639861f8e514610b855780639ca5a3d014610b9a5780639d4941d814610baf578063a1658fad14610bd0578063a1903eab14610c37578063a457c2d714610c4b578063a479e50814610c6f578063a9059cbb14610c84578063aa0b7db714610ca8578063ad1394e914610cd0578063ae2e353814610ce5578063b3320d9a14610d18578063ced72f8714610d2d578063d4aae0c414610d59578063d5002f2e14610d6e578063d505accf14610d83578063dd62ed3e14610dbc578063de4796ed14610de3578063e16a906514610df8578063e654ff1714610e0d578063e78a587514610e22578063eb85262f14610e37578063f2cfa87d14610e4c578063f352e17e14610e61578063f5eb42dc14610e79578063f999c50614610e9a578063fa64ebac14610eaf575b36156103ea576040805160e560020a62461bcd02815260206004820152600e60248201527f4e4f4e5f454d5054595f44415441000000000000000000000000000000000000604482015290519081900360640190fd5b6103f46000610ec4565b50005b34801561040357600080fd5b5061040f6004356110ca565b60408051918252519081900360200190f35b34801561042d57600080fd5b50610436611138565b005b34801561044457600080fd5b50610436600160a060020a0360043516602435611173565b34801561046857600080fd5b506104716113b0565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104ab578181015183820152602001610493565b50505050905090810190601f1680156104d85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104f257600080fd5b506104366113e7565b34801561050757600080fd5b50610510611420565b604080519115158252519081900360200190f35b34801561053057600080fd5b50610510600160a060020a0360043516602435611449565b34801561055457600080fd5b5061040f61145f565b34801561056957600080fd5b5061040f611471565b34801561057e57600080fd5b5061040f600435611480565b34801561059657600080fd5b5061043660043560243560443560643560843560a43560c43560e435610104356114ad565b3480156105c757600080fd5b50610510611598565b3480156105dc57600080fd5b50610510600160a060020a03600435811690602435166044356115b9565b34801561060657600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526106539436949293602493928401919081908401838280828437509497506115db9650505050505050565b60408051600160a060020a039092168252519081900360200190f35b34801561067b57600080fd5b506104366004356024356116be565b34801561069657600080fd5b5061040f611740565b3480156106ab57600080fd5b506106b4611764565b6040805160ff9092168252519081900360200190f35b3480156106d657600080fd5b50610653611769565b3480156106eb57600080fd5b5061040f6117de565b34801561070057600080fd5b5061043660043561183f565b34801561071857600080fd5b5061040f6118bc565b34801561072d57600080fd5b50610510600160a060020a03600435166024356118e0565b34801561075157600080fd5b50610653611921565b34801561076657600080fd5b50610510611965565b34801561077b57600080fd5b5061040f611984565b610436600160a060020a036004358116906024351661198e565b610436611be2565b3480156107b257600080fd5b50610436600160a060020a0360043516602435611cd5565b3480156107d657600080fd5b5061040f611cfd565b3480156107eb57600080fd5b50610436600435602435604435606435611d41565b34801561080c57600080fd5b5061040f611df4565b34801561082157600080fd5b5061040f611e15565b34801561083657600080fd5b5061083f611e2e565b6040805197151588529515156020880152868601949094526060860192909252608085015260a084015260c0830152519081900360e00190f35b34801561088557600080fd5b50610436611ebf565b34801561089a57600080fd5b5061040f600160a060020a0360043581169060243516604435611f2f565b3480156108c457600080fd5b5061040f600160a060020a0360043516611f6b565b3480156108e557600080fd5b50610436600435611f7e565b3480156108fd57600080fd5b506104366120de565b34801561091257600080fd5b5061091b612153565b6040805161ffff9485168152928416602084015292168183015290519081900360600190f35b610436612328565b34801561095557600080fd5b5061040f6004356123df565b34801561096d57600080fd5b50610510600160a060020a03600435166123f7565b34801561098e57600080fd5b5061040f600160a060020a03600435166123fd565b610436612418565b3480156109b757600080fd5b5061040f612567565b3480156109cc57600080fd5b506109d5612592565b60408051908101839052600160a060020a038216606082015260808082528551908201528451819060208083019160a084019189019080838360005b83811015610a29578181015183820152602001610a11565b50505050905090810190601f168015610a565780820380516001836020036101000a031916815260200191505b50838103825286518152865160209182019188019080838360005b83811015610a89578181015183820152602001610a71565b50505050905090810190601f168015610ab65780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390f35b348015610ad457600080fd5b506104366004356126e1565b348015610aec57600080fd5b5061040f612738565b348015610b0157600080fd5b5061040f612742565b348015610b1657600080fd5b5061040f61276d565b348015610b2b57600080fd5b5061040f600160a060020a0360043516602435612798565b348015610b4f57600080fd5b5061043660043560243560443560643560843560a43560c43560e4356127c8565b348015610b7c57600080fd5b50610471612b85565b348015610b9157600080fd5b50610653612bbc565b348015610ba657600080fd5b5061040f612be7565b348015610bbb57600080fd5b50610436600160a060020a0360043516612c12565b348015610bdc57600080fd5b506040805160206004604435818101358381028086018501909652808552610510958335600160a060020a0316956024803596369695606495939492019291829185019084908082843750949750612c629650505050505050565b61040f600160a060020a0360043516612dad565b348015610c5757600080fd5b50610510600160a060020a0360043516602435612db8565b348015610c7b57600080fd5b50610653612e49565b348015610c9057600080fd5b50610510600160a060020a0360043516602435612efe565b348015610cb457600080fd5b5061043660048035906024803591604435918201910135612f0b565b348015610cdc57600080fd5b5061040f6132cc565b348015610cf157600080fd5b50610cfa6132f0565b60408051938452602084019290925282820152519081900360600190f35b348015610d2457600080fd5b50610436613368565b348015610d3957600080fd5b50610d426133cc565b6040805161ffff9092168252519081900360200190f35b348015610d6557600080fd5b50610653613410565b348015610d7a57600080fd5b5061040f61343b565b348015610d8f57600080fd5b50610436600160a060020a036004358116906024351660443560643560ff6084351660a43560c435613445565b348015610dc857600080fd5b5061040f600160a060020a0360043581169060243516613690565b348015610def57600080fd5b506105106136bb565b348015610e0457600080fd5b5061040f6136ce565b348015610e1957600080fd5b506106536136e0565b348015610e2e57600080fd5b5061051061370b565b348015610e4357600080fd5b5061040f61378b565b348015610e5857600080fd5b5061040f6137af565b348015610e6d57600080fd5b50610436600435613847565b348015610e8557600080fd5b5061040f600160a060020a036004351661391e565b348015610ea657600080fd5b50610436613929565b348015610ebb57600080fd5b5061040f613952565b6000610ece61549c565b600080341515610f28576040805160e560020a62461bcd02815260206004820152600c60248201527f5a45524f5f4445504f5349540000000000000000000000000000000000000000604482015290519081900360640190fd5b610f3f60008051602061554483398151915261397d565b9250610f4a836139d0565b15610f9f576040805160e560020a62461bcd02815260206004820152600e60248201527f5354414b494e475f504155534544000000000000000000000000000000000000604482015290519081900360640190fd5b610fa8836139db565b1561104057610fb6836139ed565b915034821015611010576040805160e560020a62461bcd02815260206004820152600b60248201527f5354414b455f4c494d4954000000000000000000000000000000000000000000604482015290519081900360640190fd5b6110406110258434850363ffffffff613a7916565b6000805160206155448339815191529063ffffffff613abd16565b61104934611480565b90506110553382613b18565b5061107661107134611065613c02565b9063ffffffff613c2d16565b613cbb565b60408051348152600160a060020a0387166020820152815133927f96a25c8ce0baabc1fdefd93e9ed25d8e092a3332f3aa9a41722b5697231d1d1a928290030190a26110c23382613cee565b949350505050565b60008060006110d7613d03565b91506110e1613d0d565b9050611103816110f7868563ffffffff613d3b16565b9063ffffffff613de616565b9250611115838263ffffffff613d3b16565b611125858463ffffffff613d3b16565b14611131578260010192505b5050919050565b6111617f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c7613e86565b611169613ef8565b611171613f4a565b565b600080600160a060020a03841615156111d6576040805160e560020a62461bcd02815260206004820152601a60248201527f4d494e545f52454345495645525f5a45524f5f41444452455353000000000000604482015290519081900360640190fd5b82151561122d576040805160e560020a62461bcd02815260206004820152601a60248201527f4d494e545f5a45524f5f414d4f554e545f4f465f534841524553000000000000604482015290519081900360640190fd5b6112a36112386136e0565b600160a060020a0316636dd6e80b6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d602081101561129c57600080fd5b5051613fa0565b6112ab614000565b6112c6836110656000805160206154c483398151915261406d565b91506112d0614071565b90508082111561132a576040805160e560020a62461bcd02815260206004820152601f60248201527f45585445524e414c5f42414c414e43455f4c494d49545f455843454544454400604482015290519081900360640190fd5b6113486000805160206154c48339815191528363ffffffff61415b16565b6113528484613b18565b5061135d8484613cee565b83600160a060020a03167f18d933acf4b4ff66716a65b6485fa7184fe79acdd568c3b0804a598a0d63a52d84611392866123df565b6040805192835260208301919091528051918290030190a250505050565b60408051808201909152601781527f4c6971756964207374616b656420457468657220322e30000000000000000000602082015290565b6114107f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d613e86565b61141861415f565b6111716141b1565b60008061142b61276d565b905080158015906114435750806114406141fb565b10155b91505090565b60006114563384846141ff565b50600192915050565b60008051602061552483398151915281565b600061147b614321565b905090565b60006114a561148d613d03565b6110f7611498613d0d565b859063ffffffff613d3b16565b90505b919050565b6114f26114b86136e0565b600160a060020a0316639624e83e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b6040805189815260208101899052808201889052606081018790526080810186905260a0810183905290518a917fff08c3ef606d198e316ef5b822193c489965899eb4e3c248cea1a4626c3eda50919081900360c00190a2604080518481526020810184905280820183905290518a917faf00d86be4cd299db16aa59803992e174fa88b67d81a0c7dd0148f9a75606a8d919081900360600190a2505050505050505050565b600061147b6115b460008051602061554483398151915261397d565b6139d0565b60006115c6843384614347565b6115d18484846143e1565b5060019392505050565b60006115e5612e49565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611640578181015183820152602001611628565b50505050905090810190601f16801561166d5780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561168c57600080fd5b505af11580156116a0573d6000803e3d6000fd5b505050506040513d60208110156116b657600080fd5b505192915050565b6116d5600080516020615524833981519152613e86565b61170161102583836116f460008051602061554483398151915261397d565b919063ffffffff61440516565b604080518381526020810183905281517fce9fddf6179affa1ea7bf36d80a6bf0284e0f3b91f4b2fa6eea2af923e7fac2d929181900390910190a15050565b7f2fc10cc8ae19568712f7a176fb4978616a610650813c9d05326c34abb62749c781565b601290565b6000611773613410565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b505af11580156117c1573d6000803e3d6000fd5b505050506040513d60208110156117d757600080fd5b5051905090565b60006117e8612bbc565b600160a060020a031663b8f120b3306040518263ffffffff1660e01b81526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156117ad57600080fd5b6118687fe6dc5d79630c61871e99d341ad72c5a052bed2fc8c79e5a4480a7cd31117576c613e86565b6118866000805160206155048339815191528263ffffffff61415b16565b6040805182815290517fe0aacfc334457703148118055ec794ac17654c6f918d29638ba3b18003cee5ff9181900360200190a150565b7f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d81565b336000818152600160209081526040808320600160a060020a0387168452909152812054909161145691859061191c908663ffffffff613c2d16565b6141ff565b600061192b6136e0565b600160a060020a03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b600061197e6000805160206154e483398151915261406d565b15905090565b600061147b613c02565b61199661276d565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015611a575760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611a1c578181015183820152602001611a04565b50505050905090810190601f168015611a495780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50611a60614629565b611a907f9ef78dff90f100ea94042bd00ccb978430524befc391d3e510b5f55ff3166df78363ffffffff61415b16565b60408051600160a060020a038416815290517f61f9416d3c29deb4e424342445a2b132738430becd9fa275e11297c90668b22e9181900360200190a1611ad581614690565b611bce82600160a060020a03166337d5fe996040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611b1357600080fd5b505af1158015611b27573d6000803e3d6000fd5b505050506040513d6020811015611b3d57600080fd5b5051604080517f27810b6e0000000000000000000000000000000000000000000000000000000081529051600160a060020a038616916327810b6e9160048083019260209291908290030181600087803b158015611b9a57600080fd5b505af1158015611bae573d6000803e3d6000fd5b505050506040513d6020811015611bc457600080fd5b50516000196141ff565b611bd66147c7565b611bde6147d1565b5050565b611bea6136e0565b600160a060020a031663e441d25f6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611c2457600080fd5b505af1158015611c38573d6000803e3d6000fd5b505050506040513d6020811015611c4e57600080fd5b5051600160a060020a03163314611c6457600080fd5b611ca0611c7334611065613952565b7fafe016039542d12eec0183bb0b1ffc2ca45b027126a494672fba4154ee77facb9063ffffffff61415b16565b6040805134815290517fd27f9b0c98bdee27044afa149eadcd2047d6399cb6613a45c5b87e6aca76e6b59181900360200190a1565b611ce06114b86136e0565b611ce8614000565b611cf28282613b18565b50611bde8282613cee565b6000611d07614897565b600160a060020a031663563967156040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b611d49614000565b611d546114b86136e0565b611d847f9f70001d82b6ef54e9d3725b46581c3eb9ee3aa02b941b6aa54d678a9ca35b108363ffffffff61415b16565b611db47fa66d35f054e68143c18f32c990ed5cb972bb68a68f500cd2dd3a16bbf36864838263ffffffff61415b16565b6040805184815260208101849052815186927f1252331d4f3ee8a9f0a3484c4c2fb059c70a047b5dc5482a3ee6415f742d9f2e928290030190a250505050565b600061147b611e1060008051602061554483398151915261397d565b6148db565b600061147b6000805160206154c483398151915261406d565b6000806000806000806000611e4161549c565b611e5860008051602061554483398151915261397d565b9050611e63816139d0565b9750611e6e816139db565b9650611e79816148db565b955080606001516001606060020a03169450806040015163ffffffff16935080602001516001606060020a03169250806000015163ffffffff1691505090919293949596565b611ec7611420565b1515611f1d576040805160e560020a62461bcd02815260206004820152600f60248201527f4e4f545f494e495449414c495a45440000000000000000000000000000000000604482015290519081900360640190fd5b611f276002614914565b6111716147c7565b600080611f3b836123df565b9050611f48853383614347565b611f53858585614972565b611f5f85858386614b76565b8091505b509392505050565b60006114a5611f7983614c12565b6123df565b600080821515611fd8576040805160e560020a62461bcd02815260206004820152601a60248201527f4255524e5f5a45524f5f414d4f554e545f4f465f534841524553000000000000604482015290519081900360640190fd5b611fe36112386136e0565b611feb614000565b6120026000805160206154c483398151915261406d565b91508282101561205c576040805160e560020a62461bcd02815260206004820152601460248201527f4558545f5348415245535f544f4f5f534d414c4c000000000000000000000000604482015290519081900360640190fd5b61207c6000805160206154c483398151915284840363ffffffff61415b16565b6120863384614c2d565b50612090836123df565b905061209f3360008386614b76565b6040805184815260208101839052815133927f6e0564ed75135eb2e178547662a366099055c2bec707c550a1ecc51502019b3c928290030190a2505050565b6120f5600080516020615524833981519152613e86565b6120fd611420565b1515611169576040805160e560020a62461bcd02815260206004820152600f60248201527f4e4f545f494e495449414c495a45440000000000000000000000000000000000604482015290519081900360640190fd5b600080600080600080600080612167614897565b945084600160a060020a031663271662ec6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156121a457600080fd5b505af11580156121b8573d6000803e3d6000fd5b505050506040513d60208110156121ce57600080fd5b5051604080517f9fbb7bae0000000000000000000000000000000000000000000000000000000081529051919550600160a060020a03871691639fbb7bae916004808201926020929091908290030181600087803b15801561222f57600080fd5b505af1158015612243573d6000803e3d6000fd5b505050506040513d602081101561225957600080fd5b5051604080517fefcdcc0e000000000000000000000000000000000000000000000000000000008152815161ffff9093169550600160a060020a0388169263efcdcc0e926004808401939192918290030181600087803b1580156122bc57600080fd5b505af11580156122d0573d6000803e3d6000fd5b505050506040513d60408110156122e657600080fd5b5080516020909101516000985061ffff91821693501690508284830281151561230b57fe5b0497508284820281151561231b57fe5b0495505050505050909192565b6123306136e0565b600160a060020a03166369d421486040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561236a57600080fd5b505af115801561237e573d6000803e3d6000fd5b505050506040513d602081101561239457600080fd5b5051600160a060020a031633146123aa57600080fd5b6040805134815290517f6e5086f7e1ab04bd826e77faae35b1bcfe31bd144623361a40ea4af51670b1c39181900360200190a1565b60006114a56123ec613d0d565b6110f7611498613d03565b50600190565b600160a060020a031660009081526002602052604090205490565b600080341515612472576040805160e560020a62461bcd02815260206004820152600a60248201527f5a45524f5f56414c554500000000000000000000000000000000000000000000604482015290519081900360640190fd5b61247d6112386136e0565b612485614000565b61248e34611480565b91506124a76000805160206154c483398151915261406d565b905081811015612501576040805160e560020a62461bcd02815260206004820152601460248201527f4558545f5348415245535f544f4f5f534d414c4c000000000000000000000000604482015290519081900360640190fd5b6125216000805160206154c483398151915283830363ffffffff61415b16565b61253061107134611065613c02565b6040805134815290517f4ee34277c93491eeca655ad5c42ae1c193a5719e1c8837df9058af7696817cce9181900360200190a15050565b600061147b7fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b61406d565b6060806000806125a0612bbc565b600160a060020a031663f4409319306040518263ffffffff1660e01b81526004018082600160a060020a0316600160a060020a03168152602001915050600060405180830381600087803b1580156125f757600080fd5b505af115801561260b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052608081101561263457600080fd5b81019080805164010000000081111561264c57600080fd5b8201602081018481111561265f57600080fd5b815164010000000081118282018710171561267957600080fd5b5050929190602001805164010000000081111561269557600080fd5b820160208101848111156126a857600080fd5b81516401000000008111828201871017156126c257600080fd5b5050602082015160409092015194985096509450919250505090919293565b6127266126ec6136e0565b600160a060020a03166327810b6e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b61272e614000565b611bde3382614c2d565b600061147b614071565b600061147b7f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a661406d565b600061147b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e61406d565b6000806127a6338585614972565b6127af836123df565b90506127bd33858386614b76565b8091505b5092915050565b6000806127d3614000565b6127db6136e0565b915061281b82600160a060020a0316639624e83e6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b600086111561291c5781600160a060020a031663e441d25f6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561285f57600080fd5b505af1158015612873573d6000803e3d6000fd5b505050506040513d602081101561288957600080fd5b5051604080517f9342c8f4000000000000000000000000000000000000000000000000000000008152600481018990529051600160a060020a0390921691639342c8f4916024808201926020929091908290030181600087803b1580156128ef57600080fd5b505af1158015612903573d6000803e3d6000fd5b505050506040513d602081101561291957600080fd5b50505b6000871115612a085781600160a060020a03166369d421486040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561296057600080fd5b505af1158015612974573d6000803e3d6000fd5b505050506040513d602081101561298a57600080fd5b5051604080517f3194528a000000000000000000000000000000000000000000000000000000008152600481018a90529051600160a060020a0390921691633194528a9160248082019260009290919082900301818387803b1580156129ef57600080fd5b505af1158015612a03573d6000803e3d6000fd5b505050505b6000831115612afd5781600160a060020a03166337d5fe996040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612a4c57600080fd5b505af1158015612a60573d6000803e3d6000fd5b505050506040513d6020811015612a7657600080fd5b5051604080517fb6013cef00000000000000000000000000000000000000000000000000000000815260048101889052602481018790529051600160a060020a039092169163b6013cef918691604480830192600092919082900301818588803b158015612ae357600080fd5b505af1158015612af7573d6000803e3d6000fd5b50505050505b612b1d83612b11896110658a611065613c02565b9063ffffffff614dd716565b9050612b2881613cbb565b60408051898152602081018b9052808201899052606081018890526080810183905290518b917f92dd3cb149a1eebd51fd8c2a3653fd96f30c4ac01d4f850fc16d46abd6c3e92f919081900360a00190a250505050505050505050565b60408051808201909152600581527f7374455448000000000000000000000000000000000000000000000000000000602082015290565b600061147b7f42b2d95e1ce15ce63bf9a8d9f6312cf44b23415c977ffa3b884333422af8941c61406d565b600061147b7ff243b7ab6a2698a3d0a16e54fb43706d25b46e82d0a92f60e7e1a4aa86c30e1f61406d565b6040805160e560020a62461bcd02815260206004820152600d60248201527f4e4f545f535550504f5254454400000000000000000000000000000000000000604482015290519081900360640190fd5b600080612c6d611420565b1515612c7c5760009150611f63565b612c84613410565b9050600160a060020a0381161515612c9f5760009150611f63565b80600160a060020a031663fdef9106863087612cba88614e6b565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015612d29578181015183820152602001612d11565b50505050905090810190601f168015612d565780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015612d7857600080fd5b505af1158015612d8c573d6000803e3d6000fd5b505050506040513d6020811015612da257600080fd5b505195945050505050565b60006114a582610ec4565b336000908152600160209081526040808320600160a060020a038616845290915281205482811015612e34576040805160e560020a62461bcd02815260206004820152601460248201527f414c4c4f57414e43455f42454c4f575f5a45524f000000000000000000000000604482015290519081900360640190fd5b6115d1338561191c848763ffffffff614dd716565b600080612e54613410565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b15801561168c57600080fd5b60006114563384846143e1565b6000806000806000612f1b6136e0565b945084600160a060020a031663472c17766040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612f5857600080fd5b505af1158015612f6c573d6000803e3d6000fd5b505050506040513d6020811015612f8257600080fd5b5051600160a060020a03163314612fe3576040805160e560020a62461bcd02815260206004820152601360248201527f4150505f415554485f44534d5f4641494c454400000000000000000000000000604482015290519081900360640190fd5b612feb61370b565b1515613041576040805160e560020a62461bcd02815260206004820152600f60248201527f43414e5f4e4f545f4445504f5349540000000000000000000000000000000000604482015290519081900360640190fd5b84600160a060020a031663ef6c064c6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561307c57600080fd5b505af1158015613090573d6000803e3d6000fd5b505050506040513d60208110156130a657600080fd5b5051935061313489600160a060020a0386166319c64b798b6130c66137af565b6040518363ffffffff1660e01b81526004018083815260200182815260200192505050602060405180830381600087803b15801561310357600080fd5b505af1158015613117573d6000803e3d6000fd5b505050506040513d602081101561312d57600080fd5b5051614e75565b9250600083111561323857613158836801bc16d674ec80000063ffffffff613d3b16565b915061319661316983612b11613c02565b7fed310af23f61f96daefbcd140b306c0bdbf8c178398299741687b90e794772b09063ffffffff61415b16565b6040805183815290517f76a397bea5768d4fca97ef47792796e35f98dc81b16c1de84e28a818e1f971089181900360200190a16131e48361106560008051602061550483398151915261406d565b90506132046000805160206155048339815191528263ffffffff61415b16565b6040805182815290517fe0aacfc334457703148118055ec794ac17654c6f918d29638ba3b18003cee5ff9181900360200190a15b83600160a060020a031663aa0b7db783858b8b8b6040518663ffffffff1660e01b8152600401808581526020018481526020018060200182810382528484828181526020019250808284378201915050955050505050506000604051808303818588803b1580156132a857600080fd5b505af11580156132bc573d6000803e3d6000fd5b5050505050505050505050505050565b7fe6dc5d79630c61871e99d341ad72c5a052bed2fc8c79e5a4480a7cd31117576c81565b6000808061330b60008051602061550483398151915261406d565b92506133367f9f70001d82b6ef54e9d3725b46581c3eb9ee3aa02b941b6aa54d678a9ca35b1061406d565b91506133617fa66d35f054e68143c18f32c990ed5cb972bb68a68f500cd2dd3a16bbf368648361406d565b9050909192565b61337f600080516020615524833981519152613e86565b6133a161102561339c60008051602061554483398151915261397d565b614e8d565b6040517f9b2a687c198898fcc32a33bbc610d478f177a73ab7352023e6cc1de5bf12a3df90600090a1565b60006133d6614897565b600160a060020a0316639fbb7bae6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b600061147b7f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b61406d565b600061147b614ea0565b600080428610156134a0576040805160e560020a62461bcd02815260206004820152601060248201527f444541444c494e455f4558504952454400000000000000000000000000000000604482015290519081900360640190fd5b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98989896134cd83614ecb565b60408051602080820197909752600160a060020a0395861681830152939094166060840152608083019190915260a082015260c08082018a90528251808303909101815260e090910191829052805190928291908401908083835b602083106135475780518252601f199092019160209182019101613528565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020915061357e612bbc565b604080517f804e5eb3000000000000000000000000000000000000000000000000000000008152306004820152602481018590529051600160a060020a03929092169163804e5eb3916044808201926020929091908290030181600087803b1580156135e957600080fd5b505af11580156135fd573d6000803e3d6000fd5b505050506040513d602081101561361357600080fd5b505190506136248982878787614f15565b151561367a576040805160e560020a62461bcd02815260206004820152601160248201527f494e56414c49445f5349474e4154555245000000000000000000000000000000604482015290519081900360640190fd5b6136858989896141ff565b505050505050505050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b60006000196136c861276d565b14905090565b600061147b6136db6150da565b61511b565b600061147b7f9ef78dff90f100ea94042bd00ccb978430524befc391d3e510b5f55ff3166df761406d565b6000613715615158565b600160a060020a0316632b95b7816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561374f57600080fd5b505af1158015613763573d6000803e3d6000fd5b505050506040513d602081101561377957600080fd5b505115801561147b575061197e611965565b7f84ea57490227bc2be925c684e2a367071d69890b629590198f4125a018eb1de881565b60008060006137bc613c02565b91506137c6615158565b600160a060020a031663d0fb84e86040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561380057600080fd5b505af1158015613814573d6000803e3d6000fd5b505050506040513d602081101561382a57600080fd5b5051905080821161383c576000613840565b8082035b9250505090565b61385e600080516020615524833981519152613e86565b6127108111156138b8576040805160e560020a62461bcd02815260206004820152601a60248201527f494e56414c49445f4d41585f45585445524e414c5f524154494f000000000000604482015290519081900360640190fd5b6138e87ff243b7ab6a2698a3d0a16e54fb43706d25b46e82d0a92f60e7e1a4aa86c30e1f8263ffffffff61415b16565b6040805182815290517f13c514ee70ee403f89bdf5ab83908edba92a77e3a61e19b774670c0a2cb2d7e69181900360200190a150565b60006114a582614c12565b6114187f84ea57490227bc2be925c684e2a367071d69890b629590198f4125a018eb1de8613e86565b600061147b7fafe016039542d12eec0183bb0b1ffc2ca45b027126a494672fba4154ee77facb61406d565b61398561549c565b60006139908361406d565b63ffffffff600082901c811684526001606060020a03602083811c821690860152608083901c909116604085015260a09190911c16606083015250919050565b5163ffffffff161590565b606001516001606060020a0316151590565b600080600080846040015163ffffffff166000141515613a3657846040015163ffffffff1685606001516001606060020a0316811515613a2957fe5b046001606060020a031692505b846000015163ffffffff164303915082820285602001516001606060020a0316019050613a708186606001516001606060020a031661519c565b95945050505050565b613a8161549c565b6001606060020a03821115613a9257fe5b825163ffffffff161515613aa257fe5b506001606060020a031660208201524363ffffffff16815290565b611bde60a082606001516001606060020a0316901b6080836040015163ffffffff16901b602084602001516001606060020a0316901b6000856000015163ffffffff16901b171717836000191661415b90919063ffffffff16565b6000600160a060020a0383161515613b7a576040805160e560020a62461bcd02815260206004820152601160248201527f4d494e545f544f5f5a45524f5f41444452000000000000000000000000000000604482015290519081900360640190fd5b613b8682611065614ea0565b9050613bb87fe3b4b636e601189b5f4c6742edf2538ac12bb61ed03e6da26949d69838fa447e8263ffffffff61415b16565b600160a060020a038316600090815260208190526040902054613be1908363ffffffff613c2d16565b600160a060020a039093166000908152602081905260409020929092555090565b600061147b7fed310af23f61f96daefbcd140b306c0bdbf8c178398299741687b90e794772b061406d565b60408051808201909152601181527f4d4154485f4144445f4f564552464c4f5700000000000000000000000000000060208201526000908383019084821015611f635760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b613ceb7fed310af23f61f96daefbcd140b306c0bdbf8c178398299741687b90e794772b08263ffffffff61415b16565b50565b611bde600083613cfd846123df565b84614b76565b600061147b6150da565b60008080613d286000805160206154c483398151915261406d565b915081613d33614ea0565b039392505050565b600080831515613d4e57600091506127c1565b50828202828482811515613d5e57fe5b60408051808201909152601181527f4d4154485f4d554c5f4f564552464c4f5700000000000000000000000000000060208201529291900414611f635760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b60408051808201909152600d81527f4d4154485f4449565f5a45524f0000000000000000000000000000000000000060208201526000908190818411613e715760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b508284811515613e7d57fe5b04949350505050565b604080516000815260208101909152613ea29033908390612c62565b1515613ceb576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b613f006151ad565b613f1f6000805160206154e4833981519152600163ffffffff61415b16565b6040517f62451d457bc659158be6e6247f56ec1df424a5c7597f71c20c2bc44e0965c8f990600090a1565b613f756110256000613f6960008051602061554483398151915261397d565b9063ffffffff61521916565b6040517fedaeeae9aed70c4545d3ab0065713261c9cee8d6cf5c8b07f52f0a65fd91efda90600090a1565b33600160a060020a03821614613ceb576040805160e560020a62461bcd02815260206004820152600f60248201527f4150505f415554485f4641494c45440000000000000000000000000000000000604482015290519081900360640190fd5b6140176000805160206154e483398151915261406d565b1515611171576040805160e560020a62461bcd02815260206004820152601360248201527f434f4e54524143545f49535f53544f5050454400000000000000000000000000604482015290519081900360640190fd5b5490565b600080808061409f7ff243b7ab6a2698a3d0a16e54fb43706d25b46e82d0a92f60e7e1a4aa86c30e1f61406d565b92508215156140b15760009350614155565b6127108314156140c5576000199350614155565b6140dc6000805160206154c483398151915261406d565b91506140e6614ea0565b90506140fa8261271063ffffffff613d3b16565b61410a828563ffffffff613d3b16565b116141185760009350614155565b614152836127100361413561271085613d3b90919063ffffffff16565b614145848763ffffffff613d3b16565b039063ffffffff613de616565b93505b50505090565b9055565b614167614000565b6141866000805160206154e4833981519152600063ffffffff61415b16565b6040517f7acc84e34091ae817647a4c49116f5cc07f319078ba80f8f5fde37ea7e25cbd690600090a1565b6141d06110256001613f6960008051602061554483398151915261397d565b6040517f26d1807b479eaba249c1214b82e4b65bbb0cc73ee8a17901324b1ef1b5904e4990600090a1565b4390565b600160a060020a038316151561425f576040805160e560020a62461bcd02815260206004820152601660248201527f415050524f56455f46524f4d5f5a45524f5f4144445200000000000000000000604482015290519081900360640190fd5b600160a060020a03821615156142bf576040805160e560020a62461bcd02815260206004820152601460248201527f415050524f56455f544f5f5a45524f5f41444452000000000000000000000000604482015290519081900360640190fd5b600160a060020a03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b60008061432c6150da565b905061144361433a8261511b565b829063ffffffff613c2d16565b600160a060020a0380841660009081526001602090815260408083209386168352929052205460001981146143db57818110156143ce576040805160e560020a62461bcd02815260206004820152601260248201527f414c4c4f57414e43455f45584345454445440000000000000000000000000000604482015290519081900360640190fd5b6143db84848484036141ff565b50505050565b60006143ec82611480565b90506143f9848483614972565b6143db84848484614b76565b61440d61549c565b821515614464576040805160e560020a62461bcd02815260206004820152601460248201527f5a45524f5f4d41585f5354414b455f4c494d4954000000000000000000000000604482015290519081900360640190fd5b6001606060020a038311156144c3576040805160e560020a62461bcd02815260206004820152601960248201527f544f4f5f4c415247455f4d41585f5354414b455f4c494d495400000000000000604482015290519081900360640190fd5b8183101561451b576040805160e560020a62461bcd02815260206004820152601860248201527f544f4f5f4c415247455f4c494d49545f494e4352454153450000000000000000604482015290519081900360640190fd5b811580614537575063ffffffff828481151561453357fe5b0411155b151561458d576040805160e560020a62461bcd02815260206004820152601860248201527f544f4f5f534d414c4c5f4c494d49545f494e4352454153450000000000000000604482015290519081900360640190fd5b835163ffffffff1615806145ac575060608401516001606060020a0316155b806145c3575083602001516001606060020a031683105b156145d8576001606060020a03831660208501525b8115156145e65760006145f3565b81838115156145f157fe5b045b63ffffffff90811660408601526001606060020a0384166060860152845116156146215763ffffffff431684525b509192915050565b303180151561463457fe5b61463c614ea0565b1515613ceb5761464b81613cbb565b6040805182815260006020820152815161dead927f96a25c8ce0baabc1fdefd93e9ed25d8e092a3332f3aa9a41722b5697231d1d1a928290030190a2613ceb8161523e565b600160a060020a03811615156146f0576040805160e560020a62461bcd02815260206004820152601060248201527f5a45524f5f454950373132535445544800000000000000000000000000000000604482015290519081900360640190fd5b60006146fa612bbc565b600160a060020a031614614758576040805160e560020a62461bcd02815260206004820152601760248201527f45495037313253544554485f414c52454144595f534554000000000000000000604482015290519081900360640190fd5b6147887f42b2d95e1ce15ce63bf9a8d9f6312cf44b23415c977ffa3b884333422af8941c8263ffffffff61415b16565b60408051600160a060020a038316815290517fb80a5409082a3729c9fc139f8b41192c40e85252752df2c07caebd613086ca839181900360200190a150565b6111716003615257565b6147d961276d565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901561485e5760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b5061117161486a6141fb565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff61415b16565b60006148a16136e0565b600160a060020a031663ef6c064c6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b60006148e6826139d0565b156148f3575060006114a8565b6148fc826139db565b151561490b57506000196114a8565b6114a5826139ed565b61491c612742565b8114613ceb576040805160e560020a62461bcd02815260206004820152601b60248201527f554e45585045435445445f434f4e54524143545f56455253494f4e0000000000604482015290519081900360640190fd5b6000600160a060020a03841615156149d4576040805160e560020a62461bcd02815260206004820152601760248201527f5452414e534645525f46524f4d5f5a45524f5f41444452000000000000000000604482015290519081900360640190fd5b600160a060020a0383161515614a34576040805160e560020a62461bcd02815260206004820152601560248201527f5452414e534645525f544f5f5a45524f5f414444520000000000000000000000604482015290519081900360640190fd5b600160a060020a038316301415614a95576040805160e560020a62461bcd02815260206004820152601a60248201527f5452414e534645525f544f5f53544554485f434f4e5452414354000000000000604482015290519081900360640190fd5b614a9d614000565b50600160a060020a03831660009081526020819052604090205480821115614b0f576040805160e560020a62461bcd02815260206004820152601060248201527f42414c414e43455f455843454544454400000000000000000000000000000000604482015290519081900360640190fd5b614b1f818363ffffffff614dd716565b600160a060020a038086166000908152602081905260408082209390935590851681522054614b54908363ffffffff613c2d16565b600160a060020a03909316600090815260208190526040902092909255505050565b82600160a060020a031684600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a382600160a060020a031684600160a060020a03167f9d9c909296d9c674451c0c24f02cb64981eb3b727f99865939192f880a755dcb836040518082815260200191505060405180910390a350505050565b600160a060020a031660009081526020819052604090205490565b6000808080600160a060020a0386161515614c92576040805160e560020a62461bcd02815260206004820152601360248201527f4255524e5f46524f4d5f5a45524f5f4144445200000000000000000000000000604482015290519081900360640190fd5b600160a060020a038616600090815260208190526040902054925082851115614d05576040805160e560020a62461bcd02815260206004820152601060248201527f42414c414e43455f455843454544454400000000000000000000000000000000604482015290519081900360640190fd5b614d0e856123df565b9150614d1c85612b11614ea0565b9350614d4e7fe3b4b636e601189b5f4c6742edf2538ac12bb61ed03e6da26949d69838fa447e8563ffffffff61415b16565b614d5e838663ffffffff614dd716565b600160a060020a038716600090815260208190526040902055614d80856123df565b60408051848152602081018390528082018890529051919250600160a060020a038816917f8b2a1e1ad5e0578c3dd82494156e985dade827a87c573b5c1c7716a32162ad649181900360600190a250505092915050565b60408051808201909152601281527f4d4154485f5355425f554e444552464c4f5700000000000000000000000000006020820152600090819084841115614e635760405160e560020a62461bcd02815260040180806020018281038252838181518152602001915080519060200190808383600083811015611a1c578181015183820152602001611a04565b505050900390565b8051602002815290565b6000818310614e845781614e86565b825b9392505050565b614e9561549c565b506000606082015290565b600061147b7fe3b4b636e601189b5f4c6742edf2538ac12bb61ed03e6da26949d69838fa447e61406d565b600160a060020a038116600090815260026020526040902054614ef581600163ffffffff613c2d16565b600160a060020a0390921660009081526002602052604090209190915590565b60006060806000614f25896152bd565b156150ab5760408051602080820189905281830188905260ff8a1660f81b606083015282516041818403018152606183018452608583018c815260a58401948552815160c585015281519197507f1626ba7e00000000000000000000000000000000000000000000000000000000948d9489949293919260e5909101919085019080838360005b83811015614fc4578181015183820152602001614fac565b50505050905090810190601f168015614ff15780820380516001836020036101000a031916815260200191505b509350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509150604051602081016040526020818451602086018d5afa60203d1460018214161561507f57815192505b50507f1626ba7e00000000000000000000000000000000000000000000000000000000811493506150ce565b88600160a060020a03166150c1898989896152c5565b600160a060020a03161493505b50505095945050505050565b600061147b6150e761542f565b6110656151137fa66d35f054e68143c18f32c990ed5cb972bb68a68f500cd2dd3a16bbf368648361406d565b611065613c02565b600080806151366000805160206154c483398151915261406d565b915081615141614ea0565b0390506110c2816110f7848763ffffffff613d3b16565b60006151626136e0565b600160a060020a03166337d5fe996040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117ad57600080fd5b808210918202600192909203020190565b6151c46000805160206154e483398151915261406d565b15611171576040805160e560020a62461bcd02815260206004820152601260248201527f434f4e54524143545f49535f4143544956450000000000000000000000000000604482015290519081900360640190fd5b61522161549c565b8161522c574361522f565b60005b63ffffffff1683525090919050565b61524a61dead82613b18565b50613ceb61dead82613cee565b6152877f4dd0f6662ba1d6b081f08b350f5e9a6a7b15cf586926ba66f753594928fa64a68263ffffffff61415b16565b6040805182815290517ffddcded6b4f4730c226821172046b48372d3cd963c159701ae1b7c3bcac541bb9181900360200190a150565b6000903b1190565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083821c1115615368576040805160e560020a62461bcd02815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60408051600080825260208083018085528a905260ff8916838501526060830188905260808301879052925160019360a0808501949193601f19840193928390039091019190865af11580156153c2573d6000803e3d6000fd5b5050604051601f190151915050600160a060020a0381161515613a70576040805160e560020a62461bcd02815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015290519081900360640190fd5b6000808061544a60008051602061550483398151915261406d565b91506154757f9f70001d82b6ef54e9d3725b46581c3eb9ee3aa02b941b6aa54d678a9ca35b1061406d565b90508082101561548157fe5b6138408183036801bc16d674ec80000063ffffffff613d3b16565b6040805160808101825260008082526020820181905291810182905260608101919091529056002ab18be87d6c30f8dc2a29c9950ab4796c891232dbcc6a95a6b44b9f8aad9352644132c4ddd5bb6f0655d5fe2870dcec7870e6be4758890f366b83441f9fdecee6e35175eb53fc006520a2a9c3e9711a7c00de6ff2c32dd31df8c5a24cac1b5ca42eee1333c0758ba72be38e728b6dadb32ea767de5b4ddbaea1dae85b1b051fa3678de4a579be090bed1177e0a24f77cc29d181ac22fd7688aca344d8938015a165627a7a72305820cba81952eb2d87bb7df06feb3eee19feb853e3fa0b509bb5be460ebbf9044f6a0029
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.