Source Code
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
There are no matching entriesUpdate your filters to view other transactions | |||||||||
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RockXStaking
Compiler Version
v0.8.12+commit.f00d7308
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
// ⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀
// ⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀
// ⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⢠⣤⣤⣤⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀
// ⠉⠻⣿⡟⠛⠛⠻⣿⣄⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⣿⣿⡀⡀⡀⡀⡀⡀⡀⠙⢿⣿⡟⠁⡀⡀⠙⣿⠟⠁
// ⡀⡀⣿⡇⡀⡀⡀⢸⣿⡆⡀⡀⡀⡀⡀⣀⣀⡀⡀⡀⡀⡀⡀⡀⡀⣀⣀⣀⡀⡀⡀⡀⣿⣿⡀⡀⡀⡀⡀⡀⡀⡀⡀⢿⣿⡄⡀⡀⣾⠃⡀⡀
// ⡀⡀⣿⡇⡀⡀⡀⢸⣿⠃⡀⡀⡀⣾⡿⠉⠉⠙⣿⣄⡀⡀⡀⣴⣿⠋⠉⠻⣿⡄⡀⡀⣿⣿⡀⡀⠙⣿⠿⠉⡀⡀⡀⡀⢻⣿⣄⣿⠁⡀⡀⡀
// ⡀⡀⣿⣇⣀⣀⣤⡿⠋⡀⡀⡀⣼⣿⡀⡀⡀⡀⢸⣿⡀⡀⢠⣿⠃⡀⡀⡀⠛⡀⡀⡀⣿⣿⡀⢀⡿⠁⡀⡀⡀⡀⡀⡀⡀⢻⣿⡄⡀⡀⡀⡀
// ⡀⡀⣿⡏⠉⠻⣿⣄⡀⡀⡀⡀⣿⣿⡀⡀⡀⡀⠘⣿⡇⡀⢸⣿⡀⡀⡀⡀⡀⡀⡀⡀⣿⣿⣴⣿⣦⡀⡀⡀⡀⡀⡀⡀⢠⡿⢻⣿⡄⡀⡀⡀
// ⡀⡀⣿⡇⡀⡀⠻⣿⣆⡀⡀⡀⢿⣿⡀⡀⡀⡀⢸⣿⠁⡀⢸⣿⡀⡀⡀⡀⡀⡀⡀⡀⣿⣿⡀⠘⣿⣧⡀⡀⡀⡀⡀⣰⡟⡀⡀⢻⣿⡄⡀⡀
// ⡀⢀⣿⣧⡀⡀⡀⠻⣿⣦⡀⡀⠈⣿⣄⡀⡀⡀⣾⡿⡀⡀⡀⢿⣷⡀⡀⡀⣀⡄⡀⡀⣿⣿⡀⡀⠈⣿⣷⡀⡀⡀⣴⣿⡀⡀⡀⡀⢻⣿⣄⡀
// ⠛⠛⠛⠛⠛⡀⡀⡀⠈⠛⠛⡀⡀⡀⠛⠿⠿⠟⠋⡀⡀⡀⡀⡀⠙⠿⠿⠿⠛⡀⠘⠛⠛⠛⠛⡀⡀⡀⠙⠛⠛⠛⠛⠛⠛⡀⡀⠛⠛⠛⠛⠛
// ⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀
// ⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀
pragma solidity ^0.8.4;
import "iface.sol";
import "BytesLib.sol";
import "SafeERC20.sol";
import "Initializable.sol";
import "AccessControlUpgradeable.sol";
import "PausableUpgradeable.sol";
import "ReentrancyGuardUpgradeable.sol";
/**
* @title RockX Ethereum 2.0 Staking Contract
*
* Description:
*
* ───╔═╦═╗─╔╗╔═╗──────╔╗──╔╗╔╗─╔╦╗╔╗─╔═╗─╔╗───────╔╦╗
* ╔═╗║═╣═╬═╣╚╣═╣╔══╗╔╗╠╬═╗║╚╬╬╗╠╣╚╬╬═╣═╣╔╝╚╗╔═╦═╦╦╬╣╚╦╦╗
* ║╬╚╬═╠═║╩╣╔╬═║╠══╣║╚╣║╬╚╣╬║║╚╣║╔╣║╩╬═║╚╗╔╝║╩╣╬║║║║╔╣║║
* ╚══╩═╩═╩═╩═╩═╝╚══╝╚═╩╩══╩═╩╩═╩╩═╩╩═╩═╝─╚╝─╚═╩╗╠═╩╩═╬╗║
* ─────────────────────────────────────────────╚╝────╚═╝
*
* Term:
* ExchangeRatio: Exchange Ratio of xETH to ETH, normally >= 1.0
* TotalXETH: Total Supply of xETH
* TotalStaked: Total Ethers Staked to Validators
* TotalDebts: Total unpaid debts(generated from redeemFromValidators),
* awaiting to be paid by turn off validators to clean debts.
* TotalPending: Pending Ethers(<32 Ethers), awaiting to be staked
* RewardDebts: The amount re-staked into TotalPending
*
* AccountedUserRevenue: Overall Net revenue which belongs to all xETH holders(excluded re-staked amount)
* ReportedValidators: Latest Reported Validator Count
* ReportedValidatorBalance: Latest Reported Validator Overall Balance
* RecentReceived: The Amount this contract receives recently.
* CurrentReserve: Assets Under Management
*
* Lemma 1: (AUM)
*
* CurrentReserve = TotalPending + TotalStaked + AccountedUserRevenue - TotalDebts - RewardDebts
*
* Lemma 2: (Exchange Ratio)
*
* ExchangeRatio = CurrentReserve / TotalXETH
*
* Rule 1: (function mint) For every mint operation, the ethers pays debt in priority the reset will be put in TotalPending(deprecated),
* ethersToMint: The amount user deposits
*
* (deprecated)
* TotalDebts = TotalDebts - Min(ethersToMint, TotalDebts)
* TotalPending = TotalPending + Max(0, ethersToMint - TotalDebts)
* TotalXETH = TotalXETH + ethersToMint / ExchangeRatio
*
* (updated)
* TotalPending = TotalPending + ethersToMint
* TotalXETH = TotalXETH + ethersToMint / ExchangeRatio
*
* Rule 2: (function mint) At any time TotalPending has more than 32 Ethers, It will be staked, TotalPending
* moves to TotalStaked and keeps TotalPending less than 32 Ether.
*
* TotalPending = TotalPending - ⌊TotalPending/32ETH⌋ * 32ETH
* TotalStaked = TotalStaked + ⌊TotalPending/32ETH⌋ * 32ETH
*
* Rule 3: (function validatorStopped) Whenever a validator stopped, all value pays debts in priority, then:
* valueStopped: The value sent-back via receive() funtion
* amountUnstaked: The amount of unstaked node (base 32ethers)
* validatorStopped: The count of validator stopped
*
* incrRewardDebt := valueStopped - amountUnstaked
* RewardDebts = RewardDebt + incrRewardDebt
* RecentReceived = RecentReceived + valueStopped
* TotalPending = TotalPending + Max(0, amountUnstaked - TotalDebts) + incrRewardDebt
* TotalStaked = TotalStaked - validatorStopped * 32 ETH
*
* Rule 4.1: (function pushBeacon) Oracle push balance, rebase if new validator is alive:
* aliveValidator: The count of validators alive
*
* RewardBase = ReportedValidatorBalance + Max(0, aliveValidator - ReportedValidators) * 32 ETH
*
* Rule 4.2: (function pushBeacon) Oracle push balance, revenue calculation:
* aliveBalance: The balance of current alive validators
*
* r := aliveBalance + RecentReceived - RewardBase
* AccountedUserRevenue = AccountedUserRevenue + r * (1000 - managerFeeShare) / 1000
* RecentReceived = 0
* ReportedValidators = aliveValidator
* ReportedValidatorBalance = aliveBalance
*
* CHANGELOG
* v1(20230509): remove the use of aliveBalance after shanghai merge, this parameter is omited in pushBeacon
*
*/
contract RockXStaking is Initializable, PausableUpgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable {
using SafeERC20 for IERC20;
using Address for address payable;
using Address for address;
// stored credentials
struct ValidatorCredential {
bytes pubkey;
bytes signature;
bool stopped;
bool restaking; // UPDATE(20240115) : flag the validator is using liquid staking address
}
// track ether debts to return to async caller
struct Debt {
address account;
uint256 amount;
}
/**
Incorrect storage preservation:
|Implementation_v0 |Implementation_v1 |
|--------------------|-------------------------|
|address _owner |address _lastContributor | <=== Storage collision!
|mapping _balances |address _owner |
|uint256 _supply |mapping _balances |
|... |uint256 _supply |
| |... |
Correct storage preservation:
|Implementation_v0 |Implementation_v1 |
|--------------------|-------------------------|
|address _owner |address _owner |
|mapping _balances |mapping _balances |
|uint256 _supply |uint256 _supply |
|... |address _lastContributor | <=== Storage extension.
| |... |
*/
// Always extend storage instead of modifying it
// Variables in implementation v0
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE");
bytes32 public constant REGISTRY_ROLE = keccak256("REGISTRY_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
uint256 public constant DEPOSIT_SIZE = 32 ether;
uint256 private constant MULTIPLIER = 1e18;
uint256 private constant DEPOSIT_AMOUNT_UNIT = 1000000000 wei;
uint256 private constant SIGNATURE_LENGTH = 96;
uint256 private constant PUBKEY_LENGTH = 48;
address public ethDepositContract; // ETH 2.0 Deposit contract
address public xETHAddress; // xETH token address
address public redeemContract; // redeeming contract for user to pull ethers
uint256 public managerFeeShare; // manager's fee in 1/1000
bytes32 public withdrawalCredentials; // WithdrawCredential for all validator
// credentials, pushed by owner
ValidatorCredential [] private validatorRegistry;
mapping(bytes32 => uint256) private pubkeyIndices; // indices of validatorRegistry by pubkey hash, starts from 1
// next validator id
uint256 private nextValidatorId;
// exchange ratio related variables
// track user deposits & redeem (xETH mint & burn)
uint256 private totalPending; // track pending ethers awaiting to be staked to validators
uint256 private totalStaked; // track current staked ethers for validators, rounded to 32 ethers
uint256 private totalDebts; // track current unpaid debts
// FIFO of debts from redeemFromValidators
mapping(uint256=>Debt) private etherDebts;
uint256 private firstDebt;
uint256 private lastDebt;
mapping(address=>uint256) private userDebts; // debts from user's perspective
// track revenue from validators to form exchange ratio
uint256 private accountedUserRevenue; // accounted shared user revenue
uint256 private accountedManagerRevenue; // accounted manager's revenue
uint256 private rewardDebts; // check validatorStopped function
// revenue related variables
// track beacon validator & balance
uint256 private reportedValidators;
uint256 private reportedValidatorBalance;
// balance tracking
int256 private accountedBalance; // tracked balance change in functions,
// NOTE(x): balance might be negative for not accounting validators's redeeming
uint256 private recentSlashed; // track recently slashed value
uint256 private recentReceived; // track recently received (un-accounted) value into this contract
bytes32 private vectorClock; // a vector clock for detecting receive() & pushBeacon() causality violations
uint256 private vectorClockTicks; // record current vector clock step;
// track stopped validators
uint256 stoppedValidators; // track stopped validators count
// phase switch from 0 to 1
uint256 private phase;
// gas refunds
uint256 [] private refunds;
// PATCH VARIABLES(UPGRADES)
uint256 private recentStopped; // track recent stopped validators(update: 20220927)
/**
* @dev empty reserved space for future adding of variables
*/
uint256[31] private __gap;
// KYC control
mapping(address=>uint256) quotaUsed;
mapping(address=>bool) whiteList;
// auto-compounding
bool private autoCompoundEnabled;
// DEPRECATED(20240130): eigenlayer's restaking withdrawal credential
bytes32 private __DEPRECATED_restakingWithdrawalCredentials;
address private __DEPRECATED_restakingAddress;
// UPDATE(20240130): use variable instead of constant, require upgradeAndCall to set it's value
address public restakingContract;
/**
* ======================================================================================
*
* SYSTEM SETTINGS, OPERATED VIA OWNER(DAO/TIMELOCK)
*
* ======================================================================================
*/
receive() external payable { }
constructor() { _disableInitializers(); }
/**
* @dev only phase
*/
modifier onlyPhase(uint256 requiredPhase) {
_require(phase >= requiredPhase, "SYS001");
_;
}
/**
* @dev pause the contract
*/
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}
/**
* @dev unpause the contract
*/
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
/**
* @dev initialization address
*/
/*
function initialize() initializer public {
__Pausable_init();
__AccessControl_init();
__ReentrancyGuard_init();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ORACLE_ROLE, msg.sender);
_grantRole(REGISTRY_ROLE, msg.sender);
_grantRole(PAUSER_ROLE, msg.sender);
_grantRole(MANAGER_ROLE, msg.sender);
// init default values
managerFeeShare = 5;
firstDebt = 1;
lastDebt = 0;
phase = 0;
_vectorClockTick();
// initiate default withdrawal credential to the contract itself
// uint8('0x1') + 11 bytes(0) + this.address
bytes memory cred = abi.encodePacked(bytes1(0x01), new bytes(11), address(this));
withdrawalCredentials = BytesLib.toBytes32(cred, 0);
}
*/
/**
* UPDATE(20240130): to set a variable after upgrades
* use upgradeAndCall to initializeV2
*/
/*
function initializeV2(address restakingContract_) reinitializer(2) public {
restakingContract = restakingContract_;
}
*/
/**
* @dev phase switch
*/
function switchPhase(uint256 newPhase) external onlyRole(DEFAULT_ADMIN_ROLE) {
require (newPhase >= phase, "SYS002");
phase = newPhase;
}
/**
* @dev register a validator
*/
function registerValidator(bytes calldata pubkey, bytes calldata signature) external onlyRole(REGISTRY_ROLE) {
_require(signature.length == SIGNATURE_LENGTH, "SYS003");
_require(pubkey.length == PUBKEY_LENGTH, "SYS004");
bytes32 pubkeyHash = keccak256(pubkey);
_require(pubkeyIndices[pubkeyHash] == 0, "SYS005");
validatorRegistry.push(ValidatorCredential({pubkey:pubkey, signature:signature, stopped:false, restaking: false}));
pubkeyIndices[pubkeyHash] = validatorRegistry.length;
}
/**
* @dev replace a validator in case of msitakes
*/
function replaceValidator(bytes calldata oldpubkey, bytes calldata pubkey, bytes calldata signature) external onlyRole(REGISTRY_ROLE) {
_require(pubkey.length == PUBKEY_LENGTH, "SYS004");
_require(signature.length == SIGNATURE_LENGTH, "SYS003");
// mark old pub key to false
bytes32 oldPubKeyHash = keccak256(oldpubkey);
_require(pubkeyIndices[oldPubKeyHash] > 0, "SYS006");
uint256 index = pubkeyIndices[oldPubKeyHash] - 1;
delete pubkeyIndices[oldPubKeyHash];
// set new pubkey
bytes32 pubkeyHash = keccak256(pubkey);
validatorRegistry[index] = ValidatorCredential({pubkey:pubkey, signature:signature, stopped:false, restaking: false});
pubkeyIndices[pubkeyHash] = index+1;
}
/**
* @dev replace validators in batch
*/
function replaceValidators(bytes [] calldata oldpubkeys, bytes [] calldata pubkeys, bytes [] calldata signatures, bool restaking) external onlyRole(REGISTRY_ROLE) {
_require(pubkeys.length == signatures.length, "SYS007");
_require(oldpubkeys.length == pubkeys.length, "SYS007");
uint256 n = pubkeys.length;
for(uint256 i=0;i<n;i++) {
bytes calldata oldpubkey = oldpubkeys[i];
bytes calldata pubkey = pubkeys[i];
bytes calldata signature = signatures[i];
_require(oldpubkey.length == PUBKEY_LENGTH, "SYS004");
_require(pubkey.length == PUBKEY_LENGTH, "SYS004");
_require(signature.length == SIGNATURE_LENGTH, "SYS003");
// mark old pub key to false
bytes32 oldPubKeyHash = keccak256(oldpubkey);
_require(pubkeyIndices[oldPubKeyHash] > 0, "SYS006");
uint256 index = pubkeyIndices[oldPubKeyHash] - 1;
delete pubkeyIndices[oldPubKeyHash];
// set new pubkey
bytes32 pubkeyHash = keccak256(pubkey);
ValidatorCredential storage validator = validatorRegistry[index];
validator.pubkey = pubkey;
validator.signature = signature;
validator.restaking = restaking;
pubkeyIndices[pubkeyHash] = index+1;
}
}
/**
* @dev register a batch of validators
*/
function registerValidators(bytes [] calldata pubkeys, bytes [] calldata signatures) external onlyRole(REGISTRY_ROLE) {
_require(pubkeys.length == signatures.length, "SYS007");
uint256 n = pubkeys.length;
for(uint256 i=0;i<n;i++) {
_require(pubkeys[i].length == PUBKEY_LENGTH, "SYS004");
_require(signatures[i].length == SIGNATURE_LENGTH, "SYS003");
bytes32 pubkeyHash = keccak256(pubkeys[i]);
_require(pubkeyIndices[pubkeyHash] == 0, "SYS005");
validatorRegistry.push(ValidatorCredential({pubkey:pubkeys[i], signature:signatures[i], stopped:false, restaking: false}));
pubkeyIndices[pubkeyHash] = validatorRegistry.length;
}
}
/**
* @dev register a batch of LRT validators
* UPDATE(20240115): register a batch of validators for Liquid Restaking (EigenLayer)
*/
function registerRestakingValidators(bytes [] calldata pubkeys, bytes [] calldata signatures) external onlyRole(REGISTRY_ROLE) {
_require(pubkeys.length == signatures.length, "SYS007");
uint256 n = pubkeys.length;
for(uint256 i=0;i<n;i++) {
_require(pubkeys[i].length == PUBKEY_LENGTH, "SYS004");
_require(signatures[i].length == SIGNATURE_LENGTH, "SYS003");
bytes32 pubkeyHash = keccak256(pubkeys[i]);
_require(pubkeyIndices[pubkeyHash] == 0, "SYS005");
validatorRegistry.push(ValidatorCredential({pubkey:pubkeys[i], signature:signatures[i], stopped:false, restaking: true}));
pubkeyIndices[pubkeyHash] = validatorRegistry.length;
}
}
/**
* @dev toggleWhiteList
*/
function toggleWhiteList(address account) external onlyRole(DEFAULT_ADMIN_ROLE) {
whiteList[account] = !whiteList[account];
emit WhiteListToggle(account, whiteList[account]);
}
/**
* @dev toggle autocompound
*/
function toggleAutoCompound() external onlyRole(DEFAULT_ADMIN_ROLE) {
autoCompoundEnabled = !autoCompoundEnabled;
emit AutoCompoundToggle(autoCompoundEnabled);
}
/**
* @dev set manager's fee in 1/1000
*/
function setManagerFeeShare(uint256 milli) external onlyRole(DEFAULT_ADMIN_ROLE) {
_require(milli >=0 && milli <=1000, "SYS008");
managerFeeShare = milli;
emit ManagerFeeSet(milli);
}
/**
* @dev set xETH token contract address
*/
function setXETHContractAddress(address _xETHContract) external onlyRole(DEFAULT_ADMIN_ROLE) {
xETHAddress = _xETHContract;
emit XETHContractSet(_xETHContract);
}
/**
* @dev set eth deposit contract address
*/
function setETHDepositContract(address _ethDepositContract) external onlyRole(DEFAULT_ADMIN_ROLE) {
ethDepositContract = _ethDepositContract;
emit DepositContractSet(_ethDepositContract);
}
/**
* @dev set redeem contract
*/
function setRedeemContract(address _redeemContract) external onlyRole(DEFAULT_ADMIN_ROLE) {
redeemContract = _redeemContract;
emit RedeemContractSet(_redeemContract);
}
/**
* @dev set withdraw credential to receive revenue, usually this should be the contract itself.
*/
function setWithdrawCredential(bytes32 withdrawalCredentials_) external onlyRole(DEFAULT_ADMIN_ROLE) {
withdrawalCredentials = withdrawalCredentials_;
emit WithdrawCredentialSet(withdrawalCredentials);
}
/**
* @dev stake into eth2 staking contract by calling this function
*/
function stake() external { _stakeInternal(); }
/**
* @dev internal entry of stake() external
*/
function _stakeInternal() internal {
// spin max nodes
uint256 numValidators = totalPending / DEPOSIT_SIZE;
uint256 maxValidators = (nextValidatorId + numValidators <= validatorRegistry.length)?
numValidators:
validatorRegistry.length - nextValidatorId;
for (uint256 i = 0;i<maxValidators;i++) {
_spinup();
}
if (maxValidators > 0) {
emit ValidatorActivated(nextValidatorId);
}
}
/**
* @dev manager withdraw fees as uniETH
*/
function withdrawManagerFee(uint256 amount, address to) external nonReentrant onlyRole(MANAGER_ROLE) {
_syncBalance();
_require(amount <= accountedManagerRevenue, "SYS010");
// debts + userRevenue + managersRevenue + pending ethers
_require(address(this).balance >= amount + totalPending + totalDebts, "SYS011");
// mint uniETH while keeping the exchange ratio invariant
uint256 totalXETH = IERC20(xETHAddress).totalSupply();
uint256 totalEthers = currentReserve();
uint256 toMint = 1 * amount; // default exchange ratio 1:1
if (totalEthers > 0) { // avert division overflow
toMint = totalXETH * amount / totalEthers;
}
// NOTE: the following procdure must keep exchangeRatio invariant:
// mint equivalent `uniETH` to `amount`
IMintableContract(xETHAddress).mint(to, toMint);
// track balance change:
// shift manager's revenue from accountedManagerRevenue to totalPending
totalPending += amount;
accountedManagerRevenue -= amount;
emit ManagerFeeWithdrawed(amount, to);
}
/**
* @dev balance sync, also moves the vector clock if it has different value
*/
function syncBalance() external onlyRole(ORACLE_ROLE) { _syncBalance(); }
/**
* @dev balance sync, also moves the vector clock if it has different value
*/
function _syncBalance() internal {
assert(int256(address(this).balance) >= accountedBalance);
uint256 diff = uint256(int256(address(this).balance) - accountedBalance);
if (diff > 0) {
accountedBalance = int256(address(this).balance);
recentReceived += diff;
_vectorClockTick();
emit BalanceSynced(diff);
}
}
/**
* @dev operator reports current alive validators count and overall balance
* with default appreciation limit
*/
function pushBeacon(uint256 _aliveValidators, uint256, bytes32 clock) external onlyRole(ORACLE_ROLE) {
uint256 limit = 1000 * 32 ether/currentReserve() ;
_pushBeacon(_aliveValidators, clock, limit);
// try to initiate restaking operations
IRockXRestaking(restakingContract).withdrawBeforeRestaking();
IRockXRestaking(restakingContract).claimDelayedWithdrawals(type(uint256).max);
}
/**
* @dev operator reports current alive validators count and overall balance
* with custom appreciation limit
*/
function pushBeacon(uint256 _aliveValidators, uint256, bytes32 clock, uint256 limit) external onlyRole(ORACLE_ROLE) {
_pushBeacon(_aliveValidators, clock, limit);
// try to initiate restaking operations
IRockXRestaking(restakingContract).withdrawBeforeRestaking();
IRockXRestaking(restakingContract).claimDelayedWithdrawals(type(uint256).max);
}
function _pushBeacon(uint256 _aliveValidators, bytes32 clock, uint256 limit) internal {
_require(vectorClock == clock, "SYS012");
_require(_aliveValidators + stoppedValidators <= nextValidatorId, "SYS013");
// step 0. collect new revenue if there is any.
_syncBalance();
// Check recentStopped and recentReceived to see they match,
// this works until we can earn 32ETH per day
if (totalDebts > 0) {
_require(recentReceived/DEPOSIT_SIZE == recentStopped, "SYS030");
}
// step 1. check if new validator increased
// and adjust rewardBase to include the new validators' value
uint256 rewardBase = reportedValidatorBalance;
if (_aliveValidators + recentStopped > reportedValidators) {
// newly launched validators
uint256 newValidators = _aliveValidators + recentStopped - reportedValidators;
rewardBase += newValidators * DEPOSIT_SIZE;
}
// step 2. calc rewards, this also considers recentReceived ethers from
// either stopped validators or withdrawed ethers as rewards.
//
// During two consecutive pushBeacon operation, the ethers will ONLY:
// 1. staked to new validators
// 2. move from active validators to this contract
// 3. slashed and stopped then the remaining ethers returned to this contract
//
// so, at any time, revenue generated if:
//
// current active validator balance
// + recent received from validators(since last pushBeacon)
// + recent slashed(since last pushBeacon)
// >(GREATER THAN) reward base(last active validator balance + new nodes balance)
//
// NOTE(x): recentSlashed is accounted here, then we can adjust the basepoint to current alive validator balance.
// eg:
// _aliveBalance = 0 (slashed)
// recentReceived = 16 ETH (the ethers left)
// recentSlashed = 16 ETH (assumed slashed ethers)
//
uint256 _aliveBalance = _aliveValidators * DEPOSIT_SIZE; // computed balance
_require(_aliveBalance + recentReceived + recentSlashed >= rewardBase, "SYS015");
uint256 rewards = _aliveBalance + recentReceived + recentSlashed - rewardBase;
if (totalDebts > 0) {
// as we cannot differentiate the ethers from full withdrawal & partial withdrawal,
// to make sure we only take partial withdrawal(revenue) into reward calculation
_require(rewards * 1000 / currentReserve() < limit, "SYS016");
}
_distributeRewards(rewards);
_autocompound();
// step 3. update reportedValidators & reportedValidatorBalance
// reset the recentReceived to 0
reportedValidatorBalance = _aliveBalance;
reportedValidators = _aliveValidators;
recentReceived = 0;
recentSlashed = 0;
recentStopped = 0;
}
/**
* @dev emergentFixRecentReceived
*/
function emergentFixRecentReceived(uint256 diff) external onlyRole(DEFAULT_ADMIN_ROLE) {
recentReceived += diff;
}
/**
* @dev notify some validators stopped, and pay the debts
*/
function validatorStopped(bytes [] calldata _stoppedPubKeys, bytes32 clock) external nonReentrant onlyRole(ORACLE_ROLE) {
_require(vectorClock == clock, "SYS012");
uint256 amountUnstaked = _stoppedPubKeys.length * DEPOSIT_SIZE;
_require(_stoppedPubKeys.length > 0, "SYS017");
_require(_stoppedPubKeys.length + stoppedValidators <= nextValidatorId, "SYS018");
_require(address(this).balance >= amountUnstaked + totalPending + accountedManagerRevenue, "SYS019");
// track stopped validators
for (uint i=0;i<_stoppedPubKeys.length;i++) {
bytes32 pubkeyHash = keccak256(_stoppedPubKeys[i]);
_require(pubkeyIndices[pubkeyHash] > 0, "SYS006");
uint256 index = pubkeyIndices[pubkeyHash] - 1;
_require(!validatorRegistry[index].stopped, "SYS020");
validatorRegistry[index].stopped = true;
}
stoppedValidators += _stoppedPubKeys.length;
recentStopped += _stoppedPubKeys.length;
// NOTE(x) The following procedure MUST keep currentReserve unchanged:
// ASSUMING: paid == amountUnstaked
//
// totalPending + (totalStaked - amountUnstaked) + accountedUserRevenue - rewardDebt - (totalDebts - paid)
// ==
// totalPending + totalStaked + accountedUserRevenue - totalDebts - rewardDebt
//
// pay debts
uint256 paid = _payDebts(amountUnstaked);
_require(paid == amountUnstaked, "SYS021");
// track total staked ethers
totalStaked -= amountUnstaked;
// log
emit ValidatorStopped(_stoppedPubKeys.length);
// vector clock moves
_vectorClockTick();
}
/**
* @dev notify some validators has been slashed, turn off those stopped validator
*/
function validatorSlashedStop(bytes [] calldata _stoppedPubKeys, bytes32 clock) external nonReentrant onlyRole(ORACLE_ROLE) {
_require(vectorClock == clock, "SYS012");
uint256 amountUnstaked = _stoppedPubKeys.length * DEPOSIT_SIZE;
_require(_stoppedPubKeys.length > 0, "SYS017");
_require(address(this).balance >= _stoppedPubKeys.length * 16 ether + totalPending + accountedManagerRevenue, "SYS019");
// record slashed validators.
for (uint i=0;i<_stoppedPubKeys.length;i++) {
bytes32 pubkeyHash = keccak256(_stoppedPubKeys[i]);
_require(pubkeyIndices[pubkeyHash] > 0, "SYS006");
uint256 index = pubkeyIndices[pubkeyHash] - 1;
_require(!validatorRegistry[index].stopped, "SYS020");
validatorRegistry[index].stopped = true;
}
stoppedValidators += _stoppedPubKeys.length;
recentStopped += _stoppedPubKeys.length;
// currentReserve changed to:
// (totalPending + 16 ETH) + (totalStaked - amountUnstaked) + accountedUserRevenue - rewardDebt - totalDebts
// the remaining part(revenue) will be taken as the accruing rewards of existing holders.
totalStaked -= amountUnstaked;
totalPending += _stoppedPubKeys.length * 16 ether;
// track recent slashed
recentSlashed += _stoppedPubKeys.length * 16 ether;
// log
emit ValidatorSlashedStopped(_stoppedPubKeys.length);
// vector clock moves
_vectorClockTick();
}
/**
* ======================================================================================
*
* VIEW FUNCTIONS
*
* ======================================================================================
*/
/**
* @dev returns current reserve of ethers
*/
function currentReserve() public view returns(uint256) {
return totalPending + totalStaked + accountedUserRevenue - totalDebts - rewardDebts;
}
/*
* @dev returns current vector clock
*/
function getVectorClock() external view returns(bytes32) { return vectorClock; }
/*
* @dev returns current accounted balance
*/
function getAccountedBalance() external view returns(int256) { return accountedBalance; }
/**
* @dev return total staked ethers
*/
function getTotalStaked() external view returns (uint256) { return totalStaked; }
/**
* @dev return pending ethers
*/
function getPendingEthers() external view returns (uint256) { return totalPending; }
/**
* @dev return reward debts
*/
function getRewardDebts() external view returns (uint256) { return rewardDebts; }
/**
* @dev return current debts
*/
function getCurrentDebts() external view returns (uint256) { return totalDebts; }
/**
* @dev returns the accounted user revenue
*/
function getAccountedUserRevenue() external view returns (uint256) { return accountedUserRevenue; }
/**
* @dev returns the accounted manager's revenue
*/
function getAccountedManagerRevenue() external view returns (uint256) { return accountedManagerRevenue; }
/*
* @dev returns accumulated beacon validators
*/
function getReportedValidators() external view returns (uint256) { return reportedValidators; }
/*
* @dev returns reported validator balance snapshot
*/
function getReportedValidatorBalance() external view returns (uint256) { return reportedValidatorBalance; }
/*
* @dev returns recent slashed value
*/
function getRecentSlashed() external view returns (uint256) { return recentSlashed; }
/*
* @dev returns recent received value
*/
function getRecentReceived() external view returns (uint256) { return recentReceived; }
/*
* @dev returns recent received value
*/
function getRecentStopped() external view returns (uint256) { return recentStopped; }
/**
* @dev return debt for an account
*/
function debtOf(address account) external view returns (uint256) {
return userDebts[account];
}
/**
* @dev return number of registered validator
*/
function getRegisteredValidatorsCount() external view returns (uint256) {
return validatorRegistry.length;
}
/**
* @dev return a batch of validators credential
*/
function getRegisteredValidators(uint256 idx_from, uint256 idx_to) external view returns (bytes [] memory pubkeys, bytes [] memory signatures, bool[] memory stopped) {
pubkeys = new bytes[](idx_to - idx_from);
signatures = new bytes[](idx_to - idx_from);
stopped = new bool[](idx_to - idx_from);
uint counter = 0;
for (uint i = idx_from; i < idx_to;i++) {
pubkeys[counter] = validatorRegistry[i].pubkey;
signatures[counter] = validatorRegistry[i].signature;
stopped[counter] = validatorRegistry[i].stopped;
counter++;
}
}
/**
* @dev return a batch of validators information
* UPDATE(20240119): V2 returns restaking info
*/
function getRegisteredValidatorsV2(uint256 idx_from, uint256 idx_to) external view returns (
bytes [] memory pubkeys,
bytes [] memory signatures,
bool [] memory stopped,
bool [] memory restaking)
{
pubkeys = new bytes[](idx_to - idx_from);
signatures = new bytes[](idx_to - idx_from);
stopped = new bool[](idx_to - idx_from);
restaking = new bool[](idx_to - idx_from);
uint counter = 0;
for (uint i = idx_from; i < idx_to;i++) {
pubkeys[counter] = validatorRegistry[i].pubkey;
signatures[counter] = validatorRegistry[i].signature;
stopped[counter] = validatorRegistry[i].stopped;
restaking[counter] = validatorRegistry[i].restaking;
counter++;
}
}
/**
* @dev return next validator id
*/
function getNextValidatorId() external view returns (uint256) { return nextValidatorId; }
/**
* @dev return exchange ratio of , multiplied by 1e18
*/
function exchangeRatio() external view returns (uint256) {
uint256 xETHAmount = IERC20(xETHAddress).totalSupply();
if (xETHAmount == 0) {
return 1 * MULTIPLIER;
}
uint256 ratio = currentReserve() * MULTIPLIER / xETHAmount;
return ratio;
}
/**
* @dev return debt of index
*/
function checkDebt(uint256 index) external view returns (address account, uint256 amount) {
Debt memory debt = etherDebts[index];
return (debt.account, debt.amount);
}
/**
* @dev return debt queue index
*/
function getDebtQueue() external view returns (uint256 first, uint256 last) {
return (firstDebt, lastDebt);
}
/**
* @dev get stopped validators count
*/
function getStoppedValidatorsCount() external view returns (uint256) { return stoppedValidators; }
/**
* @dev get used quota
*/
function getQuota(address account) external view returns (uint256) { return quotaUsed[account]; }
/**
* @dev check whitelist enabled
*/
function isWhiteListed(address account) external view returns (bool) { return whiteList[account]; }
/**
* ======================================================================================
*
* EXTERNAL FUNCTIONS
*
* ======================================================================================
*/
/**
* @dev mint xETH with ETH
*/
function mint(uint256 minToMint, uint256 deadline) external payable nonReentrant whenNotPaused returns(uint256 minted){
_require(block.timestamp < deadline, "USR001");
_require(msg.value > 0, "USR002");
// for non KYC users, check the quota
if (!whiteList[msg.sender]) {
_require(quotaUsed[msg.sender] + msg.value <= 50000 ether, "USR003");
quotaUsed[msg.sender] += msg.value;
}
// track balance
_balanceIncrease(msg.value);
// mint xETH while keeping the exchange ratio invariant
uint256 totalXETH = IERC20(xETHAddress).totalSupply();
uint256 totalEthers = currentReserve();
uint256 toMint = 1 * msg.value; // default exchange ratio 1:1
if (totalEthers > 0) { // avert division overflow
toMint = totalXETH * msg.value / totalEthers;
}
// mint xETH
_require(toMint >= minToMint, "USR004");
IMintableContract(xETHAddress).mint(msg.sender, toMint);
totalPending += msg.value;
// try to initiate stake()
_stakeInternal();
// try to initiate restaking operations
IRockXRestaking(restakingContract).withdrawBeforeRestaking();
IRockXRestaking(restakingContract).claimDelayedWithdrawals(type(uint256).max);
return toMint;
}
/**
* @dev redeem N * 32Ethers, which will turn off validadators,
* note this function is asynchronous, the caller will only receive his ethers
* after the validator has turned off.
*
* this function is dedicated for institutional operations.
*
* redeem keeps the ratio invariant
*/
function redeemFromValidators(uint256 ethersToRedeem, uint256 maxToBurn, uint256 deadline) external nonReentrant onlyPhase(1) returns(uint256 burned) {
_require(block.timestamp < deadline, "USR001");
_require(ethersToRedeem % DEPOSIT_SIZE == 0, "USR005");
_require(ethersToRedeem > 0, "USR005");
uint256 totalXETH = IERC20(xETHAddress).totalSupply();
uint256 xETHToBurn = totalXETH * ethersToRedeem / currentReserve();
_require(xETHToBurn <= maxToBurn, "USR004");
// NOTE: the following procdure must keep exchangeRatio invariant:
// transfer xETH from sender & burn
IERC20(xETHAddress).safeTransferFrom(msg.sender, address(this), xETHToBurn);
IMintableContract(xETHAddress).burn(xETHToBurn);
// queue ether debts
_enqueueDebt(msg.sender, ethersToRedeem);
// try to initiate restaking operations
IRockXRestaking(restakingContract).withdrawBeforeRestaking();
IRockXRestaking(restakingContract).claimDelayedWithdrawals(type(uint256).max);
// return burned
return xETHToBurn;
}
/**
* ======================================================================================
*
* INTERNAL FUNCTIONS
*
* ======================================================================================
*/
function _balanceIncrease(uint256 amount) internal { accountedBalance += int256(amount); }
function _balanceDecrease(uint256 amount) internal { accountedBalance -= int256(amount); }
function _vectorClockTick() internal {
vectorClockTicks++;
vectorClock = keccak256(abi.encodePacked(vectorClock, block.timestamp, vectorClockTicks));
}
function _enqueueDebt(address account, uint256 amount) internal {
// debt is paid in FIFO queue
lastDebt += 1;
etherDebts[lastDebt] = Debt({account:account, amount:amount});
// track user debts
userDebts[account] += amount;
// track total debts
totalDebts += amount;
// log
emit DebtQueued(account, amount);
}
function _dequeueDebt() internal returns (Debt memory debt) {
_require(lastDebt >= firstDebt, "SYS022"); // non-empty queue
debt = etherDebts[firstDebt];
delete etherDebts[firstDebt];
firstDebt += 1;
}
/**
* @dev pay debts for a given amount
*/
function _payDebts(uint256 total) internal returns(uint256 amountPaid) {
_require(address(redeemContract) != address(0x0), "SYS023");
// ethers to pay
for (uint i=firstDebt;i<=lastDebt;i++) {
if (total == 0) {
break;
}
Debt storage debt = etherDebts[i];
// clean debts
uint256 toPay = debt.amount <= total? debt.amount:total;
debt.amount -= toPay;
total -= toPay;
userDebts[debt.account] -= toPay;
amountPaid += toPay;
// transfer money to debt contract
IRockXRedeem(redeemContract).pay{value:toPay}(debt.account);
// dequeue if cleared
if (debt.amount == 0) {
_dequeueDebt();
}
}
totalDebts -= amountPaid;
// track balance
_balanceDecrease(amountPaid);
}
/**
* @dev distribute revenue
*/
function _distributeRewards(uint256 rewards) internal {
// rewards distribution
uint256 fee = rewards * managerFeeShare / 1000;
accountedManagerRevenue += fee;
accountedUserRevenue += rewards - fee;
emit RevenueAccounted(rewards);
}
/**
* @dev auto compounding, after shanghai merge, called in pushBeacon
*/
function _autocompound() internal {
if (autoCompoundEnabled) {
// contract balance consists of maximum:
// validator assets to clear debts, rewards after shanghai merge(compound), user's pending ethers to mint and manager's revenue.
// autocompound & payDebts will race to use the incoming ethers, but eventually both will succeed.
if (address(this).balance > accountedManagerRevenue + totalPending) {
uint256 maxCompound = accountedUserRevenue - rewardDebts;
uint256 maxUsable = address(this).balance - accountedManagerRevenue - totalPending;
uint256 effectiveEthers = maxCompound < maxUsable? maxCompound:maxUsable;
totalPending += effectiveEthers;
rewardDebts += effectiveEthers;
}
}
}
/**
* @dev spin up the node
*/
function _spinup() internal {
// load credential
ValidatorCredential memory cred = validatorRegistry[nextValidatorId];
// UPDATE(20240115):
// switch withdrawal credential based on it's registration
if (!cred.restaking) {
_stake(cred.pubkey, cred.signature, withdrawalCredentials);
} else {
address eigenPod = IRockXRestaking(restakingContract).eigenPod();
bytes memory eigenPodCred = abi.encodePacked(bytes1(0x01), new bytes(11), eigenPod);
bytes32 restakingWithdrawalCredentials = BytesLib.toBytes32(eigenPodCred, 0);
_stake(cred.pubkey, cred.signature, restakingWithdrawalCredentials);
}
nextValidatorId++;
// track total staked & total pending ethers
totalStaked += DEPOSIT_SIZE;
totalPending -= DEPOSIT_SIZE;
}
/**
* @dev Invokes a deposit call to the official Deposit contract
* UPDATE(20240115): add param withCred, instead of using contract variable
*/
function _stake(bytes memory pubkey, bytes memory signature, bytes32 withCred) internal {
_require(withCred != bytes32(0x0), "SYS024");
uint256 value = DEPOSIT_SIZE;
uint256 depositAmount = DEPOSIT_SIZE / DEPOSIT_AMOUNT_UNIT;
assert(depositAmount * DEPOSIT_AMOUNT_UNIT == value); // properly rounded
// Compute deposit data root (`DepositData` hash tree root)
// https://etherscan.io/address/0x00000000219ab540356cbb839cbe05303d7705fa#code
bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0)));
bytes32 signature_root = sha256(abi.encodePacked(
sha256(BytesLib.slice(signature, 0, 64)),
sha256(abi.encodePacked(BytesLib.slice(signature, 64, SIGNATURE_LENGTH - 64), bytes32(0)))
));
bytes memory amount = to_little_endian_64(uint64(depositAmount));
bytes32 depositDataRoot = sha256(abi.encodePacked(
sha256(abi.encodePacked(pubkey_root, withCred)),
sha256(abi.encodePacked(amount, bytes24(0), signature_root))
));
IDepositContract(ethDepositContract).deposit{value:DEPOSIT_SIZE} (
pubkey, abi.encodePacked(withCred), signature, depositDataRoot);
// track balance
_balanceDecrease(DEPOSIT_SIZE);
}
/**
* @dev to little endian
* https://etherscan.io/address/0x00000000219ab540356cbb839cbe05303d7705fa#code
*/
function to_little_endian_64(uint64 value) internal pure returns (bytes memory ret) {
ret = new bytes(8);
bytes8 bytesValue = bytes8(value);
// Byteswapping during copying to bytes.
ret[0] = bytesValue[7];
ret[1] = bytesValue[6];
ret[2] = bytesValue[5];
ret[3] = bytesValue[4];
ret[4] = bytesValue[3];
ret[5] = bytesValue[2];
ret[6] = bytesValue[1];
ret[7] = bytesValue[0];
}
/**
* @dev function version of _require, which could make the code size smaller
*/
function _require(bool condition, string memory text) private pure {
require(condition, text);
}
/**
* ======================================================================================
*
* ROCKX SYSTEM EVENTS
*
* ======================================================================================
*/
event ValidatorActivated(uint256 nextValidatorId);
event ValidatorStopped(uint256 stoppedCount);
event RevenueAccounted(uint256 amount);
event ValidatorSlashedStopped(uint256 stoppedCount);
event ManagerAccountSet(address account);
event ManagerFeeSet(uint256 milli);
event ManagerFeeWithdrawed(uint256 amount, address);
event WithdrawCredentialSet(bytes32 withdrawCredential);
event RestakingAddressSet(address addr);
event DebtQueued(address creditor, uint256 amountEther);
event XETHContractSet(address addr);
event DepositContractSet(address addr);
event RedeemContractSet(address addr);
event BalanceSynced(uint256 diff);
event WhiteListToggle(address account, bool enabled);
event AutoCompoundToggle(bool enabled);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "IERC20.sol";
interface IMintableContract is IERC20 {
function mint(address account, uint256 amount) external;
function burn(uint256 amount) external;
}
// This interface is designed to be compatible with the Vyper version.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IDepositContract {
/// @notice A processed deposit event.
event DepositEvent(
bytes pubkey,
bytes withdrawal_credentials,
bytes amount,
bytes signature,
bytes index
);
/// @notice Submit a Phase 0 DepositData object.
/// @param pubkey A BLS12-381 public key.
/// @param withdrawal_credentials Commitment to a public key for withdrawals.
/// @param signature A BLS12-381 signature.
/// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
/// Used as a protection against malformed input.
function deposit(
bytes calldata pubkey,
bytes calldata withdrawal_credentials,
bytes calldata signature,
bytes32 deposit_data_root
) external payable;
/// @notice Query the current deposit root hash.
/// @return The deposit root hash.
function get_deposit_root() external view returns (bytes32);
/// @notice Query the current deposit count.
/// @return The deposit count encoded as a little endian 64-bit number.
function get_deposit_count() external view returns (bytes memory);
}
interface IRockXRedeem {
function pay(address account) external payable;
}
interface IRockXRestaking {
function getPendingWithdrawalAmount() external view returns (uint256);
function withdrawBeforeRestaking() external;
function claimDelayedWithdrawals(uint256 maxNumberOfWithdrawalsToClaim) external;
function eigenPod() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "IERC20.sol";
import "Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* 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]
* ```
* 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 Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 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. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = _setInitializedVersion(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.
*
* `initializer` is equivalent to `reinitializer(1)`, so 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.
*
* 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.
*/
modifier reinitializer(uint8 version) {
bool isTopLevelCall = _setInitializedVersion(version);
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_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() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @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.
*/
function _disableInitializers() internal virtual {
_setInitializedVersion(type(uint8).max);
}
function _setInitializedVersion(uint8 version) private returns (bool) {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, and for the lowest level
// of initializers, because in other contexts the contract may have been reentered.
if (_initializing) {
require(
version == 1 && !AddressUpgradeable.isContract(address(this)),
"Initializable: contract is already initialized"
);
return false;
} else {
require(_initialized < version, "Initializable: contract is already initialized");
_initialized = version;
return true;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "IAccessControlUpgradeable.sol";
import "ContextUpgradeable.sol";
import "StringsUpgradeable.sol";
import "ERC165Upgradeable.sol";
import "Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
StringsUpgradeable.toHexString(uint160(account), 20),
" is missing role ",
StringsUpgradeable.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "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;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "IERC165Upgradeable.sol";
import "Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)
pragma solidity ^0.8.0;
import "ContextUpgradeable.sol";
import "Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}{
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 200
},
"libraries": {
"rockx_staking.sol": {}
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"AutoCompoundToggle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"diff","type":"uint256"}],"name":"BalanceSynced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"creditor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountEther","type":"uint256"}],"name":"DebtQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"DepositContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"ManagerAccountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"milli","type":"uint256"}],"name":"ManagerFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"ManagerFeeWithdrawed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"RedeemContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"RestakingAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RevenueAccounted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nextValidatorId","type":"uint256"}],"name":"ValidatorActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stoppedCount","type":"uint256"}],"name":"ValidatorSlashedStopped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stoppedCount","type":"uint256"}],"name":"ValidatorStopped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"WhiteListToggle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawCredential","type":"bytes32"}],"name":"WithdrawCredentialSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"XETHContractSet","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REGISTRY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"checkDebt","outputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"debtOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"diff","type":"uint256"}],"name":"emergentFixRecentReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethDepositContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccountedBalance","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccountedManagerRevenue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccountedUserRevenue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentDebts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDebtQueue","outputs":[{"internalType":"uint256","name":"first","type":"uint256"},{"internalType":"uint256","name":"last","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextValidatorId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingEthers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getQuota","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRecentReceived","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRecentSlashed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRecentStopped","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idx_from","type":"uint256"},{"internalType":"uint256","name":"idx_to","type":"uint256"}],"name":"getRegisteredValidators","outputs":[{"internalType":"bytes[]","name":"pubkeys","type":"bytes[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"},{"internalType":"bool[]","name":"stopped","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegisteredValidatorsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idx_from","type":"uint256"},{"internalType":"uint256","name":"idx_to","type":"uint256"}],"name":"getRegisteredValidatorsV2","outputs":[{"internalType":"bytes[]","name":"pubkeys","type":"bytes[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"},{"internalType":"bool[]","name":"stopped","type":"bool[]"},{"internalType":"bool[]","name":"restaking","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReportedValidatorBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReportedValidators","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardDebts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStoppedValidatorsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVectorClock","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isWhiteListed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managerFeeShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minToMint","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"minted","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_aliveValidators","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"clock","type":"bytes32"}],"name":"pushBeacon","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_aliveValidators","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"clock","type":"bytes32"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"pushBeacon","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethersToRedeem","type":"uint256"},{"internalType":"uint256","name":"maxToBurn","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"redeemFromValidators","outputs":[{"internalType":"uint256","name":"burned","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"pubkeys","type":"bytes[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"registerRestakingValidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"registerValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"pubkeys","type":"bytes[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"}],"name":"registerValidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"oldpubkey","type":"bytes"},{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"replaceValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"oldpubkeys","type":"bytes[]"},{"internalType":"bytes[]","name":"pubkeys","type":"bytes[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"},{"internalType":"bool","name":"restaking","type":"bool"}],"name":"replaceValidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restakingContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ethDepositContract","type":"address"}],"name":"setETHDepositContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"milli","type":"uint256"}],"name":"setManagerFeeShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_redeemContract","type":"address"}],"name":"setRedeemContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"withdrawalCredentials_","type":"bytes32"}],"name":"setWithdrawCredential","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_xETHContract","type":"address"}],"name":"setXETHContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPhase","type":"uint256"}],"name":"switchPhase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"syncBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleAutoCompound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"toggleWhiteList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_stoppedPubKeys","type":"bytes[]"},{"internalType":"bytes32","name":"clock","type":"bytes32"}],"name":"validatorSlashedStop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_stoppedPubKeys","type":"bytes[]"},{"internalType":"bytes32","name":"clock","type":"bytes32"}],"name":"validatorStopped","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawManagerFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalCredentials","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xETHAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b62000152565b6200002e60ff62000031565b50565b60008054610100900460ff1615620000ca578160ff1660011480156200006a575062000068306200014360201b620036011760201c565b155b620000c25760405162461bcd60e51b815260206004820152602e602482015260008051602062005c4383398151915260448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b506000919050565b60005460ff808416911610620001295760405162461bcd60e51b815260206004820152602e602482015260008051602062005c4383398151915260448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401620000b9565b506000805460ff191660ff92909216919091179055600190565b6001600160a01b03163b151590565b615ae180620001626000396000f3fe6080604052600436106103fe5760003560e01c80636f9170f611610213578063cdb54a1b11610123578063e7efb747116100ab578063f22abf371161007a578063f22abf3714610c20578063f5404d6014610c4f578063fa0ec2ce14610c6f578063fc65260a14610c8f578063fd9c652b14610caf57600080fd5b8063e7efb74714610b95578063ec87621c14610bb5578063ecacf56d14610be9578063f1f3b3e714610bff57600080fd5b8063da863b3b116100f2578063da863b3b14610af5578063dc3fc3b214610b0b578063e08f2d8914610b35578063e43a495414610b4b578063e63ab1e914610b6157600080fd5b8063cdb54a1b14610a68578063d283e75f14610a7e578063d547741f14610ab5578063d7d2546114610ad557600080fd5b806391d14854116101a6578063a217fddf11610175578063a217fddf1461098a578063aba525361461099f578063b181033a146109b5578063c3d51709146109d5578063c8c3df4a146109f557600080fd5b806391d1485414610914578063934548171461093457806399629f5814610954578063a065913f1461097457600080fd5b80638456cb59116101e25780638456cb59146108b457806389d00678146108c95780638b0bfd35146108de57806391b66caa146108f457600080fd5b80636f9170f61461081a57806372cda18214610854578063755d7dd3146108745780637a4473e11461089457600080fd5b80633f4ba83a1161030e5780634f431a6f116102a157806363e547171161027057806363e547171461078e57806364363f2b146107ae5780636a42602c146107c45780636bb022c8146107da5780636e6ac7e7146107fa57600080fd5b80634f431a6f146107205780635662f706146107405780635c975abb1461076057806361c993c51461077857600080fd5b806349557df9116102dd57806349557df9146106b4578063496bf5bb146106ca5780634cd79e0a146106ea5780634e8ab1a11461070057600080fd5b80633f4ba83a146106315780634006ccc51461064657806342f1e8791461065b57806343a2a3021461067d57600080fd5b80632e12007c1161039157806336568abe1161036057806336568abe1461057757806336bf3325146105975780633884545d146105b45780633a4b66f1146105ec5780633bf39dca1461060157600080fd5b80632e12007c146105165780632f2ff15d1461052b57806330b12c8d1461054b57806333e5761f1461056157600080fd5b80631b2ef1ca116103cd5780631b2ef1ca1461049b578063226f2645146104ae578063248a9ca3146104d05780632ae45fa11461050057600080fd5b806301ffc9a71461040a57806307e2cea51461043f57806308b84c0c1461046f5780630917e7761461048557600080fd5b3661040557005b600080fd5b34801561041657600080fd5b5061042a610425366004615053565b610cc4565b60405190151581526020015b60405180910390f35b34801561044b57600080fd5b50610461600080516020615a6c83398151915281565b604051908152602001610436565b34801561047b57600080fd5b5061010b54610461565b34801561049157600080fd5b5061010454610461565b6104616104a936600461507d565b610cfb565b3480156104ba57600080fd5b506104ce6104c93660046150e7565b611093565b005b3480156104dc57600080fd5b506104616104eb366004615152565b60009081526097602052604090206001015490565b34801561050c57600080fd5b5061011754610461565b34801561052257600080fd5b50610461611274565b34801561053757600080fd5b506104ce610546366004615180565b6112b7565b34801561055757600080fd5b5061010054610461565b34801561056d57600080fd5b5061010f54610461565b34801561058357600080fd5b506104ce610592366004615180565b6112e1565b3480156105a357600080fd5b506104616801bc16d674ec80000081565b3480156105c057600080fd5b5060fb546105d4906001600160a01b031681565b6040516001600160a01b039091168152602001610436565b3480156105f857600080fd5b506104ce61135f565b34801561060d57600080fd5b5061062161061c36600461507d565b611369565b604051610436949392919061529d565b34801561063d57600080fd5b506104ce61172f565b34801561065257600080fd5b50610461611764565b34801561066757600080fd5b50610461600080516020615a8c83398151915281565b34801561068957600080fd5b506104616106983660046152ea565b6001600160a01b03166000908152610137602052604090205490565b3480156106c057600080fd5b5061011454610461565b3480156106d657600080fd5b506104ce6106e5366004615307565b61182d565b3480156106f657600080fd5b5061046160ff5481565b34801561070c57600080fd5b506104ce61071b366004615377565b611940565b34801561072c57600080fd5b506104ce61073b3660046152ea565b611c24565b34801561074c57600080fd5b506104ce61075b3660046153d6565b611c9b565b34801561076c57600080fd5b5060335460ff1661042a565b34801561078457600080fd5b5061010a54610461565b34801561079a57600080fd5b506104ce6107a9366004615152565b611fe1565b3480156107ba57600080fd5b5061010354610461565b3480156107d057600080fd5b5061010d54610461565b3480156107e657600080fd5b506104ce6107f53660046152ea565b61202f565b34801561080657600080fd5b506104ce610815366004615152565b612088565b34801561082657600080fd5b5061042a6108353660046152ea565b6001600160a01b03166000908152610138602052604090205460ff1690565b34801561086057600080fd5b506104ce61086f3660046152ea565b6120af565b34801561088057600080fd5b506104ce61088f366004615152565b612108565b3480156108a057600080fd5b5060fd546105d4906001600160a01b031681565b3480156108c057600080fd5b506104ce612175565b3480156108d557600080fd5b506104ce6121a7565b3480156108ea57600080fd5b5061010554610461565b34801561090057600080fd5b506104ce61090f3660046152ea565b612202565b34801561092057600080fd5b5061042a61092f366004615180565b61225b565b34801561094057600080fd5b506104ce61094f366004615421565b612286565b34801561096057600080fd5b506104ce61096f3660046153d6565b6122a9565b34801561098057600080fd5b5061010c54610461565b34801561099657600080fd5b50610461600081565b3480156109ab57600080fd5b5061011054610461565b3480156109c157600080fd5b5060fc546105d4906001600160a01b031681565b3480156109e157600080fd5b506104ce6109f0366004615453565b612587565b348015610a0157600080fd5b50610a49610a10366004615152565b60009081526101066020908152604091829020825180840190935280546001600160a01b03168084526001909101549290910182905291565b604080516001600160a01b039093168352602083019190915201610436565b348015610a7457600080fd5b5061010e54610461565b348015610a8a57600080fd5b50610461610a993660046152ea565b6001600160a01b03166000908152610109602052604090205490565b348015610ac157600080fd5b506104ce610ad0366004615180565b6127cf565b348015610ae157600080fd5b506104ce610af0366004615152565b6127f4565b348015610b0157600080fd5b5061010254610461565b348015610b1757600080fd5b50610107546101085460408051928352602083019190915201610436565b348015610b4157600080fd5b5061011154610461565b348015610b5757600080fd5b5061046160fe5481565b348015610b6d57600080fd5b506104617f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b348015610ba157600080fd5b506104ce610bb0366004615377565b612834565b348015610bc157600080fd5b506104617f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0881565b348015610bf557600080fd5b5061011254610461565b348015610c0b57600080fd5b5061013c546105d4906001600160a01b031681565b348015610c2c57600080fd5b50610c40610c3b36600461507d565b612a9a565b604051610436939291906154ec565b348015610c5b57600080fd5b50610461610c6a366004615307565b612db9565b348015610c7b57600080fd5b506104ce610c8a366004615180565b6130bc565b348015610c9b57600080fd5b506104ce610caa36600461553d565b61331a565b348015610cbb57600080fd5b506104ce6135e1565b60006001600160e01b03198216637965db0b60e01b1480610cf557506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000600260c9541415610d295760405162461bcd60e51b8152600401610d20906155ea565b60405180910390fd5b600260c95560335460ff1615610d745760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610d20565b610d9e8242106040518060400160405280600681526020016555535230303160d01b815250613610565b610dc960003411604051806040016040528060068152602001652aa9a918181960d11b815250613610565b336000908152610138602052604090205460ff16610e59573360009081526101376020526040902054610e3390690a968163f0a57b40000090610e0d903490615637565b11156040518060400160405280600681526020016555535230303360d01b815250613610565b336000908152610137602052604081208054349290610e53908490615637565b90915550505b610e623461362f565b60fc54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015610eac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed0919061564f565b90506000610edc611274565b90506000610eeb346001615668565b90508115610f0b5781610efe3485615668565b610f08919061569d565b90505b610f3686821015604051806040016040528060068152602001651554d48c0c0d60d21b815250613610565b60fc546040516340c10f1960e01b8152336004820152602481018390526001600160a01b03909116906340c10f1990604401600060405180830381600087803b158015610f8257600080fd5b505af1158015610f96573d6000803e3d6000fd5b50505050346101036000828254610fad9190615637565b90915550610fbb905061364a565b61013c60009054906101000a90046001600160a01b03166001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561100c57600080fd5b505af1158015611020573d6000803e3d6000fd5b505061013c54604051636a270dbb60e11b815260001960048201526001600160a01b03909116925063d44e1b769150602401600060405180830381600087803b15801561106c57600080fd5b505af1158015611080573d6000803e3d6000fd5b5050600160c95550909695505050505050565b600080516020615a8c8339815191526110ab816136fe565b60408051808201909152600681526553595330303360d01b60208201526110d6906060841490613610565b60408051808201909152600681526514d654cc0c0d60d21b6020820152611101906030861490613610565b600085856040516111139291906156b1565b6040518091039020905061115c6101016000838152602001908152602001600020546000146040518060400160405280600681526020016553595330303560d01b815250613610565b6040805160a06020601f8901819004028201810190925260808101878152610100928291908a908a9081908501838280828437600092019190915250505090825250604080516020601f8901819004810282018101909252878152918101919088908890819084018382808284376000920182905250938552505050602080830182905260409092018190528354600181018555938152819020825180519394600302909101926112109284920190614f46565b5060208281015180516112299260018501920190614f46565b50604082810151600292909201805460609094015161ffff1990941692151561ff00191692909217610100931515840217909155905460009283526101016020529120555050505050565b600061010c546101055461010a5461010454610103546112949190615637565b61129e9190615637565b6112a891906156c1565b6112b291906156c1565b905090565b6000828152609760205260409020600101546112d2816136fe565b6112dc8383613708565b505050565b6001600160a01b03811633146113515760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610d20565b61135b828261378e565b5050565b61136761364a565b565b606080808061137886866156c1565b6001600160401b0381111561138f5761138f6156d8565b6040519080825280602002602001820160405280156113c257816020015b60608152602001906001900390816113ad5790505b5093506113cf86866156c1565b6001600160401b038111156113e6576113e66156d8565b60405190808252806020026020018201604052801561141957816020015b60608152602001906001900390816114045790505b50925061142686866156c1565b6001600160401b0381111561143d5761143d6156d8565b604051908082528060200260200182016040528015611466578160200160208202803683370190505b50915061147386866156c1565b6001600160401b0381111561148a5761148a6156d8565b6040519080825280602002602001820160405280156114b3578160200160208202803683370190505b5090506000865b868110156117245761010081815481106114d6576114d66156ee565b906000526020600020906003020160000180546114f290615704565b80601f016020809104026020016040519081016040528092919081815260200182805461151e90615704565b801561156b5780601f106115405761010080835404028352916020019161156b565b820191906000526020600020905b81548152906001019060200180831161154e57829003601f168201915b5050505050868381518110611582576115826156ee565b602002602001018190525061010081815481106115a1576115a16156ee565b906000526020600020906003020160010180546115bd90615704565b80601f01602080910402602001604051908101604052809291908181526020018280546115e990615704565b80156116365780601f1061160b57610100808354040283529160200191611636565b820191906000526020600020905b81548152906001019060200180831161161957829003601f168201915b505050505085838151811061164d5761164d6156ee565b6020026020010181905250610100818154811061166c5761166c6156ee565b906000526020600020906003020160020160009054906101000a900460ff1684838151811061169d5761169d6156ee565b60200260200101901515908115158152505061010081815481106116c3576116c36156ee565b906000526020600020906003020160020160019054906101000a900460ff168383815181106116f4576116f46156ee565b911515602092830291909101909101528161170e8161573f565b925050808061171c9061573f565b9150506114ba565b505092959194509250565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a611759816136fe565b6117616137f5565b50565b60008060fc60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117de919061564f565b9050806117fe576117f8670de0b6b3a76400006001615668565b91505090565b600081670de0b6b3a7640000611812611274565b61181c9190615668565b611826919061569d565b9392505050565b600080516020615a6c833981519152611845816136fe565b600061184f611274565b611863906906c6b935b8bbd400000061569d565b9050611870858483613888565b61013c60009054906101000a90046001600160a01b03166001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156118c157600080fd5b505af11580156118d5573d6000803e3d6000fd5b505061013c54604051636a270dbb60e11b815260001960048201526001600160a01b03909116925063d44e1b769150602401600060405180830381600087803b15801561192157600080fd5b505af1158015611935573d6000803e3d6000fd5b505050505050505050565b600080516020615a8c833981519152611958816136fe565b60408051808201909152600681526553595330303760d01b60208201526119829085841490613610565b8360005b81811015611c1b576119de60308888848181106119a5576119a56156ee565b90506020028101906119b7919061575a565b9050146040518060400160405280600681526020016514d654cc0c0d60d21b815250613610565b611a2e60608686848181106119f5576119f56156ee565b9050602002810190611a07919061575a565b9050146040518060400160405280600681526020016553595330303360d01b815250613610565b6000878783818110611a4257611a426156ee565b9050602002810190611a54919061575a565b604051611a629291906156b1565b60405180910390209050611aab6101016000838152602001908152602001600020546000146040518060400160405280600681526020016553595330303560d01b815250613610565b61010060405180608001604052808a8a86818110611acb57611acb6156ee565b9050602002810190611add919061575a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001888886818110611b2957611b296156ee565b9050602002810190611b3b919061575a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093855250505060208083018290526001604090930183905284549283018555938152839020825180519394600390930290910192611bac9284920190614f46565b506020828101518051611bc59260018501920190614f46565b50604082810151600292909201805460609094015161ffff1990941692151561ff001916929092176101009315158402179091559054600092835261010160205291205580611c138161573f565b915050611986565b50505050505050565b6000611c2f816136fe565b6001600160a01b03821660008181526101386020908152604091829020805460ff8082161560ff1990921682179092558351948552161515908301527f96993f732e425c7615ed977e16e6e83d84bb45203ca23885018335b66c2e85be91015b60405180910390a15050565b600260c9541415611cbe5760405162461bcd60e51b8152600401610d20906155ea565b600260c955600080516020615a6c833981519152611cdb816136fe565b611d088261011254146040518060400160405280600681526020016529aca998189960d11b815250613610565b6000611d1d6801bc16d674ec80000085615668565b9050611d4d600086869050116040518060400160405280600681526020016553595330313760d01b815250613610565b61010b5461010354611da79190611d6c8767de0b6b3a76400000615668565b611d769190615637565b611d809190615637565b4710156040518060400160405280600681526020016553595330313960d01b815250613610565b60005b84811015611ef5576000868683818110611dc657611dc66156ee565b9050602002810190611dd8919061575a565b604051611de69291906156b1565b60405180910390209050611e2f6000610101600084815260200190815260200160002054116040518060400160405280600681526020016529aca998181b60d11b815250613610565b60008181526101016020526040812054611e4b906001906156c1565b9050611ea86101008281548110611e6457611e646156ee565b906000526020600020906003020160020160009054906101000a900460ff16156040518060400160405280600681526020016505359533032360d41b815250613610565b60016101008281548110611ebe57611ebe6156ee565b60009182526020909120600390910201600201805460ff191691151591909117905550819050611eed8161573f565b915050611daa565b50848490506101146000828254611f0c9190615637565b90915550506101178054859190600090611f27908490615637565b92505081905550806101046000828254611f4191906156c1565b90915550611f5990508467de0b6b3a76400000615668565b6101036000828254611f6b9190615637565b90915550611f8390508467de0b6b3a76400000615668565b6101106000828254611f959190615637565b90915550506040518481527f0c5c941f6f7b3b7b1624e8a6738cdc96705c25510de1f11ff37671927a5c47c09060200160405180910390a1611fd5613ab0565b5050600160c955505050565b6000611fec816136fe565b610115548210156120285760405162461bcd60e51b815260206004820152600660248201526529aca998181960d11b6044820152606401610d20565b5061011555565b600061203a816136fe565b60fd80546001600160a01b0319166001600160a01b0384169081179091556040519081527f4d3d3f5d1d8423a4e40b3fcfccaf0c1b18ca550a8592d5e38a61765931a9cf7890602001611c8f565b6000612093816136fe565b8161011160008282546120a69190615637565b90915550505050565b60006120ba816136fe565b60fc80546001600160a01b0319166001600160a01b0384169081179091556040519081527f65f24f264bd70348b9888b2fbf27cd04f9e2fb0fcc50dde8fb36483576ef32a390602001611c8f565b6000612113816136fe565b6121406103e8831115604051806040016040528060068152602001650a6b2a66060760d31b815250613610565b60fe8290556040518281527f4de90ec86e1bc56c192e2399bacbd10bdaba720caca606354d66c5cb33d6802b90602001611c8f565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61219f816136fe565b611761613b05565b60006121b2816136fe565b610139805460ff8082161560ff1990921682179092556040519116151581527f0e1bdbe9c15a50fbc7d124adb288d201acc7b9a8a535b003ca6ba80b7c9f5335906020015b60405180910390a150565b600061220d816136fe565b60fb80546001600160a01b0319166001600160a01b0384169081179091556040519081527f1781ac9526b978975dba0fd26a33e044a55a7ace054a3ee7efa5f8459513bead90602001611c8f565b60009182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600080516020615a6c83398151915261229e816136fe565b611870858484613888565b600260c95414156122cc5760405162461bcd60e51b8152600401610d20906155ea565b600260c955600080516020615a6c8339815191526122e9816136fe565b6123168261011254146040518060400160405280600681526020016529aca998189960d11b815250613610565b600061232b6801bc16d674ec80000085615668565b905061235b600086869050116040518060400160405280600681526020016553595330313760d01b815250613610565b610102546101145461239891906123729087615637565b1115604051806040016040528060068152602001650a6b2a66062760d31b815250613610565b6123ae61010b546101035483611d769190615637565b60005b848110156124b85760008686838181106123cd576123cd6156ee565b90506020028101906123df919061575a565b6040516123ed9291906156b1565b604051809103902090506124366000610101600084815260200190815260200160002054116040518060400160405280600681526020016529aca998181b60d11b815250613610565b60008181526101016020526040812054612452906001906156c1565b905061246b6101008281548110611e6457611e646156ee565b60016101008281548110612481576124816156ee565b60009182526020909120600390910201600201805460ff1916911515919091179055508190506124b08161573f565b9150506123b1565b508484905061011460008282546124cf9190615637565b909155505061011780548591906000906124ea908490615637565b90915550600090506124fb82613b80565b90506125278282146040518060400160405280600681526020016553595330323160d01b815250613610565b81610104600082825461253a91906156c1565b90915550506040518581527ff25558665a382a9abb684f20b20021df5923b51485bbf2829ff0089b5b2714109060200160405180910390a161257a613ab0565b5050600160c95550505050565b600080516020615a8c83398151915261259f816136fe565b60408051808201909152600681526514d654cc0c0d60d21b60208201526125ca906030861490613610565b60408051808201909152600681526553595330303360d01b60208201526125f5906060841490613610565b600087876040516126079291906156b1565b604051809103902090506126506000610101600084815260200190815260200160002054116040518060400160405280600681526020016529aca998181b60d11b815250613610565b6000818152610101602052604081205461266c906001906156c1565b60008381526101016020526040808220829055519192509061269190899089906156b1565b6040805191829003822060a06020601f8c018190040284018101909252608083018a815290935082918b908b9081908501838280828437600092019190915250505090825250604080516020601f8a0181900481028201810190925288815291810191908990899081908401838280828437600092018290525093855250505060208201819052604090910152610100805484908110612733576127336156ee565b9060005260206000209060030201600082015181600001908051906020019061275d929190614f46565b5060208281015180516127769260018501920190614f46565b5060408201516002909101805460609093015115156101000261ff00199215159290921661ffff19909316929092171790556127b3826001615637565b6000918252610101602052604090912055505050505050505050565b6000828152609760205260409020600101546127ea816136fe565b6112dc838361378e565b60006127ff816136fe565b60ff8290556040518281527f690facbfacb53c9319489117a6ac422718b5cb059a6ffade4871ff10f6f9aee990602001611c8f565b600080516020615a8c83398151915261284c816136fe565b60408051808201909152600681526553595330303760d01b60208201526128769085841490613610565b8360005b81811015611c1b5761289960308888848181106119a5576119a56156ee565b6128b060608686848181106119f5576119f56156ee565b60008787838181106128c4576128c46156ee565b90506020028101906128d6919061575a565b6040516128e49291906156b1565b6040518091039020905061292d6101016000838152602001908152602001600020546000146040518060400160405280600681526020016553595330303560d01b815250613610565b61010060405180608001604052808a8a8681811061294d5761294d6156ee565b905060200281019061295f919061575a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020018888868181106129ab576129ab6156ee565b90506020028101906129bd919061575a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093855250505060208083018290526040909201819052835460018101855593815281902082518051939460030290910192612a2b9284920190614f46565b506020828101518051612a449260018501920190614f46565b50604082810151600292909201805460609094015161ffff1990941692151561ff001916929092176101009315158402179091559054600092835261010160205291205580612a928161573f565b91505061287a565b60608080612aa885856156c1565b6001600160401b03811115612abf57612abf6156d8565b604051908082528060200260200182016040528015612af257816020015b6060815260200190600190039081612add5790505b509250612aff85856156c1565b6001600160401b03811115612b1657612b166156d8565b604051908082528060200260200182016040528015612b4957816020015b6060815260200190600190039081612b345790505b509150612b5685856156c1565b6001600160401b03811115612b6d57612b6d6156d8565b604051908082528060200260200182016040528015612b96578160200160208202803683370190505b5090506000855b85811015612db0576101008181548110612bb957612bb96156ee565b90600052602060002090600302016000018054612bd590615704565b80601f0160208091040260200160405190810160405280929190818152602001828054612c0190615704565b8015612c4e5780601f10612c2357610100808354040283529160200191612c4e565b820191906000526020600020905b815481529060010190602001808311612c3157829003601f168201915b5050505050858381518110612c6557612c656156ee565b60200260200101819052506101008181548110612c8457612c846156ee565b90600052602060002090600302016001018054612ca090615704565b80601f0160208091040260200160405190810160405280929190818152602001828054612ccc90615704565b8015612d195780601f10612cee57610100808354040283529160200191612d19565b820191906000526020600020905b815481529060010190602001808311612cfc57829003601f168201915b5050505050848381518110612d3057612d306156ee565b60200260200101819052506101008181548110612d4f57612d4f6156ee565b906000526020600020906003020160020160009054906101000a900460ff16838381518110612d8057612d806156ee565b9115156020928302919091019091015281612d9a8161573f565b9250508080612da89061573f565b915050612b9d565b50509250925092565b6000600260c9541415612dde5760405162461bcd60e51b8152600401610d20906155ea565b600260c9819055506001612e16816101155410156040518060400160405280600681526020016553595330303160d01b815250613610565b612e408342106040518060400160405280600681526020016555535230303160d01b815250613610565b612e7d612e566801bc16d674ec800000876157a0565b6000146040518060400160405280600681526020016555535230303560d01b815250613610565b612ea8600086116040518060400160405280600681526020016555535230303560d01b815250613610565b60fc54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612ef2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f16919061564f565b90506000612f22611274565b612f2c8884615668565b612f36919061569d565b9050612f6386821115604051806040016040528060068152602001651554d48c0c0d60d21b815250613610565b60fc54612f7b906001600160a01b0316333084613d1a565b60fc54604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b158015612fc157600080fd5b505af1158015612fd5573d6000803e3d6000fd5b50505050612fe33388613d7a565b61013c60009054906101000a90046001600160a01b03166001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561303457600080fd5b505af1158015613048573d6000803e3d6000fd5b505061013c54604051636a270dbb60e11b815260001960048201526001600160a01b03909116925063d44e1b769150602401600060405180830381600087803b15801561309457600080fd5b505af11580156130a8573d6000803e3d6000fd5b5050600160c9555090979650505050505050565b600260c95414156130df5760405162461bcd60e51b8152600401610d20906155ea565b600260c9557f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0861310e816136fe565b613116613e5c565b61314461010b548411156040518060400160405280600681526020016505359533031360d41b815250613610565b61318b61010554610103548561315a9190615637565b6131649190615637565b4710156040518060400160405280600681526020016553595330313160d01b815250613610565b60fc54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa1580156131d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f9919061564f565b90506000613205611274565b90506000613214866001615668565b9050811561323457816132278785615668565b613231919061569d565b90505b60fc546040516340c10f1960e01b81526001600160a01b03878116600483015260248201849052909116906340c10f1990604401600060405180830381600087803b15801561328257600080fd5b505af1158015613296573d6000803e3d6000fd5b505050508561010360008282546132ad9190615637565b925050819055508561010b60008282546132c791906156c1565b9091555050604080518781526001600160a01b03871660208201527f2425aa1fadefc5c570850aa9c9e3dfa4fc6b43ccd1c05b47db38dd6518a743b3910160405180910390a15050600160c95550505050565b600080516020615a8c833981519152613332816136fe565b60408051808201909152600681526553595330303760d01b602082015261335c9086851490613610565b60408051808201909152600681526553595330303760d01b60208201526133869088871490613610565b8460005b818110156135d5573660008b8b848181106133a7576133a76156ee565b90506020028101906133b9919061575a565b915091503660008b8b868181106133d2576133d26156ee565b90506020028101906133e4919061575a565b915091503660008b8b888181106133fd576133fd6156ee565b905060200281019061340f919061575a565b91509150613441603087879050146040518060400160405280600681526020016514d654cc0c0d60d21b815250613610565b60408051808201909152600681526514d654cc0c0d60d21b602082015261346c906030851490613610565b60408051808201909152600681526553595330303360d01b6020820152613497906060831490613610565b600086866040516134a99291906156b1565b604051809103902090506134f26000610101600084815260200190815260200160002054116040518060400160405280600681526020016529aca998181b60d11b815250613610565b6000818152610101602052604081205461350e906001906156c1565b60008381526101016020526040808220829055519192509061353390889088906156b1565b6040518091039020905060006101008381548110613553576135536156ee565b600091825260209091206003909102019050613570818989614fca565b5061357f600182018787614fca565b506002810180548f15156101000261ff00199091161790556135a2836001615637565b6000928352610101602052604090922091909155508897506135cd965087955061573f945050505050565b91505061338a565b50505050505050505050565b600080516020615a6c8339815191526135f9816136fe565b611761613e5c565b6001600160a01b03163b151590565b80826112dc5760405162461bcd60e51b8152600401610d2091906157b4565b8061010f600082825461364291906157c7565b909155505050565b60006801bc16d674ec80000061010354613664919061569d565b610100546101025491925060009161367d908490615637565b111561369a57610102546101005461369591906156c1565b61369c565b815b905060005b818110156136c3576136b1613ee1565b806136bb8161573f565b9150506136a1565b50801561135b577fe2a191ee805447bcf5adabadd39cb816b1b46de1364263aef69980bdafd8370f61010254604051611c8f91815260200190565b61176181336141b3565b613712828261225b565b61135b5760008281526097602090815260408083206001600160a01b03851684529091529020805460ff1916600117905561374a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b613798828261225b565b1561135b5760008281526097602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60335460ff1661383e5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610d20565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6138b58261011254146040518060400160405280600681526020016529aca998189960d11b815250613610565b6138f16101025461011454856138cb9190615637565b11156040518060400160405280600681526020016553595330313360d01b815250613610565b6138f9613e5c565b610105541561394657613946610117546801bc16d674ec80000061011154613921919061569d565b146040518060400160405280600681526020016505359533033360d41b815250613610565b61010e5461010d546101175461395c9086615637565b11156139a457600061010d5461011754866139779190615637565b61398191906156c1565b90506139966801bc16d674ec80000082615668565b6139a09083615637565b9150505b60006139b96801bc16d674ec80000086615668565b9050613a02826101105461011154846139d29190615637565b6139dc9190615637565b10156040518060400160405280600681526020016553595330313560d01b815250613610565b600082610110546101115484613a189190615637565b613a229190615637565b613a2c91906156c1565b6101055490915015613a7f57613a7f84613a44611274565b613a50846103e8615668565b613a5a919061569d565b106040518060400160405280600681526020016529aca998189b60d11b815250613610565b613a8881614217565b613a906142a0565b5061010e5550505061010d55600061011181905561011081905561011755565b6101138054906000613ac18361573f565b909155505061011254610113546040805160208101939093524290830152606082015260800160408051601f19818403018152919052805160209091012061011255565b60335460ff1615613b4b5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610d20565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861386b3390565b60fd5460408051808201909152600681526553595330323360d01b6020820152600091613bba916001600160a01b03909116151590613610565b610107545b610108548111613cf25782613bd357613cf2565b6000818152610106602052604081206001810154909190851015613bf75784613bfd565b81600101545b905080826001016000828254613c1391906156c1565b90915550613c23905081866156c1565b82546001600160a01b031660009081526101096020526040812080549297508392909190613c529084906156c1565b90915550613c6290508185615637565b60fd548354604051630c11dedd60e01b81526001600160a01b0391821660048201529296501690630c11dedd9083906024016000604051808303818588803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b5050505050816001015460001415613cdd57613cdb614346565b505b50508080613cea9061573f565b915050613bbf565b50806101056000828254613d0691906156c1565b90915550613d159050816143fc565b919050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052613d7490859061440f565b50505050565b60016101086000828254613d8e9190615637565b90915550506040805180820182526001600160a01b0384811680835260208084018681526101085460009081526101068352868120955186546001600160a01b03191695169490941785555160019094019390935581526101099091529081208054839290613dfe908490615637565b92505081905550806101056000828254613e189190615637565b9091555050604080516001600160a01b0384168152602081018390527f889f3b08db1ce169841b4f7e2aadfe4298088b1bce57b31fecae3260dd4358299101611c8f565b61010f54471215613e6f57613e6f615808565b600061010f5447613e80919061581e565b90508015611761574761010f81905550806101116000828254613ea39190615637565b90915550613eb19050613ab0565b6040518181527fe7948c33eb604391785037114655100edf93283c25b69884e9238ae197f07817906020016121f7565b60006101006101025481548110613efa57613efa6156ee565b9060005260206000209060030201604051806080016040529081600082018054613f2390615704565b80601f0160208091040260200160405190810160405280929190818152602001828054613f4f90615704565b8015613f9c5780601f10613f7157610100808354040283529160200191613f9c565b820191906000526020600020905b815481529060010190602001808311613f7f57829003601f168201915b50505050508152602001600182018054613fb590615704565b80601f0160208091040260200160405190810160405280929190818152602001828054613fe190615704565b801561402e5780601f106140035761010080835404028352916020019161402e565b820191906000526020600020905b81548152906001019060200180831161401157829003601f168201915b50505091835250506002919091015460ff80821615156020840152610100909104161515604090910152606081015190915061407e576140798160000151826020015160ff546144e1565b61415e565b61013c54604080516351d5709b60e11b815290516000926001600160a01b03169163a3aae1369160048083019260209291908290030181865afa1580156140c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ed919061585d565b60408051600b808252818301909252919250600091600160f81b91602082018180368337505060405161412793929150859060200161587a565b60405160208183030381529060405290506000614145826000614914565b905061415a84600001518560200151836144e1565b5050505b610102805490600061416f8361573f565b91905055506801bc16d674ec80000061010460008282546141909190615637565b925050819055506801bc16d674ec800000610103600082825461364291906156c1565b6141bd828261225b565b61135b576141d5816001600160a01b03166014614972565b6141e0836020614972565b6040516020016141f19291906158c9565b60408051601f198184030181529082905262461bcd60e51b8252610d20916004016157b4565b60006103e860fe548361422a9190615668565b614234919061569d565b90508061010b60008282546142499190615637565b90915550614259905081836156c1565b61010a600082825461426b9190615637565b90915550506040518281527f82f24840c0f58d92529afdd441950ddc6e8f2d60138d4458a8d74ba367540cda90602001611c8f565b6101395460ff1615611367576101035461010b546142be9190615637565b47111561136757600061010c5461010a546142d991906156c1565b905060006101035461010b54476142f091906156c1565b6142fa91906156c1565b9050600081831061430b578161430d565b825b90508061010360008282546143229190615637565b925050819055508061010c600082825461433c9190615637565b9091555050505050565b604080518082019091526000808252602082015261438b610107546101085410156040518060400160405280600681526020016529aca998191960d11b815250613610565b506101078054600081815261010660208181526040808420815180830190925280546001600160a01b03811683526001808301805485870152978752949093526001600160a01b0319909216909155928290558354929390929091906143f2908490615637565b9250508190555090565b8061010f6000828254613642919061581e565b6000614464826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614b0d9092919063ffffffff16565b8051909150156112dc5780806020019051810190614482919061593e565b6112dc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d20565b60408051808201909152600681526514d654cc0c8d60d21b602082015261450b9082151590613610565b6801bc16d674ec8000006000614525633b9aca008361569d565b905081614536633b9aca0083615668565b1461454357614543615808565b6000600286600060801b60405160200161455e92919061595b565b60408051601f198184030181529082905261457891615993565b602060405180830381855afa158015614595573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906145b8919061564f565b905060006002806145cc8860006040614b24565b6040516145d99190615993565b602060405180830381855afa1580156145f6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614619919061564f565b600261463189604061462c8160606156c1565b614b24565b60405161464491906000906020016159af565b60408051601f198184030181529082905261465e91615993565b602060405180830381855afa15801561467b573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061469e919061564f565b60408051602081019390935282015260600160408051601f19818403018152908290526146ca91615993565b602060405180830381855afa1580156146e7573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061470a919061564f565b9050600061471784614c31565b90506000600280858960405160200161473a929190918252602082015260400190565b60408051601f198184030181529082905261475491615993565b602060405180830381855afa158015614771573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614794919061564f565b6040516002906147ad90869060009089906020016159d1565b60408051601f19818403018152908290526147c791615993565b602060405180830381855afa1580156147e4573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614807919061564f565b60408051602081019390935282015260600160408051601f198184030181529082905261483391615993565b602060405180830381855afa158015614850573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614873919061564f565b60fb546040805160208082018c905282518083039091018152818301928390526304512a2360e31b9092529293506001600160a01b03909116916322895118916801bc16d674ec800000916148d0918e918e908890604401615a09565b6000604051808303818588803b1580156148e957600080fd5b505af11580156148fd573d6000803e3d6000fd5b50505050506119356801bc16d674ec8000006143fc565b6000614921826020615637565b835110156149695760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b6044820152606401610d20565b50016020015190565b60606000614981836002615668565b61498c906002615637565b6001600160401b038111156149a3576149a36156d8565b6040519080825280601f01601f1916602001820160405280156149cd576020820181803683370190505b509050600360fc1b816000815181106149e8576149e86156ee565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614a1757614a176156ee565b60200101906001600160f81b031916908160001a9053506000614a3b846002615668565b614a46906001615637565b90505b6001811115614abe576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614a7a57614a7a6156ee565b1a60f81b828281518110614a9057614a906156ee565b60200101906001600160f81b031916908160001a90535060049490941c93614ab781615a54565b9050614a49565b5083156118265760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610d20565b6060614b1c8484600085614de5565b949350505050565b606081614b3281601f615637565b1015614b715760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610d20565b614b7b8284615637565b84511015614bbf5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610d20565b606082158015614bde5760405191506000825260208201604052614c28565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614c17578051835260209283019201614bff565b5050858452601f01601f1916604052505b50949350505050565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b82600081518110614c7157614c716156ee565b60200101906001600160f81b031916908160001a9053508060061a60f81b82600181518110614ca257614ca26156ee565b60200101906001600160f81b031916908160001a9053508060051a60f81b82600281518110614cd357614cd36156ee565b60200101906001600160f81b031916908160001a9053508060041a60f81b82600381518110614d0457614d046156ee565b60200101906001600160f81b031916908160001a9053508060031a60f81b82600481518110614d3557614d356156ee565b60200101906001600160f81b031916908160001a9053508060021a60f81b82600581518110614d6657614d666156ee565b60200101906001600160f81b031916908160001a9053508060011a60f81b82600681518110614d9757614d976156ee565b60200101906001600160f81b031916908160001a9053508060001a60f81b82600781518110614dc857614dc86156ee565b60200101906001600160f81b031916908160001a90535050919050565b606082471015614e465760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d20565b843b614e945760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d20565b600080866001600160a01b03168587604051614eb09190615993565b60006040518083038185875af1925050503d8060008114614eed576040519150601f19603f3d011682016040523d82523d6000602084013e614ef2565b606091505b5091509150614f02828286614f0d565b979650505050505050565b60608315614f1c575081611826565b825115614f2c5782518084602001fd5b8160405162461bcd60e51b8152600401610d2091906157b4565b828054614f5290615704565b90600052602060002090601f016020900481019282614f745760008555614fba565b82601f10614f8d57805160ff1916838001178555614fba565b82800160010185558215614fba579182015b82811115614fba578251825591602001919060010190614f9f565b50614fc692915061503e565b5090565b828054614fd690615704565b90600052602060002090601f016020900481019282614ff85760008555614fba565b82601f106150115782800160ff19823516178555614fba565b82800160010185558215614fba579182015b82811115614fba578235825591602001919060010190615023565b5b80821115614fc6576000815560010161503f565b60006020828403121561506557600080fd5b81356001600160e01b03198116811461182657600080fd5b6000806040838503121561509057600080fd5b50508035926020909101359150565b60008083601f8401126150b157600080fd5b5081356001600160401b038111156150c857600080fd5b6020830191508360208285010111156150e057600080fd5b9250929050565b600080600080604085870312156150fd57600080fd5b84356001600160401b038082111561511457600080fd5b6151208883890161509f565b9096509450602087013591508082111561513957600080fd5b506151468782880161509f565b95989497509550505050565b60006020828403121561516457600080fd5b5035919050565b6001600160a01b038116811461176157600080fd5b6000806040838503121561519357600080fd5b8235915060208301356151a58161516b565b809150509250929050565b60005b838110156151cb5781810151838201526020016151b3565b83811115613d745750506000910152565b600081518084526151f48160208601602086016151b0565b601f01601f19169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b8481101561525357601f198684030189526152418383516151dc565b98840198925090830190600101615225565b5090979650505050505050565b600081518084526020808501945080840160005b83811015615292578151151587529582019590820190600101615274565b509495945050505050565b6080815260006152b06080830187615208565b82810360208401526152c28187615208565b905082810360408401526152d68186615260565b90508281036060840152614f028185615260565b6000602082840312156152fc57600080fd5b81356118268161516b565b60008060006060848603121561531c57600080fd5b505081359360208301359350604090920135919050565b60008083601f84011261534557600080fd5b5081356001600160401b0381111561535c57600080fd5b6020830191508360208260051b85010111156150e057600080fd5b6000806000806040858703121561538d57600080fd5b84356001600160401b03808211156153a457600080fd5b6153b088838901615333565b909650945060208701359150808211156153c957600080fd5b5061514687828801615333565b6000806000604084860312156153eb57600080fd5b83356001600160401b0381111561540157600080fd5b61540d86828701615333565b909790965060209590950135949350505050565b6000806000806080858703121561543757600080fd5b5050823594602084013594506040840135936060013592509050565b6000806000806000806060878903121561546c57600080fd5b86356001600160401b038082111561548357600080fd5b61548f8a838b0161509f565b909850965060208901359150808211156154a857600080fd5b6154b48a838b0161509f565b909650945060408901359150808211156154cd57600080fd5b506154da89828a0161509f565b979a9699509497509295939492505050565b6060815260006154ff6060830186615208565b82810360208401526155118186615208565b905082810360408401526155258185615260565b9695505050505050565b801515811461176157600080fd5b60008060008060008060006080888a03121561555857600080fd5b87356001600160401b038082111561556f57600080fd5b61557b8b838c01615333565b909950975060208a013591508082111561559457600080fd5b6155a08b838c01615333565b909750955060408a01359150808211156155b957600080fd5b506155c68a828b01615333565b90945092505060608801356155da8161552f565b8091505092959891949750929550565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000821982111561564a5761564a615621565b500190565b60006020828403121561566157600080fd5b5051919050565b600081600019048311821515161561568257615682615621565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826156ac576156ac615687565b500490565b8183823760009101908152919050565b6000828210156156d3576156d3615621565b500390565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061571857607f821691505b6020821081141561573957634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561575357615753615621565b5060010190565b6000808335601e1984360301811261577157600080fd5b8301803591506001600160401b0382111561578b57600080fd5b6020019150368190038213156150e057600080fd5b6000826157af576157af615687565b500690565b60208152600061182660208301846151dc565b600080821280156001600160ff1b03849003851316156157e9576157e9615621565b600160ff1b839003841281161561580257615802615621565b50500190565b634e487b7160e01b600052600160045260246000fd5b60008083128015600160ff1b85018412161561583c5761583c615621565b6001600160ff1b038401831381161561585757615857615621565b50500390565b60006020828403121561586f57600080fd5b81516118268161516b565b6001600160f81b031984168152825160009061589d8160018501602088016151b0565b60609390931b6bffffffffffffffffffffffff1916600192909301918201929092526015019392505050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516159018160178501602088016151b0565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516159328160288401602088016151b0565b01602801949350505050565b60006020828403121561595057600080fd5b81516118268161552f565b6000835161596d8184602088016151b0565b6fffffffffffffffffffffffffffffffff19939093169190920190815260100192915050565b600082516159a58184602087016151b0565b9190910192915050565b600083516159c18184602088016151b0565b9190910191825250602001919050565b600084516159e38184602089016151b0565b67ffffffffffffffff199490941691909301908152601881019190915260380192915050565b608081526000615a1c60808301876151dc565b8281036020840152615a2e81876151dc565b90508281036040840152615a4281866151dc565b91505082606083015295945050505050565b600081615a6357615a63615621565b50600019019056fe68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef1c2979137d1774e40fe2638d355bf7a7b092be4c67f242aad1655e1e27f9df9cca26469706673582212204b73fd7304c73963ef9e3eaa2eded32640ff3e28e4afb39097971947b2822eb264736f6c634300080c0033496e697469616c697a61626c653a20636f6e747261637420697320616c726561
Deployed Bytecode
0x6080604052600436106103fe5760003560e01c80636f9170f611610213578063cdb54a1b11610123578063e7efb747116100ab578063f22abf371161007a578063f22abf3714610c20578063f5404d6014610c4f578063fa0ec2ce14610c6f578063fc65260a14610c8f578063fd9c652b14610caf57600080fd5b8063e7efb74714610b95578063ec87621c14610bb5578063ecacf56d14610be9578063f1f3b3e714610bff57600080fd5b8063da863b3b116100f2578063da863b3b14610af5578063dc3fc3b214610b0b578063e08f2d8914610b35578063e43a495414610b4b578063e63ab1e914610b6157600080fd5b8063cdb54a1b14610a68578063d283e75f14610a7e578063d547741f14610ab5578063d7d2546114610ad557600080fd5b806391d14854116101a6578063a217fddf11610175578063a217fddf1461098a578063aba525361461099f578063b181033a146109b5578063c3d51709146109d5578063c8c3df4a146109f557600080fd5b806391d1485414610914578063934548171461093457806399629f5814610954578063a065913f1461097457600080fd5b80638456cb59116101e25780638456cb59146108b457806389d00678146108c95780638b0bfd35146108de57806391b66caa146108f457600080fd5b80636f9170f61461081a57806372cda18214610854578063755d7dd3146108745780637a4473e11461089457600080fd5b80633f4ba83a1161030e5780634f431a6f116102a157806363e547171161027057806363e547171461078e57806364363f2b146107ae5780636a42602c146107c45780636bb022c8146107da5780636e6ac7e7146107fa57600080fd5b80634f431a6f146107205780635662f706146107405780635c975abb1461076057806361c993c51461077857600080fd5b806349557df9116102dd57806349557df9146106b4578063496bf5bb146106ca5780634cd79e0a146106ea5780634e8ab1a11461070057600080fd5b80633f4ba83a146106315780634006ccc51461064657806342f1e8791461065b57806343a2a3021461067d57600080fd5b80632e12007c1161039157806336568abe1161036057806336568abe1461057757806336bf3325146105975780633884545d146105b45780633a4b66f1146105ec5780633bf39dca1461060157600080fd5b80632e12007c146105165780632f2ff15d1461052b57806330b12c8d1461054b57806333e5761f1461056157600080fd5b80631b2ef1ca116103cd5780631b2ef1ca1461049b578063226f2645146104ae578063248a9ca3146104d05780632ae45fa11461050057600080fd5b806301ffc9a71461040a57806307e2cea51461043f57806308b84c0c1461046f5780630917e7761461048557600080fd5b3661040557005b600080fd5b34801561041657600080fd5b5061042a610425366004615053565b610cc4565b60405190151581526020015b60405180910390f35b34801561044b57600080fd5b50610461600080516020615a6c83398151915281565b604051908152602001610436565b34801561047b57600080fd5b5061010b54610461565b34801561049157600080fd5b5061010454610461565b6104616104a936600461507d565b610cfb565b3480156104ba57600080fd5b506104ce6104c93660046150e7565b611093565b005b3480156104dc57600080fd5b506104616104eb366004615152565b60009081526097602052604090206001015490565b34801561050c57600080fd5b5061011754610461565b34801561052257600080fd5b50610461611274565b34801561053757600080fd5b506104ce610546366004615180565b6112b7565b34801561055757600080fd5b5061010054610461565b34801561056d57600080fd5b5061010f54610461565b34801561058357600080fd5b506104ce610592366004615180565b6112e1565b3480156105a357600080fd5b506104616801bc16d674ec80000081565b3480156105c057600080fd5b5060fb546105d4906001600160a01b031681565b6040516001600160a01b039091168152602001610436565b3480156105f857600080fd5b506104ce61135f565b34801561060d57600080fd5b5061062161061c36600461507d565b611369565b604051610436949392919061529d565b34801561063d57600080fd5b506104ce61172f565b34801561065257600080fd5b50610461611764565b34801561066757600080fd5b50610461600080516020615a8c83398151915281565b34801561068957600080fd5b506104616106983660046152ea565b6001600160a01b03166000908152610137602052604090205490565b3480156106c057600080fd5b5061011454610461565b3480156106d657600080fd5b506104ce6106e5366004615307565b61182d565b3480156106f657600080fd5b5061046160ff5481565b34801561070c57600080fd5b506104ce61071b366004615377565b611940565b34801561072c57600080fd5b506104ce61073b3660046152ea565b611c24565b34801561074c57600080fd5b506104ce61075b3660046153d6565b611c9b565b34801561076c57600080fd5b5060335460ff1661042a565b34801561078457600080fd5b5061010a54610461565b34801561079a57600080fd5b506104ce6107a9366004615152565b611fe1565b3480156107ba57600080fd5b5061010354610461565b3480156107d057600080fd5b5061010d54610461565b3480156107e657600080fd5b506104ce6107f53660046152ea565b61202f565b34801561080657600080fd5b506104ce610815366004615152565b612088565b34801561082657600080fd5b5061042a6108353660046152ea565b6001600160a01b03166000908152610138602052604090205460ff1690565b34801561086057600080fd5b506104ce61086f3660046152ea565b6120af565b34801561088057600080fd5b506104ce61088f366004615152565b612108565b3480156108a057600080fd5b5060fd546105d4906001600160a01b031681565b3480156108c057600080fd5b506104ce612175565b3480156108d557600080fd5b506104ce6121a7565b3480156108ea57600080fd5b5061010554610461565b34801561090057600080fd5b506104ce61090f3660046152ea565b612202565b34801561092057600080fd5b5061042a61092f366004615180565b61225b565b34801561094057600080fd5b506104ce61094f366004615421565b612286565b34801561096057600080fd5b506104ce61096f3660046153d6565b6122a9565b34801561098057600080fd5b5061010c54610461565b34801561099657600080fd5b50610461600081565b3480156109ab57600080fd5b5061011054610461565b3480156109c157600080fd5b5060fc546105d4906001600160a01b031681565b3480156109e157600080fd5b506104ce6109f0366004615453565b612587565b348015610a0157600080fd5b50610a49610a10366004615152565b60009081526101066020908152604091829020825180840190935280546001600160a01b03168084526001909101549290910182905291565b604080516001600160a01b039093168352602083019190915201610436565b348015610a7457600080fd5b5061010e54610461565b348015610a8a57600080fd5b50610461610a993660046152ea565b6001600160a01b03166000908152610109602052604090205490565b348015610ac157600080fd5b506104ce610ad0366004615180565b6127cf565b348015610ae157600080fd5b506104ce610af0366004615152565b6127f4565b348015610b0157600080fd5b5061010254610461565b348015610b1757600080fd5b50610107546101085460408051928352602083019190915201610436565b348015610b4157600080fd5b5061011154610461565b348015610b5757600080fd5b5061046160fe5481565b348015610b6d57600080fd5b506104617f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b348015610ba157600080fd5b506104ce610bb0366004615377565b612834565b348015610bc157600080fd5b506104617f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0881565b348015610bf557600080fd5b5061011254610461565b348015610c0b57600080fd5b5061013c546105d4906001600160a01b031681565b348015610c2c57600080fd5b50610c40610c3b36600461507d565b612a9a565b604051610436939291906154ec565b348015610c5b57600080fd5b50610461610c6a366004615307565b612db9565b348015610c7b57600080fd5b506104ce610c8a366004615180565b6130bc565b348015610c9b57600080fd5b506104ce610caa36600461553d565b61331a565b348015610cbb57600080fd5b506104ce6135e1565b60006001600160e01b03198216637965db0b60e01b1480610cf557506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000600260c9541415610d295760405162461bcd60e51b8152600401610d20906155ea565b60405180910390fd5b600260c95560335460ff1615610d745760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610d20565b610d9e8242106040518060400160405280600681526020016555535230303160d01b815250613610565b610dc960003411604051806040016040528060068152602001652aa9a918181960d11b815250613610565b336000908152610138602052604090205460ff16610e59573360009081526101376020526040902054610e3390690a968163f0a57b40000090610e0d903490615637565b11156040518060400160405280600681526020016555535230303360d01b815250613610565b336000908152610137602052604081208054349290610e53908490615637565b90915550505b610e623461362f565b60fc54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015610eac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed0919061564f565b90506000610edc611274565b90506000610eeb346001615668565b90508115610f0b5781610efe3485615668565b610f08919061569d565b90505b610f3686821015604051806040016040528060068152602001651554d48c0c0d60d21b815250613610565b60fc546040516340c10f1960e01b8152336004820152602481018390526001600160a01b03909116906340c10f1990604401600060405180830381600087803b158015610f8257600080fd5b505af1158015610f96573d6000803e3d6000fd5b50505050346101036000828254610fad9190615637565b90915550610fbb905061364a565b61013c60009054906101000a90046001600160a01b03166001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561100c57600080fd5b505af1158015611020573d6000803e3d6000fd5b505061013c54604051636a270dbb60e11b815260001960048201526001600160a01b03909116925063d44e1b769150602401600060405180830381600087803b15801561106c57600080fd5b505af1158015611080573d6000803e3d6000fd5b5050600160c95550909695505050505050565b600080516020615a8c8339815191526110ab816136fe565b60408051808201909152600681526553595330303360d01b60208201526110d6906060841490613610565b60408051808201909152600681526514d654cc0c0d60d21b6020820152611101906030861490613610565b600085856040516111139291906156b1565b6040518091039020905061115c6101016000838152602001908152602001600020546000146040518060400160405280600681526020016553595330303560d01b815250613610565b6040805160a06020601f8901819004028201810190925260808101878152610100928291908a908a9081908501838280828437600092019190915250505090825250604080516020601f8901819004810282018101909252878152918101919088908890819084018382808284376000920182905250938552505050602080830182905260409092018190528354600181018555938152819020825180519394600302909101926112109284920190614f46565b5060208281015180516112299260018501920190614f46565b50604082810151600292909201805460609094015161ffff1990941692151561ff00191692909217610100931515840217909155905460009283526101016020529120555050505050565b600061010c546101055461010a5461010454610103546112949190615637565b61129e9190615637565b6112a891906156c1565b6112b291906156c1565b905090565b6000828152609760205260409020600101546112d2816136fe565b6112dc8383613708565b505050565b6001600160a01b03811633146113515760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610d20565b61135b828261378e565b5050565b61136761364a565b565b606080808061137886866156c1565b6001600160401b0381111561138f5761138f6156d8565b6040519080825280602002602001820160405280156113c257816020015b60608152602001906001900390816113ad5790505b5093506113cf86866156c1565b6001600160401b038111156113e6576113e66156d8565b60405190808252806020026020018201604052801561141957816020015b60608152602001906001900390816114045790505b50925061142686866156c1565b6001600160401b0381111561143d5761143d6156d8565b604051908082528060200260200182016040528015611466578160200160208202803683370190505b50915061147386866156c1565b6001600160401b0381111561148a5761148a6156d8565b6040519080825280602002602001820160405280156114b3578160200160208202803683370190505b5090506000865b868110156117245761010081815481106114d6576114d66156ee565b906000526020600020906003020160000180546114f290615704565b80601f016020809104026020016040519081016040528092919081815260200182805461151e90615704565b801561156b5780601f106115405761010080835404028352916020019161156b565b820191906000526020600020905b81548152906001019060200180831161154e57829003601f168201915b5050505050868381518110611582576115826156ee565b602002602001018190525061010081815481106115a1576115a16156ee565b906000526020600020906003020160010180546115bd90615704565b80601f01602080910402602001604051908101604052809291908181526020018280546115e990615704565b80156116365780601f1061160b57610100808354040283529160200191611636565b820191906000526020600020905b81548152906001019060200180831161161957829003601f168201915b505050505085838151811061164d5761164d6156ee565b6020026020010181905250610100818154811061166c5761166c6156ee565b906000526020600020906003020160020160009054906101000a900460ff1684838151811061169d5761169d6156ee565b60200260200101901515908115158152505061010081815481106116c3576116c36156ee565b906000526020600020906003020160020160019054906101000a900460ff168383815181106116f4576116f46156ee565b911515602092830291909101909101528161170e8161573f565b925050808061171c9061573f565b9150506114ba565b505092959194509250565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a611759816136fe565b6117616137f5565b50565b60008060fc60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117de919061564f565b9050806117fe576117f8670de0b6b3a76400006001615668565b91505090565b600081670de0b6b3a7640000611812611274565b61181c9190615668565b611826919061569d565b9392505050565b600080516020615a6c833981519152611845816136fe565b600061184f611274565b611863906906c6b935b8bbd400000061569d565b9050611870858483613888565b61013c60009054906101000a90046001600160a01b03166001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156118c157600080fd5b505af11580156118d5573d6000803e3d6000fd5b505061013c54604051636a270dbb60e11b815260001960048201526001600160a01b03909116925063d44e1b769150602401600060405180830381600087803b15801561192157600080fd5b505af1158015611935573d6000803e3d6000fd5b505050505050505050565b600080516020615a8c833981519152611958816136fe565b60408051808201909152600681526553595330303760d01b60208201526119829085841490613610565b8360005b81811015611c1b576119de60308888848181106119a5576119a56156ee565b90506020028101906119b7919061575a565b9050146040518060400160405280600681526020016514d654cc0c0d60d21b815250613610565b611a2e60608686848181106119f5576119f56156ee565b9050602002810190611a07919061575a565b9050146040518060400160405280600681526020016553595330303360d01b815250613610565b6000878783818110611a4257611a426156ee565b9050602002810190611a54919061575a565b604051611a629291906156b1565b60405180910390209050611aab6101016000838152602001908152602001600020546000146040518060400160405280600681526020016553595330303560d01b815250613610565b61010060405180608001604052808a8a86818110611acb57611acb6156ee565b9050602002810190611add919061575a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001888886818110611b2957611b296156ee565b9050602002810190611b3b919061575a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093855250505060208083018290526001604090930183905284549283018555938152839020825180519394600390930290910192611bac9284920190614f46565b506020828101518051611bc59260018501920190614f46565b50604082810151600292909201805460609094015161ffff1990941692151561ff001916929092176101009315158402179091559054600092835261010160205291205580611c138161573f565b915050611986565b50505050505050565b6000611c2f816136fe565b6001600160a01b03821660008181526101386020908152604091829020805460ff8082161560ff1990921682179092558351948552161515908301527f96993f732e425c7615ed977e16e6e83d84bb45203ca23885018335b66c2e85be91015b60405180910390a15050565b600260c9541415611cbe5760405162461bcd60e51b8152600401610d20906155ea565b600260c955600080516020615a6c833981519152611cdb816136fe565b611d088261011254146040518060400160405280600681526020016529aca998189960d11b815250613610565b6000611d1d6801bc16d674ec80000085615668565b9050611d4d600086869050116040518060400160405280600681526020016553595330313760d01b815250613610565b61010b5461010354611da79190611d6c8767de0b6b3a76400000615668565b611d769190615637565b611d809190615637565b4710156040518060400160405280600681526020016553595330313960d01b815250613610565b60005b84811015611ef5576000868683818110611dc657611dc66156ee565b9050602002810190611dd8919061575a565b604051611de69291906156b1565b60405180910390209050611e2f6000610101600084815260200190815260200160002054116040518060400160405280600681526020016529aca998181b60d11b815250613610565b60008181526101016020526040812054611e4b906001906156c1565b9050611ea86101008281548110611e6457611e646156ee565b906000526020600020906003020160020160009054906101000a900460ff16156040518060400160405280600681526020016505359533032360d41b815250613610565b60016101008281548110611ebe57611ebe6156ee565b60009182526020909120600390910201600201805460ff191691151591909117905550819050611eed8161573f565b915050611daa565b50848490506101146000828254611f0c9190615637565b90915550506101178054859190600090611f27908490615637565b92505081905550806101046000828254611f4191906156c1565b90915550611f5990508467de0b6b3a76400000615668565b6101036000828254611f6b9190615637565b90915550611f8390508467de0b6b3a76400000615668565b6101106000828254611f959190615637565b90915550506040518481527f0c5c941f6f7b3b7b1624e8a6738cdc96705c25510de1f11ff37671927a5c47c09060200160405180910390a1611fd5613ab0565b5050600160c955505050565b6000611fec816136fe565b610115548210156120285760405162461bcd60e51b815260206004820152600660248201526529aca998181960d11b6044820152606401610d20565b5061011555565b600061203a816136fe565b60fd80546001600160a01b0319166001600160a01b0384169081179091556040519081527f4d3d3f5d1d8423a4e40b3fcfccaf0c1b18ca550a8592d5e38a61765931a9cf7890602001611c8f565b6000612093816136fe565b8161011160008282546120a69190615637565b90915550505050565b60006120ba816136fe565b60fc80546001600160a01b0319166001600160a01b0384169081179091556040519081527f65f24f264bd70348b9888b2fbf27cd04f9e2fb0fcc50dde8fb36483576ef32a390602001611c8f565b6000612113816136fe565b6121406103e8831115604051806040016040528060068152602001650a6b2a66060760d31b815250613610565b60fe8290556040518281527f4de90ec86e1bc56c192e2399bacbd10bdaba720caca606354d66c5cb33d6802b90602001611c8f565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61219f816136fe565b611761613b05565b60006121b2816136fe565b610139805460ff8082161560ff1990921682179092556040519116151581527f0e1bdbe9c15a50fbc7d124adb288d201acc7b9a8a535b003ca6ba80b7c9f5335906020015b60405180910390a150565b600061220d816136fe565b60fb80546001600160a01b0319166001600160a01b0384169081179091556040519081527f1781ac9526b978975dba0fd26a33e044a55a7ace054a3ee7efa5f8459513bead90602001611c8f565b60009182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b600080516020615a6c83398151915261229e816136fe565b611870858484613888565b600260c95414156122cc5760405162461bcd60e51b8152600401610d20906155ea565b600260c955600080516020615a6c8339815191526122e9816136fe565b6123168261011254146040518060400160405280600681526020016529aca998189960d11b815250613610565b600061232b6801bc16d674ec80000085615668565b905061235b600086869050116040518060400160405280600681526020016553595330313760d01b815250613610565b610102546101145461239891906123729087615637565b1115604051806040016040528060068152602001650a6b2a66062760d31b815250613610565b6123ae61010b546101035483611d769190615637565b60005b848110156124b85760008686838181106123cd576123cd6156ee565b90506020028101906123df919061575a565b6040516123ed9291906156b1565b604051809103902090506124366000610101600084815260200190815260200160002054116040518060400160405280600681526020016529aca998181b60d11b815250613610565b60008181526101016020526040812054612452906001906156c1565b905061246b6101008281548110611e6457611e646156ee565b60016101008281548110612481576124816156ee565b60009182526020909120600390910201600201805460ff1916911515919091179055508190506124b08161573f565b9150506123b1565b508484905061011460008282546124cf9190615637565b909155505061011780548591906000906124ea908490615637565b90915550600090506124fb82613b80565b90506125278282146040518060400160405280600681526020016553595330323160d01b815250613610565b81610104600082825461253a91906156c1565b90915550506040518581527ff25558665a382a9abb684f20b20021df5923b51485bbf2829ff0089b5b2714109060200160405180910390a161257a613ab0565b5050600160c95550505050565b600080516020615a8c83398151915261259f816136fe565b60408051808201909152600681526514d654cc0c0d60d21b60208201526125ca906030861490613610565b60408051808201909152600681526553595330303360d01b60208201526125f5906060841490613610565b600087876040516126079291906156b1565b604051809103902090506126506000610101600084815260200190815260200160002054116040518060400160405280600681526020016529aca998181b60d11b815250613610565b6000818152610101602052604081205461266c906001906156c1565b60008381526101016020526040808220829055519192509061269190899089906156b1565b6040805191829003822060a06020601f8c018190040284018101909252608083018a815290935082918b908b9081908501838280828437600092019190915250505090825250604080516020601f8a0181900481028201810190925288815291810191908990899081908401838280828437600092018290525093855250505060208201819052604090910152610100805484908110612733576127336156ee565b9060005260206000209060030201600082015181600001908051906020019061275d929190614f46565b5060208281015180516127769260018501920190614f46565b5060408201516002909101805460609093015115156101000261ff00199215159290921661ffff19909316929092171790556127b3826001615637565b6000918252610101602052604090912055505050505050505050565b6000828152609760205260409020600101546127ea816136fe565b6112dc838361378e565b60006127ff816136fe565b60ff8290556040518281527f690facbfacb53c9319489117a6ac422718b5cb059a6ffade4871ff10f6f9aee990602001611c8f565b600080516020615a8c83398151915261284c816136fe565b60408051808201909152600681526553595330303760d01b60208201526128769085841490613610565b8360005b81811015611c1b5761289960308888848181106119a5576119a56156ee565b6128b060608686848181106119f5576119f56156ee565b60008787838181106128c4576128c46156ee565b90506020028101906128d6919061575a565b6040516128e49291906156b1565b6040518091039020905061292d6101016000838152602001908152602001600020546000146040518060400160405280600681526020016553595330303560d01b815250613610565b61010060405180608001604052808a8a8681811061294d5761294d6156ee565b905060200281019061295f919061575a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020018888868181106129ab576129ab6156ee565b90506020028101906129bd919061575a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093855250505060208083018290526040909201819052835460018101855593815281902082518051939460030290910192612a2b9284920190614f46565b506020828101518051612a449260018501920190614f46565b50604082810151600292909201805460609094015161ffff1990941692151561ff001916929092176101009315158402179091559054600092835261010160205291205580612a928161573f565b91505061287a565b60608080612aa885856156c1565b6001600160401b03811115612abf57612abf6156d8565b604051908082528060200260200182016040528015612af257816020015b6060815260200190600190039081612add5790505b509250612aff85856156c1565b6001600160401b03811115612b1657612b166156d8565b604051908082528060200260200182016040528015612b4957816020015b6060815260200190600190039081612b345790505b509150612b5685856156c1565b6001600160401b03811115612b6d57612b6d6156d8565b604051908082528060200260200182016040528015612b96578160200160208202803683370190505b5090506000855b85811015612db0576101008181548110612bb957612bb96156ee565b90600052602060002090600302016000018054612bd590615704565b80601f0160208091040260200160405190810160405280929190818152602001828054612c0190615704565b8015612c4e5780601f10612c2357610100808354040283529160200191612c4e565b820191906000526020600020905b815481529060010190602001808311612c3157829003601f168201915b5050505050858381518110612c6557612c656156ee565b60200260200101819052506101008181548110612c8457612c846156ee565b90600052602060002090600302016001018054612ca090615704565b80601f0160208091040260200160405190810160405280929190818152602001828054612ccc90615704565b8015612d195780601f10612cee57610100808354040283529160200191612d19565b820191906000526020600020905b815481529060010190602001808311612cfc57829003601f168201915b5050505050848381518110612d3057612d306156ee565b60200260200101819052506101008181548110612d4f57612d4f6156ee565b906000526020600020906003020160020160009054906101000a900460ff16838381518110612d8057612d806156ee565b9115156020928302919091019091015281612d9a8161573f565b9250508080612da89061573f565b915050612b9d565b50509250925092565b6000600260c9541415612dde5760405162461bcd60e51b8152600401610d20906155ea565b600260c9819055506001612e16816101155410156040518060400160405280600681526020016553595330303160d01b815250613610565b612e408342106040518060400160405280600681526020016555535230303160d01b815250613610565b612e7d612e566801bc16d674ec800000876157a0565b6000146040518060400160405280600681526020016555535230303560d01b815250613610565b612ea8600086116040518060400160405280600681526020016555535230303560d01b815250613610565b60fc54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612ef2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f16919061564f565b90506000612f22611274565b612f2c8884615668565b612f36919061569d565b9050612f6386821115604051806040016040528060068152602001651554d48c0c0d60d21b815250613610565b60fc54612f7b906001600160a01b0316333084613d1a565b60fc54604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b158015612fc157600080fd5b505af1158015612fd5573d6000803e3d6000fd5b50505050612fe33388613d7a565b61013c60009054906101000a90046001600160a01b03166001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561303457600080fd5b505af1158015613048573d6000803e3d6000fd5b505061013c54604051636a270dbb60e11b815260001960048201526001600160a01b03909116925063d44e1b769150602401600060405180830381600087803b15801561309457600080fd5b505af11580156130a8573d6000803e3d6000fd5b5050600160c9555090979650505050505050565b600260c95414156130df5760405162461bcd60e51b8152600401610d20906155ea565b600260c9557f241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0861310e816136fe565b613116613e5c565b61314461010b548411156040518060400160405280600681526020016505359533031360d41b815250613610565b61318b61010554610103548561315a9190615637565b6131649190615637565b4710156040518060400160405280600681526020016553595330313160d01b815250613610565b60fc54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa1580156131d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f9919061564f565b90506000613205611274565b90506000613214866001615668565b9050811561323457816132278785615668565b613231919061569d565b90505b60fc546040516340c10f1960e01b81526001600160a01b03878116600483015260248201849052909116906340c10f1990604401600060405180830381600087803b15801561328257600080fd5b505af1158015613296573d6000803e3d6000fd5b505050508561010360008282546132ad9190615637565b925050819055508561010b60008282546132c791906156c1565b9091555050604080518781526001600160a01b03871660208201527f2425aa1fadefc5c570850aa9c9e3dfa4fc6b43ccd1c05b47db38dd6518a743b3910160405180910390a15050600160c95550505050565b600080516020615a8c833981519152613332816136fe565b60408051808201909152600681526553595330303760d01b602082015261335c9086851490613610565b60408051808201909152600681526553595330303760d01b60208201526133869088871490613610565b8460005b818110156135d5573660008b8b848181106133a7576133a76156ee565b90506020028101906133b9919061575a565b915091503660008b8b868181106133d2576133d26156ee565b90506020028101906133e4919061575a565b915091503660008b8b888181106133fd576133fd6156ee565b905060200281019061340f919061575a565b91509150613441603087879050146040518060400160405280600681526020016514d654cc0c0d60d21b815250613610565b60408051808201909152600681526514d654cc0c0d60d21b602082015261346c906030851490613610565b60408051808201909152600681526553595330303360d01b6020820152613497906060831490613610565b600086866040516134a99291906156b1565b604051809103902090506134f26000610101600084815260200190815260200160002054116040518060400160405280600681526020016529aca998181b60d11b815250613610565b6000818152610101602052604081205461350e906001906156c1565b60008381526101016020526040808220829055519192509061353390889088906156b1565b6040518091039020905060006101008381548110613553576135536156ee565b600091825260209091206003909102019050613570818989614fca565b5061357f600182018787614fca565b506002810180548f15156101000261ff00199091161790556135a2836001615637565b6000928352610101602052604090922091909155508897506135cd965087955061573f945050505050565b91505061338a565b50505050505050505050565b600080516020615a6c8339815191526135f9816136fe565b611761613e5c565b6001600160a01b03163b151590565b80826112dc5760405162461bcd60e51b8152600401610d2091906157b4565b8061010f600082825461364291906157c7565b909155505050565b60006801bc16d674ec80000061010354613664919061569d565b610100546101025491925060009161367d908490615637565b111561369a57610102546101005461369591906156c1565b61369c565b815b905060005b818110156136c3576136b1613ee1565b806136bb8161573f565b9150506136a1565b50801561135b577fe2a191ee805447bcf5adabadd39cb816b1b46de1364263aef69980bdafd8370f61010254604051611c8f91815260200190565b61176181336141b3565b613712828261225b565b61135b5760008281526097602090815260408083206001600160a01b03851684529091529020805460ff1916600117905561374a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b613798828261225b565b1561135b5760008281526097602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60335460ff1661383e5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610d20565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6138b58261011254146040518060400160405280600681526020016529aca998189960d11b815250613610565b6138f16101025461011454856138cb9190615637565b11156040518060400160405280600681526020016553595330313360d01b815250613610565b6138f9613e5c565b610105541561394657613946610117546801bc16d674ec80000061011154613921919061569d565b146040518060400160405280600681526020016505359533033360d41b815250613610565b61010e5461010d546101175461395c9086615637565b11156139a457600061010d5461011754866139779190615637565b61398191906156c1565b90506139966801bc16d674ec80000082615668565b6139a09083615637565b9150505b60006139b96801bc16d674ec80000086615668565b9050613a02826101105461011154846139d29190615637565b6139dc9190615637565b10156040518060400160405280600681526020016553595330313560d01b815250613610565b600082610110546101115484613a189190615637565b613a229190615637565b613a2c91906156c1565b6101055490915015613a7f57613a7f84613a44611274565b613a50846103e8615668565b613a5a919061569d565b106040518060400160405280600681526020016529aca998189b60d11b815250613610565b613a8881614217565b613a906142a0565b5061010e5550505061010d55600061011181905561011081905561011755565b6101138054906000613ac18361573f565b909155505061011254610113546040805160208101939093524290830152606082015260800160408051601f19818403018152919052805160209091012061011255565b60335460ff1615613b4b5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610d20565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861386b3390565b60fd5460408051808201909152600681526553595330323360d01b6020820152600091613bba916001600160a01b03909116151590613610565b610107545b610108548111613cf25782613bd357613cf2565b6000818152610106602052604081206001810154909190851015613bf75784613bfd565b81600101545b905080826001016000828254613c1391906156c1565b90915550613c23905081866156c1565b82546001600160a01b031660009081526101096020526040812080549297508392909190613c529084906156c1565b90915550613c6290508185615637565b60fd548354604051630c11dedd60e01b81526001600160a01b0391821660048201529296501690630c11dedd9083906024016000604051808303818588803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b5050505050816001015460001415613cdd57613cdb614346565b505b50508080613cea9061573f565b915050613bbf565b50806101056000828254613d0691906156c1565b90915550613d159050816143fc565b919050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052613d7490859061440f565b50505050565b60016101086000828254613d8e9190615637565b90915550506040805180820182526001600160a01b0384811680835260208084018681526101085460009081526101068352868120955186546001600160a01b03191695169490941785555160019094019390935581526101099091529081208054839290613dfe908490615637565b92505081905550806101056000828254613e189190615637565b9091555050604080516001600160a01b0384168152602081018390527f889f3b08db1ce169841b4f7e2aadfe4298088b1bce57b31fecae3260dd4358299101611c8f565b61010f54471215613e6f57613e6f615808565b600061010f5447613e80919061581e565b90508015611761574761010f81905550806101116000828254613ea39190615637565b90915550613eb19050613ab0565b6040518181527fe7948c33eb604391785037114655100edf93283c25b69884e9238ae197f07817906020016121f7565b60006101006101025481548110613efa57613efa6156ee565b9060005260206000209060030201604051806080016040529081600082018054613f2390615704565b80601f0160208091040260200160405190810160405280929190818152602001828054613f4f90615704565b8015613f9c5780601f10613f7157610100808354040283529160200191613f9c565b820191906000526020600020905b815481529060010190602001808311613f7f57829003601f168201915b50505050508152602001600182018054613fb590615704565b80601f0160208091040260200160405190810160405280929190818152602001828054613fe190615704565b801561402e5780601f106140035761010080835404028352916020019161402e565b820191906000526020600020905b81548152906001019060200180831161401157829003601f168201915b50505091835250506002919091015460ff80821615156020840152610100909104161515604090910152606081015190915061407e576140798160000151826020015160ff546144e1565b61415e565b61013c54604080516351d5709b60e11b815290516000926001600160a01b03169163a3aae1369160048083019260209291908290030181865afa1580156140c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ed919061585d565b60408051600b808252818301909252919250600091600160f81b91602082018180368337505060405161412793929150859060200161587a565b60405160208183030381529060405290506000614145826000614914565b905061415a84600001518560200151836144e1565b5050505b610102805490600061416f8361573f565b91905055506801bc16d674ec80000061010460008282546141909190615637565b925050819055506801bc16d674ec800000610103600082825461364291906156c1565b6141bd828261225b565b61135b576141d5816001600160a01b03166014614972565b6141e0836020614972565b6040516020016141f19291906158c9565b60408051601f198184030181529082905262461bcd60e51b8252610d20916004016157b4565b60006103e860fe548361422a9190615668565b614234919061569d565b90508061010b60008282546142499190615637565b90915550614259905081836156c1565b61010a600082825461426b9190615637565b90915550506040518281527f82f24840c0f58d92529afdd441950ddc6e8f2d60138d4458a8d74ba367540cda90602001611c8f565b6101395460ff1615611367576101035461010b546142be9190615637565b47111561136757600061010c5461010a546142d991906156c1565b905060006101035461010b54476142f091906156c1565b6142fa91906156c1565b9050600081831061430b578161430d565b825b90508061010360008282546143229190615637565b925050819055508061010c600082825461433c9190615637565b9091555050505050565b604080518082019091526000808252602082015261438b610107546101085410156040518060400160405280600681526020016529aca998191960d11b815250613610565b506101078054600081815261010660208181526040808420815180830190925280546001600160a01b03811683526001808301805485870152978752949093526001600160a01b0319909216909155928290558354929390929091906143f2908490615637565b9250508190555090565b8061010f6000828254613642919061581e565b6000614464826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614b0d9092919063ffffffff16565b8051909150156112dc5780806020019051810190614482919061593e565b6112dc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d20565b60408051808201909152600681526514d654cc0c8d60d21b602082015261450b9082151590613610565b6801bc16d674ec8000006000614525633b9aca008361569d565b905081614536633b9aca0083615668565b1461454357614543615808565b6000600286600060801b60405160200161455e92919061595b565b60408051601f198184030181529082905261457891615993565b602060405180830381855afa158015614595573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906145b8919061564f565b905060006002806145cc8860006040614b24565b6040516145d99190615993565b602060405180830381855afa1580156145f6573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614619919061564f565b600261463189604061462c8160606156c1565b614b24565b60405161464491906000906020016159af565b60408051601f198184030181529082905261465e91615993565b602060405180830381855afa15801561467b573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061469e919061564f565b60408051602081019390935282015260600160408051601f19818403018152908290526146ca91615993565b602060405180830381855afa1580156146e7573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061470a919061564f565b9050600061471784614c31565b90506000600280858960405160200161473a929190918252602082015260400190565b60408051601f198184030181529082905261475491615993565b602060405180830381855afa158015614771573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614794919061564f565b6040516002906147ad90869060009089906020016159d1565b60408051601f19818403018152908290526147c791615993565b602060405180830381855afa1580156147e4573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614807919061564f565b60408051602081019390935282015260600160408051601f198184030181529082905261483391615993565b602060405180830381855afa158015614850573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190614873919061564f565b60fb546040805160208082018c905282518083039091018152818301928390526304512a2360e31b9092529293506001600160a01b03909116916322895118916801bc16d674ec800000916148d0918e918e908890604401615a09565b6000604051808303818588803b1580156148e957600080fd5b505af11580156148fd573d6000803e3d6000fd5b50505050506119356801bc16d674ec8000006143fc565b6000614921826020615637565b835110156149695760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b6044820152606401610d20565b50016020015190565b60606000614981836002615668565b61498c906002615637565b6001600160401b038111156149a3576149a36156d8565b6040519080825280601f01601f1916602001820160405280156149cd576020820181803683370190505b509050600360fc1b816000815181106149e8576149e86156ee565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614a1757614a176156ee565b60200101906001600160f81b031916908160001a9053506000614a3b846002615668565b614a46906001615637565b90505b6001811115614abe576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614a7a57614a7a6156ee565b1a60f81b828281518110614a9057614a906156ee565b60200101906001600160f81b031916908160001a90535060049490941c93614ab781615a54565b9050614a49565b5083156118265760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610d20565b6060614b1c8484600085614de5565b949350505050565b606081614b3281601f615637565b1015614b715760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610d20565b614b7b8284615637565b84511015614bbf5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610d20565b606082158015614bde5760405191506000825260208201604052614c28565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614c17578051835260209283019201614bff565b5050858452601f01601f1916604052505b50949350505050565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b82600081518110614c7157614c716156ee565b60200101906001600160f81b031916908160001a9053508060061a60f81b82600181518110614ca257614ca26156ee565b60200101906001600160f81b031916908160001a9053508060051a60f81b82600281518110614cd357614cd36156ee565b60200101906001600160f81b031916908160001a9053508060041a60f81b82600381518110614d0457614d046156ee565b60200101906001600160f81b031916908160001a9053508060031a60f81b82600481518110614d3557614d356156ee565b60200101906001600160f81b031916908160001a9053508060021a60f81b82600581518110614d6657614d666156ee565b60200101906001600160f81b031916908160001a9053508060011a60f81b82600681518110614d9757614d976156ee565b60200101906001600160f81b031916908160001a9053508060001a60f81b82600781518110614dc857614dc86156ee565b60200101906001600160f81b031916908160001a90535050919050565b606082471015614e465760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d20565b843b614e945760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d20565b600080866001600160a01b03168587604051614eb09190615993565b60006040518083038185875af1925050503d8060008114614eed576040519150601f19603f3d011682016040523d82523d6000602084013e614ef2565b606091505b5091509150614f02828286614f0d565b979650505050505050565b60608315614f1c575081611826565b825115614f2c5782518084602001fd5b8160405162461bcd60e51b8152600401610d2091906157b4565b828054614f5290615704565b90600052602060002090601f016020900481019282614f745760008555614fba565b82601f10614f8d57805160ff1916838001178555614fba565b82800160010185558215614fba579182015b82811115614fba578251825591602001919060010190614f9f565b50614fc692915061503e565b5090565b828054614fd690615704565b90600052602060002090601f016020900481019282614ff85760008555614fba565b82601f106150115782800160ff19823516178555614fba565b82800160010185558215614fba579182015b82811115614fba578235825591602001919060010190615023565b5b80821115614fc6576000815560010161503f565b60006020828403121561506557600080fd5b81356001600160e01b03198116811461182657600080fd5b6000806040838503121561509057600080fd5b50508035926020909101359150565b60008083601f8401126150b157600080fd5b5081356001600160401b038111156150c857600080fd5b6020830191508360208285010111156150e057600080fd5b9250929050565b600080600080604085870312156150fd57600080fd5b84356001600160401b038082111561511457600080fd5b6151208883890161509f565b9096509450602087013591508082111561513957600080fd5b506151468782880161509f565b95989497509550505050565b60006020828403121561516457600080fd5b5035919050565b6001600160a01b038116811461176157600080fd5b6000806040838503121561519357600080fd5b8235915060208301356151a58161516b565b809150509250929050565b60005b838110156151cb5781810151838201526020016151b3565b83811115613d745750506000910152565b600081518084526151f48160208601602086016151b0565b601f01601f19169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b8481101561525357601f198684030189526152418383516151dc565b98840198925090830190600101615225565b5090979650505050505050565b600081518084526020808501945080840160005b83811015615292578151151587529582019590820190600101615274565b509495945050505050565b6080815260006152b06080830187615208565b82810360208401526152c28187615208565b905082810360408401526152d68186615260565b90508281036060840152614f028185615260565b6000602082840312156152fc57600080fd5b81356118268161516b565b60008060006060848603121561531c57600080fd5b505081359360208301359350604090920135919050565b60008083601f84011261534557600080fd5b5081356001600160401b0381111561535c57600080fd5b6020830191508360208260051b85010111156150e057600080fd5b6000806000806040858703121561538d57600080fd5b84356001600160401b03808211156153a457600080fd5b6153b088838901615333565b909650945060208701359150808211156153c957600080fd5b5061514687828801615333565b6000806000604084860312156153eb57600080fd5b83356001600160401b0381111561540157600080fd5b61540d86828701615333565b909790965060209590950135949350505050565b6000806000806080858703121561543757600080fd5b5050823594602084013594506040840135936060013592509050565b6000806000806000806060878903121561546c57600080fd5b86356001600160401b038082111561548357600080fd5b61548f8a838b0161509f565b909850965060208901359150808211156154a857600080fd5b6154b48a838b0161509f565b909650945060408901359150808211156154cd57600080fd5b506154da89828a0161509f565b979a9699509497509295939492505050565b6060815260006154ff6060830186615208565b82810360208401526155118186615208565b905082810360408401526155258185615260565b9695505050505050565b801515811461176157600080fd5b60008060008060008060006080888a03121561555857600080fd5b87356001600160401b038082111561556f57600080fd5b61557b8b838c01615333565b909950975060208a013591508082111561559457600080fd5b6155a08b838c01615333565b909750955060408a01359150808211156155b957600080fd5b506155c68a828b01615333565b90945092505060608801356155da8161552f565b8091505092959891949750929550565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000821982111561564a5761564a615621565b500190565b60006020828403121561566157600080fd5b5051919050565b600081600019048311821515161561568257615682615621565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826156ac576156ac615687565b500490565b8183823760009101908152919050565b6000828210156156d3576156d3615621565b500390565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061571857607f821691505b6020821081141561573957634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141561575357615753615621565b5060010190565b6000808335601e1984360301811261577157600080fd5b8301803591506001600160401b0382111561578b57600080fd5b6020019150368190038213156150e057600080fd5b6000826157af576157af615687565b500690565b60208152600061182660208301846151dc565b600080821280156001600160ff1b03849003851316156157e9576157e9615621565b600160ff1b839003841281161561580257615802615621565b50500190565b634e487b7160e01b600052600160045260246000fd5b60008083128015600160ff1b85018412161561583c5761583c615621565b6001600160ff1b038401831381161561585757615857615621565b50500390565b60006020828403121561586f57600080fd5b81516118268161516b565b6001600160f81b031984168152825160009061589d8160018501602088016151b0565b60609390931b6bffffffffffffffffffffffff1916600192909301918201929092526015019392505050565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516159018160178501602088016151b0565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516159328160288401602088016151b0565b01602801949350505050565b60006020828403121561595057600080fd5b81516118268161552f565b6000835161596d8184602088016151b0565b6fffffffffffffffffffffffffffffffff19939093169190920190815260100192915050565b600082516159a58184602087016151b0565b9190910192915050565b600083516159c18184602088016151b0565b9190910191825250602001919050565b600084516159e38184602089016151b0565b67ffffffffffffffff199490941691909301908152601881019190915260380192915050565b608081526000615a1c60808301876151dc565b8281036020840152615a2e81876151dc565b90508281036040840152615a4281866151dc565b91505082606083015295945050505050565b600081615a6357615a63615621565b50600019019056fe68e79a7bf1e0bc45d0a330c573bc367f9cf464fd326078812f301165fbda4ef1c2979137d1774e40fe2638d355bf7a7b092be4c67f242aad1655e1e27f9df9cca26469706673582212204b73fd7304c73963ef9e3eaa2eded32640ff3e28e4afb39097971947b2822eb264736f6c634300080c0033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.