More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 7,400 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Multicall | 21275393 | 1 min ago | IN | 0 ETH | 0.00115314 | ||||
Undelegate | 21273622 | 5 hrs ago | IN | 0 ETH | 0.0028763 | ||||
Claim Pending Un... | 21272879 | 8 hrs ago | IN | 0 ETH | 0.00159133 | ||||
Delegate | 21271159 | 14 hrs ago | IN | 0 ETH | 0.00161045 | ||||
Undelegate | 21270644 | 15 hrs ago | IN | 0 ETH | 0.00232794 | ||||
Undelegate | 21270232 | 17 hrs ago | IN | 0 ETH | 0.00156147 | ||||
Multicall | 21270220 | 17 hrs ago | IN | 0 ETH | 0.00112323 | ||||
Undelegate | 21269493 | 19 hrs ago | IN | 0 ETH | 0.0009988 | ||||
Multicall | 21269486 | 19 hrs ago | IN | 0 ETH | 0.00074622 | ||||
Redelegate Deleg... | 21265725 | 32 hrs ago | IN | 0 ETH | 0.00534453 | ||||
Claim Pending Un... | 21265192 | 34 hrs ago | IN | 0 ETH | 0.00144343 | ||||
Claim Pending Un... | 21264501 | 36 hrs ago | IN | 0 ETH | 0.00173078 | ||||
Undelegate | 21263488 | 39 hrs ago | IN | 0 ETH | 0.00140458 | ||||
Multicall | 21262290 | 43 hrs ago | IN | 0 ETH | 0.00075023 | ||||
Multicall | 21260544 | 2 days ago | IN | 0 ETH | 0.00104188 | ||||
Undelegate | 21259710 | 2 days ago | IN | 0 ETH | 0.00172929 | ||||
Undelegate | 21258828 | 2 days ago | IN | 0 ETH | 0.00180863 | ||||
Multicall | 21258822 | 2 days ago | IN | 0 ETH | 0.00120647 | ||||
Redelegate Deleg... | 21258363 | 2 days ago | IN | 0 ETH | 0.00235265 | ||||
Undelegate | 21258311 | 2 days ago | IN | 0 ETH | 0.00169651 | ||||
Multicall | 21258303 | 2 days ago | IN | 0 ETH | 0.00108229 | ||||
Migrate Delegato... | 21258296 | 2 days ago | IN | 0 ETH | 0.00235391 | ||||
Undelegate | 21257410 | 2 days ago | IN | 0 ETH | 0.00130873 | ||||
Multicall | 21257401 | 2 days ago | IN | 0 ETH | 0.00109511 | ||||
Redelegate Deleg... | 21257099 | 2 days ago | IN | 0 ETH | 0.00187542 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
15275019 | 845 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
AnkrTokenStakingProxy
Compiler Version
v0.8.14+commit.80d49f37
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "@ankr.com/contracts/libs/ManageableProxy.sol"; import "@ankr.com/contracts/protocol/AnkrTokenStaking.sol"; contract AnkrTokenStakingProxy is ManageableProxy { constructor(IStakingConfig stakingConfig, IERC20 ankrToken) ManageableProxy( stakingConfig, _deployDefault(), abi.encodeWithSelector(AnkrTokenStaking.initialize.selector, stakingConfig, ankrToken) ) { } function _deployDefault() internal returns (address) { AnkrTokenStaking impl = new AnkrTokenStaking{ salt : keccak256("AnkrTokenStakingV0") }(); return address(impl); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; interface IGovernable { function getGovernanceAddress() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "./IStakingConfig.sol"; interface IStaking { function getStakingConfig() external view returns (IStakingConfig); function getValidators() external view returns (address[] memory); function isValidatorActive(address validator) external view returns (bool); function isValidator(address validator) external view returns (bool); function getValidatorStatus(address validator) external view returns ( address ownerAddress, uint8 status, uint256 totalDelegated, uint32 slashesCount, uint64 changedAt, uint64 jailedBefore, uint64 claimedAt, uint16 commissionRate, uint96 totalRewards ); function getValidatorStatusAtEpoch(address validator, uint64 epoch) external view returns ( address ownerAddress, uint8 status, uint256 totalDelegated, uint32 slashesCount, uint64 changedAt, uint64 jailedBefore, uint64 claimedAt, uint16 commissionRate, uint96 totalRewards ); function getValidatorByOwner(address owner) external view returns (address); function registerValidator(address validator, uint16 commissionRate) payable external; function addValidator(address validator) external; function removeValidator(address validator) external; function activateValidator(address validator) external; function disableValidator(address validator) external; function releaseValidatorFromJail(address validator) external; function changeValidatorCommissionRate(address validator, uint16 commissionRate) external; function changeValidatorOwner(address validator, address newOwner) external; function getValidatorDelegation(address validator, address delegator) external view returns ( uint256 delegatedAmount, uint64 atEpoch ); function delegate(address validator, uint256 amount) payable external; function undelegate(address validator, uint256 amount) external; function getValidatorFee(address validator) external view returns (uint256); function getPendingValidatorFee(address validator) external view returns (uint256); function claimValidatorFee(address validator) external; function getDelegatorFee(address validator, address delegator) external view returns (uint256); function getPendingDelegatorFee(address validator, address delegator) external view returns (uint256); function claimDelegatorFee(address validator) external; function claimStakingRewards(address validatorAddress) external; function claimPendingUndelegates(address validator) external; function calcAvailableForRedelegateAmount(address validator, address delegator) external view returns (uint256 amountToStake, uint256 rewardsDust); function redelegateDelegatorFee(address validator) external; function currentEpoch() external view returns (uint64); function nextEpoch() external view returns (uint64); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "./IGovernable.sol"; interface IStakingConfig is IGovernable { function getActiveValidatorsLength() external view returns (uint32); function setActiveValidatorsLength(uint32 newValue) external; function getEpochBlockInterval() external view returns (uint32); function setEpochBlockInterval(uint32 newValue) external; function getMisdemeanorThreshold() external view returns (uint32); function setMisdemeanorThreshold(uint32 newValue) external; function getFelonyThreshold() external view returns (uint32); function setFelonyThreshold(uint32 newValue) external; function getValidatorJailEpochLength() external view returns (uint32); function setValidatorJailEpochLength(uint32 newValue) external; function getUndelegatePeriod() external view returns (uint32); function setUndelegatePeriod(uint32 newValue) external; function getMinValidatorStakeAmount() external view returns (uint256); function setMinValidatorStakeAmount(uint256 newValue) external; function getMinStakingAmount() external view returns (uint256); function setMinStakingAmount(uint256 newValue) external; function getGovernanceAddress() external view override returns (address); function setGovernanceAddress(address newValue) external; function getTreasuryAddress() external view returns (address); function setTreasuryAddress(address newValue) external; function getLockPeriod() external view returns (uint64); function setLockPeriod(uint64 newValue) external; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IStaking.sol"; interface ITokenStaking is IStaking { function getErc20Token() external view returns (IERC20); function distributeRewards(address validatorAddress, uint256 amount) external; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "../interfaces/IGovernable.sol"; abstract contract ManageableProxy is ERC1967Proxy { constructor(IGovernable governable, address defaultVersion, bytes memory inputData) ERC1967Proxy(defaultVersion, inputData) { _changeAdmin(address(governable)); } function getCurrentVersion() public view returns (address) { return _implementation(); } modifier onlyFromGovernance() { require(msg.sender == IGovernable(_getAdmin()).getGovernanceAddress(), "ManageableProxy: only governance"); _; } function upgradeToAndCall(address impl, bytes memory data) external onlyFromGovernance { _upgradeToAndCall(impl, data, false); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; contract Multicall { function multicall(bytes[] calldata data) external returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { // this is an optimized a bit multicall w/o using of Address library (it safes a lot of bytecode) results[i] = _fastDelegateCall(data[i]); } return results; } function _fastDelegateCall(bytes memory data) private returns (bytes memory _result) { (bool success, bytes memory returnData) = address(this).delegatecall(data); if (success) { return returnData; } if (returnData.length > 0) { assembly { revert(add(32, returnData), mload(returnData)) } } else { revert(); } } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "../staking/extension/TokenStaking.sol"; import "../staking/StakingConfig.sol"; contract AnkrTokenStaking is TokenStaking { function initialize(IStakingConfig stakingConfig, IERC20 ankrToken) external initializer { __TokenStaking_init(stakingConfig, ankrToken); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../libs/Multicall.sol"; import "../interfaces/IStakingConfig.sol"; import "../interfaces/IStaking.sol"; abstract contract Staking is Initializable, Multicall, IStaking { /** * This constant indicates precision of storing compact balances in the storage or floating point. Since default * balance precision is 256 bits it might gain some overhead on the storage because we don't need to store such huge * amount range. That is why we compact balances in uint112 values instead of uint256. By managing this value * you can set the precision of your balances, aka min and max possible staking amount. This value depends * mostly on your asset price in USD, for example ETH costs 4000$ then if we use 1 ether precision it takes 4000$ * as min amount that might be problematic for users to do the stake. We can set 1 gwei precision and in this case * we increase min staking amount in 1e9 times, but also decreases max staking amount or total amount of staked assets. * * Here is an universal formula, if your asset is cheap in USD equivalent, like ~1$, then use 1 ether precision, * otherwise it might be better to use 1 gwei precision or any other amount that your want. * * Also be careful with setting `minValidatorStakeAmount` and `minStakingAmount`, because these values has * the same precision as specified here. It means that if you set precision 1 ether, then min staking amount of 10 * tokens should have 10 raw value. For 1 gwei precision 10 tokens min amount should be stored as 10000000000. * * For the 112 bits we have ~32 decimals lg(2**112)=33.71 (lets round to 32 for simplicity). We split this amount * into integer (24) and for fractional (8) parts. It means that we can have only 8 decimals after zero. * * Based in current params we have next min/max values: * - min staking amount: 0.00000001 or 1e-8 * - max staking amount: 1000000000000000000000000 or 1e+24 * * WARNING: precision must be a 1eN format (A=1, N>0) */ uint256 internal constant BALANCE_COMPACT_PRECISION = 1e10; /** * Here is min/max commission rates. Lets don't allow to set more than 30% of validator commission, because it's * too big commission for validator. Commission rate is a percents divided by 100 stored with 0 decimals as percents*100 (=pc/1e2*1e4) * * Here is some examples: * + 0.3% => 0.3*100=30 * + 3% => 3*100=300 * + 30% => 30*100=3000 */ uint16 internal constant COMMISSION_RATE_MIN_VALUE = 0; // 0% uint16 internal constant COMMISSION_RATE_MAX_VALUE = 3000; // 30% /** * This gas limit is used for internal transfers, BSC doesn't support berlin and it * might cause problems with smart contracts who used to stake transparent proxies or * beacon proxies that have a lot of expensive SLOAD instructions. */ uint64 internal constant TRANSFER_GAS_LIMIT = 30_000; /** * Some items are stored in the queues and we must iterate though them to * execute one by one. Somtimes gas might not be enough for the tx execution. */ uint32 internal constant CLAIM_BEFORE_GAS = 100_000; // validator events event ValidatorAdded(address indexed validator, address owner, uint8 status, uint16 commissionRate); event ValidatorModified(address indexed validator, address owner, uint8 status, uint16 commissionRate); event ValidatorRemoved(address indexed validator); event ValidatorOwnerClaimed(address indexed validator, uint256 amount, uint64 epoch); event ValidatorSlashed(address indexed validator, uint32 slashes, uint64 epoch); event ValidatorJailed(address indexed validator, uint64 epoch); event ValidatorDeposited(address indexed validator, uint256 amount, uint64 epoch); event ValidatorReleased(address indexed validator, uint64 epoch); // staker events event Delegated(address indexed validator, address indexed staker, uint256 amount, uint64 epoch); event Undelegated(address indexed validator, address indexed staker, uint256 amount, uint64 epoch); event Claimed(address indexed validator, address indexed staker, uint256 amount, uint64 epoch); event Redelegated(address indexed validator, address indexed staker, uint256 amount, uint256 dust, uint64 epoch); enum ValidatorStatus { NotFound, Active, Pending, Jail } struct ValidatorSnapshot { uint96 totalRewards; uint112 totalDelegated; uint32 slashesCount; uint16 commissionRate; } struct Validator { address validatorAddress; address ownerAddress; ValidatorStatus status; uint64 changedAt; uint64 jailedBefore; uint64 claimedAt; } struct DelegationOpDelegate { uint112 amount; uint64 epoch; } struct DelegationOpUndelegate { uint112 amount; uint64 epoch; } struct ValidatorDelegation { DelegationOpDelegate[] delegateQueue; uint64 delegateGap; DelegationOpUndelegate[] undelegateQueue; uint64 undelegateGap; } // mapping from validator address to validator mapping(address => Validator) internal _validatorsMap; // mapping from validator owner to validator address mapping(address => address) internal _validatorOwners; // list of all validators that are in validators mapping address[] internal _activeValidatorsList; // mapping with stakers to validators at epoch (validator -> delegator -> delegation) mapping(address => mapping(address => ValidatorDelegation)) internal _validatorDelegations; // mapping with validator snapshots per each epoch (validator -> epoch -> snapshot) mapping(address => mapping(uint64 => ValidatorSnapshot)) internal _validatorSnapshots; // chain config with params IStakingConfig internal _stakingConfig; // reserve some gap for the future upgrades uint256[100 - 7] private __reserved; function __Staking_init(IStakingConfig stakingConfig) internal { _stakingConfig = stakingConfig; } modifier onlyFromGovernance() virtual { require(msg.sender == _stakingConfig.getGovernanceAddress(), "Staking: only governance"); _; } function getStakingConfig() external view override returns (IStakingConfig) { return _stakingConfig; } function getValidatorDelegation(address validatorAddress, address delegator) external view override returns ( uint256 delegatedAmount, uint64 atEpoch ) { ValidatorDelegation memory delegation = _validatorDelegations[validatorAddress][delegator]; if (delegation.delegateQueue.length == 0) { return (0, 0); } DelegationOpDelegate memory snapshot = delegation.delegateQueue[delegation.delegateQueue.length - 1]; return (uint256(snapshot.amount) * BALANCE_COMPACT_PRECISION, snapshot.epoch); } function getValidatorStatus(address validatorAddress) external view override returns ( address ownerAddress, uint8 status, uint256 totalDelegated, uint32 slashesCount, uint64 changedAt, uint64 jailedBefore, uint64 claimedAt, uint16 commissionRate, uint96 totalRewards ) { Validator memory validator = _validatorsMap[validatorAddress]; ValidatorSnapshot memory snapshot = _validatorSnapshots[validator.validatorAddress][validator.changedAt]; return ( ownerAddress = validator.ownerAddress, status = uint8(validator.status), totalDelegated = uint256(snapshot.totalDelegated) * BALANCE_COMPACT_PRECISION, slashesCount = snapshot.slashesCount, changedAt = validator.changedAt, jailedBefore = validator.jailedBefore, claimedAt = validator.claimedAt, commissionRate = snapshot.commissionRate, totalRewards = snapshot.totalRewards ); } function getValidatorStatusAtEpoch(address validatorAddress, uint64 epoch) external view override returns ( address ownerAddress, uint8 status, uint256 totalDelegated, uint32 slashesCount, uint64 changedAt, uint64 jailedBefore, uint64 claimedAt, uint16 commissionRate, uint96 totalRewards ) { Validator memory validator = _validatorsMap[validatorAddress]; ValidatorSnapshot memory snapshot = _touchValidatorSnapshotImmutable(validator, epoch); return ( ownerAddress = validator.ownerAddress, status = uint8(validator.status), totalDelegated = uint256(snapshot.totalDelegated) * BALANCE_COMPACT_PRECISION, slashesCount = snapshot.slashesCount, changedAt = validator.changedAt, jailedBefore = validator.jailedBefore, claimedAt = validator.claimedAt, commissionRate = snapshot.commissionRate, totalRewards = snapshot.totalRewards ); } function getValidatorByOwner(address owner) external view override returns (address) { return _validatorOwners[owner]; } function releaseValidatorFromJail(address validatorAddress) external override { // make sure validator is in jail Validator memory validator = _validatorsMap[validatorAddress]; require(validator.status == ValidatorStatus.Jail, "bad status"); // only validator owner require(msg.sender == validator.ownerAddress, "only owner"); require(currentEpoch() >= validator.jailedBefore, "still in jail"); // release validator from jail _releaseValidatorFromJail(validator); } function forceUnJailValidator(address validatorAddress) external onlyFromGovernance { // make sure validator is in jail Validator memory validator = _validatorsMap[validatorAddress]; require(validator.status == ValidatorStatus.Jail, "bad status"); // release validator from jail _releaseValidatorFromJail(validator); } function _releaseValidatorFromJail(Validator memory validator) internal { address validatorAddress = validator.validatorAddress; // update validator status validator.status = ValidatorStatus.Active; validator.jailedBefore = 0; _validatorsMap[validatorAddress] = validator; _activeValidatorsList.push(validatorAddress); // emit event emit ValidatorReleased(validatorAddress, currentEpoch()); } function undelegate(address validatorAddress, uint256 amount) external override { _undelegateFrom(msg.sender, validatorAddress, amount); } function currentEpoch() public view override returns (uint64) { return uint64(block.number / _stakingConfig.getEpochBlockInterval()); } function nextEpoch() public view override returns (uint64) { return currentEpoch() + 1; } function _touchValidatorSnapshot(Validator memory validator, uint64 epoch) internal returns (ValidatorSnapshot storage) { ValidatorSnapshot storage snapshot = _validatorSnapshots[validator.validatorAddress][epoch]; // if snapshot is already initialized then just return it if (snapshot.totalDelegated > 0) { return snapshot; } // find previous snapshot to copy parameters from it ValidatorSnapshot memory lastModifiedSnapshot = _validatorSnapshots[validator.validatorAddress][validator.changedAt]; // last modified snapshot might store zero value, for first delegation it might happen and its not critical snapshot.totalDelegated = lastModifiedSnapshot.totalDelegated; snapshot.commissionRate = lastModifiedSnapshot.commissionRate; // we must save last affected epoch for this validator to be able to restore total delegated // amount in the future (check condition upper) if (epoch > validator.changedAt) { validator.changedAt = epoch; } return snapshot; } function _touchValidatorSnapshotImmutable(Validator memory validator, uint64 epoch) internal view returns (ValidatorSnapshot memory) { ValidatorSnapshot memory snapshot = _validatorSnapshots[validator.validatorAddress][epoch]; // if snapshot is already initialized then just return it if (snapshot.totalDelegated > 0) { return snapshot; } // find previous snapshot to copy parameters from it ValidatorSnapshot memory lastModifiedSnapshot = _validatorSnapshots[validator.validatorAddress][validator.changedAt]; // last modified snapshot might store zero value, for first delegation it might happen and its not critical snapshot.totalDelegated = lastModifiedSnapshot.totalDelegated; snapshot.commissionRate = lastModifiedSnapshot.commissionRate; // return existing or new snapshot return snapshot; } function _delegateTo(address fromDelegator, address toValidator, uint256 amount) internal { // check is minimum delegate amount require(amount >= _stakingConfig.getMinStakingAmount() && amount != 0, "too low"); require(amount % BALANCE_COMPACT_PRECISION == 0, "no remainder"); // make sure amount is greater than min staking amount // make sure validator exists at least Validator memory validator = _validatorsMap[toValidator]; require(validator.status != ValidatorStatus.NotFound, "not found"); uint64 sinceEpoch = nextEpoch(); // Lets upgrade next snapshot parameters: // + find snapshot for the next epoch after current block // + increase total delegated amount in the next epoch for this validator // + re-save validator because last affected epoch might change ValidatorSnapshot storage validatorSnapshot = _touchValidatorSnapshot(validator, sinceEpoch); validatorSnapshot.totalDelegated += uint112(amount / BALANCE_COMPACT_PRECISION); _validatorsMap[toValidator] = validator; // if last pending delegate has the same next epoch then its safe to just increase total // staked amount because it can't affect current validator set, but otherwise we must create // new record in delegation queue with the last epoch (delegations are ordered by epoch) ValidatorDelegation storage delegation = _validatorDelegations[toValidator][fromDelegator]; if (delegation.delegateQueue.length > 0) { DelegationOpDelegate storage recentDelegateOp = delegation.delegateQueue[delegation.delegateQueue.length - 1]; // if we already have pending snapshot for the next epoch then just increase new amount, // otherwise create next pending snapshot. (tbh it can't be greater, but what we can do here instead?) if (recentDelegateOp.epoch >= sinceEpoch) { recentDelegateOp.amount += uint112(amount / BALANCE_COMPACT_PRECISION); } else { delegation.delegateQueue.push(DelegationOpDelegate({epoch : sinceEpoch, amount : recentDelegateOp.amount + uint112(amount / BALANCE_COMPACT_PRECISION)})); } } else { // there is no any delegations at al, lets create the first one delegation.delegateQueue.push(DelegationOpDelegate({epoch : sinceEpoch, amount : uint112(amount / BALANCE_COMPACT_PRECISION)})); } // emit event with the next epoch emit Delegated(toValidator, fromDelegator, amount, sinceEpoch); } function calcUnlockedDelegatedAmount(address validator, address delegator) public view returns (uint256) { ValidatorDelegation storage delegation = _validatorDelegations[validator][delegator]; uint256 unlockedAmount = _calcUnlockedDelegatedAmount(delegation, nextEpoch()); if (unlockedAmount < type(uint256).max || delegation.delegateQueue.length == 0) { return unlockedAmount; } DelegationOpDelegate memory latestDelegate = delegation.delegateQueue[delegation.delegateQueue.length - 1]; return latestDelegate.amount; } function _calcUnlockedDelegatedAmount(ValidatorDelegation storage delegation, uint64 beforeEpochExclusive) internal view returns (uint256 unlockedAmount) { uint64 lockPeriod = _stakingConfig.getLockPeriod(); // if lock period is zero than this feature is disabled if (lockPeriod == 0) { return type(uint256).max; } for (uint256 i = delegation.delegateGap; i < delegation.delegateQueue.length; i++) { DelegationOpDelegate memory delegateOp = delegation.delegateQueue[i]; if (beforeEpochExclusive <= delegateOp.epoch + lockPeriod) { break; } unlockedAmount = uint256(delegateOp.amount) * BALANCE_COMPACT_PRECISION; } for (uint256 i = delegation.undelegateGap; i < delegation.undelegateQueue.length; i++) { DelegationOpUndelegate memory undelegateOp = delegation.undelegateQueue[i]; unlockedAmount -= uint256(undelegateOp.amount) * BALANCE_COMPACT_PRECISION; } return unlockedAmount; } function _undelegateFrom(address toDelegator, address fromValidator, uint256 amount) internal { // check minimum delegate amount require(amount >= _stakingConfig.getMinStakingAmount() && amount != 0, "too low"); require(amount % BALANCE_COMPACT_PRECISION == 0, "no remainder"); // make sure validator exists at least Validator memory validator = _validatorsMap[fromValidator]; uint64 beforeEpoch = nextEpoch(); // Lets upgrade next snapshot parameters: // + find snapshot for the next epoch after current block // + increase total delegated amount in the next epoch for this validator // + re-save validator because last affected epoch might change ValidatorSnapshot storage validatorSnapshot = _touchValidatorSnapshot(validator, beforeEpoch); require(validatorSnapshot.totalDelegated >= uint112(amount / BALANCE_COMPACT_PRECISION), "insufficient balance"); validatorSnapshot.totalDelegated -= uint112(amount / BALANCE_COMPACT_PRECISION); _validatorsMap[fromValidator] = validator; // if last pending delegate has the same next epoch then its safe to just increase total // staked amount because it can't affect current validator set, but otherwise we must create // new record in delegation queue with the last epoch (delegations are ordered by epoch) ValidatorDelegation storage delegation = _validatorDelegations[fromValidator][toDelegator]; require(delegation.delegateQueue.length > 0, "insufficient balance"); DelegationOpDelegate storage recentDelegateOp = delegation.delegateQueue[delegation.delegateQueue.length - 1]; require(recentDelegateOp.amount >= uint64(amount / BALANCE_COMPACT_PRECISION), "insufficient balance"); // disallow to undelegate if lock period is not reached yet require(amount <= _calcUnlockedDelegatedAmount(delegation, beforeEpoch), "still locked"); // calc next delegated amount uint112 nextDelegatedAmount = recentDelegateOp.amount - uint112(amount / BALANCE_COMPACT_PRECISION); if (recentDelegateOp.epoch >= beforeEpoch) { // decrease total delegated amount for the next epoch recentDelegateOp.amount = nextDelegatedAmount; } else { // there is no pending delegations, so lets create the new one with the new amount delegation.delegateQueue.push(DelegationOpDelegate({epoch : beforeEpoch, amount : nextDelegatedAmount})); } // create new undelegate queue operation with soft lock delegation.undelegateQueue.push(DelegationOpUndelegate({amount : uint112(amount / BALANCE_COMPACT_PRECISION), epoch : beforeEpoch + _stakingConfig.getUndelegatePeriod()})); // emit event with the next epoch number emit Undelegated(fromValidator, toDelegator, amount, beforeEpoch); } function _transferDelegatorRewards(address validator, address delegator, uint64 beforeEpochExclude, bool withRewards, bool withUndelegates) internal { ValidatorDelegation storage delegation = _validatorDelegations[validator][delegator]; // claim rewards and undelegates uint256 availableFunds = 0; if (withRewards) { availableFunds += _processDelegateQueue(validator, delegation, beforeEpochExclude); } if (withUndelegates) { availableFunds += _processUndelegateQueue(delegation, beforeEpochExclude); } // for transfer claim mode just all rewards to the user _safeTransferWithGasLimit(payable(delegator), availableFunds); // emit event emit Claimed(validator, delegator, availableFunds, beforeEpochExclude); } function _redelegateDelegatorRewards(address validator, address delegator, uint64 beforeEpochExclude, bool withRewards, bool withUndelegates) internal { ValidatorDelegation storage delegation = _validatorDelegations[validator][delegator]; // claim rewards and undelegates uint256 availableFunds = 0; if (withRewards) { availableFunds += _processDelegateQueue(validator, delegation, beforeEpochExclude); } if (withUndelegates) { availableFunds += _processUndelegateQueue(delegation, beforeEpochExclude); } (uint256 amountToStake, uint256 rewardsDust) = _calcAvailableForRedelegateAmount(availableFunds); // if we have something to re-stake then delegate it to the validator if (amountToStake > 0) { _delegateTo(delegator, validator, amountToStake); } // if we have dust from staking then send it to user (we can't keep them in the contract) if (rewardsDust > 0) { _safeTransferWithGasLimit(payable(delegator), rewardsDust); } // emit event emit Redelegated(validator, delegator, amountToStake, rewardsDust, beforeEpochExclude); } function _processDelegateQueue(address validator, ValidatorDelegation storage delegation, uint64 beforeEpochExclude) internal returns (uint256 availableFunds) { uint64 lockPeriod = _stakingConfig.getLockPeriod(); uint64 delegateGap = delegation.delegateGap; for (uint256 queueLength = delegation.delegateQueue.length; delegateGap < queueLength && gasleft() > CLAIM_BEFORE_GAS;) { DelegationOpDelegate memory delegateOp = delegation.delegateQueue[delegateGap]; if (delegateOp.epoch >= beforeEpochExclude + lockPeriod) { break; } uint256 voteChangedAtEpoch = 0; if (delegateGap < queueLength - 1) { voteChangedAtEpoch = delegation.delegateQueue[delegateGap + 1].epoch; } for (; delegateOp.epoch < beforeEpochExclude && (voteChangedAtEpoch == 0 || delegateOp.epoch < voteChangedAtEpoch) && gasleft() > CLAIM_BEFORE_GAS; delegateOp.epoch++) { ValidatorSnapshot memory validatorSnapshot = _validatorSnapshots[validator][delegateOp.epoch]; if (validatorSnapshot.totalDelegated == 0) { continue; } (uint256 delegatorFee, /*uint256 ownerFee*/, /*uint256 systemFee*/) = _calcValidatorSnapshotEpochPayout(validatorSnapshot); availableFunds += delegatorFee * delegateOp.amount / validatorSnapshot.totalDelegated; } // if we have reached end of the delegation list then lets stay on the last item, but with updated latest processed epoch if (delegateGap >= queueLength - 1) { delegation.delegateQueue[delegateGap] = delegateOp; break; } delete delegation.delegateQueue[delegateGap]; ++delegateGap; } delegation.delegateGap = delegateGap; return availableFunds; } function _processUndelegateQueue(ValidatorDelegation storage delegation, uint64 beforeEpochExclude) internal returns (uint256 availableFunds) { uint64 undelegateGap = delegation.undelegateGap; for (uint256 queueLength = delegation.undelegateQueue.length; undelegateGap < queueLength && gasleft() > CLAIM_BEFORE_GAS;) { DelegationOpUndelegate memory undelegateOp = delegation.undelegateQueue[undelegateGap]; if (undelegateOp.epoch > beforeEpochExclude) { break; } availableFunds += uint256(undelegateOp.amount) * BALANCE_COMPACT_PRECISION; delete delegation.undelegateQueue[undelegateGap]; ++undelegateGap; } delegation.undelegateGap = undelegateGap; return availableFunds; } function _calcDelegatorRewardsAndPendingUndelegates(address validator, address delegator, uint64 beforeEpoch, bool withUndelegate) internal view returns (uint256) { uint64 lockPeriod = _stakingConfig.getLockPeriod(); ValidatorDelegation memory delegation = _validatorDelegations[validator][delegator]; uint256 availableFunds = 0; // process delegate queue to calculate staking rewards while (delegation.delegateGap < delegation.delegateQueue.length) { DelegationOpDelegate memory delegateOp = delegation.delegateQueue[delegation.delegateGap]; if (delegateOp.epoch >= beforeEpoch + lockPeriod) { break; } uint256 voteChangedAtEpoch = 0; if (delegation.delegateGap < delegation.delegateQueue.length - 1) { voteChangedAtEpoch = delegation.delegateQueue[delegation.delegateGap + 1].epoch; } for (; delegateOp.epoch < beforeEpoch && (voteChangedAtEpoch == 0 || delegateOp.epoch < voteChangedAtEpoch); delegateOp.epoch++) { ValidatorSnapshot memory validatorSnapshot = _validatorSnapshots[validator][delegateOp.epoch]; if (validatorSnapshot.totalDelegated == 0) { continue; } (uint256 delegatorFee, /*uint256 ownerFee*/, /*uint256 systemFee*/) = _calcValidatorSnapshotEpochPayout(validatorSnapshot); availableFunds += delegatorFee * delegateOp.amount / validatorSnapshot.totalDelegated; } ++delegation.delegateGap; } // process all items from undelegate queue while (withUndelegate && delegation.undelegateGap < delegation.undelegateQueue.length) { DelegationOpUndelegate memory undelegateOp = delegation.undelegateQueue[delegation.undelegateGap]; if (undelegateOp.epoch > beforeEpoch) { break; } availableFunds += uint256(undelegateOp.amount) * BALANCE_COMPACT_PRECISION; ++delegation.undelegateGap; } // return available for claim funds return availableFunds; } function _claimValidatorOwnerRewards(Validator storage validator, uint64 beforeEpoch) internal { uint256 availableFunds = 0; uint256 systemFee = 0; uint64 claimAt = validator.claimedAt; for (; claimAt < beforeEpoch && gasleft() > CLAIM_BEFORE_GAS; claimAt++) { ValidatorSnapshot memory validatorSnapshot = _validatorSnapshots[validator.validatorAddress][claimAt]; (/*uint256 delegatorFee*/, uint256 ownerFee, uint256 slashingFee) = _calcValidatorSnapshotEpochPayout(validatorSnapshot); availableFunds += ownerFee; systemFee += slashingFee; } validator.claimedAt = claimAt; _safeTransferWithGasLimit(payable(validator.ownerAddress), availableFunds); // if we have system fee then pay it to treasury account if (systemFee > 0) { _unsafeTransfer(payable(_stakingConfig.getTreasuryAddress()), systemFee); } emit ValidatorOwnerClaimed(validator.validatorAddress, availableFunds, beforeEpoch); } function _calcValidatorOwnerRewards(Validator memory validator, uint64 beforeEpoch) internal view returns (uint256) { uint256 availableFunds = 0; for (; validator.claimedAt < beforeEpoch; validator.claimedAt++) { ValidatorSnapshot memory validatorSnapshot = _validatorSnapshots[validator.validatorAddress][validator.claimedAt]; (/*uint256 delegatorFee*/, uint256 ownerFee, /*uint256 systemFee*/) = _calcValidatorSnapshotEpochPayout(validatorSnapshot); availableFunds += ownerFee; } return availableFunds; } function _calcValidatorSnapshotEpochPayout(ValidatorSnapshot memory validatorSnapshot) internal view returns (uint256 delegatorFee, uint256 ownerFee, uint256 systemFee) { // detect validator slashing to transfer all rewards to treasury if (validatorSnapshot.slashesCount >= _stakingConfig.getMisdemeanorThreshold()) { return (delegatorFee = 0, ownerFee = 0, systemFee = validatorSnapshot.totalRewards); } else if (validatorSnapshot.totalDelegated == 0) { return (delegatorFee = 0, ownerFee = validatorSnapshot.totalRewards, systemFee = 0); } // ownerFee_(18+4-4=18) = totalRewards_18 * commissionRate_4 / 1e4 ownerFee = uint256(validatorSnapshot.totalRewards) * validatorSnapshot.commissionRate / 1e4; // delegatorRewards = totalRewards - ownerFee delegatorFee = validatorSnapshot.totalRewards - ownerFee; // default system fee is zero for epoch systemFee = 0; } function registerValidator(address validatorAddress, uint16 commissionRate) payable external override { uint256 initialStake = msg.value; // // initial stake amount should be greater than minimum validator staking amount require(initialStake >= _stakingConfig.getMinValidatorStakeAmount(), "too low"); require(initialStake % BALANCE_COMPACT_PRECISION == 0, "no remainder"); // add new validator as pending _addValidator(validatorAddress, msg.sender, ValidatorStatus.Pending, commissionRate, initialStake, nextEpoch()); } function addValidator(address account) external onlyFromGovernance virtual override { _addValidator(account, account, ValidatorStatus.Active, 0, 0, nextEpoch()); } function _addValidator(address validatorAddress, address validatorOwner, ValidatorStatus status, uint16 commissionRate, uint256 initialStake, uint64 sinceEpoch) internal { // validator commission rate require(commissionRate >= COMMISSION_RATE_MIN_VALUE && commissionRate <= COMMISSION_RATE_MAX_VALUE, "bad commission"); // init validator default params Validator memory validator = _validatorsMap[validatorAddress]; require(_validatorsMap[validatorAddress].status == ValidatorStatus.NotFound, "already exist"); validator.validatorAddress = validatorAddress; validator.ownerAddress = validatorOwner; validator.status = status; validator.changedAt = sinceEpoch; _validatorsMap[validatorAddress] = validator; // save validator owner require(_validatorOwners[validatorOwner] == address(0x00), "owner in use"); _validatorOwners[validatorOwner] = validatorAddress; // add new validator to array if (status == ValidatorStatus.Active) { _activeValidatorsList.push(validatorAddress); } // push initial validator snapshot at zero epoch with default params _validatorSnapshots[validatorAddress][sinceEpoch] = ValidatorSnapshot(0, uint112(initialStake / BALANCE_COMPACT_PRECISION), 0, commissionRate); // delegate initial stake to validator owner ValidatorDelegation storage delegation = _validatorDelegations[validatorAddress][validatorOwner]; require(delegation.delegateQueue.length == 0); delegation.delegateQueue.push(DelegationOpDelegate(uint112(initialStake / BALANCE_COMPACT_PRECISION), sinceEpoch)); emit Delegated(validatorAddress, validatorOwner, initialStake, sinceEpoch); // emit event emit ValidatorAdded(validatorAddress, validatorOwner, uint8(status), commissionRate); } function _calcLockPeriod(uint64 sinceEpoch) internal view returns (uint64) { uint64 lockPeriod = _stakingConfig.getLockPeriod(); if (lockPeriod == 0) { return 0; } return sinceEpoch + lockPeriod; } function removeValidator(address account) external onlyFromGovernance virtual override { Validator memory validator = _validatorsMap[account]; require(validator.status != ValidatorStatus.NotFound, "not found"); // remove validator from active list if exists _removeValidatorFromActiveList(account); // remove from validators map delete _validatorOwners[validator.ownerAddress]; delete _validatorsMap[account]; // emit event about it emit ValidatorRemoved(account); } function _removeValidatorFromActiveList(address validatorAddress) internal { // find index of validator in validator set int256 indexOf = - 1; for (uint256 i = 0; i < _activeValidatorsList.length; i++) { if (_activeValidatorsList[i] != validatorAddress) continue; indexOf = int256(i); break; } // remove validator from array (since we remove only active it might not exist in the list) if (indexOf >= 0) { if (_activeValidatorsList.length > 1 && uint256(indexOf) != _activeValidatorsList.length - 1) { _activeValidatorsList[uint256(indexOf)] = _activeValidatorsList[_activeValidatorsList.length - 1]; } _activeValidatorsList.pop(); } } function activateValidator(address validatorAddress) external onlyFromGovernance virtual override { Validator memory validator = _validatorsMap[validatorAddress]; require(_validatorsMap[validatorAddress].status == ValidatorStatus.Pending, "bad status"); _activeValidatorsList.push(validatorAddress); validator.status = ValidatorStatus.Active; _validatorsMap[validatorAddress] = validator; ValidatorSnapshot storage snapshot = _touchValidatorSnapshot(validator, nextEpoch()); emit ValidatorModified(validatorAddress, validator.ownerAddress, uint8(validator.status), snapshot.commissionRate); } function disableValidator(address validatorAddress) external onlyFromGovernance virtual override { Validator memory validator = _validatorsMap[validatorAddress]; require(validator.status == ValidatorStatus.Active || validator.status == ValidatorStatus.Jail, "bad status"); _removeValidatorFromActiveList(validatorAddress); validator.status = ValidatorStatus.Pending; _validatorsMap[validatorAddress] = validator; ValidatorSnapshot storage snapshot = _touchValidatorSnapshot(validator, nextEpoch()); emit ValidatorModified(validatorAddress, validator.ownerAddress, uint8(validator.status), snapshot.commissionRate); } function changeValidatorCommissionRate(address validatorAddress, uint16 commissionRate) external override { require(commissionRate >= COMMISSION_RATE_MIN_VALUE && commissionRate <= COMMISSION_RATE_MAX_VALUE, "bad commission"); Validator memory validator = _validatorsMap[validatorAddress]; require(validator.status != ValidatorStatus.NotFound, "not found"); require(validator.ownerAddress == msg.sender, "only owner"); ValidatorSnapshot storage snapshot = _touchValidatorSnapshot(validator, nextEpoch()); snapshot.commissionRate = commissionRate; _validatorsMap[validatorAddress] = validator; emit ValidatorModified(validator.validatorAddress, validator.ownerAddress, uint8(validator.status), commissionRate); } function changeValidatorOwner(address validatorAddress, address newOwner) external override { Validator memory validator = _validatorsMap[validatorAddress]; require(validator.ownerAddress == msg.sender, "only owner"); require(_validatorOwners[newOwner] == address(0x00), "owner in use"); delete _validatorOwners[validator.ownerAddress]; validator.ownerAddress = newOwner; _validatorOwners[newOwner] = validatorAddress; _validatorsMap[validatorAddress] = validator; ValidatorSnapshot storage snapshot = _touchValidatorSnapshot(validator, nextEpoch()); emit ValidatorModified(validator.validatorAddress, validator.ownerAddress, uint8(validator.status), snapshot.commissionRate); } function isValidatorActive(address account) external override view returns (bool) { if (_validatorsMap[account].status != ValidatorStatus.Active) { return false; } address[] memory topValidators = getValidators(); for (uint256 i = 0; i < topValidators.length; i++) { if (topValidators[i] == account) return true; } return false; } function isValidator(address account) external override view returns (bool) { return _validatorsMap[account].status != ValidatorStatus.NotFound; } function getValidators() public view override returns (address[] memory) { uint256 n = _activeValidatorsList.length; address[] memory orderedValidators = new address[](n); for (uint256 i = 0; i < n; i++) { orderedValidators[i] = _activeValidatorsList[i]; } // we need to select k top validators out of n uint256 k = _stakingConfig.getActiveValidatorsLength(); if (k > n) { k = n; } for (uint256 i = 0; i < k; i++) { uint256 nextValidator = i; Validator memory currentMax = _validatorsMap[orderedValidators[nextValidator]]; ValidatorSnapshot memory maxSnapshot = _validatorSnapshots[currentMax.validatorAddress][currentMax.changedAt]; for (uint256 j = i + 1; j < n; j++) { Validator memory current = _validatorsMap[orderedValidators[j]]; ValidatorSnapshot memory currentSnapshot = _validatorSnapshots[current.validatorAddress][current.changedAt]; if (maxSnapshot.totalDelegated < currentSnapshot.totalDelegated) { nextValidator = j; currentMax = current; maxSnapshot = currentSnapshot; } } address backup = orderedValidators[i]; orderedValidators[i] = orderedValidators[nextValidator]; orderedValidators[nextValidator] = backup; } // this is to cut array to first k elements without copying assembly { mstore(orderedValidators, k) } return orderedValidators; } function _depositFee(address validatorAddress, uint256 amount) internal { // make sure validator is active Validator memory validator = _validatorsMap[validatorAddress]; require(validator.status != ValidatorStatus.NotFound, "not found"); uint64 epoch = currentEpoch(); // increase total pending rewards for validator for current epoch ValidatorSnapshot storage currentSnapshot = _touchValidatorSnapshot(validator, epoch); currentSnapshot.totalRewards += uint96(amount); // emit event emit ValidatorDeposited(validatorAddress, amount, epoch); } function getValidatorFee(address validatorAddress) external override view returns (uint256) { // make sure validator exists at least Validator memory validator = _validatorsMap[validatorAddress]; if (validator.status == ValidatorStatus.NotFound) { return 0; } // calc validator rewards return _calcValidatorOwnerRewards(validator, currentEpoch()); } function getPendingValidatorFee(address validatorAddress) external override view returns (uint256) { // make sure validator exists at least Validator memory validator = _validatorsMap[validatorAddress]; if (validator.status == ValidatorStatus.NotFound) { return 0; } // calc validator rewards return _calcValidatorOwnerRewards(validator, nextEpoch()); } function claimValidatorFee(address validatorAddress) external override { // make sure validator exists at least Validator storage validator = _validatorsMap[validatorAddress]; // only validator owner can claim deposit fee require(msg.sender == validator.ownerAddress, "only owner"); // claim all validator fees _claimValidatorOwnerRewards(validator, currentEpoch()); } function getDelegatorFee(address validatorAddress, address delegatorAddress) external override view returns (uint256) { return _calcDelegatorRewardsAndPendingUndelegates(validatorAddress, delegatorAddress, currentEpoch(), true); } function getPendingDelegatorFee(address validatorAddress, address delegatorAddress) external override view returns (uint256) { return _calcDelegatorRewardsAndPendingUndelegates(validatorAddress, delegatorAddress, nextEpoch(), true); } function claimDelegatorFee(address validatorAddress) external override { // claim all confirmed delegator fees including undelegates _transferDelegatorRewards(validatorAddress, msg.sender, currentEpoch(), true, true); } function getStakingRewards(address validator, address delegator) external view returns (uint256) { return _calcDelegatorRewardsAndPendingUndelegates(validator, delegator, currentEpoch(), false); } function claimStakingRewards(address validatorAddress) external override { // claim only staking rewards _transferDelegatorRewards(validatorAddress, msg.sender, currentEpoch(), true, false); } function claimPendingUndelegates(address validator) external override { // claim only pending undelegates _transferDelegatorRewards(validator, msg.sender, currentEpoch(), false, true); } function _calcAvailableForRedelegateAmount(uint256 claimableRewards) internal view returns (uint256 amountToStake, uint256 rewardsDust) { // for redelegate we must split amount into stake-able and dust amountToStake = (claimableRewards / BALANCE_COMPACT_PRECISION) * BALANCE_COMPACT_PRECISION; if (amountToStake < _stakingConfig.getMinStakingAmount()) { return (0, claimableRewards); } // if we have dust remaining after re-stake then send it to user (we can't keep it in the contract) return (amountToStake, claimableRewards - amountToStake); } function calcAvailableForRedelegateAmount(address validator, address delegator) external view override returns (uint256 amountToStake, uint256 rewardsDust) { uint256 claimableRewards = _calcDelegatorRewardsAndPendingUndelegates(validator, delegator, currentEpoch(), false); return _calcAvailableForRedelegateAmount(claimableRewards); } function redelegateDelegatorFee(address validator) external override { // claim rewards in the redelegate mode (check function code for more info) _redelegateDelegatorRewards(validator, msg.sender, currentEpoch(), true, false); } function _safeTransferWithGasLimit(address payable recipient, uint256 amount) internal virtual { (bool success,) = recipient.call{value : amount, gas : TRANSFER_GAS_LIMIT}(""); require(success); } function _unsafeTransfer(address payable recipient, uint256 amount) internal virtual { (bool success,) = payable(address(recipient)).call{value : amount}(""); require(success); } function _slashValidator(address validatorAddress) internal { // make sure validator exists Validator memory validator = _validatorsMap[validatorAddress]; require(validator.status != ValidatorStatus.NotFound, "not found"); uint64 epoch = currentEpoch(); // increase slashes for current epoch ValidatorSnapshot storage currentSnapshot = _touchValidatorSnapshot(validator, epoch); uint32 slashesCount = currentSnapshot.slashesCount + 1; currentSnapshot.slashesCount = slashesCount; // if validator has a lot of misses then put it in jail for 1 week (if epoch is 1 day) if (slashesCount == _stakingConfig.getFelonyThreshold()) { validator.jailedBefore = currentEpoch() + _stakingConfig.getValidatorJailEpochLength(); validator.status = ValidatorStatus.Jail; _removeValidatorFromActiveList(validatorAddress); _validatorsMap[validatorAddress] = validator; emit ValidatorJailed(validatorAddress, epoch); } else { // validator state might change, lets update it _validatorsMap[validatorAddress] = validator; } // emit event emit ValidatorSlashed(validatorAddress, slashesCount, epoch); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "../interfaces/IStakingConfig.sol"; contract StakingConfig is Initializable, IStakingConfig { event ActiveValidatorsLengthChanged(uint32 prevValue, uint32 newValue); event EpochBlockIntervalChanged(uint32 prevValue, uint32 newValue); event MisdemeanorThresholdChanged(uint32 prevValue, uint32 newValue); event FelonyThresholdChanged(uint32 prevValue, uint32 newValue); event ValidatorJailEpochLengthChanged(uint32 prevValue, uint32 newValue); event UndelegatePeriodChanged(uint32 prevValue, uint32 newValue); event MinValidatorStakeAmountChanged(uint256 prevValue, uint256 newValue); event MinStakingAmountChanged(uint256 prevValue, uint256 newValue); event GovernanceAddressChanged(address prevValue, address newValue); event TreasuryAddressChanged(address prevValue, address newValue); event LockPeriodChanged(uint64 prevValue, uint64 newValue); struct Slot0 { uint32 activeValidatorsLength; uint32 epochBlockInterval; uint32 misdemeanorThreshold; uint32 felonyThreshold; uint32 validatorJailEpochLength; uint32 undelegatePeriod; uint256 minValidatorStakeAmount; uint256 minStakingAmount; address governanceAddress; address treasuryAddress; uint64 lockPeriod; } Slot0 private _slot0; function initialize( uint32 activeValidatorsLength, uint32 epochBlockInterval, uint32 misdemeanorThreshold, uint32 felonyThreshold, uint32 validatorJailEpochLength, uint32 undelegatePeriod, uint256 minValidatorStakeAmount, uint256 minStakingAmount, address governanceAddress, address treasuryAddress, uint64 lockPeriod ) external initializer { _slot0.activeValidatorsLength = activeValidatorsLength; emit ActiveValidatorsLengthChanged(0, activeValidatorsLength); _slot0.epochBlockInterval = epochBlockInterval; emit EpochBlockIntervalChanged(0, epochBlockInterval); _slot0.misdemeanorThreshold = misdemeanorThreshold; emit MisdemeanorThresholdChanged(0, misdemeanorThreshold); _slot0.felonyThreshold = felonyThreshold; emit FelonyThresholdChanged(0, felonyThreshold); _slot0.validatorJailEpochLength = validatorJailEpochLength; emit ValidatorJailEpochLengthChanged(0, validatorJailEpochLength); _slot0.undelegatePeriod = undelegatePeriod; emit UndelegatePeriodChanged(0, undelegatePeriod); _slot0.minValidatorStakeAmount = minValidatorStakeAmount; emit MinValidatorStakeAmountChanged(0, minValidatorStakeAmount); _slot0.minStakingAmount = minStakingAmount; emit MinStakingAmountChanged(0, minStakingAmount); _slot0.governanceAddress = governanceAddress; emit GovernanceAddressChanged(address(0x00), governanceAddress); _slot0.treasuryAddress = treasuryAddress; emit TreasuryAddressChanged(address(0x00), treasuryAddress); _slot0.lockPeriod = lockPeriod; emit LockPeriodChanged(0, lockPeriod); } modifier onlyFromGovernance() virtual { require(msg.sender == _slot0.governanceAddress, "Staking: only governance"); _; } function getSlot0() external view returns (Slot0 memory) { return _slot0; } function getActiveValidatorsLength() external view override returns (uint32) { return _slot0.activeValidatorsLength; } function setActiveValidatorsLength(uint32 newValue) external override onlyFromGovernance { uint32 prevValue = _slot0.activeValidatorsLength; _slot0.activeValidatorsLength = newValue; emit ActiveValidatorsLengthChanged(prevValue, newValue); } function getEpochBlockInterval() external view override returns (uint32) { return _slot0.epochBlockInterval; } function setEpochBlockInterval(uint32 newValue) external override onlyFromGovernance { uint32 prevValue = _slot0.epochBlockInterval; _slot0.epochBlockInterval = newValue; emit EpochBlockIntervalChanged(prevValue, newValue); } function getMisdemeanorThreshold() external view override returns (uint32) { return _slot0.misdemeanorThreshold; } function setMisdemeanorThreshold(uint32 newValue) external override onlyFromGovernance { uint32 prevValue = _slot0.misdemeanorThreshold; _slot0.misdemeanorThreshold = newValue; emit MisdemeanorThresholdChanged(prevValue, newValue); } function getFelonyThreshold() external view override returns (uint32) { return _slot0.felonyThreshold; } function setFelonyThreshold(uint32 newValue) external override onlyFromGovernance { uint32 prevValue = _slot0.felonyThreshold; _slot0.felonyThreshold = newValue; emit FelonyThresholdChanged(prevValue, newValue); } function getValidatorJailEpochLength() external view override returns (uint32) { return _slot0.validatorJailEpochLength; } function setValidatorJailEpochLength(uint32 newValue) external override onlyFromGovernance { uint32 prevValue = _slot0.validatorJailEpochLength; _slot0.validatorJailEpochLength = newValue; emit ValidatorJailEpochLengthChanged(prevValue, newValue); } function getUndelegatePeriod() external view override returns (uint32) { return _slot0.undelegatePeriod; } function setUndelegatePeriod(uint32 newValue) external override onlyFromGovernance { uint32 prevValue = _slot0.undelegatePeriod; _slot0.undelegatePeriod = newValue; emit UndelegatePeriodChanged(prevValue, newValue); } function getMinValidatorStakeAmount() external view override returns (uint256) { return _slot0.minValidatorStakeAmount; } function setMinValidatorStakeAmount(uint256 newValue) external override { uint256 prevValue = _slot0.minValidatorStakeAmount; _slot0.minValidatorStakeAmount = newValue; emit MinValidatorStakeAmountChanged(prevValue, newValue); } function getMinStakingAmount() external view override returns (uint256) { return _slot0.minStakingAmount; } function setMinStakingAmount(uint256 newValue) external override { uint256 prevValue = _slot0.minStakingAmount; _slot0.minStakingAmount = newValue; emit MinStakingAmountChanged(prevValue, newValue); } function getGovernanceAddress() external view override returns (address) { return _slot0.governanceAddress; } function setGovernanceAddress(address newValue) external override { address prevValue = _slot0.governanceAddress; _slot0.governanceAddress = newValue; emit GovernanceAddressChanged(prevValue, newValue); } function getTreasuryAddress() external view override returns (address) { return _slot0.treasuryAddress; } function setTreasuryAddress(address newValue) external override { address prevValue = _slot0.treasuryAddress; _slot0.treasuryAddress = newValue; emit TreasuryAddressChanged(prevValue, newValue); } function getLockPeriod() external view override returns (uint64) { return _slot0.lockPeriod; } function setLockPeriod(uint64 newValue) external override onlyFromGovernance { uint64 prevValue = _slot0.lockPeriod; _slot0.lockPeriod = newValue; emit LockPeriodChanged(prevValue, newValue); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.7; import "../../interfaces/ITokenStaking.sol"; import "../Staking.sol"; contract TokenStaking is Staking, ITokenStaking { // address of the erc20 token IERC20 internal _erc20Token; // reserve some gap for the future upgrades uint256[100 - 2] private __reserved; function __TokenStaking_init(IStakingConfig chainConfig, IERC20 erc20Token) internal { _stakingConfig = chainConfig; _erc20Token = erc20Token; } function getErc20Token() external view override returns (IERC20) { return _erc20Token; } function delegate(address validatorAddress, uint256 amount) payable external override { require(_erc20Token.transferFrom(msg.sender, address(this), amount), "failed to transfer"); _delegateTo(msg.sender, validatorAddress, amount); } function distributeRewards(address validatorAddress, uint256 amount) external override { require(_erc20Token.transferFrom(msg.sender, address(this), amount), "failed to transfer"); _depositFee(validatorAddress, amount); } function _safeTransferWithGasLimit(address payable recipient, uint256 amount) internal override { require(_erc20Token.transfer(recipient, amount), "failed to safe transfer"); } function _unsafeTransfer(address payable recipient, uint256 amount) internal override { require(_erc20Token.transfer(recipient, amount), "failed to safe transfer"); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.0; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() initializer {} * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol) pragma solidity ^0.8.0; import "../Proxy.sol"; import "./ERC1967Upgrade.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. * * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded * function call, and allows initializating the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) payable { assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); _upgradeToAndCall(_logic, _data, false); } /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { return ERC1967Upgrade._getImplementation(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol) pragma solidity ^0.8.0; /** * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to * be specified by overriding the virtual {_implementation} function. * * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a * different contract through the {_delegate} function. * * The success and return data of the delegated call will be returned back to the caller of the proxy. */ abstract contract Proxy { /** * @dev Delegates the current call to `implementation`. * * This function does not return to its internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function * and {_fallback} should delegate. */ function _implementation() internal view virtual returns (address); /** * @dev Delegates the current call to the address returned by `_implementation()`. * * This function does not return to its internall call site, it will return directly to the external caller. */ function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other * function in the contract matches the call data. */ fallback() external payable virtual { _fallback(); } /** * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data * is empty. */ receive() external payable virtual { _fallback(); } /** * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` * call, or as part of the Solidity `fallback` or `receive` functions. * * If overriden should call `super._beforeFallback()`. */ function _beforeFallback() internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol) pragma solidity ^0.8.0; import "../ERC1967/ERC1967Proxy.sol"; /** * @dev This contract implements a proxy that is upgradeable by an admin. * * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector * clashing], which can potentially be used in an attack, this contract uses the * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two * things that go hand in hand: * * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if * that call matches one of the admin functions exposed by the proxy itself. * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the * implementation. If the admin tries to call a function on the implementation it will fail with an error that says * "admin cannot fallback to proxy target". * * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due * to sudden errors when trying to call a function from the proxy implementation. * * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. */ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. */ constructor( address _logic, address admin_, bytes memory _data ) payable ERC1967Proxy(_logic, _data) { assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); _changeAdmin(admin_); } /** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. */ modifier ifAdmin() { if (msg.sender == _getAdmin()) { _; } else { _fallback(); } } /** * @dev Returns the current admin. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function admin() external ifAdmin returns (address admin_) { admin_ = _getAdmin(); } /** * @dev Returns the current implementation. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function implementation() external ifAdmin returns (address implementation_) { implementation_ = _implementation(); } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. * * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ function changeAdmin(address newAdmin) external virtual ifAdmin { _changeAdmin(newAdmin); } /** * @dev Upgrade the implementation of the proxy. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeToAndCall(newImplementation, bytes(""), false); } /** * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the * proxied contract. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. */ function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin { _upgradeToAndCall(newImplementation, data, true); } /** * @dev Returns the current admin. */ function _admin() internal view virtual returns (address) { return _getAdmin(); } /** * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. */ function _beforeFallback() internal virtual override { require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); super._beforeFallback(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } }
{ "remappings": [], "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "london", "libraries": {}, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IStakingConfig","name":"stakingConfig","type":"address"},{"internalType":"contract IERC20","name":"ankrToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"getCurrentVersion","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"impl","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162006b2038038062006b2083398101604081905262000034916200054e565b816200003f62000100565b604080516001600160a01b03868116602483015285166044808301919091528251808303909101815260649091019091526020810180516001600160e01b031663485cc95560e01b1790528181620000b960017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd6200058d565b60008051602062006ad983398151915214620000d957620000d9620005b3565b620000e7828260006200015a565b50620000f590508362000197565b50505050506200064b565b6000807f44c0af46f92325c7c1b95e7178841f8fb94fa9600c46d90cadf4d815d7804fdc60405162000132906200052a565b8190604051809103906000f590508015801562000153573d6000803e3d6000fd5b5092915050565b6200016583620001f2565b600082511180620001735750805b1562000192576200019083836200023460201b620001941760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620001c262000263565b604080516001600160a01b03928316815291841660208301520160405180910390a1620001ef816200029c565b50565b620001fd8162000351565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200025c838360405180606001604052806027815260200162006af960279139620003f4565b9392505050565b60006200028d60008051602062006ab983398151915260001b620004da60201b620001c01760201c565b546001600160a01b0316919050565b6001600160a01b038116620003075760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b806200033060008051602062006ab983398151915260001b620004da60201b620001c01760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6200036781620004dd60201b620001c31760201c565b620003cb5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620002fe565b806200033060008051602062006ad983398151915260001b620004da60201b620001c01760201c565b60606001600160a01b0384163b6200045e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401620002fe565b600080856001600160a01b0316856040516200047b9190620005f8565b600060405180830381855af49150503d8060008114620004b8576040519150601f19603f3d011682016040523d82523d6000602084013e620004bd565b606091505b509092509050620004d0828286620004ec565b9695505050505050565b90565b6001600160a01b03163b151590565b60608315620004fd5750816200025c565b8251156200050e5782518084602001fd5b8160405162461bcd60e51b8152600401620002fe919062000616565b615de88062000cd183390190565b6001600160a01b0381168114620001ef57600080fd5b600080604083850312156200056257600080fd5b82516200056f8162000538565b6020840151909250620005828162000538565b809150509250929050565b600082821015620005ae57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b60005b83811015620005e6578181015183820152602001620005cc565b83811115620001905750506000910152565b600082516200060c818460208701620005c9565b9190910192915050565b602081526000825180602084015262000637816040850160208701620005c9565b601f01601f19169190910160400192915050565b610676806200065b6000396000f3fe60806040526004361061002d5760003560e01c80634f1ef28614610044578063fabec44a146100645761003c565b3661003c5761003a610095565b005b61003a610095565b34801561005057600080fd5b5061003a61005f3660046104bd565b6100a7565b34801561007057600080fd5b50610079610185565b6040516001600160a01b03909116815260200160405180910390f35b6100a56100a06101d2565b6101dc565b565b6100af610205565b6001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101109190610581565b6001600160a01b0316336001600160a01b0316146101755760405162461bcd60e51b815260206004820181905260248201527f4d616e61676561626c6550726f78793a206f6e6c7920676f7665726e616e636560448201526064015b60405180910390fd5b61018182826000610238565b5050565b600061018f6101d2565b905090565b60606101b9838360405180606001604052806027815260200161061a60279139610263565b9392505050565b90565b6001600160a01b03163b151590565b600061018f610340565b3660008037600080366000845af43d6000803e8080156101fb573d6000f35b3d6000fd5b505050565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61024183610368565b60008251118061024e5750805b156102005761025d8383610194565b50505050565b60606001600160a01b0384163b6102cb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161016c565b600080856001600160a01b0316856040516102e691906105ca565b600060405180830381855af49150503d8060008114610321576040519150601f19603f3d011682016040523d82523d6000602084013e610326565b606091505b50915091506103368282866103a8565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610229565b610371816103e1565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606083156103b75750816101b9565b8251156103c75782518084602001fd5b8160405162461bcd60e51b815260040161016c91906105e6565b6001600160a01b0381163b61044e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161016c565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03811681146104a457600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156104d057600080fd5b82356104db8161048f565b9150602083013567ffffffffffffffff808211156104f857600080fd5b818501915085601f83011261050c57600080fd5b81358181111561051e5761051e6104a7565b604051601f8201601f19908116603f01168101908382118183101715610546576105466104a7565b8160405282815288602084870101111561055f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60006020828403121561059357600080fd5b81516101b98161048f565b60005b838110156105b95781810151838201526020016105a1565b8381111561025d5750506000910152565b600082516105dc81846020870161059e565b9190910192915050565b602081526000825180602084015261060581604085016020870161059e565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c7bcabc54654f019fb468ff8f08cd8f4a1e9224d1697be83da48c369f3f8b6a664736f6c634300080e0033608060405234801561001057600080fd5b50615dc780620000216000396000f3fe6080604052600436106102195760003560e01c806373a3dda611610123578063b7ab4db5116100ab578063e6bf24271161006f578063e6bf24271461070a578063facd743b14610728578063fda259e014610748578063feb1824b14610768578063ff4794fc1461078657600080fd5b8063b7ab4db51461064b578063c2fd58fc1461066d578063c6fb90651461068d578063d951e186146106ad578063d9c5c734146106ea57600080fd5b8063a310624f116100f2578063a310624f146105a9578063a8031a1d146105c9578063ac9650d8146105e9578063aea0e78b14610616578063b46e55201461062b57600080fd5b806373a3dda61461051c578063766718081461053c5780638ecb3fc91461056957806396bb1fef1461058957600080fd5b8063457179fd116101a65780634d99dd16116101755780634d99dd161461047457806352b7bea2146104945780635ef9e8c6146104b457806361cadbf4146104e957806362b15fdc146104fc57600080fd5b8063457179fd1461037957806348124d26146103a7578063485cc955146104345780634d238c8e1461045457600080fd5b806323b9d662116101ed57806323b9d6621461029357806330108c22146102b357806340a141ff14610309578063426594b11461032957806342ad55ac1461034957600080fd5b806252c9e11461021e578063026e402b1461024057806314f8649f146102535780631fe9768414610273575b600080fd5b34801561022a57600080fd5b5061023e610239366004615720565b6107a6565b005b61023e61024e366004615759565b610a72565b34801561025f57600080fd5b5061023e61026e366004615785565b610b3c565b34801561027f57600080fd5b5061023e61028e3660046157ba565b610df1565b34801561029f57600080fd5b5061023e6102ae3660046157ba565b61111a565b3480156102bf57600080fd5b506102ec6102ce3660046157ba565b6001600160a01b039081166000908152600260205260409020541690565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561031557600080fd5b5061023e6103243660046157ba565b611133565b34801561033557600080fd5b5061023e6103443660046157ba565b611356565b34801561035557600080fd5b506103696103643660046157ba565b61136b565b6040519015158152602001610300565b34801561038557600080fd5b506103996103943660046157ba565b611420565b604051908152602001610300565b3480156103b357600080fd5b506103c76103c23660046157ec565b611507565b604080516001600160a01b03909a168a5260ff90981660208a01529688019590955263ffffffff90931660608701526001600160401b039182166080870152811660a08601521660c084015261ffff1660e08301526001600160601b031661010082015261012001610300565b34801561044057600080fd5b5061023e61044f366004615720565b61165e565b34801561046057600080fd5b5061023e61046f3660046157ba565b61174c565b34801561048057600080fd5b5061023e61048f366004615759565b61180a565b3480156104a057600080fd5b506103996104af366004615720565b611815565b3480156104c057600080fd5b506104d46104cf366004615720565b611834565b60408051928352602083019190915201610300565b61023e6104f7366004615785565b611865565b34801561050857600080fd5b50610399610517366004615720565b61192e565b34801561052857600080fd5b5061023e6105373660046157ba565b61193d565b34801561054857600080fd5b50610551611ab9565b6040516001600160401b039091168152602001610300565b34801561057557600080fd5b5061023e6105843660046157ba565b611b3c565b34801561059557600080fd5b5061023e6105a43660046157ba565b611b52565b3480156105b557600080fd5b506103c76105c43660046157ba565b611b68565b3480156105d557600080fd5b5061023e6105e4366004615759565b611d2e565b3480156105f557600080fd5b5061060961060436600461581a565b611df3565b60405161030091906158be565b34801561062257600080fd5b50610551611ee6565b34801561063757600080fd5b5061023e6106463660046157ba565b611efb565b34801561065757600080fd5b506106606120f8565b6040516103009190615938565b34801561067957600080fd5b50610399610688366004615720565b6125f5565b34801561069957600080fd5b506103996106a83660046157ba565b612604565b3480156106b957600080fd5b506106cd6106c8366004615720565b6126df565b604080519283526001600160401b03909116602083015201610300565b3480156106f657600080fd5b50610399610705366004615720565b6128a0565b34801561071657600080fd5b506006546001600160a01b03166102ec565b34801561073457600080fd5b506103696107433660046157ba565b612960565b34801561075457600080fd5b5061023e6107633660046157ba565b6129a3565b34801561077457600080fd5b506064546001600160a01b03166102ec565b34801561079257600080fd5b5061023e6107a13660046157ba565b612b2b565b6001600160a01b038281166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff16600381111561080357610803615985565b600381111561081457610814615985565b815260018201546001600160401b03600160a81b90910481166020808401919091526002909301548082166040840152600160401b9004166060909101528101519091506001600160a01b031633146108885760405162461bcd60e51b815260040161087f9061599b565b60405180910390fd5b6001600160a01b0382811660009081526002602052604090205416156108df5760405162461bcd60e51b815260206004820152600c60248201526b6f776e657220696e2075736560a01b604482015260640161087f565b602081810180516001600160a01b0390811660009081526002808552604080832080546001600160a01b03199081169091558885168087528452918652808320805483168a8616908117909155835260019586905291829020865181548316908516178155935194840180549182169590931694851783559085015185949092916001600160a81b03191617600160a01b83600381111561098257610982615985565b0217905550606082015160018201805467ffffffffffffffff60a81b1916600160a81b6001600160401b039384160217905560808301516002909201805460a0909401519282166001600160801b031990941693909317600160401b929091169190910217905560006109fc826109f7611ee6565b612b7d565b905081600001516001600160a01b03167fc00107e0d011ac7c8e4dfa18e3dd3623ff151f8bfcc3821cd39bc114bd6504d9836020015184604001516003811115610a4857610a48615985565b8454604051610a64939291600160f01b900461ffff16906159bf565b60405180910390a250505050565b606480546040516323b872dd60e01b8152336004820152306024820152604481018490526001600160a01b03909116916323b872dd91016020604051808303816000875af1158015610ac8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aec91906159e7565b610b2d5760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161087f565b610b38338383612cb6565b5050565b610bb861ffff82161115610b835760405162461bcd60e51b815260206004820152600e60248201526d3130b21031b7b6b6b4b9b9b4b7b760911b604482015260640161087f565b6001600160a01b038281166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff166003811115610be057610be0615985565b6003811115610bf157610bf1615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b90049091166060909101529050600081604001516003811115610c4757610c47615985565b03610c645760405162461bcd60e51b815260040161087f90615a09565b60208101516001600160a01b03163314610c905760405162461bcd60e51b815260040161087f9061599b565b6000610c9e826109f7611ee6565b805461ffff8516600160f01b026001600160f01b039091161781556001600160a01b03808616600090815260016020818152604092839020875181549086166001600160a01b031991821617825591880151928101805493909516918316821785559287015194955086949293916001600160a81b03191617600160a01b836003811115610d2e57610d2e615985565b0217905550606082015160018201805467ffffffffffffffff60a81b1916600160a81b6001600160401b039384160217905560808301516002909201805460a0909401519282166001600160801b031990941693909317600160401b92909116919091021790558151602083015160408401516001600160a01b03909216917fc00107e0d011ac7c8e4dfa18e3dd3623ff151f8bfcc3821cd39bc114bd6504d991906003811115610de157610de1615985565b86604051610a64939291906159bf565b600660009054906101000a90046001600160a01b03166001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e689190615a2c565b6001600160a01b0316336001600160a01b031614610e985760405162461bcd60e51b815260040161087f90615a49565b6001600160a01b038181166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff166003811115610ef557610ef5615985565b6003811115610f0657610f06615985565b81526001828101546001600160401b03600160a81b909104811660208401526002909301548084166040840152600160401b900490921660609091015290915081604001516003811115610f5c57610f5c615985565b1480610f7d5750600381604001516003811115610f7b57610f7b615985565b145b610f995760405162461bcd60e51b815260040161087f90615a80565b610fa2826131d5565b6040810160025b90816003811115610fbc57610fbc615985565b9052506001600160a01b03808316600090815260016020818152604092839020855181549086166001600160a01b03199182161782559186015192810180549390951691831682178555928501518594909290916001600160a81b031990911617600160a01b83600381111561103457611034615985565b0217905550606082015160018201805467ffffffffffffffff60a81b1916600160a81b6001600160401b039384160217905560808301516002909201805460a0909401519282166001600160801b031990941693909317600160401b929091169190910217905560006110a9826109f7611ee6565b9050826001600160a01b03167fc00107e0d011ac7c8e4dfa18e3dd3623ff151f8bfcc3821cd39bc114bd6504d98360200151846040015160038111156110f1576110f1615985565b845460405161110d939291600160f01b900461ffff16906159bf565b60405180910390a2505050565b6111308133611127611ab9565b60006001613316565b50565b600660009054906101000a90046001600160a01b03166001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611186573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111aa9190615a2c565b6001600160a01b0316336001600160a01b0316146111da5760405162461bcd60e51b815260040161087f90615a49565b6001600160a01b038181166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff16600381111561123757611237615985565b600381111561124857611248615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b9004909116606090910152905060008160400151600381111561129e5761129e615985565b036112bb5760405162461bcd60e51b815260040161087f90615a09565b6112c4826131d5565b6020808201516001600160a01b0390811660009081526002808452604080832080546001600160a01b03199081169091559387168084526001958690528184208054909516855594840180546001600160e81b0319169055920180546001600160801b031916905590517fe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f19190a25050565b6111308133611363611ab9565b600180613316565b6001600160a01b03811660009081526001602081905260408220810154600160a01b900460ff1660038111156113a3576113a3615985565b146113b057506000919050565b60006113ba6120f8565b905060005b815181101561141657836001600160a01b03168282815181106113e4576113e4615aa4565b60200260200101516001600160a01b031603611404575060019392505050565b8061140e81615ad0565b9150506113bf565b5060009392505050565b6001600160a01b038181166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292938493830190600160a01b900460ff16600381111561147a5761147a615985565b600381111561148b5761148b615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b900490911660609091015290506000816040015160038111156114e1576114e1615985565b036114ef5750600092915050565b611500816114fb611ab9565b6133d1565b9392505050565b6001600160a01b038281166000908152600160208181526040808420815160c08101835281548716815293810154958616928401929092529293849384938493849384938493849384938493830190600160a01b900460ff16600381111561157157611571615985565b600381111561158257611582615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b9004909116606090910152905060006115cc828d6134b6565b905081602001519a508a826040015160038111156115ec576115ec615985565b9a508a6402540be40083602001516001600160701b031661160d9190615ae9565b9a508a83604001519a508a85606001519a508a86608001519a508a8760a001519a508a87606001519a508a88600001519a509a509a509a509a509a509a509a509a5050509295985092959850929598565b600054610100900460ff166116795760005460ff161561167d565b303b155b6116e05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161087f565b600054610100900460ff16158015611702576000805461ffff19166101011790555b6117358383600680546001600160a01b039384166001600160a01b03199182161790915560648054929093169116179055565b8015611747576000805461ff00191690555b505050565b600660009054906101000a90046001600160a01b03166001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa15801561179f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c39190615a2c565b6001600160a01b0316336001600160a01b0316146117f35760405162461bcd60e51b815260040161087f90615a49565b61113081826001600080611805611ee6565b613601565b610b38338383613bab565b600061182b8383611824611ab9565b60016141e6565b90505b92915050565b600080600061184d8585611846611ab9565b60006141e6565b9050611858816146b1565b92509250505b9250929050565b60065460408051636f85684760e01b8152905134926001600160a01b031691636f8568479160048083019260209291908290030181865afa1580156118ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d29190615b08565b8110156118f15760405162461bcd60e51b815260040161087f90615b21565b6119006402540be40082615b58565b1561191d5760405162461bcd60e51b815260040161087f90615b6c565b611747833360028585611805611ee6565b600061182b8383611846611ab9565b6001600160a01b038181166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff16600381111561199a5761199a615985565b60038111156119ab576119ab615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b90049091166060909101529050600381604001516003811115611a0157611a01615985565b14611a1e5760405162461bcd60e51b815260040161087f90615a80565b80602001516001600160a01b0316336001600160a01b031614611a535760405162461bcd60e51b815260040161087f9061599b565b80608001516001600160401b0316611a69611ab9565b6001600160401b03161015611ab05760405162461bcd60e51b815260206004820152600d60248201526c1cdd1a5b1b081a5b881a985a5b609a1b604482015260640161087f565b610b388161476a565b6006546040805163068d921560e31b815290516000926001600160a01b03169163346c90a89160048083019260209291908290030181865afa158015611b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b279190615b92565b611b379063ffffffff1643615bb8565b905090565b6111308133611b49611ab9565b600160006148e4565b6111308133611b5f611ab9565b60016000613316565b6001600160a01b038181166000908152600160208181526040808420815160c08101835281548716815293810154958616928401929092529293849384938493849384938493849384938493830190600160a01b900460ff166003811115611bd257611bd2615985565b6003811115611be357611be3615985565b81526001820154600160a81b90046001600160401b03908116602080840191909152600290930154808216604080850191909152600160401b909104821660609384015284516001600160a01b031660009081526005855281812086850151909316815291845290819020815160808101835290546001600160601b0381168252600160601b81046001600160701b031682860152600160d01b810463ffffffff1682840152600160f01b900461ffff16928101929092529183015191830151919c509192508b906003811115611cbc57611cbc615985565b9a508a6402540be40083602001516001600160701b0316611cdd9190615ae9565b9a508a83604001519a508a85606001519a508a86608001519a508a8760a001519a508a87606001519a508a88600001519a509a509a509a509a509a509a509a509a5050509193959799909294969850565b606480546040516323b872dd60e01b8152336004820152306024820152604481018490526001600160a01b03909116916323b872dd91016020604051808303816000875af1158015611d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da891906159e7565b611de95760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161087f565b610b3882826149da565b6060816001600160401b03811115611e0d57611e0d615bcc565b604051908082528060200260200182016040528015611e4057816020015b6060815260200190600190039081611e2b5790505b50905060005b82811015611edf57611eaf848483818110611e6357611e63615aa4565b9050602002810190611e759190615be2565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250614b7392505050565b828281518110611ec157611ec1615aa4565b60200260200101819052508080611ed790615ad0565b915050611e46565b5092915050565b6000611ef0611ab9565b611b37906001615c28565b600660009054906101000a90046001600160a01b03166001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f729190615a2c565b6001600160a01b0316336001600160a01b031614611fa25760405162461bcd60e51b815260040161087f90615a49565b6001600160a01b038181166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff166003811115611fff57611fff615985565b600381111561201057612010615985565b815260018201546001600160401b03600160a81b909104811660208301526002928301548082166040840152600160401b9004166060909101529091506001600160a01b03831660009081526001602081905260409091200154600160a01b900460ff16600381111561208557612085615985565b146120a25760405162461bcd60e51b815260040161087f90615a80565b60038054600180820183556000929092527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b0319166001600160a01b0385161790556040820190610fa9565b6003546060906000816001600160401b0381111561211857612118615bcc565b604051908082528060200260200182016040528015612141578160200160208202803683370190505b50905060005b828110156121bc576003818154811061216257612162615aa4565b9060005260206000200160009054906101000a90046001600160a01b031682828151811061219257612192615aa4565b6001600160a01b0390921660209283029190910190910152806121b481615ad0565b915050612147565b50600654604080516306598de160e31b815290516000926001600160a01b0316916332cc6f089160048083019260209291908290030181865afa158015612207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222b9190615b92565b63ffffffff1690508281111561223e5750815b60005b818110156125ec57600081905060006001600086848151811061226657612266615aa4565b6020908102919091018101516001600160a01b039081168352828201939093526040918201600020825160c08101845281548516815260018201549485169281019290925290929091830190600160a01b900460ff1660038111156122cd576122cd615985565b60038111156122de576122de615985565b8152600182810154600160a81b90046001600160401b03908116602080850191909152600290940154808216604080860191909152600160401b909104821660609485015285516001600160a01b0316600090815260058652818120878601519093168152918552808220815160808101835290546001600160601b0381168252600160601b81046001600160701b031696820196909652600160d01b860463ffffffff1691810191909152600160f01b90940461ffff169284019290925292935090916123ad908690615c53565b90505b87811015612537576000600160008984815181106123d0576123d0615aa4565b6020908102919091018101516001600160a01b039081168352828201939093526040918201600020825160c08101845281548516815260018201549485169281019290925290929091830190600160a01b900460ff16600381111561243757612437615985565b600381111561244857612448615985565b81526001820154600160a81b90046001600160401b03908116602080840191909152600290930154808216604080850191909152600160401b909104821660609384015284516001600160a01b031660009081526005855281812086850151909316815291845290819020815160808101835290546001600160601b0381168252600160601b81046001600160701b03908116838701819052600160d01b830463ffffffff1694840194909452600160f01b90910461ffff1693820193909352928701519394509192161015612522578295508194508093505b5050808061252f90615ad0565b9150506123b0565b50600086858151811061254c5761254c615aa4565b6020026020010151905086848151811061256857612568615aa4565b602002602001015187868151811061258257612582615aa4565b60200260200101906001600160a01b031690816001600160a01b031681525050808785815181106125b5576125b5615aa4565b60200260200101906001600160a01b031690816001600160a01b0316815250505050505080806125e490615ad0565b915050612241565b50815292915050565b600061182b8383611824611ee6565b6001600160a01b038181166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292938493830190600160a01b900460ff16600381111561265e5761265e615985565b600381111561266f5761266f615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b900490911660609091015290506000816040015160038111156126c5576126c5615985565b036126d35750600092915050565b611500816114fb611ee6565b6001600160a01b03808316600090815260046020908152604080832093851683529281528282208351815460a0938102820184019095526080810185815293948594859492939284928491879085015b8282101561277e57600084815260209081902060408051808201909152908401546001600160701b0381168252600160701b90046001600160401b03168183015282526001909201910161272f565b5050509082525060018201546001600160401b0316602080830191909152600283018054604080518285028101850182528281529401939260009084015b8282101561280b57600084815260209081902060408051808201909152908401546001600160701b0381168252600160701b90046001600160401b0316818301528252600190920191016127bc565b50505090825250600391909101546001600160401b031660209091015280515190915060000361284257600080925092505061185e565b805180516000919061285690600190615c6b565b8151811061286657612866615aa4565b602002602001015190506402540be40081600001516001600160701b031661288e9190615ae9565b81602001519350935050509250929050565b6001600160a01b0380831660009081526004602090815260408083209385168352929052908120816128d9826128d4611ee6565b614bf1565b90506000198110806128ea57508154155b156128f857915061182e9050565b8154600090839061290b90600190615c6b565b8154811061291b5761291b615aa4565b6000918252602091829020604080518082019091529101546001600160701b038116808352600160701b9091046001600160401b031691909201529695505050505050565b6000806001600160a01b03831660009081526001602081905260409091200154600160a01b900460ff16600381111561299b5761299b615985565b141592915050565b600660009054906101000a90046001600160a01b03166001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1a9190615a2c565b6001600160a01b0316336001600160a01b031614612a4a5760405162461bcd60e51b815260040161087f90615a49565b6001600160a01b038181166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff166003811115612aa757612aa7615985565b6003811115612ab857612ab8615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b90049091166060909101529050600381604001516003811115612b0e57612b0e615985565b14611ab05760405162461bcd60e51b815260040161087f90615a80565b6001600160a01b038181166000908152600160208190526040909120908101549091163314612b6c5760405162461bcd60e51b815260040161087f9061599b565b610b3881612b78611ab9565b614df8565b81516001600160a01b031660009081526005602090815260408083206001600160401b038516845290915281208054600160601b90046001600160701b031615612bc857905061182e565b83516001600160a01b03166000908152600560209081526040808320606080890180516001600160401b03908116875292855294839020835160808101855290546001600160601b0381168252600160601b8082046001600160701b0316968301879052600160d01b820463ffffffff1695830195909552600160f01b9081900461ffff1692820183905287547dffffffff0000000000000000000000000000ffffffffffffffffffffffff16959094026001600160f01b0316949094179202919091178455915190919081169085161115612cae576001600160401b03841660608601525b509392505050565b600660009054906101000a90046001600160a01b03166001600160a01b031663eea9a01b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2d9190615b08565b8110158015612d3b57508015155b612d575760405162461bcd60e51b815260040161087f90615b21565b612d666402540be40082615b58565b15612d835760405162461bcd60e51b815260040161087f90615b6c565b6001600160a01b038281166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff166003811115612de057612de0615985565b6003811115612df157612df1615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b90049091166060909101529050600081604001516003811115612e4757612e47615985565b03612e645760405162461bcd60e51b815260040161087f90615a09565b6000612e6e611ee6565b90506000612e7c8383612b7d565b9050612e8d6402540be40085615bb8565b81548290600c90612eaf908490600160601b90046001600160701b0316615c82565b82546001600160701b039182166101009390930a9283029190920219909116179055506001600160a01b03808616600090815260016020818152604092839020875181549086166001600160a01b03199182161782559188015192810180549390951691831682178555928701518794909290916001600160a81b031990911617600160a01b836003811115612f4757612f47615985565b0217905550606082015160018201805467ffffffffffffffff60a81b1916600160a81b6001600160401b039384160217905560808301516002909201805460a0909401519282166001600160801b031990941693909317600160401b92909116919091021790556001600160a01b038581166000908152600460209081526040808320938a168352929052208054156131075780546000908290612fed90600190615c6b565b81548110612ffd57612ffd615aa4565b600091825260209091200180549091506001600160401b03808616600160701b9092041610613079576130356402540be40087615bb8565b815482906000906130509084906001600160701b0316615c82565b92506101000a8154816001600160701b0302191690836001600160701b03160217905550613101565b604080518082019091528290806130956402540be4008a615bb8565b84546130aa91906001600160701b0316615c82565b6001600160701b0390811682526001600160401b038089166020938401528454600181018655600095865294839020845195018054949093015116600160701b026001600160b01b03199093169316929092171790555b5061317a565b604080518082019091528190806131236402540be40089615bb8565b6001600160701b0390811682526001600160401b038088166020938401528454600181018655600095865294839020845195018054949093015116600160701b026001600160b01b03199093169316929092171790555b604080518681526001600160401b03851660208201526001600160a01b03808a1692908916917f30bcda2f188b532c7644e632473e83a6fb3c5c79717650d0ac790d141bb1b17791015b60405180910390a350505050505050565b60001960005b60035481101561323657826001600160a01b03166003828154811061320257613202615aa4565b6000918252602090912001546001600160a01b03160361322457809150613236565b8061322e81615ad0565b9150506131db565b5060008112610b3857600354600110801561325f575060035461325b90600190615c6b565b8114155b156132df576003805461327490600190615c6b565b8154811061328457613284615aa4565b600091825260209091200154600380546001600160a01b0390921691839081106132b0576132b0615aa4565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60038054806132f0576132f0615ca4565b600082815260209020810160001990810180546001600160a01b03191690550190555050565b6001600160a01b038086166000908152600460209081526040808320938816835292905290812090831561335c5761334f878387615005565b6133599082615c53565b90505b82156133795761336c82866153df565b6133769082615c53565b90505b613383868261551d565b604080518281526001600160401b03871660208201526001600160a01b0380891692908a16917fb22dec804803f8b1c5333f626cdbfdfb1bd629f1e1bb45dcfb22b5f74ed46b1c91016131c4565b6000805b826001600160401b03168460a001516001600160401b0316101561182b5783516001600160a01b0316600090815260056020908152604080832060a08801516001600160401b031684528252808320815160808101835290546001600160601b0381168252600160601b81046001600160701b031693820193909352600160d01b830463ffffffff1691810191909152600160f01b90910461ffff16606082015290613480826155e0565b50915061348f90508184615c53565b925050508360a00180518091906134a590615cba565b6001600160401b03169052506133d5565b60408051608081018252600080825260208201819052918101829052606081019190915282516001600160a01b031660009081526005602090815260408083206001600160401b0386168452825291829020825160808101845290546001600160601b0381168252600160601b81046001600160701b0316928201839052600160d01b810463ffffffff1693820193909352600160f01b90920461ffff1660608301521561356557905061182e565b83516001600160a01b031660009081526005602090815260408083206060808901516001600160401b0316855290835292819020815160808101835290546001600160601b03811682526001600160701b03600160601b82041682850181905263ffffffff600160d01b8304169383019390935261ffff600160f01b909104811691850191825292850191909152511690820152905092915050565b610bb861ffff841611156136485760405162461bcd60e51b815260206004820152600e60248201526d3130b21031b7b6b6b4b9b9b4b7b760911b604482015260640161087f565b6001600160a01b038681166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff1660038111156136a5576136a5615985565b60038111156136b6576136b6615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b9004909116606090910152905060006001600160a01b03881660009081526001602081905260409091200154600160a01b900460ff16600381111561372e5761372e615985565b1461376b5760405162461bcd60e51b815260206004820152600d60248201526c185b1c9958591e48195e1a5cdd609a1b604482015260640161087f565b6001600160a01b038088168252861660208201526040810185600381111561379557613795615985565b908160038111156137a8576137a8615985565b9052506001600160401b03821660608201526001600160a01b03808816600090815260016020818152604092839020855181549086166001600160a01b03199182161782559186015192810180549390951691831682178555928501518594909290916001600160a81b031990911617600160a01b83600381111561382f5761382f615985565b0217905550606082015160018201805467ffffffffffffffff60a81b1916600160a81b6001600160401b039384160217905560808301516002928301805460a0909501519183166001600160801b031990951694909417600160401b9190921602179091556001600160a01b03878116600090815260209290925260409091205416156138ed5760405162461bcd60e51b815260206004820152600c60248201526b6f776e657220696e2075736560a01b604482015260640161087f565b6001600160a01b03868116600090815260026020526040902080546001600160a01b031916918916919091179055600185600381111561392f5761392f615985565b0361398057600380546001810182556000919091527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b0319166001600160a01b0389161790555b604080516080810190915260008152602081016139a26402540be40086615bb8565b6001600160701b0390811682526000602080840182905261ffff808a166040958601526001600160a01b03808e16808552600584528685206001600160401b038b1686528452868520885181548a8701518b8b01516060909c0151909616600160f01b026001600160f01b0363ffffffff9c909c16600160d01b029b909b166001600160d01b0396909916600160601b026001600160d01b03199091166001600160601b039092169190911717939093169590951796909617905591815260048252828120938a1681529290529020805415613a7d57600080fd5b60408051808201909152819080613a996402540be40088615bb8565b6001600160701b0390811682526001600160401b038088166020938401528454600181018655600095865294839020845195018054949093015116600160701b026001600160b01b03199093169316929092171790556040516001600160a01b0380891691908a16907f30bcda2f188b532c7644e632473e83a6fb3c5c79717650d0ac790d141bb1b17790613b4390889088909182526001600160401b0316602082015260400190565b60405180910390a3876001600160a01b03167f42449fd19d367b0177da9082fe6da7d4da41af7573e3a3c1750ecffeffe26f9d88886003811115613b8957613b89615985565b88604051613b99939291906159bf565b60405180910390a25050505050505050565b600660009054906101000a90046001600160a01b03166001600160a01b031663eea9a01b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c229190615b08565b8110158015613c3057508015155b613c4c5760405162461bcd60e51b815260040161087f90615b21565b613c5b6402540be40082615b58565b15613c785760405162461bcd60e51b815260040161087f90615b6c565b6001600160a01b038281166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff166003811115613cd557613cd5615985565b6003811115613ce657613ce6615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b900490911660609091015290506000613d2e611ee6565b90506000613d3c8383612b7d565b9050613d4d6402540be40085615bb8565b81546001600160701b03918216600160601b9091049091161015613d835760405162461bcd60e51b815260040161087f90615ce0565b613d926402540be40085615bb8565b81548290600c90613db4908490600160601b90046001600160701b0316615d0e565b82546001600160701b039182166101009390930a9283029190920219909116179055506001600160a01b03808616600090815260016020818152604092839020875181549086166001600160a01b03199182161782559188015192810180549390951691831682178555928701518794909290916001600160a81b031990911617600160a01b836003811115613e4c57613e4c615985565b0217905550606082015160018201805467ffffffffffffffff60a81b1916600160a81b6001600160401b039384160217905560808301516002909201805460a0909401519282166001600160801b031990941693909317600160401b92909116919091021790556001600160a01b038581166000908152600460209081526040808320938a168352929052208054613ef65760405162461bcd60e51b815260040161087f90615ce0565b80546000908290613f0990600190615c6b565b81548110613f1957613f19615aa4565b9060005260206000200190506402540be40086613f369190615bb8565b81546001600160401b03919091166001600160701b039091161015613f6d5760405162461bcd60e51b815260040161087f90615ce0565b613f778285614bf1565b861115613fb55760405162461bcd60e51b815260206004820152600c60248201526b1cdd1a5b1b081b1bd8dad95960a21b604482015260640161087f565b6000613fc66402540be40088615bb8565b8254613fdb91906001600160701b0316615d0e565b82549091506001600160401b03808716600160701b909204161061401e5781546dffffffffffffffffffffffffffff19166001600160701b038216178255614082565b604080518082019091526001600160701b0380831682526001600160401b03808816602080850191825287546001810189556000898152919091209451940180549151909216600160701b026001600160b01b031990911693909216929092171790555b8260020160405180604001604052806402540be4008a6140a29190615bb8565b6001600160701b0316815260065460408051635e7b72ad60e01b815290516020938401936001600160a01b0390931692635e7b72ad92600480820193918290030181865afa1580156140f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061411c9190615b92565b61412c9063ffffffff1689615c28565b6001600160401b03908116909152825460018101845560009384526020938490208351910180549490930151909116600160701b026001600160b01b03199093166001600160701b03909116179190911790556040516001600160a01b03808b1691908a16907fa410e32157a44414a502bb47d775234de1aa7da123f5adfe426898f1601883fd906141d3908b908a909182526001600160401b0316602082015260400190565b60405180910390a3505050505050505050565b600080600660009054906101000a90046001600160a01b03166001600160a01b031663e43db1936040518163ffffffff1660e01b8152600401602060405180830381865afa15801561423c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142609190615d36565b6001600160a01b038088166000908152600460209081526040808320938a1683529281528282208351815460a09381028201840190955260808101858152959650929492939092849290918491879085015b8282101561430157600084815260209081902060408051808201909152908401546001600160701b0381168252600160701b90046001600160401b0316818301528252600190920191016142b2565b5050509082525060018201546001600160401b0316602080830191909152600283018054604080518285028101850182528281529401939260009084015b8282101561438e57600084815260209081902060408051808201909152908401546001600160701b0381168252600160701b90046001600160401b03168183015282526001909201910161433f565b50505090825250600391909101546001600160401b0316602090910152905060005b81515160208301516001600160401b031610156145e9576000826000015183602001516001600160401b0316815181106143ec576143ec615aa4565b6020026020010151905083876144029190615c28565b6001600160401b031681602001516001600160401b03161061442457506145e9565b82515160009061443690600190615c6b565b84602001516001600160401b0316101561448d578351602085015161445c906001615c28565b6001600160401b03168151811061447557614475615aa4565b6020026020010151602001516001600160401b031690505b876001600160401b031682602001516001600160401b03161080156144c657508015806144c657508082602001516001600160401b0316105b156145c7576001600160a01b038a166000908152600560209081526040808320858301516001600160401b031684528252808320815160808101835290546001600160601b0381168252600160601b81046001600160701b0316938201849052600160d01b810463ffffffff1692820192909252600160f01b90910461ffff166060820152910361455757506145a6565b6000614562826155e0565b5050905081602001516001600160701b031684600001516001600160701b03168261458d9190615ae9565b6145979190615bb8565b6145a19086615c53565b945050505b602082018051906145b682615cba565b6001600160401b031690525061448d565b8360200180516145d690615cba565b6001600160401b03169052506143b09050565b848015614607575081604001515182606001516001600160401b0316105b156146a6576000826040015183606001516001600160401b03168151811061463157614631615aa4565b60200260200101519050866001600160401b031681602001516001600160401b0316111561465f57506146a6565b805161467a906402540be400906001600160701b0316615ae9565b6146849083615c53565b915082606001805161469590615cba565b6001600160401b03169052506145e9565b979650505050505050565b6000806402540be4006146c48185615bb8565b6146ce9190615ae9565b9150600660009054906101000a90046001600160a01b03166001600160a01b031663eea9a01b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614723573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147479190615b08565b82101561475657506000929050565b816147618185615c6b565b91509150915091565b8051600160408084018281526000608086018190526001600160a01b038086168252602085815293909120865181549083166001600160a01b0319918216178255938701519481018054959092169385168417825591518694929390926001600160a81b03191617600160a01b8360038111156147e9576147e9615985565b021790555060608201516001828101805467ffffffffffffffff60a81b1916600160a81b6001600160401b039485160217905560808401516002909301805460a0909501519383166001600160801b031990951694909417600160401b9390921692909202179091556003805491820181556000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b0319166001600160a01b0383169081179091557f7bd9ec00705b7640a93da0fcf84dc0bfce1b2c9a5146d548ab1dabd23322c9ac6148c5611ab9565b6040516001600160401b03909116815260200160405180910390a25050565b6001600160a01b038086166000908152600460209081526040808320938816835292905290812090831561492a5761491d878387615005565b6149279082615c53565b90505b82156149475761493a82866153df565b6149449082615c53565b90505b600080614953836146b1565b9092509050811561496957614969888a84612cb6565b801561497957614979888261551d565b876001600160a01b0316896001600160a01b03167fa82f74002b6639f6cfc2cfd4f3ade1998108eda0f484d9064e3098c211e81d6e84848b6040516141d39392919092835260208301919091526001600160401b0316604082015260600190565b6001600160a01b038281166000908152600160208181526040808420815160c081018352815487168152938101549586169284019290925292939192909190830190600160a01b900460ff166003811115614a3757614a37615985565b6003811115614a4857614a48615985565b815260018201546001600160401b03600160a81b909104811660208301526002909201548083166040830152600160401b90049091166060909101529050600081604001516003811115614a9e57614a9e615985565b03614abb5760405162461bcd60e51b815260040161087f90615a09565b6000614ac5611ab9565b90506000614ad38383612b7d565b805490915084908290600090614af39084906001600160601b0316615d53565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550846001600160a01b03167f9fce3fb7dc05df2879421f9d9c06784dad3d39aba44c0c1ee0b9d094e76550058584604051614b649291909182526001600160401b0316602082015260400190565b60405180910390a25050505050565b6060600080306001600160a01b031684604051614b909190615d75565b600060405180830381855af49150503d8060008114614bcb576040519150601f19603f3d011682016040523d82523d6000602084013e614bd0565b606091505b50915091508115614be2579392505050565b80511561021957805181602001fd5b600080600660009054906101000a90046001600160a01b03166001600160a01b031663e43db1936040518163ffffffff1660e01b8152600401602060405180830381865afa158015614c47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c6b9190615d36565b9050806001600160401b0316600003614c895760001991505061182e565b60018401546001600160401b03165b8454811015614d4e576000856000018281548110614cb857614cb8615aa4565b6000918252602091829020604080518082019091529101546001600160701b0381168252600160701b90046001600160401b03169181018290529150614cff908490615c28565b6001600160401b0316856001600160401b031611614d1d5750614d4e565b8051614d38906402540be400906001600160701b0316615ae9565b9350508080614d4690615ad0565b915050614c98565b5060038401546001600160401b03165b6002850154811015614df0576000856002018281548110614d8157614d81615aa4565b6000918252602091829020604080518082019091529101546001600160701b038116808352600160701b9091046001600160401b0316928201929092529150614dd0906402540be40090615ae9565b614dda9085615c6b565b9350508080614de890615ad0565b915050614d5e565b505092915050565b60028201546000908190600160401b90046001600160401b03165b836001600160401b0316816001600160401b0316108015614e365750620186a05a115b15614efa5784546001600160a01b031660009081526005602090815260408083206001600160401b03851684528252808320815160808101835290546001600160601b0381168252600160601b81046001600160701b031693820193909352600160d01b830463ffffffff1691810191909152600160f01b90910461ffff1660608201529080614ec5836155e0565b92509250508186614ed69190615c53565b9550614ee28186615c53565b94505050508080614ef290615cba565b915050614e13565b6002850180546fffffffffffffffff00000000000000001916600160401b6001600160401b038416021790556001850154614f3e906001600160a01b03168461551d565b8115614fb95760065460408051633800918160e21b81529051614fb9926001600160a01b03169163e00246049160048083019260209291908290030181865afa158015614f8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614fb39190615a2c565b8361551d565b8454604080518581526001600160401b03871660208201526001600160a01b03909216917fb947d7b49cedaf132fd7a9592099c21170864455405d51b482503244153241009101614b64565b600080600660009054906101000a90046001600160a01b03166001600160a01b031663e43db1936040518163ffffffff1660e01b8152600401602060405180830381865afa15801561505b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061507f9190615d36565b600185015485549192506001600160401b0316905b80826001600160401b03161080156150ae5750620186a05a115b156153b257600086600001836001600160401b0316815481106150d3576150d3615aa4565b6000918252602091829020604080518082019091529101546001600160701b0381168252600160701b90046001600160401b031691810191909152905061511a8487615c28565b6001600160401b031681602001516001600160401b03161061513c57506153b2565b6000615149600184615c6b565b846001600160401b0316101561519d5787615165856001615c28565b6001600160401b03168154811061517e5761517e615aa4565b600091825260209091200154600160701b90046001600160401b031690505b866001600160401b031682602001516001600160401b03161080156151d657508015806151d657508082602001516001600160401b0316105b80156151e45750620186a05a115b156152e5576001600160a01b0389166000908152600560209081526040808320858301516001600160401b031684528252808320815160808101835290546001600160601b0381168252600160601b81046001600160701b0316938201849052600160d01b810463ffffffff1692820192909252600160f01b90910461ffff166060820152910361527557506152c4565b6000615280826155e0565b5050905081602001516001600160701b031684600001516001600160701b0316826152ab9190615ae9565b6152b59190615bb8565b6152bf9089615c53565b975050505b602082018051906152d482615cba565b6001600160401b031690525061519d565b6152f0600184615c6b565b846001600160401b031610615369578188600001856001600160401b03168154811061531e5761531e615aa4565b600091825260209182902083519101805493909201516001600160401b0316600160701b026001600160b01b03199093166001600160701b0390911617919091179055506153b29050565b87600001846001600160401b03168154811061538757615387615aa4565b600091825260209091200180546001600160b01b03191690556153a984615cba565b93505050615094565b506001850180546001600160401b0390921667ffffffffffffffff19909216919091179055509392505050565b600382015460028301546000916001600160401b0316905b80826001600160401b03161080156154115750620186a05a115b156154f257600085600201836001600160401b03168154811061543657615436615aa4565b6000918252602091829020604080518082019091529101546001600160701b03811682526001600160401b03600160701b90910481169282018390529092508616101561548357506154f2565b805161549e906402540be400906001600160701b0316615ae9565b6154a89085615c53565b935085600201836001600160401b0316815481106154c8576154c8615aa4565b600091825260209091200180546001600160b01b03191690556154ea83615cba565b9250506153f7565b506003840180546001600160401b0390921667ffffffffffffffff1990921691909117905592915050565b60645460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015615570573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061559491906159e7565b610b385760405162461bcd60e51b815260206004820152601760248201527f6661696c656420746f2073616665207472616e73666572000000000000000000604482015260640161087f565b6000806000600660009054906101000a90046001600160a01b03166001600160a01b0316639dbf97db6040518163ffffffff1660e01b8152600401602060405180830381865afa158015615638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061565c9190615b92565b63ffffffff16846040015163ffffffff161061568a57505081516000915081906001600160601b0316615704565b83602001516001600160701b03166000036156b65750508151600091506001600160601b031681615704565b612710846060015161ffff1685600001516001600160601b03166156da9190615ae9565b6156e49190615bb8565b84519092506156fd9083906001600160601b0316615c6b565b9250600090505b9193909250565b6001600160a01b038116811461113057600080fd5b6000806040838503121561573357600080fd5b823561573e8161570b565b9150602083013561574e8161570b565b809150509250929050565b6000806040838503121561576c57600080fd5b82356157778161570b565b946020939093013593505050565b6000806040838503121561579857600080fd5b82356157a38161570b565b9150602083013561ffff8116811461574e57600080fd5b6000602082840312156157cc57600080fd5b813561182b8161570b565b6001600160401b038116811461113057600080fd5b600080604083850312156157ff57600080fd5b823561580a8161570b565b9150602083013561574e816157d7565b6000806020838503121561582d57600080fd5b82356001600160401b038082111561584457600080fd5b818501915085601f83011261585857600080fd5b81358181111561586757600080fd5b8660208260051b850101111561587c57600080fd5b60209290920196919550909350505050565b60005b838110156158a9578181015183820152602001615891565b838111156158b8576000848401525b50505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561592b57878503603f190184528151805180875261590c818989018a850161588e565b601f01601f1916959095018601945092850192908501906001016158e5565b5092979650505050505050565b6020808252825182820181905260009190848201906040850190845b818110156159795783516001600160a01b031683529284019291840191600101615954565b50909695505050505050565b634e487b7160e01b600052602160045260246000fd5b6020808252600a908201526937b7363c9037bbb732b960b11b604082015260600190565b6001600160a01b0393909316835260ff91909116602083015261ffff16604082015260600190565b6000602082840312156159f957600080fd5b8151801515811461182b57600080fd5b6020808252600990820152681b9bdd08199bdd5b9960ba1b604082015260600190565b600060208284031215615a3e57600080fd5b815161182b8161570b565b60208082526018908201527f5374616b696e673a206f6e6c7920676f7665726e616e63650000000000000000604082015260600190565b6020808252600a90820152696261642073746174757360b01b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201615ae257615ae2615aba565b5060010190565b6000816000190483118215151615615b0357615b03615aba565b500290565b600060208284031215615b1a57600080fd5b5051919050565b602080825260079082015266746f6f206c6f7760c81b604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082615b6757615b67615b42565b500690565b6020808252600c908201526b3737903932b6b0b4b73232b960a11b604082015260600190565b600060208284031215615ba457600080fd5b815163ffffffff8116811461182b57600080fd5b600082615bc757615bc7615b42565b500490565b634e487b7160e01b600052604160045260246000fd5b6000808335601e19843603018112615bf957600080fd5b8301803591506001600160401b03821115615c1357600080fd5b60200191503681900382131561185e57600080fd5b60006001600160401b03808316818516808303821115615c4a57615c4a615aba565b01949350505050565b60008219821115615c6657615c66615aba565b500190565b600082821015615c7d57615c7d615aba565b500390565b60006001600160701b03808316818516808303821115615c4a57615c4a615aba565b634e487b7160e01b600052603160045260246000fd5b60006001600160401b03808316818103615cd657615cd6615aba565b6001019392505050565b602080825260149082015273696e73756666696369656e742062616c616e636560601b604082015260600190565b60006001600160701b0383811690831681811015615d2e57615d2e615aba565b039392505050565b600060208284031215615d4857600080fd5b815161182b816157d7565b60006001600160601b03808316818516808303821115615c4a57615c4a615aba565b60008251615d8781846020870161588e565b919091019291505056fea264697066735822122045d124f94864ebe8002e0ef7a4df59c35596270bf946a452697e42332415503764736f6c634300080e0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c65640000000000000000000000002d3f893c7c45c2be3ec63cf5385deafd7ece6aae0000000000000000000000008290333cef9e6d528dd5618fb97a76f268f3edd4
Deployed Bytecode
0x60806040526004361061002d5760003560e01c80634f1ef28614610044578063fabec44a146100645761003c565b3661003c5761003a610095565b005b61003a610095565b34801561005057600080fd5b5061003a61005f3660046104bd565b6100a7565b34801561007057600080fd5b50610079610185565b6040516001600160a01b03909116815260200160405180910390f35b6100a56100a06101d2565b6101dc565b565b6100af610205565b6001600160a01b031663732524946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101109190610581565b6001600160a01b0316336001600160a01b0316146101755760405162461bcd60e51b815260206004820181905260248201527f4d616e61676561626c6550726f78793a206f6e6c7920676f7665726e616e636560448201526064015b60405180910390fd5b61018182826000610238565b5050565b600061018f6101d2565b905090565b60606101b9838360405180606001604052806027815260200161061a60279139610263565b9392505050565b90565b6001600160a01b03163b151590565b600061018f610340565b3660008037600080366000845af43d6000803e8080156101fb573d6000f35b3d6000fd5b505050565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61024183610368565b60008251118061024e5750805b156102005761025d8383610194565b50505050565b60606001600160a01b0384163b6102cb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161016c565b600080856001600160a01b0316856040516102e691906105ca565b600060405180830381855af49150503d8060008114610321576040519150601f19603f3d011682016040523d82523d6000602084013e610326565b606091505b50915091506103368282866103a8565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610229565b610371816103e1565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606083156103b75750816101b9565b8251156103c75782518084602001fd5b8160405162461bcd60e51b815260040161016c91906105e6565b6001600160a01b0381163b61044e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161016c565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03811681146104a457600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156104d057600080fd5b82356104db8161048f565b9150602083013567ffffffffffffffff808211156104f857600080fd5b818501915085601f83011261050c57600080fd5b81358181111561051e5761051e6104a7565b604051601f8201601f19908116603f01168101908382118183101715610546576105466104a7565b8160405282815288602084870101111561055f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60006020828403121561059357600080fd5b81516101b98161048f565b60005b838110156105b95781810151838201526020016105a1565b8381111561025d5750506000910152565b600082516105dc81846020870161059e565b9190910192915050565b602081526000825180602084015261060581604085016020870161059e565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c7bcabc54654f019fb468ff8f08cd8f4a1e9224d1697be83da48c369f3f8b6a664736f6c634300080e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002d3f893c7c45c2be3ec63cf5385deafd7ece6aae0000000000000000000000008290333cef9e6d528dd5618fb97a76f268f3edd4
-----Decoded View---------------
Arg [0] : stakingConfig (address): 0x2d3F893c7c45C2BE3Ec63cf5385DeAfD7Ece6AAE
Arg [1] : ankrToken (address): 0x8290333ceF9e6D528dD5618Fb97a76f268f3EDD4
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002d3f893c7c45c2be3ec63cf5385deafd7ece6aae
Arg [1] : 0000000000000000000000008290333cef9e6d528dd5618fb97a76f268f3edd4
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.040812 | 312,915,818.7412 | $12,770,773.59 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.