Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
SFC
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {Decimal} from "../common/Decimal.sol"; import {NodeDriverAuth} from "./NodeDriverAuth.sol"; import {ConstantsManager} from "./ConstantsManager.sol"; import {Version} from "../version/Version.sol"; /** * @title Special Fee Contract for Sonic network * @notice The SFC maintains a list of validators and delegators and distributes rewards to them. * @custom:security-contact [email protected] */ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { uint256 internal constant OK_STATUS = 0; uint256 internal constant WITHDRAWN_BIT = 1; uint256 internal constant OFFLINE_BIT = 1 << 3; uint256 internal constant OFFLINE_AVG_BIT = 1 << 4; uint256 internal constant DOUBLESIGN_BIT = 1 << 7; uint256 internal constant CHEATER_MASK = DOUBLESIGN_BIT; /** * @dev The staking for validation */ struct Validator { uint256 status; uint256 receivedStake; // from all delegators (weight of the validator) address auth; // self-stake delegator uint256 createdEpoch; uint256 createdTime; uint256 deactivatedTime; uint256 deactivatedEpoch; } NodeDriverAuth internal node; // last sealed epoch (currentEpoch - 1) uint256 public currentSealedEpoch; mapping(uint256 validatorID => Validator) public getValidator; mapping(address auth => uint256 validatorID) public getValidatorID; mapping(uint256 validatorID => bytes pubkey) public getValidatorPubkey; uint256 public lastValidatorID; // total stake of all validators - includes slashed/offline validators uint256 public totalStake; // total stake of active (OK_STATUS) validators (total weight) uint256 public totalActiveStake; // unresolved fees that failed to be send to the treasury uint256 public unresolvedTreasuryFees; // delegator => validator ID => stashed rewards (to be claimed/restaked) mapping(address delegator => mapping(uint256 validatorID => uint256 stashedRewards)) internal _rewardsStash; // delegator => validator ID => last epoch number for which were rewards stashed mapping(address delegator => mapping(uint256 validatorID => uint256 epoch)) public stashedRewardsUntilEpoch; struct WithdrawalRequest { uint256 epoch; // epoch where undelegated uint256 time; // when undelegated uint256 amount; } // delegator => validator ID => withdrawal ID => withdrawal request mapping(address delegator => mapping(uint256 validatorID => mapping(uint256 wrID => WithdrawalRequest))) public getWithdrawalRequest; // delegator => validator ID => current stake mapping(address delegator => mapping(uint256 validatorID => uint256 stake)) public getStake; // data structure to compute average uptime for each active validator struct AverageUptime { // average uptime ratio as a value between 0 and 1e18 uint64 averageUptime; // remainder from the division in the average calculation uint32 remainder; // number of epochs in the average (at most averageUptimeEpochsWindow) uint32 epochs; } struct EpochSnapshot { // validator ID => validator weight in the epoch mapping(uint256 => uint256) receivedStake; // validator ID => accumulated ( delegatorsReward * 1e18 / receivedStake ) mapping(uint256 => uint256) accumulatedRewardPerToken; // validator ID => accumulated online time mapping(uint256 => uint256) accumulatedUptime; // validator ID => average uptime as a percentage mapping(uint256 => AverageUptime) averageUptime; // validator ID => gas fees from txs originated by the validator mapping(uint256 => uint256) accumulatedOriginatedTxsFee; mapping(uint256 => uint256) offlineTime; mapping(uint256 => uint256) offlineBlocks; uint256[] validatorIDs; uint256 endTime; uint256 endBlock; uint256 epochFee; // gas fees from txs in the epoch uint256 baseRewardPerSecond; // the base reward to divide among validators for each second of the epoch uint256 totalStake; // total weight of all validators uint256 totalSupply; // total supply of native tokens } // the total supply of native tokens in the chain uint256 public totalSupply; // epoch id => epoch snapshot mapping(uint256 epoch => EpochSnapshot) public getEpochSnapshot; // validator ID -> slashing refund ratio (allows to withdraw slashed stake) mapping(uint256 validatorID => uint256 refundRatio) public slashingRefundRatio; // the treasure contract (receives unlock penalties and a part of epoch fees) address public treasuryAddress; ConstantsManager internal c; // the contract subscribed to stake changes notifications address public stakeSubscriberAddress; // address derived from the validator pubkey => validator id mapping(address pubkeyAddress => uint256 validatorID) public pubkeyAddressToValidatorID; // address authorized to initiate redirection address public redirectionAuthorizer; // delegator => withdrawals receiver mapping(address delegator => address receiver) public getRedirectionRequest; // delegator => withdrawals receiver mapping(address delegator => address receiver) public getRedirection; struct SealEpochRewardsCtx { uint256[] baseRewardWeights; uint256 totalBaseRewardWeight; uint256[] txRewardWeights; uint256 totalTxRewardWeight; uint256 epochFee; } // auth error NotDriverAuth(); error NotAuthorized(); // addresses error ZeroAddress(); error SameAddress(); // values error ZeroAmount(); error ZeroRewards(); error ValueTooLarge(); // pubkeys error PubkeyUsedByOtherValidator(); error MalformedPubkey(); // redirections error AlreadyRedirected(); error SameRedirectionAuthorizer(); error Redirected(); // validators error ValidatorNotExists(); error ValidatorExists(); error ValidatorNotActive(); error ValidatorDelegationLimitExceeded(); error NotDeactivatedStatus(); // requests error RequestExists(); error RequestNotExists(); // transfers error TransfersNotAllowed(); error TransferFailed(); // stake changes subscriber error StakeSubscriberFailed(); // staking error InsufficientSelfStake(); error NotEnoughTimePassed(); error NotEnoughEpochsPassed(); error StakeIsFullySlashed(); // stashing error NothingToStash(); // slashing error ValidatorNotSlashed(); error RefundRatioTooHigh(); // treasury error TreasuryNotSet(); error NoUnresolvedTreasuryFees(); event DeactivatedValidator(uint256 indexed validatorID, uint256 deactivatedEpoch, uint256 deactivatedTime); event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status); event CreatedValidator( uint256 indexed validatorID, address indexed auth, uint256 createdEpoch, uint256 createdTime ); event Delegated(address indexed delegator, uint256 indexed toValidatorID, uint256 amount); event Undelegated(address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount); event Withdrawn( address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount, uint256 penalty ); event ClaimedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards); event RestakedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards); event BurntNativeTokens(uint256 amount); event UpdatedSlashingRefundRatio(uint256 indexed validatorID, uint256 refundRatio); event RefundedSlashedLegacyDelegation(address indexed delegator, uint256 indexed validatorID, uint256 amount); event AnnouncedRedirection(address indexed from, address indexed to); event TreasuryFeesResolved(uint256 amount); modifier onlyDriver() { if (!isNode(msg.sender)) { revert NotDriverAuth(); } _; } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// Initialization is called only once, after the contract deployment. /// Because the contract code is written directly into genesis, constructor cannot be used. function initialize( uint256 sealedEpoch, uint256 _totalSupply, address nodeDriver, address _c, address owner ) external initializer { __Ownable_init(owner); __UUPSUpgradeable_init(); currentSealedEpoch = sealedEpoch; node = NodeDriverAuth(nodeDriver); c = ConstantsManager(_c); totalSupply = _totalSupply; getEpochSnapshot[sealedEpoch].endTime = _now(); } /// Override the upgrade authorization check to allow upgrades only from the owner. // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address) internal override onlyOwner {} /// Receive fallback to revert transfers. receive() external payable { revert TransfersNotAllowed(); } /// Set admin address responsible for initiating redirections. function setRedirectionAuthorizer(address v) external onlyOwner { if (redirectionAuthorizer == v) { revert SameRedirectionAuthorizer(); } redirectionAuthorizer = v; } /// Announce redirection of address to be called by validator whose auth key was compromised. /// Produced events are used to notify redirect authorizer about redirection request. /// Redirect authorizer then initiates creating of appropriate redirect by calling initiateRedirection(). function announceRedirection(address to) external { emit AnnouncedRedirection(msg.sender, to); } /// Initiate redirection of withdrawals/claims for a compromised validator account. /// Needs to be accepted by validator key holder before the redirect is active. function initiateRedirection(address from, address to) external { if (msg.sender != redirectionAuthorizer) { revert NotAuthorized(); } if (getRedirection[from] == to) { revert AlreadyRedirected(); } if (from == to) { revert SameAddress(); } getRedirectionRequest[from] = to; } /// Accept redirection proposal. /// Redirection must by accepted by the validator key holder before it start to be applied. function redirect(address to) external { address from = msg.sender; if (to == address(0)) { revert ZeroAddress(); } if (getRedirectionRequest[from] != to) { revert RequestNotExists(); } getRedirection[from] = to; getRedirectionRequest[from] = address(0); } /// Seal current epoch - deactivate validators who were offline too long, create an epoch snapshot /// for the current epoch (provides information for rewards calculation), calculate new minimal gas price. /// This method is called BEFORE the epoch sealing made by the client itself. function sealEpoch( uint256[] calldata offlineTime, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyDriver { EpochSnapshot storage snapshot = getEpochSnapshot[currentEpoch()]; uint256[] memory validatorIDs = snapshot.validatorIDs; _sealEpochOffline(snapshot, validatorIDs, offlineTime, offlineBlocks); { EpochSnapshot storage prevSnapshot = getEpochSnapshot[currentSealedEpoch]; uint256 epochDuration = 1; if (_now() > prevSnapshot.endTime) { epochDuration = _now() - prevSnapshot.endTime; } _sealEpochRewards(epochDuration, snapshot, prevSnapshot, validatorIDs, uptimes, originatedTxsFee); _sealEpochAverageUptime(epochDuration, snapshot, prevSnapshot, validatorIDs, uptimes); } currentSealedEpoch = currentEpoch(); snapshot.endTime = _now(); snapshot.endBlock = block.number; snapshot.baseRewardPerSecond = c.baseRewardPerSecond(); snapshot.totalSupply = totalSupply; } /// Finish epoch sealing - store validators of the new epoch into a snapshot. /// This method is called AFTER the epoch sealing made by the client itself. function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyDriver { EpochSnapshot storage snapshot = getEpochSnapshot[currentEpoch()]; // fill data for the next snapshot for (uint256 i = 0; i < nextValidatorIDs.length; i++) { uint256 validatorID = nextValidatorIDs[i]; uint256 receivedStake = getValidator[validatorID].receivedStake; snapshot.receivedStake[validatorID] = receivedStake; snapshot.totalStake = snapshot.totalStake + receivedStake; } snapshot.validatorIDs = nextValidatorIDs; } /// Set an initial validator. /// Called only as part of network initialization/genesis file generating. function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external onlyDriver { _rawCreateValidator( auth, validatorID, pubkey, OK_STATUS, 0, // createdEpoch createdTime, 0, // deactivatedEpoch - not deactivated 0 // deactivatedTime - not deactivated ); if (validatorID > lastValidatorID) { lastValidatorID = validatorID; } } /// Set an initial delegation. /// Called only as part of network initialization/genesis file generating. function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external onlyDriver { _rawDelegate(delegator, toValidatorID, stake, false); _mintNativeToken(stake); } /// Create a validator with a given public key while using attached value as the validator's self-stake. function createValidator(bytes calldata pubkey) external payable { if (msg.value < c.minSelfStake()) { revert InsufficientSelfStake(); } if (pubkey.length != 66 || pubkey[0] != 0xc0) { revert MalformedPubkey(); } if (pubkeyAddressToValidatorID[_pubkeyToAddress(pubkey)] != 0) { revert PubkeyUsedByOtherValidator(); } _createValidator(msg.sender, pubkey); _delegate(msg.sender, lastValidatorID, msg.value); } /// Update slashing refund ratio for a validator. /// The refund ratio is used to calculate the amount of stake that can be withdrawn after slashing. function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio) external onlyOwner { if (!isSlashed(validatorID)) { revert ValidatorNotSlashed(); } if (refundRatio > Decimal.unit()) { revert RefundRatioTooHigh(); } slashingRefundRatio[validatorID] = refundRatio; emit UpdatedSlashingRefundRatio(validatorID, refundRatio); } /// Delegate stake to a validator. function delegate(uint256 toValidatorID) external payable { _delegate(msg.sender, toValidatorID, msg.value); } /// Withdraw stake from a validator after its un-delegation. /// Un-delegated stake is locked for a certain period of time. function withdraw(uint256 toValidatorID, uint256 wrID) public { _withdraw(msg.sender, toValidatorID, wrID, _receiverOf(msg.sender)); } /// Deactivate a validator. /// Called by the chain client when a client misbehavior is observed. function deactivateValidator(uint256 validatorID, uint256 status) external onlyDriver { if (status == OK_STATUS) { revert NotDeactivatedStatus(); } _setValidatorDeactivated(validatorID, status); _syncValidator(validatorID, false); address validatorAddr = getValidator[validatorID].auth; _notifyStakeSubscriber(validatorAddr, validatorAddr, false); } /// Stash rewards for a delegator. function stashRewards(address delegator, uint256 toValidatorID) external { if (!_stashRewards(delegator, toValidatorID)) { revert NothingToStash(); } } /// Resolve failed treasury transfers and send the unresolved fees to the treasury address. function resolveTreasuryFees() external { if (treasuryAddress == address(0)) { revert TreasuryNotSet(); } if (unresolvedTreasuryFees == 0) { revert NoUnresolvedTreasuryFees(); } // zero the fees before sending to prevent re-entrancy uint256 fees = unresolvedTreasuryFees; unresolvedTreasuryFees = 0; (bool success, ) = treasuryAddress.call{value: fees, gas: 1000000}(""); if (!success) { revert TransferFailed(); } emit TreasuryFeesResolved(fees); } /// Burn native tokens by sending them to the SFC contract. function burnNativeTokens() external payable { if (msg.value == 0) { revert ZeroAmount(); } _burnNativeTokens(msg.value); } /// Issue tokens to the issued tokens recipient as a counterparty to the burnt FTM tokens. function issueTokens(uint256 amount) external onlyOwner { if (c.issuedTokensRecipient() == address(0)) { revert ZeroAddress(); } node.incBalance(c.issuedTokensRecipient(), amount); totalSupply += amount; } /// Update treasury address. function updateTreasuryAddress(address v) external onlyOwner { treasuryAddress = v; } /// Update consts address. function updateConstsAddress(address v) external onlyOwner { c = ConstantsManager(v); } /// Update voteBook address. function updateStakeSubscriberAddress(address v) external onlyOwner { stakeSubscriberAddress = v; } /// Get consts address. function constsAddress() external view returns (address) { return address(c); } /// Claim rewards for stake delegated to a validator. function claimRewards(uint256 toValidatorID) public { address delegator = msg.sender; uint256 rewards = _claimRewards(delegator, toValidatorID); // It's important that we transfer after erasing (protection against Re-Entrancy) (bool sent, ) = _receiverOf(delegator).call{value: rewards}(""); if (!sent) { revert TransferFailed(); } emit ClaimedRewards(delegator, toValidatorID, rewards); } /// Get amount of currently stashed rewards. function rewardsStash(address delegator, uint256 validatorID) public view returns (uint256) { return _rewardsStash[delegator][validatorID]; } /// Un-delegate stake from a validator. function undelegate(uint256 toValidatorID, uint256 wrID, uint256 amount) public { address delegator = msg.sender; _stashRewards(delegator, toValidatorID); if (amount == 0) { revert ZeroAmount(); } if (getWithdrawalRequest[delegator][toValidatorID][wrID].amount != 0) { revert RequestExists(); } _rawUndelegate(delegator, toValidatorID, amount, true, false, true); getWithdrawalRequest[delegator][toValidatorID][wrID].amount = amount; getWithdrawalRequest[delegator][toValidatorID][wrID].epoch = currentEpoch(); getWithdrawalRequest[delegator][toValidatorID][wrID].time = _now(); _syncValidator(toValidatorID, false); emit Undelegated(delegator, toValidatorID, wrID, amount); } /// Re-stake rewards - claim rewards for staking and delegate it immediately /// to the same validator - add it to the current stake. function restakeRewards(uint256 toValidatorID) public { address delegator = msg.sender; uint256 rewards = _claimRewards(delegator, toValidatorID); _delegate(delegator, toValidatorID, rewards); emit RestakedRewards(delegator, toValidatorID, rewards); } /// Get the current epoch number. function currentEpoch() public view returns (uint256) { return currentSealedEpoch + 1; } /// Get self-stake of a validator. function getSelfStake(uint256 validatorID) public view returns (uint256) { return getStake[getValidator[validatorID].auth][validatorID]; } /// Get validator IDs for given epoch. function getEpochValidatorIDs(uint256 epoch) public view returns (uint256[] memory) { return getEpochSnapshot[epoch].validatorIDs; } /// Get received stake for a validator in a given epoch. function getEpochReceivedStake(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].receivedStake[validatorID]; } /// Get accumulated reward per token for a validator in a given epoch. function getEpochAccumulatedRewardPerToken(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedRewardPerToken[validatorID]; } /// Get accumulated uptime for a validator in a given epoch. function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedUptime[validatorID]; } /// Get average uptime for a validator in a given epoch. function getEpochAverageUptime(uint256 epoch, uint256 validatorID) public view returns (uint64) { return getEpochSnapshot[epoch].averageUptime[validatorID].averageUptime; } /// Get accumulated originated txs fee for a validator in a given epoch. function getEpochAccumulatedOriginatedTxsFee(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedOriginatedTxsFee[validatorID]; } /// Get offline time for a validator in a given epoch. function getEpochOfflineTime(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].offlineTime[validatorID]; } /// Get offline blocks for a validator in a given epoch. function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].offlineBlocks[validatorID]; } /// Get end block for a given epoch. function getEpochEndBlock(uint256 epoch) public view returns (uint256) { return getEpochSnapshot[epoch].endBlock; } /// Check whether the given validator is slashed - the stake (or its part) cannot /// be withdrawn because of misbehavior (double-sign) of the validator. function isSlashed(uint256 validatorID) public view returns (bool) { return getValidator[validatorID].status & CHEATER_MASK != 0; } /// Get the amount of rewards which can be currently claimed by the given delegator for the given validator. function pendingRewards(address delegator, uint256 toValidatorID) public view returns (uint256) { uint256 reward = _newRewards(delegator, toValidatorID); return _rewardsStash[delegator][toValidatorID] + reward; } /// Check whether the self-stake covers the required fraction of all delegations for the given validator. function _checkDelegatedStakeLimit(uint256 validatorID) internal view returns (bool) { return getValidator[validatorID].receivedStake <= (getSelfStake(validatorID) * c.maxDelegatedRatio()) / Decimal.unit(); } /// Check if an address is the NodeDriverAuth contract. function isNode(address addr) internal view virtual returns (bool) { return addr == address(node); } /// Delegate stake to a validator. function _delegate(address delegator, uint256 toValidatorID, uint256 amount) internal { if (!_validatorExists(toValidatorID)) { revert ValidatorNotExists(); } if (getValidator[toValidatorID].status != OK_STATUS) { revert ValidatorNotActive(); } _rawDelegate(delegator, toValidatorID, amount, true); if (!_checkDelegatedStakeLimit(toValidatorID)) { revert ValidatorDelegationLimitExceeded(); } } /// Delegate stake to a validator without checking delegation limit. function _rawDelegate(address delegator, uint256 toValidatorID, uint256 amount, bool strict) internal { if (amount == 0) { revert ZeroAmount(); } _stashRewards(delegator, toValidatorID); getStake[delegator][toValidatorID] = getStake[delegator][toValidatorID] + amount; uint256 origStake = getValidator[toValidatorID].receivedStake; getValidator[toValidatorID].receivedStake = origStake + amount; totalStake = totalStake + amount; if (getValidator[toValidatorID].status == OK_STATUS) { totalActiveStake = totalActiveStake + amount; } _syncValidator(toValidatorID, origStake == 0); emit Delegated(delegator, toValidatorID, amount); _notifyStakeSubscriber(delegator, getValidator[toValidatorID].auth, strict); } /// Un-delegate stake from a validator. function _rawUndelegate( address delegator, uint256 toValidatorID, uint256 amount, bool strict, bool forceful, bool checkDelegatedStake ) internal { getStake[delegator][toValidatorID] -= amount; getValidator[toValidatorID].receivedStake = getValidator[toValidatorID].receivedStake - amount; totalStake = totalStake - amount; if (getValidator[toValidatorID].status == OK_STATUS) { totalActiveStake = totalActiveStake - amount; } uint256 selfStakeAfterwards = getSelfStake(toValidatorID); if (selfStakeAfterwards != 0 && getValidator[toValidatorID].status == OK_STATUS) { if (!(selfStakeAfterwards >= c.minSelfStake())) { if (forceful) { revert InsufficientSelfStake(); } else { _setValidatorDeactivated(toValidatorID, WITHDRAWN_BIT); } } if (checkDelegatedStake && !_checkDelegatedStakeLimit(toValidatorID)) { revert ValidatorDelegationLimitExceeded(); } } else { _setValidatorDeactivated(toValidatorID, WITHDRAWN_BIT); } _notifyStakeSubscriber(delegator, getValidator[toValidatorID].auth, strict); } /// Get slashing penalty for a stake. function getSlashingPenalty( uint256 amount, bool isCheater, uint256 refundRatio ) internal pure returns (uint256 penalty) { if (!isCheater || refundRatio >= Decimal.unit()) { return 0; } // round penalty upwards (ceiling) to prevent dust amount attacks penalty = (amount * (Decimal.unit() - refundRatio)) / Decimal.unit() + 1; if (penalty > amount) { return amount; } return penalty; } /// Withdraw stake from a validator. /// The stake must be undelegated first. function _withdraw(address delegator, uint256 toValidatorID, uint256 wrID, address payable receiver) private { WithdrawalRequest memory request = getWithdrawalRequest[delegator][toValidatorID][wrID]; if (request.epoch == 0) { revert RequestNotExists(); } uint256 requestTime = request.time; uint256 requestEpoch = request.epoch; if ( getValidator[toValidatorID].deactivatedTime != 0 && getValidator[toValidatorID].deactivatedTime < requestTime ) { requestTime = getValidator[toValidatorID].deactivatedTime; requestEpoch = getValidator[toValidatorID].deactivatedEpoch; } if (_now() < requestTime + c.withdrawalPeriodTime()) { revert NotEnoughTimePassed(); } if (currentEpoch() < requestEpoch + c.withdrawalPeriodEpochs()) { revert NotEnoughEpochsPassed(); } uint256 amount = getWithdrawalRequest[delegator][toValidatorID][wrID].amount; bool isCheater = isSlashed(toValidatorID); uint256 penalty = getSlashingPenalty(amount, isCheater, slashingRefundRatio[toValidatorID]); delete getWithdrawalRequest[delegator][toValidatorID][wrID]; if (amount <= penalty) { revert StakeIsFullySlashed(); } // It's important that we transfer after erasing (protection against Re-Entrancy) (bool sent, ) = receiver.call{value: amount - penalty}(""); if (!sent) { revert TransferFailed(); } _burnNativeTokens(penalty); emit Withdrawn(delegator, toValidatorID, wrID, amount - penalty, penalty); } /// Get highest epoch for which can be claimed rewards for the given validator. // If the validator is deactivated, the highest payable epoch is the deactivation epoch // or the current epoch, whichever is lower function _highestPayableEpoch(uint256 validatorID) internal view returns (uint256) { if (getValidator[validatorID].deactivatedEpoch != 0) { if (currentSealedEpoch < getValidator[validatorID].deactivatedEpoch) { return currentSealedEpoch; } return getValidator[validatorID].deactivatedEpoch; } return currentSealedEpoch; } /// Get new rewards for a delegator. /// The rewards are calculated from the last stashed epoch until the highest payable epoch. function _newRewards(address delegator, uint256 toValidatorID) internal view returns (uint256) { uint256 stashedUntil = stashedRewardsUntilEpoch[delegator][toValidatorID]; uint256 payableUntil = _highestPayableEpoch(toValidatorID); uint256 wholeStake = getStake[delegator][toValidatorID]; uint256 fullReward = _newRewardsOf(wholeStake, toValidatorID, stashedUntil, payableUntil); return fullReward; } /// Get new rewards for a delegator for a given stake amount and epoch range. function _newRewardsOf( uint256 stakeAmount, uint256 toValidatorID, uint256 fromEpoch, uint256 toEpoch ) internal view returns (uint256) { if (fromEpoch >= toEpoch) { return 0; } uint256 stashedRate = getEpochSnapshot[fromEpoch].accumulatedRewardPerToken[toValidatorID]; uint256 currentRate = getEpochSnapshot[toEpoch].accumulatedRewardPerToken[toValidatorID]; return ((currentRate - stashedRate) * stakeAmount) / Decimal.unit(); } /// Stash rewards for a delegator. function _stashRewards(address delegator, uint256 toValidatorID) internal returns (bool updated) { uint256 nonStashedReward = _newRewards(delegator, toValidatorID); stashedRewardsUntilEpoch[delegator][toValidatorID] = _highestPayableEpoch(toValidatorID); _rewardsStash[delegator][toValidatorID] += nonStashedReward; return nonStashedReward != 0; } /// Claim rewards for a delegator. function _claimRewards(address delegator, uint256 toValidatorID) internal returns (uint256) { _stashRewards(delegator, toValidatorID); uint256 rewards = _rewardsStash[delegator][toValidatorID]; if (rewards == 0) { revert ZeroRewards(); } delete _rewardsStash[delegator][toValidatorID]; // It's important that we mint after erasing (protection against Re-Entrancy) _mintNativeToken(rewards); return rewards; } /// Burn native tokens. /// The tokens are sent to the zero address. function _burnNativeTokens(uint256 amount) internal { if (amount != 0) { if (amount > totalSupply) { revert ValueTooLarge(); } totalSupply -= amount; payable(address(0)).transfer(amount); emit BurntNativeTokens(amount); } } /// Get epoch end time. function epochEndTime(uint256 epoch) internal view returns (uint256) { return getEpochSnapshot[epoch].endTime; } /// Check if an address is redirected. function _redirected(address addr) internal view returns (bool) { return getRedirection[addr] != address(0); } /// Get address which should receive rewards and withdrawn stake for the given delegator. /// The delegator is usually the receiver, unless a redirection is created. function _receiverOf(address addr) internal view returns (address payable) { address to = getRedirection[addr]; if (to == address(0)) { return payable(address(uint160(addr))); } return payable(address(uint160(to))); } /// Seal epoch - sync validators. function _sealEpochOffline( EpochSnapshot storage snapshot, uint256[] memory validatorIDs, uint256[] memory offlineTime, uint256[] memory offlineBlocks ) internal { // mark offline nodes for (uint256 i = 0; i < validatorIDs.length; i++) { if ( offlineBlocks[i] > c.offlinePenaltyThresholdBlocksNum() && offlineTime[i] >= c.offlinePenaltyThresholdTime() ) { _setValidatorDeactivated(validatorIDs[i], OFFLINE_BIT); _syncValidator(validatorIDs[i], false); } // log data snapshot.offlineTime[validatorIDs[i]] = offlineTime[i]; snapshot.offlineBlocks[validatorIDs[i]] = offlineBlocks[i]; } } /// Seal epoch - calculate rewards. function _sealEpochRewards( uint256 epochDuration, EpochSnapshot storage snapshot, EpochSnapshot storage prevSnapshot, uint256[] memory validatorIDs, uint256[] memory uptimes, uint256[] memory accumulatedOriginatedTxsFee ) internal { SealEpochRewardsCtx memory ctx = SealEpochRewardsCtx( new uint256[](validatorIDs.length), 0, new uint256[](validatorIDs.length), 0, 0 ); for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 prevAccumulatedTxsFee = prevSnapshot.accumulatedOriginatedTxsFee[validatorIDs[i]]; uint256 originatedTxsFee = 0; if (accumulatedOriginatedTxsFee[i] > prevAccumulatedTxsFee) { originatedTxsFee = accumulatedOriginatedTxsFee[i] - prevAccumulatedTxsFee; } // txRewardWeight = {originatedTxsFee} * {uptime} // originatedTxsFee is roughly proportional to {uptime} * {stake}, so the whole formula is roughly // {stake} * {uptime} ^ 2 ctx.txRewardWeights[i] = (originatedTxsFee * uptimes[i]) / epochDuration; ctx.totalTxRewardWeight = ctx.totalTxRewardWeight + ctx.txRewardWeights[i]; ctx.epochFee = ctx.epochFee + originatedTxsFee; } for (uint256 i = 0; i < validatorIDs.length; i++) { // baseRewardWeight = {stake} * {uptime ^ 2} ctx.baseRewardWeights[i] = (((snapshot.receivedStake[validatorIDs[i]] * uptimes[i]) / epochDuration) * uptimes[i]) / epochDuration; ctx.totalBaseRewardWeight = ctx.totalBaseRewardWeight + ctx.baseRewardWeights[i]; } for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 rawReward = _calcRawValidatorEpochBaseReward( epochDuration, c.baseRewardPerSecond(), ctx.baseRewardWeights[i], ctx.totalBaseRewardWeight ); rawReward = rawReward + _calcRawValidatorEpochTxReward(ctx.epochFee, ctx.txRewardWeights[i], ctx.totalTxRewardWeight); uint256 validatorID = validatorIDs[i]; address validatorAddr = getValidator[validatorID].auth; // accounting validator's commission uint256 commissionRewardFull = _calcValidatorCommission(rawReward, c.validatorCommission()); uint256 selfStake = getStake[validatorAddr][validatorID]; if (selfStake != 0) { _rewardsStash[validatorAddr][validatorID] += commissionRewardFull; } // accounting reward per token for delegators uint256 delegatorsReward = rawReward - commissionRewardFull; // note: use latest stake for the sake of rewards distribution accuracy, not snapshot.receivedStake uint256 receivedStake = getValidator[validatorID].receivedStake; uint256 rewardPerToken = 0; if (receivedStake != 0) { rewardPerToken = (delegatorsReward * Decimal.unit()) / receivedStake; } snapshot.accumulatedRewardPerToken[validatorID] = prevSnapshot.accumulatedRewardPerToken[validatorID] + rewardPerToken; snapshot.accumulatedOriginatedTxsFee[validatorID] = accumulatedOriginatedTxsFee[i]; snapshot.accumulatedUptime[validatorID] = prevSnapshot.accumulatedUptime[validatorID] + uptimes[i]; } snapshot.epochFee = ctx.epochFee; if (totalSupply > snapshot.epochFee) { totalSupply -= snapshot.epochFee; } else { totalSupply = 0; } // transfer 10% of fees to treasury if (treasuryAddress != address(0)) { uint256 feeShare = (ctx.epochFee * c.treasuryFeeShare()) / Decimal.unit(); _mintNativeToken(feeShare); (bool success, ) = treasuryAddress.call{value: feeShare, gas: 1000000}(""); // solhint-disable-next-line no-empty-blocks if (!success) { // ignore treasury transfer failure // the treasury failure must not endanger the epoch sealing // store the unresolved treasury fees to be resolved later unresolvedTreasuryFees += feeShare; } } } /// Seal epoch - recalculate average uptime time of validators function _sealEpochAverageUptime( uint256 epochDuration, EpochSnapshot storage snapshot, EpochSnapshot storage prevSnapshot, uint256[] memory validatorIDs, uint256[] memory uptimes ) internal { for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 validatorID = validatorIDs[i]; // compute normalised uptime as a percentage in the fixed-point format uint256 normalisedUptime = (uptimes[i] * Decimal.unit()) / epochDuration; if (normalisedUptime > Decimal.unit()) { normalisedUptime = Decimal.unit(); } AverageUptime memory previous = prevSnapshot.averageUptime[validatorID]; AverageUptime memory current = _addElementIntoAverageUptime(uint64(normalisedUptime), previous); snapshot.averageUptime[validatorID] = current; // remove validator if average uptime drops below min average uptime // (by setting minAverageUptime to zero, this check is ignored) if (current.averageUptime < c.minAverageUptime() && current.epochs >= c.averageUptimeEpochWindow()) { _setValidatorDeactivated(validatorID, OFFLINE_AVG_BIT); _syncValidator(validatorID, false); } } } function _addElementIntoAverageUptime( uint64 newValue, AverageUptime memory prev ) private view returns (AverageUptime memory) { AverageUptime memory cur; if (prev.epochs == 0) { cur.averageUptime = newValue; // the only element for the average cur.epochs = 1; return cur; } // the number of elements the average is calculated from uint128 n = prev.epochs + 1; // add new value into the average uint128 tmp = (n - 1) * uint128(prev.averageUptime) + uint128(newValue) + prev.remainder; cur.averageUptime = uint64(tmp / n); cur.remainder = uint32(tmp % n); if (cur.averageUptime > Decimal.unit()) { cur.averageUptime = uint64(Decimal.unit()); } if (prev.epochs < c.averageUptimeEpochWindow()) { cur.epochs = prev.epochs + 1; } else { cur.epochs = prev.epochs; } return cur; } /// Create a new validator. function _createValidator(address auth, bytes calldata pubkey) internal { uint256 validatorID = ++lastValidatorID; _rawCreateValidator(auth, validatorID, pubkey, OK_STATUS, currentEpoch(), _now(), 0, 0); } /// Create a new validator without incrementing lastValidatorID. function _rawCreateValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 status, uint256 createdEpoch, uint256 createdTime, uint256 deactivatedEpoch, uint256 deactivatedTime ) internal { if (getValidatorID[auth] != 0) { revert ValidatorExists(); } getValidatorID[auth] = validatorID; getValidator[validatorID].status = status; getValidator[validatorID].createdEpoch = createdEpoch; getValidator[validatorID].createdTime = createdTime; getValidator[validatorID].deactivatedTime = deactivatedTime; getValidator[validatorID].deactivatedEpoch = deactivatedEpoch; getValidator[validatorID].auth = auth; getValidatorPubkey[validatorID] = pubkey; pubkeyAddressToValidatorID[_pubkeyToAddress(pubkey)] = validatorID; emit CreatedValidator(validatorID, auth, createdEpoch, createdTime); if (deactivatedEpoch != 0) { emit DeactivatedValidator(validatorID, deactivatedEpoch, deactivatedTime); } if (status != 0) { emit ChangedValidatorStatus(validatorID, status); } } /// Calculate raw validator epoch transaction reward. function _calcRawValidatorEpochTxReward( uint256 epochFee, uint256 txRewardWeight, uint256 totalTxRewardWeight ) internal view returns (uint256) { if (txRewardWeight == 0) { return 0; } uint256 txReward = (epochFee * txRewardWeight) / totalTxRewardWeight; // fee reward except burntFeeShare and treasuryFeeShare return (txReward * (Decimal.unit() - c.burntFeeShare() - c.treasuryFeeShare())) / Decimal.unit(); } /// Calculate raw validator epoch base reward. function _calcRawValidatorEpochBaseReward( uint256 epochDuration, uint256 _baseRewardPerSecond, uint256 baseRewardWeight, uint256 totalBaseRewardWeight ) internal pure returns (uint256) { if (baseRewardWeight == 0) { return 0; } uint256 totalReward = epochDuration * _baseRewardPerSecond; return (totalReward * baseRewardWeight) / totalBaseRewardWeight; } /// Mint native token. function _mintNativeToken(uint256 amount) internal { // balance will be increased after the transaction is processed node.incBalance(address(this), amount); totalSupply = totalSupply + amount; } /// Notify stake subscriber about staking changes. /// Used to recount votes from delegators in the governance contract. function _notifyStakeSubscriber(address delegator, address validatorAuth, bool strict) internal { if (stakeSubscriberAddress != address(0)) { // Don't allow announceStakeChange to use up all the gas // solhint-disable-next-line avoid-low-level-calls (bool success, ) = stakeSubscriberAddress.call{gas: 8000000}( abi.encodeWithSignature("announceStakeChange(address,address)", delegator, validatorAuth) ); // Don't revert if announceStakeChange failed unless strict mode enabled if (!success && strict) { revert StakeSubscriberFailed(); } } } /// Set validator deactivated status. function _setValidatorDeactivated(uint256 validatorID, uint256 status) internal { if (getValidator[validatorID].status == OK_STATUS && status != OK_STATUS) { totalActiveStake = totalActiveStake - getValidator[validatorID].receivedStake; } // status as a number is proportional to severity if (status > getValidator[validatorID].status) { getValidator[validatorID].status = status; if (getValidator[validatorID].deactivatedEpoch == 0) { getValidator[validatorID].deactivatedEpoch = currentEpoch(); getValidator[validatorID].deactivatedTime = _now(); emit DeactivatedValidator( validatorID, getValidator[validatorID].deactivatedEpoch, getValidator[validatorID].deactivatedTime ); } emit ChangedValidatorStatus(validatorID, status); } } /// Sync validator with node. function _syncValidator(uint256 validatorID, bool syncPubkey) public { if (!_validatorExists(validatorID)) { revert ValidatorNotExists(); } // emit special log for node uint256 weight = getValidator[validatorID].receivedStake; if (getValidator[validatorID].status != OK_STATUS) { weight = 0; } node.updateValidatorWeight(validatorID, weight); if (syncPubkey && weight != 0) { node.updateValidatorPubkey(validatorID, getValidatorPubkey[validatorID]); } } /// Check if a validator exists. function _validatorExists(uint256 validatorID) internal view returns (bool) { return getValidator[validatorID].createdTime != 0; } /// Calculate validator commission. function _calcValidatorCommission(uint256 rawReward, uint256 commission) internal pure returns (uint256) { return (rawReward * commission) / Decimal.unit(); } /// Derive address from validator private key function _pubkeyToAddress(bytes calldata pubkey) private pure returns (address) { return address(uint160(uint256(keccak256(pubkey[2:])))); } /// Get current time. function _now() internal view virtual returns (uint256) { return block.timestamp; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC-1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.21; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This library provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit IERC1967.Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit IERC1967.AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the ERC-1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit IERC1967.BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @custom:security-contact [email protected] */ library Decimal { // unit is used for decimals, e.g. 0.123456 function unit() internal pure returns (uint256) { return 1e18; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @title EVM Writer Interface * @notice Allows the NodeDriver contract to write into the state database. * @dev Implemented in the native code of the Sonic client. * @custom:security-contact [email protected] */ interface IEVMWriter { function setBalance(address acc, uint256 value) external; function copyCode(address acc, address from) external; function swapCode(address acc, address where) external; function setStorage(address acc, bytes32 key, bytes32 value) external; function incNonce(address acc, uint256 diff) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @title Node Driver Contract Interface * @notice Ensures interaction of on-chain contracts with the Sonic client itself. * @dev Methods with onlyNode modifier are called by Sonic internal txs during epoch sealing. * @custom:security-contact [email protected] */ interface INodeDriver { /// Set an initial validator. Called only as part of network initialization/genesis file generating. function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external; /// Set an initial delegation. Called only as part of network initialization/genesis file generating. function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external; /// Deactivate a validator. Called by network node when a double-sign of the given validator is registered. /// Is called before sealEpoch() call. function deactivateValidator(uint256 validatorID, uint256 status) external; /// Seal epoch. Called BEFORE epoch sealing made by the client itself. function sealEpoch( uint256[] calldata offlineTimes, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external; /// Seal epoch. Called AFTER epoch sealing made by the client itself. function sealEpochValidators(uint256[] calldata nextValidatorIDs) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @title Node Driver Executable * @notice A batch of operations to be executed with NodeDriver permissions. * @notice Contracts implementing this interface should be executed using NodeDriverAuth.execute() or mutExecute(). * @custom:security-contact [email protected] */ interface INodeDriverExecutable { function execute() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @title Special Fee Contract for Sonic network * @notice The SFC maintains a list of validators and delegators and distributes rewards to them. * @custom:security-contact [email protected] */ interface ISFC { event CreatedValidator( uint256 indexed validatorID, address indexed auth, uint256 createdEpoch, uint256 createdTime ); event Delegated(address indexed delegator, uint256 indexed toValidatorID, uint256 amount); event Undelegated(address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount); event Withdrawn( address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount, uint256 penalty ); event ClaimedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards); event RestakedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards); event BurntFTM(uint256 amount); event UpdatedSlashingRefundRatio(uint256 indexed validatorID, uint256 refundRatio); event RefundedSlashedLegacyDelegation(address indexed delegator, uint256 indexed validatorID, uint256 amount); event DeactivatedValidator(uint256 indexed validatorID, uint256 deactivatedEpoch, uint256 deactivatedTime); event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status); event AnnouncedRedirection(address indexed from, address indexed to); function currentSealedEpoch() external view returns (uint256); function getEpochSnapshot( uint256 ) external view returns ( uint256 endTime, uint256 endBlock, uint256 epochFee, uint256 baseRewardPerSecond, uint256 totalStake, uint256 totalSupply ); function getStake(address, uint256) external view returns (uint256); function getValidator( uint256 ) external view returns ( uint256 status, uint256 receivedStake, address auth, uint256 createdEpoch, uint256 createdTime, uint256 deactivatedTime, uint256 deactivatedEpoch ); function getValidatorID(address) external view returns (uint256); function getValidatorPubkey(uint256) external view returns (bytes memory); function pubkeyAddressToValidatorID(address pubkeyAddress) external view returns (uint256); function getWithdrawalRequest( address, uint256, uint256 ) external view returns (uint256 epoch, uint256 time, uint256 amount); function isOwner() external view returns (bool); function lastValidatorID() external view returns (uint256); function minGasPrice() external view returns (uint256); function owner() external view returns (address); function renounceOwnership() external; function slashingRefundRatio(uint256) external view returns (uint256); function stashedRewardsUntilEpoch(address, uint256) external view returns (uint256); function totalActiveStake() external view returns (uint256); function totalStake() external view returns (uint256); function totalSupply() external view returns (uint256); function transferOwnership(address newOwner) external; function treasuryAddress() external view returns (address); function version() external pure returns (bytes3); function currentEpoch() external view returns (uint256); function updateConstsAddress(address v) external; function constsAddress() external view returns (address); function getEpochValidatorIDs(uint256 epoch) external view returns (uint256[] memory); function getEpochReceivedStake(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochAccumulatedRewardPerToken(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochAverageUptime(uint256 epoch, uint256 validatorID) external view returns (uint32); function getEpochAccumulatedOriginatedTxsFee(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochOfflineTime(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochEndBlock(uint256 epoch) external view returns (uint256); function rewardsStash(address delegator, uint256 validatorID) external view returns (uint256); function createValidator(bytes calldata pubkey) external payable; function getSelfStake(uint256 validatorID) external view returns (uint256); function delegate(uint256 toValidatorID) external payable; function undelegate(uint256 toValidatorID, uint256 wrID, uint256 amount) external; function isSlashed(uint256 validatorID) external view returns (bool); function withdraw(uint256 toValidatorID, uint256 wrID) external; function deactivateValidator(uint256 validatorID, uint256 status) external; function pendingRewards(address delegator, uint256 toValidatorID) external view returns (uint256); function stashRewards(address delegator, uint256 toValidatorID) external; function claimRewards(uint256 toValidatorID) external; function restakeRewards(uint256 toValidatorID) external; function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio) external; function updateTreasuryAddress(address v) external; function burnFTM(uint256 amount) external; function sealEpoch( uint256[] calldata offlineTime, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external; function sealEpochValidators(uint256[] calldata nextValidatorIDs) external; function initialize( uint256 sealedEpoch, uint256 _totalSupply, address nodeDriver, address consts, address _owner ) external; function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external; function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external; function updateStakeSubscriberAddress(address v) external; function stakeSubscriberAddress() external view returns (address); function setRedirectionAuthorizer(address v) external; function announceRedirection(address to) external; function initiateRedirection(address from, address to) external; function redirect(address to) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Decimal} from "../common/Decimal.sol"; /** * @custom:security-contact [email protected] */ contract ConstantsManager is Ownable { // Minimum amount of stake for a validator, i.e., 500000 FTM uint256 public minSelfStake; // Maximum ratio of delegations a validator can have, say, 15 times of self-stake uint256 public maxDelegatedRatio; // The commission fee in percentage a validator will get from a delegation, e.g., 15% uint256 public validatorCommission; // The percentage of fees to burn, e.g., 20% uint256 public burntFeeShare; // The percentage of fees to transfer to treasury address, e.g., 10% uint256 public treasuryFeeShare; // the number of epochs that undelegated stake is locked for uint256 public withdrawalPeriodEpochs; // the number of seconds that undelegated stake is locked for uint256 public withdrawalPeriodTime; uint256 public baseRewardPerSecond; uint256 public offlinePenaltyThresholdBlocksNum; uint256 public offlinePenaltyThresholdTime; uint256 public targetGasPowerPerSecond; uint256 public gasPriceBalancingCounterweight; // The number of epochs to calculate the average uptime ratio from, acceptable bound [10, 87600]. // Is also the minimum number of epochs necessary for deactivation of offline validators. uint32 public averageUptimeEpochWindow; // Minimum average uptime ratio in fixed-point format; acceptable bounds [0,0.9]. // Zero to disable validators deactivation by this metric. uint64 public minAverageUptime; // The address of the recipient that receives issued tokens // as a counterparty to the burnt FTM tokens address public issuedTokensRecipient; /** * @dev Given value is too small */ error ValueTooSmall(); /** * @dev Given value is too large */ error ValueTooLarge(); constructor(address owner) Ownable(owner) {} function updateMinSelfStake(uint256 v) external virtual onlyOwner { if (v < 100000 * 1e18) { revert ValueTooSmall(); } if (v > 10000000 * 1e18) { revert ValueTooLarge(); } minSelfStake = v; } function updateMaxDelegatedRatio(uint256 v) external virtual onlyOwner { if (v < Decimal.unit()) { revert ValueTooSmall(); } if (v > 31 * Decimal.unit()) { revert ValueTooLarge(); } maxDelegatedRatio = v; } function updateValidatorCommission(uint256 v) external virtual onlyOwner { if (v > Decimal.unit() / 2) { revert ValueTooLarge(); } validatorCommission = v; } function updateBurntFeeShare(uint256 v) external virtual onlyOwner { if (v > Decimal.unit() / 2) { revert ValueTooLarge(); } burntFeeShare = v; } function updateTreasuryFeeShare(uint256 v) external virtual onlyOwner { if (v > Decimal.unit() / 2) { revert ValueTooLarge(); } treasuryFeeShare = v; } function updateWithdrawalPeriodEpochs(uint256 v) external virtual onlyOwner { if (v < 2) { revert ValueTooSmall(); } if (v > 100) { revert ValueTooLarge(); } withdrawalPeriodEpochs = v; } function updateWithdrawalPeriodTime(uint256 v) external virtual onlyOwner { if (v < 86400) { revert ValueTooSmall(); } if (v > 30 * 86400) { revert ValueTooLarge(); } withdrawalPeriodTime = v; } function updateBaseRewardPerSecond(uint256 v) external virtual onlyOwner { if (v < 0.5 * 1e18) { revert ValueTooSmall(); } if (v > 32 * 1e18) { revert ValueTooLarge(); } baseRewardPerSecond = v; } function updateOfflinePenaltyThresholdTime(uint256 v) external virtual onlyOwner { if (v < 86400) { revert ValueTooSmall(); } if (v > 10 * 86400) { revert ValueTooLarge(); } offlinePenaltyThresholdTime = v; } function updateOfflinePenaltyThresholdBlocksNum(uint256 v) external virtual onlyOwner { if (v < 100) { revert ValueTooSmall(); } if (v > 1000000) { revert ValueTooLarge(); } offlinePenaltyThresholdBlocksNum = v; } function updateTargetGasPowerPerSecond(uint256 v) external virtual onlyOwner { if (v < 1000000) { revert ValueTooSmall(); } if (v > 500000000) { revert ValueTooLarge(); } targetGasPowerPerSecond = v; } function updateGasPriceBalancingCounterweight(uint256 v) external virtual onlyOwner { if (v < 100) { revert ValueTooSmall(); } if (v > 10 * 86400) { revert ValueTooLarge(); } gasPriceBalancingCounterweight = v; } function updateAverageUptimeEpochWindow(uint32 v) external virtual onlyOwner { if (v < 10) { // needs to be long enough to allow permissible downtime for validators maintenance revert ValueTooSmall(); } if (v > 87600) { revert ValueTooLarge(); } averageUptimeEpochWindow = v; } function updateMinAverageUptime(uint64 v) external virtual onlyOwner { if (v > ((Decimal.unit() * 9) / 10)) { revert ValueTooLarge(); } minAverageUptime = v; } function updateIssuedTokensRecipient(address v) external virtual onlyOwner { issuedTokensRecipient = v; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {NodeDriverAuth} from "./NodeDriverAuth.sol"; import {IEVMWriter} from "../interfaces/IEVMWriter.sol"; import {INodeDriver} from "../interfaces/INodeDriver.sol"; /** * @title Node Driver Contract * @notice Ensures interaction of on-chain contracts with the Sonic client itself. * @dev Methods with onlyNode modifier are called by Sonic internal txs during epoch sealing. * @custom:security-contact [email protected] */ contract NodeDriver is OwnableUpgradeable, UUPSUpgradeable, INodeDriver { NodeDriverAuth internal backend; IEVMWriter internal evmWriter; error NotNode(); error NotBackend(); /// Callable only by NodeDriverAuth (which mediates calls from SFC and from admins) modifier onlyBackend() { if (msg.sender != address(backend)) { revert NotBackend(); } _; } event UpdateValidatorWeight(uint256 indexed validatorID, uint256 weight); event UpdateValidatorPubkey(uint256 indexed validatorID, bytes pubkey); event UpdateNetworkRules(bytes diff); event UpdateNetworkVersion(uint256 version); event AdvanceEpochs(uint256 num); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// Initialization is called only once, after the contract deployment. /// Because the contract code is written directly into genesis, constructor cannot be used. function initialize(address _backend, address _evmWriterAddress, address _owner) external initializer { __Ownable_init(_owner); __UUPSUpgradeable_init(); backend = NodeDriverAuth(_backend); evmWriter = IEVMWriter(_evmWriterAddress); } /// Override the upgrade authorization check to allow upgrades only from the owner. // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address) internal override onlyOwner {} function setBalance(address acc, uint256 value) external onlyBackend { evmWriter.setBalance(acc, value); } function copyCode(address acc, address from) external onlyBackend { evmWriter.copyCode(acc, from); } function swapCode(address acc, address where) external onlyBackend { evmWriter.swapCode(acc, where); } function setStorage(address acc, bytes32 key, bytes32 value) external onlyBackend { evmWriter.setStorage(acc, key, value); } function incNonce(address acc, uint256 diff) external onlyBackend { evmWriter.incNonce(acc, diff); } /// Update network rules configuring the chain. /// Emitted event is being observed by Sonic client. function updateNetworkRules(bytes calldata diff) external onlyBackend { emit UpdateNetworkRules(diff); } /// Update advertised version of the network. /// Emitted event is being observed by Sonic client. function updateNetworkVersion(uint256 version) external onlyBackend { emit UpdateNetworkVersion(version); } /// Enforce sealing given number of epochs. /// Emitted event is being observed by Sonic client. function advanceEpochs(uint256 num) external onlyBackend { emit AdvanceEpochs(num); } /// Update weight of a validator. Used to propagate a stake change from SFC to the client. /// Emitted event is being observed by Sonic client. function updateValidatorWeight(uint256 validatorID, uint256 value) external onlyBackend { emit UpdateValidatorWeight(validatorID, value); } /// Update public key of a validator. Used to propagate a change from SFC to the client. /// Emitted event is being observed by Sonic client. function updateValidatorPubkey(uint256 validatorID, bytes calldata pubkey) external onlyBackend { emit UpdateValidatorPubkey(validatorID, pubkey); } /// Callable only from Sonic client itself as an internal tx. /// Used for propagating network event (validator doublesign, epoch sealing) from node to SFC. modifier onlyNode() { if (msg.sender != address(0)) { revert NotNode(); } _; } // Methods which are called only by the node /// Set an initial validator. Called only as part of network initialization/genesis file generating. function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external onlyNode { backend.setGenesisValidator(auth, validatorID, pubkey, createdTime); } /// Set an initial delegation. Called only as part of network initialization/genesis file generating. function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external onlyNode { backend.setGenesisDelegation(delegator, toValidatorID, stake); } /// Deactivate a validator. Called by network node when a double-sign of the given validator is registered. /// Is called before sealEpoch() call. function deactivateValidator(uint256 validatorID, uint256 status) external onlyNode { backend.deactivateValidator(validatorID, status); } /// Seal epoch. Called BEFORE epoch sealing made by the client itself. function sealEpoch( uint256[] calldata offlineTimes, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyNode { backend.sealEpoch(offlineTimes, offlineBlocks, uptimes, originatedTxsFee); } /// Seal epoch. Called AFTER epoch sealing made by the client itself. function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyNode { backend.sealEpochValidators(nextValidatorIDs); } uint256[50] private __gap; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ISFC} from "../interfaces/ISFC.sol"; import {NodeDriver} from "./NodeDriver.sol"; import {INodeDriverExecutable} from "../interfaces/INodeDriverExecutable.sol"; /** * @custom:security-contact [email protected] */ contract NodeDriverAuth is OwnableUpgradeable, UUPSUpgradeable { ISFC internal sfc; NodeDriver internal driver; error NotSFC(); error NotDriver(); error NotContract(); error SelfCodeHashMismatch(); error DriverCodeHashMismatch(); error RecipientNotSFC(); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } // Initialize NodeDriverAuth, NodeDriver and SFC in one call to allow fewer genesis transactions function initialize(address payable _sfc, address _driver, address _owner) external initializer { __Ownable_init(_owner); __UUPSUpgradeable_init(); driver = NodeDriver(_driver); sfc = ISFC(_sfc); } /// Override the upgrade authorization check to allow upgrades only from the owner. // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address) internal override onlyOwner {} /// Callable only by SFC contract. modifier onlySFC() { if (msg.sender != address(sfc)) { revert NotSFC(); } _; } /// Callable only by NodeDriver (mediates messages from the network client) modifier onlyDriver() { if (msg.sender != address(driver)) { revert NotDriver(); } _; } function _execute(address executable, address newOwner, bytes32 selfCodeHash, bytes32 driverCodeHash) internal { _transferOwnership(executable); INodeDriverExecutable(executable).execute(); _transferOwnership(newOwner); //require(driver.backend() == address(this), "ownership of driver is lost"); if (_getCodeHash(address(this)) != selfCodeHash) { revert SelfCodeHashMismatch(); } if (_getCodeHash(address(driver)) != driverCodeHash) { revert DriverCodeHashMismatch(); } } /// Execute a batch update of network configuration. /// Run given contract with a permission of the NodeDriverAuth owner. /// Does not allow changing NodeDriver and NodeDriverAuth code. function execute(address executable) external onlyOwner { _execute(executable, owner(), _getCodeHash(address(this)), _getCodeHash(address(driver))); } /// Execute a batch update of network configuration. /// Run given contract with a permission of the NodeDriverAuth owner. /// Allows changing NodeDriver and NodeDriverAuth code. function mutExecute( address executable, address newOwner, bytes32 selfCodeHash, bytes32 driverCodeHash ) external onlyOwner { _execute(executable, newOwner, selfCodeHash, driverCodeHash); } /// Mint native token. To be used by SFC for minting validators rewards. function incBalance(address acc, uint256 diff) external onlySFC { driver.setBalance(acc, address(acc).balance + diff); } /// Upgrade code of given contract by coping it from other deployed contract. /// Avoids setting code to an external address. function upgradeCode(address acc, address from) external onlyOwner { if (!isContract(acc) || !isContract(from)) { revert NotContract(); } driver.copyCode(acc, from); } /// Upgrade code of given contract by coping it from other deployed contract. /// Does not avoid setting code to an external address. (DANGEROUS!) function copyCode(address acc, address from) external onlyOwner { driver.copyCode(acc, from); } /// Increment nonce of the given account. function incNonce(address acc, uint256 diff) external onlyOwner { driver.incNonce(acc, diff); } /// Update network rules by providing a JSON patch. function updateNetworkRules(bytes calldata diff) external onlyOwner { driver.updateNetworkRules(diff); } /// Update advertised network version. function updateNetworkVersion(uint256 version) external onlyOwner { driver.updateNetworkVersion(version); } /// Enforce sealing given number of epochs. function advanceEpochs(uint256 num) external onlyOwner { driver.advanceEpochs(num); } /// Update weight of a validator. Used to propagate a stake change from SFC to the client. function updateValidatorWeight(uint256 validatorID, uint256 value) external onlySFC { driver.updateValidatorWeight(validatorID, value); } /// Update public key of a validator. Used to propagate a change from SFC to the client. function updateValidatorPubkey(uint256 validatorID, bytes calldata pubkey) external onlySFC { driver.updateValidatorPubkey(validatorID, pubkey); } /// Set an initial validator into SFC. Called only as part of network initialization/genesis file generating. function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external onlyDriver { sfc.setGenesisValidator(auth, validatorID, pubkey, createdTime); } /// Set an initial delegation. Called only as part of network initialization/genesis file generating. function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external onlyDriver { sfc.setGenesisDelegation(delegator, toValidatorID, stake); } /// Deactivate a validator. Called by network node when a double-sign of the given validator is registered. /// Is called before sealEpoch() call. function deactivateValidator(uint256 validatorID, uint256 status) external onlyDriver { sfc.deactivateValidator(validatorID, status); } /// Seal epoch. Called BEFORE epoch sealing made by the client itself. function sealEpoch( uint256[] calldata offlineTimes, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyDriver { sfc.sealEpoch(offlineTimes, offlineBlocks, uptimes, originatedTxsFee); } /// Seal epoch. Called AFTER epoch sealing made by the client itself. function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyDriver { sfc.sealEpochValidators(nextValidatorIDs); } function isContract(address account) internal view returns (bool) { uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } function _getCodeHash(address addr) internal view returns (bytes32) { bytes32 codeHash; assembly { codeHash := extcodehash(addr) } return codeHash; } uint256[50] private __gap; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @dev Version contract gives the versioning information of the implementation contract */ contract Version { /** * @dev Returns the version of the SFC contract */ function version() public pure returns (bytes3) { return 0x040000; // version 4.0.0 } }
{ "evmVersion": "cancun", "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"AlreadyRedirected","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"InsufficientSelfStake","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"MalformedPubkey","type":"error"},{"inputs":[],"name":"NoUnresolvedTreasuryFees","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotDeactivatedStatus","type":"error"},{"inputs":[],"name":"NotDriverAuth","type":"error"},{"inputs":[],"name":"NotEnoughEpochsPassed","type":"error"},{"inputs":[],"name":"NotEnoughTimePassed","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NothingToStash","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PubkeyUsedByOtherValidator","type":"error"},{"inputs":[],"name":"Redirected","type":"error"},{"inputs":[],"name":"RefundRatioTooHigh","type":"error"},{"inputs":[],"name":"RequestExists","type":"error"},{"inputs":[],"name":"RequestNotExists","type":"error"},{"inputs":[],"name":"SameAddress","type":"error"},{"inputs":[],"name":"SameRedirectionAuthorizer","type":"error"},{"inputs":[],"name":"StakeIsFullySlashed","type":"error"},{"inputs":[],"name":"StakeSubscriberFailed","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"TransfersNotAllowed","type":"error"},{"inputs":[],"name":"TreasuryNotSet","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"ValidatorDelegationLimitExceeded","type":"error"},{"inputs":[],"name":"ValidatorExists","type":"error"},{"inputs":[],"name":"ValidatorNotActive","type":"error"},{"inputs":[],"name":"ValidatorNotExists","type":"error"},{"inputs":[],"name":"ValidatorNotSlashed","type":"error"},{"inputs":[],"name":"ValueTooLarge","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroRewards","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"AnnouncedRedirection","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BurntNativeTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"status","type":"uint256"}],"name":"ChangedValidatorStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"ClaimedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":true,"internalType":"address","name":"auth","type":"address"},{"indexed":false,"internalType":"uint256","name":"createdEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"createdTime","type":"uint256"}],"name":"CreatedValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deactivatedEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deactivatedTime","type":"uint256"}],"name":"DeactivatedValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Delegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RefundedSlashedLegacyDelegation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"RestakedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TreasuryFeesResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wrID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Undelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refundRatio","type":"uint256"}],"name":"UpdatedSlashingRefundRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"wrID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penalty","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"bool","name":"syncPubkey","type":"bool"}],"name":"_syncValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"announceRedirection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnNativeTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"constsAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"}],"name":"createValidator","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"currentEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentSealedEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"uint256","name":"status","type":"uint256"}],"name":"deactivateValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"delegate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedOriginatedTxsFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedRewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAccumulatedUptime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochAverageUptime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getEpochEndBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochOfflineBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochOfflineTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getEpochReceivedStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getEpochSnapshot","outputs":[{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"uint256","name":"epochFee","type":"uint256"},{"internalType":"uint256","name":"baseRewardPerSecond","type":"uint256"},{"internalType":"uint256","name":"totalStake","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getEpochValidatorIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"}],"name":"getRedirection","outputs":[{"internalType":"address","name":"receiver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"}],"name":"getRedirectionRequest","outputs":[{"internalType":"address","name":"receiver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getSelfStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getStake","outputs":[{"internalType":"uint256","name":"stake","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getValidator","outputs":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"uint256","name":"receivedStake","type":"uint256"},{"internalType":"address","name":"auth","type":"address"},{"internalType":"uint256","name":"createdEpoch","type":"uint256"},{"internalType":"uint256","name":"createdTime","type":"uint256"},{"internalType":"uint256","name":"deactivatedTime","type":"uint256"},{"internalType":"uint256","name":"deactivatedEpoch","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auth","type":"address"}],"name":"getValidatorID","outputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"getValidatorPubkey","outputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"uint256","name":"wrID","type":"uint256"}],"name":"getWithdrawalRequest","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sealedEpoch","type":"uint256"},{"internalType":"uint256","name":"_totalSupply","type":"uint256"},{"internalType":"address","name":"nodeDriver","type":"address"},{"internalType":"address","name":"_c","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"initiateRedirection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"isSlashed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"issueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastValidatorID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pubkeyAddress","type":"address"}],"name":"pubkeyAddressToValidatorID","outputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"redirect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redirectionAuthorizer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resolveTreasuryFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"restakeRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"rewardsStash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"offlineTime","type":"uint256[]"},{"internalType":"uint256[]","name":"offlineBlocks","type":"uint256[]"},{"internalType":"uint256[]","name":"uptimes","type":"uint256[]"},{"internalType":"uint256[]","name":"originatedTxsFee","type":"uint256[]"}],"name":"sealEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nextValidatorIDs","type":"uint256[]"}],"name":"sealEpochValidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"stake","type":"uint256"}],"name":"setGenesisDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"auth","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"uint256","name":"createdTime","type":"uint256"}],"name":"setGenesisValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"v","type":"address"}],"name":"setRedirectionAuthorizer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"slashingRefundRatio","outputs":[{"internalType":"uint256","name":"refundRatio","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakeSubscriberAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"toValidatorID","type":"uint256"}],"name":"stashRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"validatorID","type":"uint256"}],"name":"stashedRewardsUntilEpoch","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalActiveStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"wrID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"undelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unresolvedTreasuryFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"v","type":"address"}],"name":"updateConstsAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"validatorID","type":"uint256"},{"internalType":"uint256","name":"refundRatio","type":"uint256"}],"name":"updateSlashingRefundRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"v","type":"address"}],"name":"updateStakeSubscriberAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"v","type":"address"}],"name":"updateTreasuryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"bytes3","name":"","type":"bytes3"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"toValidatorID","type":"uint256"},{"internalType":"uint256","name":"wrID","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a060405230608052348015610013575f5ffd5b5061001c610021565b6100d3565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100715760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100d05780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051614f466100f95f395f81816128a0015281816128c90152612ca20152614f465ff3fe6080604052600436106103d7575f3560e01c80638b0e9f3f116101ff578063c65ee0e111610113578063dc31e1af116100a8578063e880a15911610078578063e880a15914610df9578063e9a505a714610e18578063ebdf104c14610e37578063f2fde38b14610e56578063fb36025f14610e75575f5ffd5b8063dc31e1af14610d2c578063df00c92214610d66578063e08d7e6614610da0578063e261641a14610dbf575f5ffd5b8063cfd47663116100e3578063cfd4766314610c8c578063d46fa51814610cc2578063d725e91f14610cdf578063db5ca3e514610cfe575f5ffd5b8063c65ee0e114610c0e578063c7be95de14610c39578063cc17278414610c4e578063cc8343aa14610c6d575f5ffd5b8063a86a056f11610194578063b0ef386c11610164578063b0ef386c14610ac1578063b5d8962714610ae0578063b88a37e214610b83578063c3de580e14610baf578063c5f956af14610bef575f5ffd5b8063a86a056f146109e1578063a8ab09ba14610a17578063aa5d829214610a36578063ad3cb1cc14610a91575f5ffd5b80639fa6dd35116101cf5780639fa6dd3514610962578063a198d22914610975578063a5820daa146109af578063a5a470ad146109ce575f5ffd5b80638b0e9f3f146108dd5780638cddb015146108f25780638d2da32e146109115780638da5cb5b14610926575f5ffd5b806352d1902d116102f6578063736de9ae1161028b578063841e45611161025b578063841e45611461085757806384b863e014610876578063850a10c01461088a578063854873e114610892578063860c2750146108be575f5ffd5b8063736de9ae146107db578063766718081461080f57806376fed43a146108235780637cacb1d614610842575f5ffd5b80636099ecb2116102c65780636099ecb21461072d57806361e53fcc1461074c5780636f49866314610786578063715018a6146107c7575f5ffd5b806352d1902d146106bd57806354fd4d50146106d15780635601fe01146106ef57806358f95b801461070e575f5ffd5b806339b80c001161036c57806346f1ca351161033c57806346f1ca351461064d5780634f1ef2861461066c5780634f7c4efb1461067f5780634f864df41461069e575f5ffd5b806339b80c001461055d5780633fbfd4df146105db578063441a3e70146105fa578063468f35ee14610619575f5ffd5b806318160ddd116103a757806318160ddd146104ae5780631e702f83146104c35780631f270152146104e257806328f7314814610548575f5ffd5b80630135b1db146103f957806308c3687414610437578063093b41d0146104585780630962ef791461048f575f5ffd5b366103f55760405163ab064ad360e01b815260040160405180910390fd5b5f5ffd5b348015610404575f5ffd5b506104246104133660046145e0565b60036020525f908152604090205481565b6040519081526020015b60405180910390f35b348015610442575f5ffd5b506104566104513660046145fb565b610ea0565b005b348015610463575f5ffd5b50601254610477906001600160a01b031681565b6040516001600160a01b03909116815260200161042e565b34801561049a575f5ffd5b506104566104a93660046145fb565b610f02565b3480156104b9575f5ffd5b50610424600d5481565b3480156104ce575f5ffd5b506104566104dd366004614612565b610fd2565b3480156104ed575f5ffd5b5061052d6104fc366004614632565b600b60209081525f938452604080852082529284528284209052825290208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161042e565b348015610553575f5ffd5b5061042460075481565b348015610568575f5ffd5b506105ae6105773660046145fb565b600e6020525f9081526040902060088101546009820154600a830154600b840154600c850154600d90950154939492939192909186565b604080519687526020870195909552938501929092526060840152608083015260a082015260c00161042e565b3480156105e6575f5ffd5b506104566105f5366004614664565b61105b565b348015610605575f5ffd5b50610456610614366004614612565b6111c4565b348015610624575f5ffd5b506104776106333660046145e0565b60156020525f90815260409020546001600160a01b031681565b348015610658575f5ffd5b506104566106673660046145e0565b6111dc565b61045661067a3660046146d3565b611214565b34801561068a575f5ffd5b50610456610699366004614612565b61122f565b3480156106a9575f5ffd5b506104566106b8366004614796565b6112de565b3480156106c8575f5ffd5b5061042461142b565b3480156106dc575f5ffd5b50604051600160fa1b815260200161042e565b3480156106fa575f5ffd5b506104246107093660046145fb565b611446565b348015610719575f5ffd5b50610424610728366004614612565b611478565b348015610738575f5ffd5b506104246107473660046147bf565b611498565b348015610757575f5ffd5b50610424610766366004614612565b5f918252600e602090815260408084209284526001909201905290205490565b348015610791575f5ffd5b506104246107a03660046147bf565b6001600160a01b03919091165f908152600960209081526040808320938352929052205490565b3480156107d2575f5ffd5b506104566114dd565b3480156107e6575f5ffd5b506104776107f53660046145e0565b60166020525f90815260409020546001600160a01b031681565b34801561081a575f5ffd5b506104246114f0565b34801561082e575f5ffd5b5061045661083d36600461482d565b611505565b34801561084d575f5ffd5b5061042460015481565b348015610862575f5ffd5b506104566108713660046145e0565b611557565b348015610881575f5ffd5b50610456611581565b610456611686565b34801561089d575f5ffd5b506108b16108ac3660046145fb565b6116af565b60405161042e91906148b9565b3480156108c9575f5ffd5b506104566108d83660046145e0565b611746565b3480156108e8575f5ffd5b5061042460065481565b3480156108fd575f5ffd5b5061045661090c3660046147bf565b611770565b34801561091c575f5ffd5b5061042460085481565b348015610931575f5ffd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610477565b6104566109703660046145fb565b611797565b348015610980575f5ffd5b5061042461098f366004614612565b5f918252600e602090815260408084209284526006909201905290205490565b3480156109ba575f5ffd5b506104566109c93660046145fb565b6117a5565b6104566109dc3660046148cb565b611928565b3480156109ec575f5ffd5b506104246109fb3660046147bf565b600a60209081525f928352604080842090915290825290205481565b348015610a22575f5ffd5b50610456610a31366004614632565b611a6f565b348015610a41575f5ffd5b50610a79610a50366004614612565b5f918252600e60209081526040808420928452600390920190529020546001600160401b031690565b6040516001600160401b03909116815260200161042e565b348015610a9c575f5ffd5b506108b1604051806040016040528060058152602001640352e302e360dc1b81525081565b348015610acc575f5ffd5b50610456610adb3660046145e0565b611aae565b348015610aeb575f5ffd5b50610b40610afa3660046145fb565b600260208190525f918252604090912080546001820154928201546003830154600484015460058501546006909501549395946001600160a01b03909316939192909187565b6040805197885260208801969096526001600160a01b03909416948601949094526060850191909152608084015260a083019190915260c082015260e00161042e565b348015610b8e575f5ffd5b50610ba2610b9d3660046145fb565b611b06565b60405161042e9190614909565b348015610bba575f5ffd5b50610bdf610bc93660046145fb565b5f90815260026020526040902054608016151590565b604051901515815260200161042e565b348015610bfa575f5ffd5b50601054610477906001600160a01b031681565b348015610c19575f5ffd5b50610424610c283660046145fb565b600f6020525f908152604090205481565b348015610c44575f5ffd5b5061042460055481565b348015610c59575f5ffd5b50610456610c6836600461494b565b611b68565b348015610c78575f5ffd5b50610456610c87366004614982565b611c2e565b348015610c97575f5ffd5b50610424610ca63660046147bf565b600c60209081525f928352604080842090915290825290205481565b348015610ccd575f5ffd5b506011546001600160a01b0316610477565b348015610cea575f5ffd5b50610456610cf93660046145e0565b611d58565b348015610d09575f5ffd5b50610424610d183660046145fb565b5f908152600e602052604090206009015490565b348015610d37575f5ffd5b50610424610d46366004614612565b5f918252600e602090815260408084209284526004909201905290205490565b348015610d71575f5ffd5b50610424610d80366004614612565b5f918252600e602090815260408084209284526002909201905290205490565b348015610dab575f5ffd5b50610456610dba3660046149e9565b611dfe565b348015610dca575f5ffd5b50610424610dd9366004614612565b5f918252600e602090815260408084209284526005909201905290205490565b348015610e04575f5ffd5b50610456610e133660046145e0565b611ebf565b348015610e23575f5ffd5b50601454610477906001600160a01b031681565b348015610e42575f5ffd5b50610456610e51366004614a1b565b611ee9565b348015610e61575f5ffd5b50610456610e703660046145e0565b61218d565b348015610e80575f5ffd5b50610424610e8f3660046145e0565b60136020525f908152604090205481565b335f610eac82846121cc565b9050610eb982848361224f565b82826001600160a01b03167f663e0f63f4fc6b01be195c4b56111fd6f14b947d6264497119b08daf77e26da583604051610ef591815260200190565b60405180910390a3505050565b335f610f0e82846121cc565b90505f610f1a836122dc565b6001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610f61576040519150601f19603f3d011682016040523d82523d5f602084013e610f66565b606091505b5050905080610f88576040516312171d8360e31b815260040160405180910390fd5b83836001600160a01b03167f70de20a533702af05c8faf1637846c4586a021bbc71b6928b089b6d555e4fbc284604051610fc491815260200190565b60405180910390a350505050565b5f546001600160a01b03163314610ffc5760405163c78d372960e01b815260040160405180910390fd5b8061101a5760405163396bd83560e21b815260040160405180910390fd5b6110248282612304565b61102e825f611c2e565b5f828152600260208190526040822001546001600160a01b0316906110569082908190612406565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f8115801561109f5750825b90505f826001600160401b031660011480156110ba5750303b155b9050811580156110c8575080155b156110e65760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561111057845460ff60401b1916600160401b1785555b611119866124e2565b6111216124f3565b60018a90555f80546001600160a01b03808b166001600160a01b03199283161790925560118054928a1692909116919091179055600d8990556111614290565b5f8b8152600e602052604090206008015583156111b857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b6111d83383836111d3336122dc565b6124fb565b5050565b6040516001600160a01b0382169033907f857125196131cfcd709c738c6d1fd2701ce70f2a03785aeadae6f4b47fe73c1d905f90a350565b61121c612895565b61122582612939565b6111d88282612941565b6112376129fd565b5f82815260026020526040902054608016611265576040516321b6a8f960e11b815260040160405180910390fd5b670de0b6b3a764000081111561128e576040516357c70d6360e01b815260040160405180910390fd5b5f828152600f6020526040908190208290555182907f047575f43f09a7a093d94ec483064acfc61b7e25c0de28017da442abf99cb917906112d29084815260200190565b60405180910390a25050565b336112e98185612a58565b50815f0361130a57604051631f2a200560e01b815260040160405180910390fd5b6001600160a01b0381165f908152600b602090815260408083208784528252808320868452909152902060020154156113565760405163756f5c2d60e11b815260040160405180910390fd5b61136681858460015f6001612ac6565b6001600160a01b0381165f908152600b602090815260408083208784528252808320868452909152902060020182905561139e6114f0565b6001600160a01b0382165f908152600b6020908152604080832088845282528083208784529091528120918255426001909201919091556113e0908590611c2e565b8284826001600160a01b03167fd3bb4e423fbea695d16b982f9f682dc5f35152e5411646a8a5a79a6b02ba8d578560405161141d91815260200190565b60405180910390a450505050565b5f611434612c97565b505f516020614ef15f395f51905f5290565b5f818152600260208181526040808420909201546001600160a01b03168352600c815281832093835292909252205490565b5f828152600e602090815260408083208484529091529020545b92915050565b5f5f6114a48484612ce0565b6001600160a01b0385165f9081526009602090815260408083208784529091529020549091506114d5908290614af9565b949350505050565b6114e56129fd565b6114ee5f612d4a565b565b5f60015460016115009190614af9565b905090565b5f546001600160a01b0316331461152f5760405163c78d372960e01b815260040160405180910390fd5b611540858585855f5f875f5f612dba565b6005548411156115505760058490555b5050505050565b61155f6129fd565b601080546001600160a01b0319166001600160a01b0392909216919091179055565b6010546001600160a01b03166115aa5760405163b2c4cce960e01b815260040160405180910390fd5b6008545f036115cc5760405163211a852360e21b815260040160405180910390fd5b600880545f918290556010546040519192916001600160a01b0390911690620f424090849084818181858888f193505050503d805f8114611628576040519150601f19603f3d011682016040523d82523d5f602084013e61162d565b606091505b505090508061164f576040516312171d8360e31b815260040160405180910390fd5b6040518281527f6dd5bb8ebf4cfb647c1cc0e9364ed9ecbf56202f7d3c9f058473df82664478d89060200160405180910390a15050565b345f036116a657604051631f2a200560e01b815260040160405180910390fd5b6114ee34612f65565b60046020525f9081526040902080546116c790614b0c565b80601f01602080910402602001604051908101604052809291908181526020018280546116f390614b0c565b801561173e5780601f106117155761010080835404028352916020019161173e565b820191905f5260205f20905b81548152906001019060200180831161172157829003601f168201915b505050505081565b61174e6129fd565b601180546001600160a01b0319166001600160a01b0392909216919091179055565b61177a8282612a58565b6111d85760405163208e0a4160e11b815260040160405180910390fd5b6117a233823461224f565b50565b6117ad6129fd565b601154604080516375840fab60e01b815290515f926001600160a01b0316916375840fab9160048083019260209291908290030181865afa1580156117f4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118189190614b44565b6001600160a01b03160361183f5760405163d92e233d60e01b815260040160405180910390fd5b5f54601154604080516375840fab60e01b815290516001600160a01b03938416936366e7ea0f9316916375840fab9160048083019260209291908290030181865afa158015611890573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118b49190614b44565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044015f604051808303815f87803b1580156118f9575f5ffd5b505af115801561190b573d5f5f3e3d5ffd5b5050505080600d5f8282546119209190614af9565b909155505050565b60115f9054906101000a90046001600160a01b03166001600160a01b031663c5f530af6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611978573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061199c9190614b5f565b3410156119bc5760405163047447a360e11b815260040160405180910390fd5b6042811415806119f5575081815f8181106119d9576119d9614b76565b9050013560f81c60f81b6001600160f81b03191660c060f81b14155b15611a13576040516338497f4960e11b815260040160405180910390fd5b60135f611a208484613005565b6001600160a01b0316815260208101919091526040015f205415611a575760405163028aeb6760e21b815260040160405180910390fd5b611a62338383613031565b6111d8336005543461224f565b5f546001600160a01b03163314611a995760405163c78d372960e01b815260040160405180910390fd5b611aa58383835f61305f565b611056816131ad565b611ab66129fd565b6014546001600160a01b03808316911603611ae457604051639b92bed360e01b815260040160405180910390fd5b601480546001600160a01b0319166001600160a01b0392909216919091179055565b5f818152600e6020908152604091829020600701805483518184028101840190945280845260609392830182828015611b5c57602002820191905f5260205f20905b815481526020019060010190808311611b48575b50505050509050919050565b6014546001600160a01b03163314611b935760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b038281165f90815260166020526040902054818316911603611bcf5760405163eb81e1a360e01b815260040160405180910390fd5b806001600160a01b0316826001600160a01b031603611c015760405163367558c360e01b815260040160405180910390fd5b6001600160a01b039182165f90815260156020526040902080546001600160a01b03191691909216179055565b5f82815260026020526040902060040154611c5c57604051635926e0c360e01b815260040160405180910390fd5b5f8281526002602052604090206001810154905415611c7857505f5b5f5460405163520337df60e11b815260048101859052602481018390526001600160a01b039091169063a4066fbe906044015f604051808303815f87803b158015611cc1575f5ffd5b505af1158015611cd3573d5f5f3e3d5ffd5b50505050818015611ce357508015155b15611056575f805484825260046020819052604092839020925163242a6e3f60e01b81526001600160a01b039092169263242a6e3f92611d269288929101614b8a565b5f604051808303815f87803b158015611d3d575f5ffd5b505af1158015611d4f573d5f5f3e3d5ffd5b50505050505050565b336001600160a01b038216611d805760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038181165f90815260156020526040902054811690831614611dbc57604051630fe3b3c160e31b815260040160405180910390fd5b6001600160a01b039081165f9081526016602090815260408083208054949095166001600160a01b031994851617909455601590529190912080549091169055565b5f546001600160a01b03163314611e285760405163c78d372960e01b815260040160405180910390fd5b5f600e5f611e346114f0565b81526020019081526020015f2090505f5f90505b82811015611eaa575f848483818110611e6357611e63614b76565b602090810292909201355f81815260028452604080822060010154948890529020839055600c860154909350611e9b91508290614af9565b600c8501555050600101611e48565b50611eb960078201848461456f565b50505050565b611ec76129fd565b601280546001600160a01b0319166001600160a01b0392909216919091179055565b5f546001600160a01b03163314611f135760405163c78d372960e01b815260040160405180910390fd5b5f600e5f611f1f6114f0565b81526020019081526020015f2090505f81600701805480602002602001604051908101604052809291908181526020018280548015611f7b57602002820191905f5260205f20905b815481526020019060010190808311611f67575b5050505050905061200082828c8c808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061321f92505050565b600180545f908152600e60205260409020600881015490919042111561203257600882015461202f9042614c18565b90505b6120b2818584868c8c808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061343992505050565b6120f1818584868c8c808060200260200160405190810160405280939291908181526020018383602002808284375f92019190915250613b7392505050565b50506120fb6114f0565b6001554260088301554360098301556011546040805163d9a7c1f960e01b815290516001600160a01b039092169163d9a7c1f9916004808201926020929091908290030181865afa158015612152573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121769190614b5f565b600b83015550600d80549101555050505050505050565b6121956129fd565b6001600160a01b0381166121c357604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6117a281612d4a565b5f6121d78383612a58565b506001600160a01b0383165f9081526009602090815260408083208584529091528120549081900361221c5760405163899aaa9d60e01b815260040160405180910390fd5b6001600160a01b0384165f908152600960209081526040808320868452909152812055612248816131ad565b9392505050565b5f8281526002602052604090206004015461227d57604051635926e0c360e01b815260040160405180910390fd5b5f82815260026020526040902054156122a9576040516353670afb60e11b815260040160405180910390fd5b6122b6838383600161305f565b6122bf82613df1565b6110565760405163c2eb4ead60e01b815260040160405180910390fd5b6001600160a01b038082165f9081526016602052604081205490911680611492575090919050565b5f8281526002602052604090205415801561231e57508015155b15612345575f828152600260205260409020600101546007546123419190614c18565b6007555b5f828152600260205260409020548111156111d8575f8281526002602052604081208281556006015490036123d45761237c6114f0565b5f8381526002602090815260409182902060068101849055426005909101819055825193845290830152805184927fac4801c32a6067ff757446524ee4e7a373797278ac3c883eac5c693b4ad72e4792908290030190a25b817fcd35267e7654194727477d6c78b541a553483cff7f92a055d17868d3da6e953e826040516112d291815260200190565b6012546001600160a01b031615611056576012546040516001600160a01b03858116602483015284811660448301525f921690627a12009060640160408051601f198184030181529181526020820180516001600160e01b0316631fbcb08360e11b179052516124769190614c2b565b5f604051808303815f8787f1925050503d805f81146124b0576040519150601f19603f3d011682016040523d82523d5f602084013e6124b5565b606091505b50509050801580156124c45750815b15611eb9576040516347b4be6960e11b815260040160405180910390fd5b6124ea613ea8565b6117a281613ef1565b6114ee613ea8565b6001600160a01b0384165f908152600b60209081526040808320868452825280832085845282528083208151606081018352815480825260018301549482019490945260029091015491810191909152910361256a57604051630fe3b3c160e31b815260040160405180910390fd5b60208082015182515f8781526002909352604090922060050154909190158015906125a457505f8681526002602052604090206005015482115b156125c45750505f84815260026020526040902060058101546006909101545b60115f9054906101000a90046001600160a01b03166001600160a01b031663b82b84276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612614573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126389190614b5f565b6126429083614af9565b42101561266257604051635ada9a9960e01b815260040160405180910390fd5b60115f9054906101000a90046001600160a01b03166001600160a01b031663650acd666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126d69190614b5f565b6126e09082614af9565b6126e86114f0565b1015612707576040516323ea994d60e01b815260040160405180910390fd5b6001600160a01b0387165f908152600b60209081526040808320898452825280832088845282528083206002908101548a855290835281842054600f9093529083205490926080909216151591906127629084908490613ef9565b6001600160a01b038b165f908152600b602090815260408083208d845282528083208c84529091528120818155600181018290556002015590508083116127bc576040516318f967fb60e01b815260040160405180910390fd5b5f6001600160a01b0388166127d18386614c18565b6040515f81818185875af1925050503d805f811461280a576040519150601f19603f3d011682016040523d82523d5f602084013e61280f565b606091505b5050905080612831576040516312171d8360e31b815260040160405180910390fd5b61283a82612f65565b888a6001600160a01b038d167f94ffd6b85c71b847775c89ef6496b93cee961bdc6ff827fd117f174f06f745ae6128718689614c18565b60408051918252602082018890520160405180910390a45050505050505050505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061291b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661290f5f516020614ef15f395f51905f52546001600160a01b031690565b6001600160a01b031614155b156114ee5760405163703e46dd60e11b815260040160405180910390fd5b6117a26129fd565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561299b575060408051601f3d908101601f1916820190925261299891810190614b5f565b60015b6129c357604051634c9c8ce360e01b81526001600160a01b03831660048201526024016121ba565b5f516020614ef15f395f51905f5281146129f357604051632a87526960e21b8152600481018290526024016121ba565b6110568383613f5f565b33612a2f7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146114ee5760405163118cdaa760e01b81523360048201526024016121ba565b5f5f612a648484612ce0565b9050612a6f83613fb4565b6001600160a01b0385165f818152600a60209081526040808320888452825280832094909455918152600982528281208682529091529081208054839290612ab8908490614af9565b909155505015159392505050565b6001600160a01b0386165f908152600c6020908152604080832088845290915281208054869290612af8908490614c18565b90915550505f85815260026020526040902060010154612b19908590614c18565b5f86815260026020526040902060010155600654612b38908590614c18565b6006555f85815260026020526040902054612b5f5783600754612b5b9190614c18565b6007555b5f612b6986611446565b90508015801590612b8557505f86815260026020526040902054155b15612c655760115f9054906101000a90046001600160a01b03166001600160a01b031663c5f530af6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bda573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bfe9190614b5f565b811015612c2f578215612c245760405163047447a360e11b815260040160405180910390fd5b612c2f866001612304565b818015612c425750612c4086613df1565b155b15612c605760405163c2eb4ead60e01b815260040160405180910390fd5b612c70565b612c70866001612304565b5f8681526002602081905260409091200154611d4f9088906001600160a01b031686612406565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146114ee5760405163703e46dd60e11b815260040160405180910390fd5b6001600160a01b0382165f908152600a6020908152604080832084845290915281205481612d0d84613fb4565b6001600160a01b0386165f908152600c60209081526040808320888452909152812054919250612d3f82878686614009565b979650505050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b6001600160a01b0389165f9081526003602052604090205415612df057604051633f4dc7d360e11b815260040160405180910390fd5b6001600160a01b0389165f8181526003602081815260408084208d90558c845260028083528185208b81559384018a905560048085018a90556005850188905560068501899055930180546001600160a01b0319169095179094555220612e58878983614c85565b508760135f612e678a8a613005565b6001600160a01b03166001600160a01b031681526020019081526020015f2081905550886001600160a01b0316887f49bca1ed2666922f9f1690c26a569e1299c2a715fe57647d77e81adfabbf25bf8686604051612ecf929190918252602082015260400190565b60405180910390a38115612f1957604080518381526020810183905289917fac4801c32a6067ff757446524ee4e7a373797278ac3c883eac5c693b4ad72e47910160405180910390a25b8415612f5a57877fcd35267e7654194727477d6c78b541a553483cff7f92a055d17868d3da6e953e86604051612f5191815260200190565b60405180910390a25b505050505050505050565b80156117a257600d54811115612f8e57604051632ad907fb60e01b815260040160405180910390fd5b80600d5f828254612f9f9190614c18565b90915550506040515f9082156108fc0290839083818181858288f19350505050158015612fce573d5f5f3e3d5ffd5b506040518181527f66ac49f046ee1185a59a920bbdfe95faba2bba02afc4b64a97ac35d5d14acc479060200160405180910390a150565b5f6130138260028186614d3e565b604051613021929190614d65565b6040519081900390209392505050565b5f60055f815461304090614d74565b91829055509050611eb9848285855f6130576114f0565b425f5f612dba565b815f0361307f57604051631f2a200560e01b815260040160405180910390fd5b6130898484612a58565b506001600160a01b0384165f908152600c602090815260408083208684529091529020546130b8908390614af9565b6001600160a01b0385165f908152600c602090815260408083208784528252808320939093556002905220600101546130f18382614af9565b5f85815260026020526040902060010155600654613110908490614af9565b6006555f8481526002602052604090205461313757826007546131339190614af9565b6007555b613142848215611c2e565b83856001600160a01b03167f9a8f44850296624dadfd9c246d17e47171d35727a181bd090aa14bbbe00238bb8560405161317e91815260200190565b60405180910390a35f84815260026020819052604090912001546115509086906001600160a01b031684612406565b5f546040516366e7ea0f60e01b8152306004820152602481018390526001600160a01b03909116906366e7ea0f906044015f604051808303815f87803b1580156131f5575f5ffd5b505af1158015613207573d5f5f3e3d5ffd5b5050505080600d546132199190614af9565b600d5550565b5f5b83518110156115505760115f9054906101000a90046001600160a01b03166001600160a01b0316635a68f01a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561327a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061329e9190614b5f565b8282815181106132b0576132b0614b76565b6020026020010151118015613350575060115f9054906101000a90046001600160a01b03166001600160a01b031662cc7f836040518163ffffffff1660e01b8152600401602060405180830381865afa15801561330f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133339190614b5f565b83828151811061334557613345614b76565b602002602001015110155b1561339c5761337984828151811061336a5761336a614b76565b60200260200101516008612304565b61339c84828151811061338e5761338e614b76565b60200260200101515f611c2e565b8281815181106133ae576133ae614b76565b6020026020010151856005015f8684815181106133cd576133cd614b76565b602002602001015181526020019081526020015f20819055508181815181106133f8576133f8614b76565b6020026020010151856006015f86848151811061341757613417614b76565b60209081029190910181015182528101919091526040015f2055600101613221565b5f6040518060a0016040528085516001600160401b0381111561345e5761345e6146bf565b604051908082528060200260200182016040528015613487578160200160208202803683370190505b5081526020015f815260200185516001600160401b038111156134ac576134ac6146bf565b6040519080825280602002602001820160405280156134d5578160200160208202803683370190505b5081526020015f81526020015f81525090505f5f90505b8451811015613615575f866004015f87848151811061350d5761350d614b76565b602002602001015181526020019081526020015f205490505f5f90508185848151811061353c5761353c614b76565b60200260200101511115613572578185848151811061355d5761355d614b76565b602002602001015161356f9190614c18565b90505b8986848151811061358557613585614b76565b6020026020010151826135989190614d8c565b6135a29190614db7565b846040015184815181106135b8576135b8614b76565b602002602001018181525050836040015183815181106135da576135da614b76565b602002602001015184606001516135f19190614af9565b60608501526080840151613606908290614af9565b608085015250506001016134ec565b505f5b8451811015613702578784828151811061363457613634614b76565b60200260200101518986848151811061364f5761364f614b76565b60200260200101518a5f015f8a878151811061366d5761366d614b76565b602002602001015181526020019081526020015f205461368d9190614d8c565b6136979190614db7565b6136a19190614d8c565b6136ab9190614db7565b82518051839081106136bf576136bf614b76565b602090810291909101015281518051829081106136de576136de614b76565b602002602001015182602001516136f59190614af9565b6020830152600101613618565b505f5b8451811015613a06575f6137ad8960115f9054906101000a90046001600160a01b03166001600160a01b031663d9a7c1f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613763573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137879190614b5f565b855180518690811061379b5761379b614b76565b60200260200101518660200151614072565b90506137df8360800151846040015184815181106137cd576137cd614b76565b602002602001015185606001516140ad565b6137e99082614af9565b90505f8683815181106137fe576137fe614b76565b6020908102919091018101515f8181526002808452604080832090910154601154825163a778651560e01b815292519496506001600160a01b03918216959394613896948994929093169263a778651592600480820193918290030181865afa15801561386d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138919190614b5f565b6141fe565b6001600160a01b0383165f908152600c6020908152604080832087845290915290205490915080156138fa576001600160a01b0383165f908152600960209081526040808320878452909152812080548492906138f4908490614af9565b90915550505b5f6139058387614c18565b5f86815260026020526040812060010154919250811561393f5781613932670de0b6b3a764000085614d8c565b61393c9190614db7565b90505b5f87815260018f01602052604090205461395a908290614af9565b8f6001015f8981526020019081526020015f20819055508a898151811061398357613983614b76565b60200260200101518f6004015f8981526020019081526020015f20819055508b89815181106139b4576139b4614b76565b60200260200101518e6002015f8981526020019081526020015f20546139da9190614af9565b8f6002015f8981526020019081526020015f208190555050505050505050508080600101915050613705565b506080810151600a8701819055600d541115613a3c5785600a0154600d5f828254613a319190614c18565b90915550613a419050565b5f600d555b6010546001600160a01b031615611d4f575f670de0b6b3a764000060115f9054906101000a90046001600160a01b03166001600160a01b03166394c3e9146040518163ffffffff1660e01b8152600401602060405180830381865afa158015613aac573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ad09190614b5f565b8360800151613adf9190614d8c565b613ae99190614db7565b9050613af4816131ad565b6010546040515f916001600160a01b031690620f424090849084818181858888f193505050503d805f8114613b44576040519150601f19603f3d011682016040523d82523d5f602084013e613b49565b606091505b5050905080612f5a578160085f828254613b639190614af9565b9091555050505050505050505050565b5f5b8251811015613de9575f838281518110613b9157613b91614b76565b602002602001015190505f87613bac670de0b6b3a764000090565b858581518110613bbe57613bbe614b76565b6020026020010151613bd09190614d8c565b613bda9190614db7565b9050670de0b6b3a7640000811115613bf75750670de0b6b3a76400005b5f8281526003870160209081526040808320815160608101835290546001600160401b038116825263ffffffff600160401b8204811694830194909452600160601b90049092169082015290613c4d838361421c565b5f85815260038b0160209081526040918290208351815485840151868601516001600160401b039093166bffffffffffffffffffffffff1990921691909117600160401b63ffffffff928316021763ffffffff60601b1916600160601b91909216021790556011548251631c25433760e01b815292519394506001600160a01b031692631c2543379260048082019392918290030181865afa158015613cf5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d199190614dca565b6001600160401b0316815f01516001600160401b0316108015613dbf575060115f9054906101000a90046001600160a01b03166001600160a01b0316633fa225486040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d87573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613dab9190614df0565b63ffffffff16816040015163ffffffff1610155b15613dd957613dcf846010612304565b613dd9845f611c2e565b505060019092019150613b759050565b505050505050565b5f670de0b6b3a764000060115f9054906101000a90046001600160a01b03166001600160a01b0316632265f2846040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e4b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e6f9190614b5f565b613e7884611446565b613e829190614d8c565b613e8c9190614db7565b5f92835260026020526040909220600101549190911115919050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166114ee57604051631afcd79f60e31b815260040160405180910390fd5b612195613ea8565b5f821580613f0f5750670de0b6b3a76400008210155b15613f1b57505f612248565b670de0b6b3a7640000613f2e8382614c18565b613f389086614d8c565b613f429190614db7565b613f4d906001614af9565b90508381111561224857509192915050565b613f68826143ff565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a2805115613fac576110568282614462565b6111d86144cb565b5f8181526002602052604081206006015415614001575f828152600260205260409020600601546001541015613fec57505060015490565b505f9081526002602052604090206006015490565b505060015490565b5f81831061401857505f6114d5565b5f838152600e6020818152604080842088855260019081018352818520548786529383528185208986520190915290912054670de0b6b3a76400008761405e8484614c18565b6140689190614d8c565b612d3f9190614db7565b5f825f0361408157505f6114d5565b5f61408c8587614d8c565b9050826140998583614d8c565b6140a39190614db7565b9695505050505050565b5f825f036140bc57505f612248565b5f826140c88587614d8c565b6140d29190614db7565b9050670de0b6b3a764000060115f9054906101000a90046001600160a01b03166001600160a01b03166394c3e9146040518163ffffffff1660e01b8152600401602060405180830381865afa15801561412d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141519190614b5f565b60115f9054906101000a90046001600160a01b03166001600160a01b031663c74dd6216040518163ffffffff1660e01b8152600401602060405180830381865afa1580156141a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141c59190614b5f565b6141d790670de0b6b3a7640000614c18565b6141e19190614c18565b6141eb9083614d8c565b6141f59190614db7565b95945050505050565b5f670de0b6b3a76400006142128385614d8c565b6122489190614db7565b604080516060810182525f8082526020820181905291810191909152604080516060810182525f8082526020820181905291810191909152826040015163ffffffff165f0361427f576001600160401b0384168152600160408201529050611492565b5f836040015160016142919190614e13565b63ffffffff1690505f846020015163ffffffff16866001600160401b0316865f01516001600160401b03166001856142c99190614e2f565b6142d39190614e4e565b6142dd9190614e77565b6142e79190614e77565b90506142f38282614e96565b6001600160401b031683526143088282614ec3565b63ffffffff166020840152670de0b6b3a764000083516001600160401b0316111561433957670de0b6b3a764000083525b60115f9054906101000a90046001600160a01b03166001600160a01b0316633fa225486040518163ffffffff1660e01b8152600401602060405180830381865afa158015614389573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143ad9190614df0565b63ffffffff16856040015163ffffffff1610156143e45760408501516143d4906001614e13565b63ffffffff1660408401526143f5565b60408086015163ffffffff16908401525b5090949350505050565b806001600160a01b03163b5f0361443457604051634c9c8ce360e01b81526001600160a01b03821660048201526024016121ba565b5f516020614ef15f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b03168460405161447e9190614c2b565b5f60405180830381855af49150503d805f81146144b6576040519150601f19603f3d011682016040523d82523d5f602084013e6144bb565b606091505b50915091506141f58583836144ea565b34156114ee5760405163b398979f60e01b815260040160405180910390fd5b6060826144ff576144fa82614546565b612248565b815115801561451657506001600160a01b0384163b155b1561453f57604051639996b31560e01b81526001600160a01b03851660048201526024016121ba565b5080612248565b8051156145565780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b828054828255905f5260205f209081019282156145a8579160200282015b828111156145a857823582559160200191906001019061458d565b506145b49291506145b8565b5090565b5b808211156145b4575f81556001016145b9565b6001600160a01b03811681146117a2575f5ffd5b5f602082840312156145f0575f5ffd5b8135612248816145cc565b5f6020828403121561460b575f5ffd5b5035919050565b5f5f60408385031215614623575f5ffd5b50508035926020909101359150565b5f5f5f60608486031215614644575f5ffd5b833561464f816145cc565b95602085013595506040909401359392505050565b5f5f5f5f5f60a08688031215614678575f5ffd5b85359450602086013593506040860135614691816145cc565b925060608601356146a1816145cc565b915060808601356146b1816145cc565b809150509295509295909350565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156146e4575f5ffd5b82356146ef816145cc565b915060208301356001600160401b03811115614709575f5ffd5b8301601f81018513614719575f5ffd5b80356001600160401b03811115614732576147326146bf565b604051601f8201601f19908116603f011681016001600160401b0381118282101715614760576147606146bf565b604052818152828201602001871015614777575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f5f5f606084860312156147a8575f5ffd5b505081359360208301359350604090920135919050565b5f5f604083850312156147d0575f5ffd5b82356147db816145cc565b946020939093013593505050565b5f5f83601f8401126147f9575f5ffd5b5081356001600160401b0381111561480f575f5ffd5b602083019150836020828501011115614826575f5ffd5b9250929050565b5f5f5f5f5f60808688031215614841575f5ffd5b853561484c816145cc565b94506020860135935060408601356001600160401b0381111561486d575f5ffd5b614879888289016147e9565b96999598509660600135949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f612248602083018461488b565b5f5f602083850312156148dc575f5ffd5b82356001600160401b038111156148f1575f5ffd5b6148fd858286016147e9565b90969095509350505050565b602080825282518282018190525f918401906040840190835b81811015614940578351835260209384019390920191600101614922565b509095945050505050565b5f5f6040838503121561495c575f5ffd5b8235614967816145cc565b91506020830135614977816145cc565b809150509250929050565b5f5f60408385031215614993575f5ffd5b8235915060208301358015158114614977575f5ffd5b5f5f83601f8401126149b9575f5ffd5b5081356001600160401b038111156149cf575f5ffd5b6020830191508360208260051b8501011115614826575f5ffd5b5f5f602083850312156149fa575f5ffd5b82356001600160401b03811115614a0f575f5ffd5b6148fd858286016149a9565b5f5f5f5f5f5f5f5f6080898b031215614a32575f5ffd5b88356001600160401b03811115614a47575f5ffd5b614a538b828c016149a9565b90995097505060208901356001600160401b03811115614a71575f5ffd5b614a7d8b828c016149a9565b90975095505060408901356001600160401b03811115614a9b575f5ffd5b614aa78b828c016149a9565b90955093505060608901356001600160401b03811115614ac5575f5ffd5b614ad18b828c016149a9565b999c989b5096995094979396929594505050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561149257611492614ae5565b600181811c90821680614b2057607f821691505b602082108103614b3e57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215614b54575f5ffd5b8151612248816145cc565b5f60208284031215614b6f575f5ffd5b5051919050565b634e487b7160e01b5f52603260045260245ffd5b828152604060208201525f5f8354614ba181614b0c565b806040860152600182165f8114614bbf5760018114614bdb57614c0c565b60ff1983166060870152606082151560051b8701019350614c0c565b865f5260205f205f5b83811015614c0357815488820160600152600190910190602001614be4565b87016060019450505b50919695505050505050565b8181038181111561149257611492614ae5565b5f82518060208501845e5f920191825250919050565b601f82111561105657805f5260205f20601f840160051c81016020851015614c665750805b601f840160051c820191505b81811015611550575f8155600101614c72565b6001600160401b03831115614c9c57614c9c6146bf565b614cb083614caa8354614b0c565b83614c41565b5f601f841160018114614ce1575f8515614cca5750838201355b5f19600387901b1c1916600186901b178355611550565b5f83815260208120601f198716915b82811015614d105786850135825560209485019460019092019101614cf0565b5086821015614d2c575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b5f5f85851115614d4c575f5ffd5b83861115614d58575f5ffd5b5050820193919092039150565b818382375f9101908152919050565b5f60018201614d8557614d85614ae5565b5060010190565b808202811582820484141761149257611492614ae5565b634e487b7160e01b5f52601260045260245ffd5b5f82614dc557614dc5614da3565b500490565b5f60208284031215614dda575f5ffd5b81516001600160401b0381168114612248575f5ffd5b5f60208284031215614e00575f5ffd5b815163ffffffff81168114612248575f5ffd5b63ffffffff818116838216019081111561149257611492614ae5565b6001600160801b03828116828216039081111561149257611492614ae5565b6001600160801b038181168382160290811690818114614e7057614e70614ae5565b5092915050565b6001600160801b03818116838216019081111561149257611492614ae5565b5f6001600160801b03831680614eae57614eae614da3565b806001600160801b0384160491505092915050565b5f6001600160801b03831680614edb57614edb614da3565b806001600160801b038416069150509291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212202c157fddf75482e9928130a6824fe60a3cb8e4a7a69e7e8a5a01f582673d363e64736f6c634300081b0033
Deployed Bytecode
0x6080604052600436106103d7575f3560e01c80638b0e9f3f116101ff578063c65ee0e111610113578063dc31e1af116100a8578063e880a15911610078578063e880a15914610df9578063e9a505a714610e18578063ebdf104c14610e37578063f2fde38b14610e56578063fb36025f14610e75575f5ffd5b8063dc31e1af14610d2c578063df00c92214610d66578063e08d7e6614610da0578063e261641a14610dbf575f5ffd5b8063cfd47663116100e3578063cfd4766314610c8c578063d46fa51814610cc2578063d725e91f14610cdf578063db5ca3e514610cfe575f5ffd5b8063c65ee0e114610c0e578063c7be95de14610c39578063cc17278414610c4e578063cc8343aa14610c6d575f5ffd5b8063a86a056f11610194578063b0ef386c11610164578063b0ef386c14610ac1578063b5d8962714610ae0578063b88a37e214610b83578063c3de580e14610baf578063c5f956af14610bef575f5ffd5b8063a86a056f146109e1578063a8ab09ba14610a17578063aa5d829214610a36578063ad3cb1cc14610a91575f5ffd5b80639fa6dd35116101cf5780639fa6dd3514610962578063a198d22914610975578063a5820daa146109af578063a5a470ad146109ce575f5ffd5b80638b0e9f3f146108dd5780638cddb015146108f25780638d2da32e146109115780638da5cb5b14610926575f5ffd5b806352d1902d116102f6578063736de9ae1161028b578063841e45611161025b578063841e45611461085757806384b863e014610876578063850a10c01461088a578063854873e114610892578063860c2750146108be575f5ffd5b8063736de9ae146107db578063766718081461080f57806376fed43a146108235780637cacb1d614610842575f5ffd5b80636099ecb2116102c65780636099ecb21461072d57806361e53fcc1461074c5780636f49866314610786578063715018a6146107c7575f5ffd5b806352d1902d146106bd57806354fd4d50146106d15780635601fe01146106ef57806358f95b801461070e575f5ffd5b806339b80c001161036c57806346f1ca351161033c57806346f1ca351461064d5780634f1ef2861461066c5780634f7c4efb1461067f5780634f864df41461069e575f5ffd5b806339b80c001461055d5780633fbfd4df146105db578063441a3e70146105fa578063468f35ee14610619575f5ffd5b806318160ddd116103a757806318160ddd146104ae5780631e702f83146104c35780631f270152146104e257806328f7314814610548575f5ffd5b80630135b1db146103f957806308c3687414610437578063093b41d0146104585780630962ef791461048f575f5ffd5b366103f55760405163ab064ad360e01b815260040160405180910390fd5b5f5ffd5b348015610404575f5ffd5b506104246104133660046145e0565b60036020525f908152604090205481565b6040519081526020015b60405180910390f35b348015610442575f5ffd5b506104566104513660046145fb565b610ea0565b005b348015610463575f5ffd5b50601254610477906001600160a01b031681565b6040516001600160a01b03909116815260200161042e565b34801561049a575f5ffd5b506104566104a93660046145fb565b610f02565b3480156104b9575f5ffd5b50610424600d5481565b3480156104ce575f5ffd5b506104566104dd366004614612565b610fd2565b3480156104ed575f5ffd5b5061052d6104fc366004614632565b600b60209081525f938452604080852082529284528284209052825290208054600182015460029092015490919083565b6040805193845260208401929092529082015260600161042e565b348015610553575f5ffd5b5061042460075481565b348015610568575f5ffd5b506105ae6105773660046145fb565b600e6020525f9081526040902060088101546009820154600a830154600b840154600c850154600d90950154939492939192909186565b604080519687526020870195909552938501929092526060840152608083015260a082015260c00161042e565b3480156105e6575f5ffd5b506104566105f5366004614664565b61105b565b348015610605575f5ffd5b50610456610614366004614612565b6111c4565b348015610624575f5ffd5b506104776106333660046145e0565b60156020525f90815260409020546001600160a01b031681565b348015610658575f5ffd5b506104566106673660046145e0565b6111dc565b61045661067a3660046146d3565b611214565b34801561068a575f5ffd5b50610456610699366004614612565b61122f565b3480156106a9575f5ffd5b506104566106b8366004614796565b6112de565b3480156106c8575f5ffd5b5061042461142b565b3480156106dc575f5ffd5b50604051600160fa1b815260200161042e565b3480156106fa575f5ffd5b506104246107093660046145fb565b611446565b348015610719575f5ffd5b50610424610728366004614612565b611478565b348015610738575f5ffd5b506104246107473660046147bf565b611498565b348015610757575f5ffd5b50610424610766366004614612565b5f918252600e602090815260408084209284526001909201905290205490565b348015610791575f5ffd5b506104246107a03660046147bf565b6001600160a01b03919091165f908152600960209081526040808320938352929052205490565b3480156107d2575f5ffd5b506104566114dd565b3480156107e6575f5ffd5b506104776107f53660046145e0565b60166020525f90815260409020546001600160a01b031681565b34801561081a575f5ffd5b506104246114f0565b34801561082e575f5ffd5b5061045661083d36600461482d565b611505565b34801561084d575f5ffd5b5061042460015481565b348015610862575f5ffd5b506104566108713660046145e0565b611557565b348015610881575f5ffd5b50610456611581565b610456611686565b34801561089d575f5ffd5b506108b16108ac3660046145fb565b6116af565b60405161042e91906148b9565b3480156108c9575f5ffd5b506104566108d83660046145e0565b611746565b3480156108e8575f5ffd5b5061042460065481565b3480156108fd575f5ffd5b5061045661090c3660046147bf565b611770565b34801561091c575f5ffd5b5061042460085481565b348015610931575f5ffd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610477565b6104566109703660046145fb565b611797565b348015610980575f5ffd5b5061042461098f366004614612565b5f918252600e602090815260408084209284526006909201905290205490565b3480156109ba575f5ffd5b506104566109c93660046145fb565b6117a5565b6104566109dc3660046148cb565b611928565b3480156109ec575f5ffd5b506104246109fb3660046147bf565b600a60209081525f928352604080842090915290825290205481565b348015610a22575f5ffd5b50610456610a31366004614632565b611a6f565b348015610a41575f5ffd5b50610a79610a50366004614612565b5f918252600e60209081526040808420928452600390920190529020546001600160401b031690565b6040516001600160401b03909116815260200161042e565b348015610a9c575f5ffd5b506108b1604051806040016040528060058152602001640352e302e360dc1b81525081565b348015610acc575f5ffd5b50610456610adb3660046145e0565b611aae565b348015610aeb575f5ffd5b50610b40610afa3660046145fb565b600260208190525f918252604090912080546001820154928201546003830154600484015460058501546006909501549395946001600160a01b03909316939192909187565b6040805197885260208801969096526001600160a01b03909416948601949094526060850191909152608084015260a083019190915260c082015260e00161042e565b348015610b8e575f5ffd5b50610ba2610b9d3660046145fb565b611b06565b60405161042e9190614909565b348015610bba575f5ffd5b50610bdf610bc93660046145fb565b5f90815260026020526040902054608016151590565b604051901515815260200161042e565b348015610bfa575f5ffd5b50601054610477906001600160a01b031681565b348015610c19575f5ffd5b50610424610c283660046145fb565b600f6020525f908152604090205481565b348015610c44575f5ffd5b5061042460055481565b348015610c59575f5ffd5b50610456610c6836600461494b565b611b68565b348015610c78575f5ffd5b50610456610c87366004614982565b611c2e565b348015610c97575f5ffd5b50610424610ca63660046147bf565b600c60209081525f928352604080842090915290825290205481565b348015610ccd575f5ffd5b506011546001600160a01b0316610477565b348015610cea575f5ffd5b50610456610cf93660046145e0565b611d58565b348015610d09575f5ffd5b50610424610d183660046145fb565b5f908152600e602052604090206009015490565b348015610d37575f5ffd5b50610424610d46366004614612565b5f918252600e602090815260408084209284526004909201905290205490565b348015610d71575f5ffd5b50610424610d80366004614612565b5f918252600e602090815260408084209284526002909201905290205490565b348015610dab575f5ffd5b50610456610dba3660046149e9565b611dfe565b348015610dca575f5ffd5b50610424610dd9366004614612565b5f918252600e602090815260408084209284526005909201905290205490565b348015610e04575f5ffd5b50610456610e133660046145e0565b611ebf565b348015610e23575f5ffd5b50601454610477906001600160a01b031681565b348015610e42575f5ffd5b50610456610e51366004614a1b565b611ee9565b348015610e61575f5ffd5b50610456610e703660046145e0565b61218d565b348015610e80575f5ffd5b50610424610e8f3660046145e0565b60136020525f908152604090205481565b335f610eac82846121cc565b9050610eb982848361224f565b82826001600160a01b03167f663e0f63f4fc6b01be195c4b56111fd6f14b947d6264497119b08daf77e26da583604051610ef591815260200190565b60405180910390a3505050565b335f610f0e82846121cc565b90505f610f1a836122dc565b6001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610f61576040519150601f19603f3d011682016040523d82523d5f602084013e610f66565b606091505b5050905080610f88576040516312171d8360e31b815260040160405180910390fd5b83836001600160a01b03167f70de20a533702af05c8faf1637846c4586a021bbc71b6928b089b6d555e4fbc284604051610fc491815260200190565b60405180910390a350505050565b5f546001600160a01b03163314610ffc5760405163c78d372960e01b815260040160405180910390fd5b8061101a5760405163396bd83560e21b815260040160405180910390fd5b6110248282612304565b61102e825f611c2e565b5f828152600260208190526040822001546001600160a01b0316906110569082908190612406565b505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f8115801561109f5750825b90505f826001600160401b031660011480156110ba5750303b155b9050811580156110c8575080155b156110e65760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561111057845460ff60401b1916600160401b1785555b611119866124e2565b6111216124f3565b60018a90555f80546001600160a01b03808b166001600160a01b03199283161790925560118054928a1692909116919091179055600d8990556111614290565b5f8b8152600e602052604090206008015583156111b857845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b6111d83383836111d3336122dc565b6124fb565b5050565b6040516001600160a01b0382169033907f857125196131cfcd709c738c6d1fd2701ce70f2a03785aeadae6f4b47fe73c1d905f90a350565b61121c612895565b61122582612939565b6111d88282612941565b6112376129fd565b5f82815260026020526040902054608016611265576040516321b6a8f960e11b815260040160405180910390fd5b670de0b6b3a764000081111561128e576040516357c70d6360e01b815260040160405180910390fd5b5f828152600f6020526040908190208290555182907f047575f43f09a7a093d94ec483064acfc61b7e25c0de28017da442abf99cb917906112d29084815260200190565b60405180910390a25050565b336112e98185612a58565b50815f0361130a57604051631f2a200560e01b815260040160405180910390fd5b6001600160a01b0381165f908152600b602090815260408083208784528252808320868452909152902060020154156113565760405163756f5c2d60e11b815260040160405180910390fd5b61136681858460015f6001612ac6565b6001600160a01b0381165f908152600b602090815260408083208784528252808320868452909152902060020182905561139e6114f0565b6001600160a01b0382165f908152600b6020908152604080832088845282528083208784529091528120918255426001909201919091556113e0908590611c2e565b8284826001600160a01b03167fd3bb4e423fbea695d16b982f9f682dc5f35152e5411646a8a5a79a6b02ba8d578560405161141d91815260200190565b60405180910390a450505050565b5f611434612c97565b505f516020614ef15f395f51905f5290565b5f818152600260208181526040808420909201546001600160a01b03168352600c815281832093835292909252205490565b5f828152600e602090815260408083208484529091529020545b92915050565b5f5f6114a48484612ce0565b6001600160a01b0385165f9081526009602090815260408083208784529091529020549091506114d5908290614af9565b949350505050565b6114e56129fd565b6114ee5f612d4a565b565b5f60015460016115009190614af9565b905090565b5f546001600160a01b0316331461152f5760405163c78d372960e01b815260040160405180910390fd5b611540858585855f5f875f5f612dba565b6005548411156115505760058490555b5050505050565b61155f6129fd565b601080546001600160a01b0319166001600160a01b0392909216919091179055565b6010546001600160a01b03166115aa5760405163b2c4cce960e01b815260040160405180910390fd5b6008545f036115cc5760405163211a852360e21b815260040160405180910390fd5b600880545f918290556010546040519192916001600160a01b0390911690620f424090849084818181858888f193505050503d805f8114611628576040519150601f19603f3d011682016040523d82523d5f602084013e61162d565b606091505b505090508061164f576040516312171d8360e31b815260040160405180910390fd5b6040518281527f6dd5bb8ebf4cfb647c1cc0e9364ed9ecbf56202f7d3c9f058473df82664478d89060200160405180910390a15050565b345f036116a657604051631f2a200560e01b815260040160405180910390fd5b6114ee34612f65565b60046020525f9081526040902080546116c790614b0c565b80601f01602080910402602001604051908101604052809291908181526020018280546116f390614b0c565b801561173e5780601f106117155761010080835404028352916020019161173e565b820191905f5260205f20905b81548152906001019060200180831161172157829003601f168201915b505050505081565b61174e6129fd565b601180546001600160a01b0319166001600160a01b0392909216919091179055565b61177a8282612a58565b6111d85760405163208e0a4160e11b815260040160405180910390fd5b6117a233823461224f565b50565b6117ad6129fd565b601154604080516375840fab60e01b815290515f926001600160a01b0316916375840fab9160048083019260209291908290030181865afa1580156117f4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118189190614b44565b6001600160a01b03160361183f5760405163d92e233d60e01b815260040160405180910390fd5b5f54601154604080516375840fab60e01b815290516001600160a01b03938416936366e7ea0f9316916375840fab9160048083019260209291908290030181865afa158015611890573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118b49190614b44565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044015f604051808303815f87803b1580156118f9575f5ffd5b505af115801561190b573d5f5f3e3d5ffd5b5050505080600d5f8282546119209190614af9565b909155505050565b60115f9054906101000a90046001600160a01b03166001600160a01b031663c5f530af6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611978573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061199c9190614b5f565b3410156119bc5760405163047447a360e11b815260040160405180910390fd5b6042811415806119f5575081815f8181106119d9576119d9614b76565b9050013560f81c60f81b6001600160f81b03191660c060f81b14155b15611a13576040516338497f4960e11b815260040160405180910390fd5b60135f611a208484613005565b6001600160a01b0316815260208101919091526040015f205415611a575760405163028aeb6760e21b815260040160405180910390fd5b611a62338383613031565b6111d8336005543461224f565b5f546001600160a01b03163314611a995760405163c78d372960e01b815260040160405180910390fd5b611aa58383835f61305f565b611056816131ad565b611ab66129fd565b6014546001600160a01b03808316911603611ae457604051639b92bed360e01b815260040160405180910390fd5b601480546001600160a01b0319166001600160a01b0392909216919091179055565b5f818152600e6020908152604091829020600701805483518184028101840190945280845260609392830182828015611b5c57602002820191905f5260205f20905b815481526020019060010190808311611b48575b50505050509050919050565b6014546001600160a01b03163314611b935760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b038281165f90815260166020526040902054818316911603611bcf5760405163eb81e1a360e01b815260040160405180910390fd5b806001600160a01b0316826001600160a01b031603611c015760405163367558c360e01b815260040160405180910390fd5b6001600160a01b039182165f90815260156020526040902080546001600160a01b03191691909216179055565b5f82815260026020526040902060040154611c5c57604051635926e0c360e01b815260040160405180910390fd5b5f8281526002602052604090206001810154905415611c7857505f5b5f5460405163520337df60e11b815260048101859052602481018390526001600160a01b039091169063a4066fbe906044015f604051808303815f87803b158015611cc1575f5ffd5b505af1158015611cd3573d5f5f3e3d5ffd5b50505050818015611ce357508015155b15611056575f805484825260046020819052604092839020925163242a6e3f60e01b81526001600160a01b039092169263242a6e3f92611d269288929101614b8a565b5f604051808303815f87803b158015611d3d575f5ffd5b505af1158015611d4f573d5f5f3e3d5ffd5b50505050505050565b336001600160a01b038216611d805760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038181165f90815260156020526040902054811690831614611dbc57604051630fe3b3c160e31b815260040160405180910390fd5b6001600160a01b039081165f9081526016602090815260408083208054949095166001600160a01b031994851617909455601590529190912080549091169055565b5f546001600160a01b03163314611e285760405163c78d372960e01b815260040160405180910390fd5b5f600e5f611e346114f0565b81526020019081526020015f2090505f5f90505b82811015611eaa575f848483818110611e6357611e63614b76565b602090810292909201355f81815260028452604080822060010154948890529020839055600c860154909350611e9b91508290614af9565b600c8501555050600101611e48565b50611eb960078201848461456f565b50505050565b611ec76129fd565b601280546001600160a01b0319166001600160a01b0392909216919091179055565b5f546001600160a01b03163314611f135760405163c78d372960e01b815260040160405180910390fd5b5f600e5f611f1f6114f0565b81526020019081526020015f2090505f81600701805480602002602001604051908101604052809291908181526020018280548015611f7b57602002820191905f5260205f20905b815481526020019060010190808311611f67575b5050505050905061200082828c8c808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061321f92505050565b600180545f908152600e60205260409020600881015490919042111561203257600882015461202f9042614c18565b90505b6120b2818584868c8c808060200260200160405190810160405280939291908181526020018383602002808284375f81840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061343992505050565b6120f1818584868c8c808060200260200160405190810160405280939291908181526020018383602002808284375f92019190915250613b7392505050565b50506120fb6114f0565b6001554260088301554360098301556011546040805163d9a7c1f960e01b815290516001600160a01b039092169163d9a7c1f9916004808201926020929091908290030181865afa158015612152573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121769190614b5f565b600b83015550600d80549101555050505050505050565b6121956129fd565b6001600160a01b0381166121c357604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6117a281612d4a565b5f6121d78383612a58565b506001600160a01b0383165f9081526009602090815260408083208584529091528120549081900361221c5760405163899aaa9d60e01b815260040160405180910390fd5b6001600160a01b0384165f908152600960209081526040808320868452909152812055612248816131ad565b9392505050565b5f8281526002602052604090206004015461227d57604051635926e0c360e01b815260040160405180910390fd5b5f82815260026020526040902054156122a9576040516353670afb60e11b815260040160405180910390fd5b6122b6838383600161305f565b6122bf82613df1565b6110565760405163c2eb4ead60e01b815260040160405180910390fd5b6001600160a01b038082165f9081526016602052604081205490911680611492575090919050565b5f8281526002602052604090205415801561231e57508015155b15612345575f828152600260205260409020600101546007546123419190614c18565b6007555b5f828152600260205260409020548111156111d8575f8281526002602052604081208281556006015490036123d45761237c6114f0565b5f8381526002602090815260409182902060068101849055426005909101819055825193845290830152805184927fac4801c32a6067ff757446524ee4e7a373797278ac3c883eac5c693b4ad72e4792908290030190a25b817fcd35267e7654194727477d6c78b541a553483cff7f92a055d17868d3da6e953e826040516112d291815260200190565b6012546001600160a01b031615611056576012546040516001600160a01b03858116602483015284811660448301525f921690627a12009060640160408051601f198184030181529181526020820180516001600160e01b0316631fbcb08360e11b179052516124769190614c2b565b5f604051808303815f8787f1925050503d805f81146124b0576040519150601f19603f3d011682016040523d82523d5f602084013e6124b5565b606091505b50509050801580156124c45750815b15611eb9576040516347b4be6960e11b815260040160405180910390fd5b6124ea613ea8565b6117a281613ef1565b6114ee613ea8565b6001600160a01b0384165f908152600b60209081526040808320868452825280832085845282528083208151606081018352815480825260018301549482019490945260029091015491810191909152910361256a57604051630fe3b3c160e31b815260040160405180910390fd5b60208082015182515f8781526002909352604090922060050154909190158015906125a457505f8681526002602052604090206005015482115b156125c45750505f84815260026020526040902060058101546006909101545b60115f9054906101000a90046001600160a01b03166001600160a01b031663b82b84276040518163ffffffff1660e01b8152600401602060405180830381865afa158015612614573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126389190614b5f565b6126429083614af9565b42101561266257604051635ada9a9960e01b815260040160405180910390fd5b60115f9054906101000a90046001600160a01b03166001600160a01b031663650acd666040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126d69190614b5f565b6126e09082614af9565b6126e86114f0565b1015612707576040516323ea994d60e01b815260040160405180910390fd5b6001600160a01b0387165f908152600b60209081526040808320898452825280832088845282528083206002908101548a855290835281842054600f9093529083205490926080909216151591906127629084908490613ef9565b6001600160a01b038b165f908152600b602090815260408083208d845282528083208c84529091528120818155600181018290556002015590508083116127bc576040516318f967fb60e01b815260040160405180910390fd5b5f6001600160a01b0388166127d18386614c18565b6040515f81818185875af1925050503d805f811461280a576040519150601f19603f3d011682016040523d82523d5f602084013e61280f565b606091505b5050905080612831576040516312171d8360e31b815260040160405180910390fd5b61283a82612f65565b888a6001600160a01b038d167f94ffd6b85c71b847775c89ef6496b93cee961bdc6ff827fd117f174f06f745ae6128718689614c18565b60408051918252602082018890520160405180910390a45050505050505050505050565b306001600160a01b037f0000000000000000000000000ab8f3b709a52c096f33702fe8153776472305ed16148061291b57507f0000000000000000000000000ab8f3b709a52c096f33702fe8153776472305ed6001600160a01b031661290f5f516020614ef15f395f51905f52546001600160a01b031690565b6001600160a01b031614155b156114ee5760405163703e46dd60e11b815260040160405180910390fd5b6117a26129fd565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561299b575060408051601f3d908101601f1916820190925261299891810190614b5f565b60015b6129c357604051634c9c8ce360e01b81526001600160a01b03831660048201526024016121ba565b5f516020614ef15f395f51905f5281146129f357604051632a87526960e21b8152600481018290526024016121ba565b6110568383613f5f565b33612a2f7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146114ee5760405163118cdaa760e01b81523360048201526024016121ba565b5f5f612a648484612ce0565b9050612a6f83613fb4565b6001600160a01b0385165f818152600a60209081526040808320888452825280832094909455918152600982528281208682529091529081208054839290612ab8908490614af9565b909155505015159392505050565b6001600160a01b0386165f908152600c6020908152604080832088845290915281208054869290612af8908490614c18565b90915550505f85815260026020526040902060010154612b19908590614c18565b5f86815260026020526040902060010155600654612b38908590614c18565b6006555f85815260026020526040902054612b5f5783600754612b5b9190614c18565b6007555b5f612b6986611446565b90508015801590612b8557505f86815260026020526040902054155b15612c655760115f9054906101000a90046001600160a01b03166001600160a01b031663c5f530af6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bda573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bfe9190614b5f565b811015612c2f578215612c245760405163047447a360e11b815260040160405180910390fd5b612c2f866001612304565b818015612c425750612c4086613df1565b155b15612c605760405163c2eb4ead60e01b815260040160405180910390fd5b612c70565b612c70866001612304565b5f8681526002602081905260409091200154611d4f9088906001600160a01b031686612406565b306001600160a01b037f0000000000000000000000000ab8f3b709a52c096f33702fe8153776472305ed16146114ee5760405163703e46dd60e11b815260040160405180910390fd5b6001600160a01b0382165f908152600a6020908152604080832084845290915281205481612d0d84613fb4565b6001600160a01b0386165f908152600c60209081526040808320888452909152812054919250612d3f82878686614009565b979650505050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b6001600160a01b0389165f9081526003602052604090205415612df057604051633f4dc7d360e11b815260040160405180910390fd5b6001600160a01b0389165f8181526003602081815260408084208d90558c845260028083528185208b81559384018a905560048085018a90556005850188905560068501899055930180546001600160a01b0319169095179094555220612e58878983614c85565b508760135f612e678a8a613005565b6001600160a01b03166001600160a01b031681526020019081526020015f2081905550886001600160a01b0316887f49bca1ed2666922f9f1690c26a569e1299c2a715fe57647d77e81adfabbf25bf8686604051612ecf929190918252602082015260400190565b60405180910390a38115612f1957604080518381526020810183905289917fac4801c32a6067ff757446524ee4e7a373797278ac3c883eac5c693b4ad72e47910160405180910390a25b8415612f5a57877fcd35267e7654194727477d6c78b541a553483cff7f92a055d17868d3da6e953e86604051612f5191815260200190565b60405180910390a25b505050505050505050565b80156117a257600d54811115612f8e57604051632ad907fb60e01b815260040160405180910390fd5b80600d5f828254612f9f9190614c18565b90915550506040515f9082156108fc0290839083818181858288f19350505050158015612fce573d5f5f3e3d5ffd5b506040518181527f66ac49f046ee1185a59a920bbdfe95faba2bba02afc4b64a97ac35d5d14acc479060200160405180910390a150565b5f6130138260028186614d3e565b604051613021929190614d65565b6040519081900390209392505050565b5f60055f815461304090614d74565b91829055509050611eb9848285855f6130576114f0565b425f5f612dba565b815f0361307f57604051631f2a200560e01b815260040160405180910390fd5b6130898484612a58565b506001600160a01b0384165f908152600c602090815260408083208684529091529020546130b8908390614af9565b6001600160a01b0385165f908152600c602090815260408083208784528252808320939093556002905220600101546130f18382614af9565b5f85815260026020526040902060010155600654613110908490614af9565b6006555f8481526002602052604090205461313757826007546131339190614af9565b6007555b613142848215611c2e565b83856001600160a01b03167f9a8f44850296624dadfd9c246d17e47171d35727a181bd090aa14bbbe00238bb8560405161317e91815260200190565b60405180910390a35f84815260026020819052604090912001546115509086906001600160a01b031684612406565b5f546040516366e7ea0f60e01b8152306004820152602481018390526001600160a01b03909116906366e7ea0f906044015f604051808303815f87803b1580156131f5575f5ffd5b505af1158015613207573d5f5f3e3d5ffd5b5050505080600d546132199190614af9565b600d5550565b5f5b83518110156115505760115f9054906101000a90046001600160a01b03166001600160a01b0316635a68f01a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561327a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061329e9190614b5f565b8282815181106132b0576132b0614b76565b6020026020010151118015613350575060115f9054906101000a90046001600160a01b03166001600160a01b031662cc7f836040518163ffffffff1660e01b8152600401602060405180830381865afa15801561330f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133339190614b5f565b83828151811061334557613345614b76565b602002602001015110155b1561339c5761337984828151811061336a5761336a614b76565b60200260200101516008612304565b61339c84828151811061338e5761338e614b76565b60200260200101515f611c2e565b8281815181106133ae576133ae614b76565b6020026020010151856005015f8684815181106133cd576133cd614b76565b602002602001015181526020019081526020015f20819055508181815181106133f8576133f8614b76565b6020026020010151856006015f86848151811061341757613417614b76565b60209081029190910181015182528101919091526040015f2055600101613221565b5f6040518060a0016040528085516001600160401b0381111561345e5761345e6146bf565b604051908082528060200260200182016040528015613487578160200160208202803683370190505b5081526020015f815260200185516001600160401b038111156134ac576134ac6146bf565b6040519080825280602002602001820160405280156134d5578160200160208202803683370190505b5081526020015f81526020015f81525090505f5f90505b8451811015613615575f866004015f87848151811061350d5761350d614b76565b602002602001015181526020019081526020015f205490505f5f90508185848151811061353c5761353c614b76565b60200260200101511115613572578185848151811061355d5761355d614b76565b602002602001015161356f9190614c18565b90505b8986848151811061358557613585614b76565b6020026020010151826135989190614d8c565b6135a29190614db7565b846040015184815181106135b8576135b8614b76565b602002602001018181525050836040015183815181106135da576135da614b76565b602002602001015184606001516135f19190614af9565b60608501526080840151613606908290614af9565b608085015250506001016134ec565b505f5b8451811015613702578784828151811061363457613634614b76565b60200260200101518986848151811061364f5761364f614b76565b60200260200101518a5f015f8a878151811061366d5761366d614b76565b602002602001015181526020019081526020015f205461368d9190614d8c565b6136979190614db7565b6136a19190614d8c565b6136ab9190614db7565b82518051839081106136bf576136bf614b76565b602090810291909101015281518051829081106136de576136de614b76565b602002602001015182602001516136f59190614af9565b6020830152600101613618565b505f5b8451811015613a06575f6137ad8960115f9054906101000a90046001600160a01b03166001600160a01b031663d9a7c1f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613763573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137879190614b5f565b855180518690811061379b5761379b614b76565b60200260200101518660200151614072565b90506137df8360800151846040015184815181106137cd576137cd614b76565b602002602001015185606001516140ad565b6137e99082614af9565b90505f8683815181106137fe576137fe614b76565b6020908102919091018101515f8181526002808452604080832090910154601154825163a778651560e01b815292519496506001600160a01b03918216959394613896948994929093169263a778651592600480820193918290030181865afa15801561386d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138919190614b5f565b6141fe565b6001600160a01b0383165f908152600c6020908152604080832087845290915290205490915080156138fa576001600160a01b0383165f908152600960209081526040808320878452909152812080548492906138f4908490614af9565b90915550505b5f6139058387614c18565b5f86815260026020526040812060010154919250811561393f5781613932670de0b6b3a764000085614d8c565b61393c9190614db7565b90505b5f87815260018f01602052604090205461395a908290614af9565b8f6001015f8981526020019081526020015f20819055508a898151811061398357613983614b76565b60200260200101518f6004015f8981526020019081526020015f20819055508b89815181106139b4576139b4614b76565b60200260200101518e6002015f8981526020019081526020015f20546139da9190614af9565b8f6002015f8981526020019081526020015f208190555050505050505050508080600101915050613705565b506080810151600a8701819055600d541115613a3c5785600a0154600d5f828254613a319190614c18565b90915550613a419050565b5f600d555b6010546001600160a01b031615611d4f575f670de0b6b3a764000060115f9054906101000a90046001600160a01b03166001600160a01b03166394c3e9146040518163ffffffff1660e01b8152600401602060405180830381865afa158015613aac573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ad09190614b5f565b8360800151613adf9190614d8c565b613ae99190614db7565b9050613af4816131ad565b6010546040515f916001600160a01b031690620f424090849084818181858888f193505050503d805f8114613b44576040519150601f19603f3d011682016040523d82523d5f602084013e613b49565b606091505b5050905080612f5a578160085f828254613b639190614af9565b9091555050505050505050505050565b5f5b8251811015613de9575f838281518110613b9157613b91614b76565b602002602001015190505f87613bac670de0b6b3a764000090565b858581518110613bbe57613bbe614b76565b6020026020010151613bd09190614d8c565b613bda9190614db7565b9050670de0b6b3a7640000811115613bf75750670de0b6b3a76400005b5f8281526003870160209081526040808320815160608101835290546001600160401b038116825263ffffffff600160401b8204811694830194909452600160601b90049092169082015290613c4d838361421c565b5f85815260038b0160209081526040918290208351815485840151868601516001600160401b039093166bffffffffffffffffffffffff1990921691909117600160401b63ffffffff928316021763ffffffff60601b1916600160601b91909216021790556011548251631c25433760e01b815292519394506001600160a01b031692631c2543379260048082019392918290030181865afa158015613cf5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d199190614dca565b6001600160401b0316815f01516001600160401b0316108015613dbf575060115f9054906101000a90046001600160a01b03166001600160a01b0316633fa225486040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d87573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613dab9190614df0565b63ffffffff16816040015163ffffffff1610155b15613dd957613dcf846010612304565b613dd9845f611c2e565b505060019092019150613b759050565b505050505050565b5f670de0b6b3a764000060115f9054906101000a90046001600160a01b03166001600160a01b0316632265f2846040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e4b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e6f9190614b5f565b613e7884611446565b613e829190614d8c565b613e8c9190614db7565b5f92835260026020526040909220600101549190911115919050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166114ee57604051631afcd79f60e31b815260040160405180910390fd5b612195613ea8565b5f821580613f0f5750670de0b6b3a76400008210155b15613f1b57505f612248565b670de0b6b3a7640000613f2e8382614c18565b613f389086614d8c565b613f429190614db7565b613f4d906001614af9565b90508381111561224857509192915050565b613f68826143ff565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a2805115613fac576110568282614462565b6111d86144cb565b5f8181526002602052604081206006015415614001575f828152600260205260409020600601546001541015613fec57505060015490565b505f9081526002602052604090206006015490565b505060015490565b5f81831061401857505f6114d5565b5f838152600e6020818152604080842088855260019081018352818520548786529383528185208986520190915290912054670de0b6b3a76400008761405e8484614c18565b6140689190614d8c565b612d3f9190614db7565b5f825f0361408157505f6114d5565b5f61408c8587614d8c565b9050826140998583614d8c565b6140a39190614db7565b9695505050505050565b5f825f036140bc57505f612248565b5f826140c88587614d8c565b6140d29190614db7565b9050670de0b6b3a764000060115f9054906101000a90046001600160a01b03166001600160a01b03166394c3e9146040518163ffffffff1660e01b8152600401602060405180830381865afa15801561412d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141519190614b5f565b60115f9054906101000a90046001600160a01b03166001600160a01b031663c74dd6216040518163ffffffff1660e01b8152600401602060405180830381865afa1580156141a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141c59190614b5f565b6141d790670de0b6b3a7640000614c18565b6141e19190614c18565b6141eb9083614d8c565b6141f59190614db7565b95945050505050565b5f670de0b6b3a76400006142128385614d8c565b6122489190614db7565b604080516060810182525f8082526020820181905291810191909152604080516060810182525f8082526020820181905291810191909152826040015163ffffffff165f0361427f576001600160401b0384168152600160408201529050611492565b5f836040015160016142919190614e13565b63ffffffff1690505f846020015163ffffffff16866001600160401b0316865f01516001600160401b03166001856142c99190614e2f565b6142d39190614e4e565b6142dd9190614e77565b6142e79190614e77565b90506142f38282614e96565b6001600160401b031683526143088282614ec3565b63ffffffff166020840152670de0b6b3a764000083516001600160401b0316111561433957670de0b6b3a764000083525b60115f9054906101000a90046001600160a01b03166001600160a01b0316633fa225486040518163ffffffff1660e01b8152600401602060405180830381865afa158015614389573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143ad9190614df0565b63ffffffff16856040015163ffffffff1610156143e45760408501516143d4906001614e13565b63ffffffff1660408401526143f5565b60408086015163ffffffff16908401525b5090949350505050565b806001600160a01b03163b5f0361443457604051634c9c8ce360e01b81526001600160a01b03821660048201526024016121ba565b5f516020614ef15f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b03168460405161447e9190614c2b565b5f60405180830381855af49150503d805f81146144b6576040519150601f19603f3d011682016040523d82523d5f602084013e6144bb565b606091505b50915091506141f58583836144ea565b34156114ee5760405163b398979f60e01b815260040160405180910390fd5b6060826144ff576144fa82614546565b612248565b815115801561451657506001600160a01b0384163b155b1561453f57604051639996b31560e01b81526001600160a01b03851660048201526024016121ba565b5080612248565b8051156145565780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b828054828255905f5260205f209081019282156145a8579160200282015b828111156145a857823582559160200191906001019061458d565b506145b49291506145b8565b5090565b5b808211156145b4575f81556001016145b9565b6001600160a01b03811681146117a2575f5ffd5b5f602082840312156145f0575f5ffd5b8135612248816145cc565b5f6020828403121561460b575f5ffd5b5035919050565b5f5f60408385031215614623575f5ffd5b50508035926020909101359150565b5f5f5f60608486031215614644575f5ffd5b833561464f816145cc565b95602085013595506040909401359392505050565b5f5f5f5f5f60a08688031215614678575f5ffd5b85359450602086013593506040860135614691816145cc565b925060608601356146a1816145cc565b915060808601356146b1816145cc565b809150509295509295909350565b634e487b7160e01b5f52604160045260245ffd5b5f5f604083850312156146e4575f5ffd5b82356146ef816145cc565b915060208301356001600160401b03811115614709575f5ffd5b8301601f81018513614719575f5ffd5b80356001600160401b03811115614732576147326146bf565b604051601f8201601f19908116603f011681016001600160401b0381118282101715614760576147606146bf565b604052818152828201602001871015614777575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f5f5f606084860312156147a8575f5ffd5b505081359360208301359350604090920135919050565b5f5f604083850312156147d0575f5ffd5b82356147db816145cc565b946020939093013593505050565b5f5f83601f8401126147f9575f5ffd5b5081356001600160401b0381111561480f575f5ffd5b602083019150836020828501011115614826575f5ffd5b9250929050565b5f5f5f5f5f60808688031215614841575f5ffd5b853561484c816145cc565b94506020860135935060408601356001600160401b0381111561486d575f5ffd5b614879888289016147e9565b96999598509660600135949350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f612248602083018461488b565b5f5f602083850312156148dc575f5ffd5b82356001600160401b038111156148f1575f5ffd5b6148fd858286016147e9565b90969095509350505050565b602080825282518282018190525f918401906040840190835b81811015614940578351835260209384019390920191600101614922565b509095945050505050565b5f5f6040838503121561495c575f5ffd5b8235614967816145cc565b91506020830135614977816145cc565b809150509250929050565b5f5f60408385031215614993575f5ffd5b8235915060208301358015158114614977575f5ffd5b5f5f83601f8401126149b9575f5ffd5b5081356001600160401b038111156149cf575f5ffd5b6020830191508360208260051b8501011115614826575f5ffd5b5f5f602083850312156149fa575f5ffd5b82356001600160401b03811115614a0f575f5ffd5b6148fd858286016149a9565b5f5f5f5f5f5f5f5f6080898b031215614a32575f5ffd5b88356001600160401b03811115614a47575f5ffd5b614a538b828c016149a9565b90995097505060208901356001600160401b03811115614a71575f5ffd5b614a7d8b828c016149a9565b90975095505060408901356001600160401b03811115614a9b575f5ffd5b614aa78b828c016149a9565b90955093505060608901356001600160401b03811115614ac5575f5ffd5b614ad18b828c016149a9565b999c989b5096995094979396929594505050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561149257611492614ae5565b600181811c90821680614b2057607f821691505b602082108103614b3e57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215614b54575f5ffd5b8151612248816145cc565b5f60208284031215614b6f575f5ffd5b5051919050565b634e487b7160e01b5f52603260045260245ffd5b828152604060208201525f5f8354614ba181614b0c565b806040860152600182165f8114614bbf5760018114614bdb57614c0c565b60ff1983166060870152606082151560051b8701019350614c0c565b865f5260205f205f5b83811015614c0357815488820160600152600190910190602001614be4565b87016060019450505b50919695505050505050565b8181038181111561149257611492614ae5565b5f82518060208501845e5f920191825250919050565b601f82111561105657805f5260205f20601f840160051c81016020851015614c665750805b601f840160051c820191505b81811015611550575f8155600101614c72565b6001600160401b03831115614c9c57614c9c6146bf565b614cb083614caa8354614b0c565b83614c41565b5f601f841160018114614ce1575f8515614cca5750838201355b5f19600387901b1c1916600186901b178355611550565b5f83815260208120601f198716915b82811015614d105786850135825560209485019460019092019101614cf0565b5086821015614d2c575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b5f5f85851115614d4c575f5ffd5b83861115614d58575f5ffd5b5050820193919092039150565b818382375f9101908152919050565b5f60018201614d8557614d85614ae5565b5060010190565b808202811582820484141761149257611492614ae5565b634e487b7160e01b5f52601260045260245ffd5b5f82614dc557614dc5614da3565b500490565b5f60208284031215614dda575f5ffd5b81516001600160401b0381168114612248575f5ffd5b5f60208284031215614e00575f5ffd5b815163ffffffff81168114612248575f5ffd5b63ffffffff818116838216019081111561149257611492614ae5565b6001600160801b03828116828216039081111561149257611492614ae5565b6001600160801b038181168382160290811690818114614e7057614e70614ae5565b5092915050565b6001600160801b03818116838216019081111561149257611492614ae5565b5f6001600160801b03831680614eae57614eae614da3565b806001600160801b0384160491505092915050565b5f6001600160801b03831680614edb57614edb614da3565b806001600160801b038416069150509291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212202c157fddf75482e9928130a6824fe60a3cb8e4a7a69e7e8a5a01f582673d363e64736f6c634300081b0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.