Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- NetworkWithdraw
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-10-17T08:20:49.940725Z
contracts/NetworkWithdraw.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "./interfaces/INetworkWithdraw.sol";
import "./interfaces/ILsdToken.sol";
import "./interfaces/INetworkProposal.sol";
import "./interfaces/INetworkBalances.sol";
import "./interfaces/IUserDeposit.sol";
import "./interfaces/IFeePool.sol";
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
contract NetworkWithdraw is Initializable, UUPSUpgradeable, INetworkWithdraw {
using EnumerableSet for EnumerableSet.UintSet;
address public lsdTokenAddress;
address public userDepositAddress;
address public networkProposalAddress;
address public networkBalancesAddress;
address public feePoolAddress;
address public factoryAddress;
uint256 public nextWithdrawIndex;
uint256 public maxClaimableWithdrawIndex;
uint256 public ejectedStartCycle;
uint256 public latestDistributeWithdrawalsHeight;
uint256 public latestDistributePriorityFeeHeight;
uint256 public totalMissingAmountForWithdraw;
uint256 public withdrawCycleSeconds;
uint256 public stackCommissionRate;
uint256 public platformCommissionRate;
uint256 public nodeCommissionRate;
uint256 public totalPlatformCommission;
uint256 public totalPlatformClaimedAmount;
uint256 public latestMerkleRootEpoch;
bytes32 public merkleRoot;
string public nodeRewardsFileCid;
bool public nodeClaimEnabled;
mapping(uint256 => Withdrawal) public withdrawalAtIndex;
mapping(address => EnumerableSet.UintSet) internal unclaimedWithdrawalsOfUser;
mapping(uint256 => uint256[]) public ejectedValidatorsAtCycle;
mapping(address => uint256) public totalClaimedRewardOfNode;
mapping(address => uint256) public totalClaimedDepositOfNode;
modifier onlyAdmin() {
if (!INetworkProposal(networkProposalAddress).isAdmin(msg.sender)) {
revert CallerNotAllowed();
}
_;
}
modifier onlyNetworkProposal() {
if (networkProposalAddress != msg.sender) {
revert CallerNotAllowed();
}
_;
}
constructor() {
_disableInitializers();
}
function init(
address _lsdTokenAddress,
address _userDepositAddress,
address _networkProposalAddress,
address _networkBalancesAddress,
address _feePoolAddress,
address _factoryAddress
) public virtual override initializer {
withdrawCycleSeconds = 86400; // 1 day
stackCommissionRate = 10e16; // 10%
platformCommissionRate = 5e16; // 5%
nodeCommissionRate = 5e16; // 5%
nextWithdrawIndex = 1;
nodeClaimEnabled = true;
lsdTokenAddress = _lsdTokenAddress;
userDepositAddress = _userDepositAddress;
networkProposalAddress = _networkProposalAddress;
networkBalancesAddress = _networkBalancesAddress;
feePoolAddress = _feePoolAddress;
factoryAddress = _factoryAddress;
}
function reinit() public virtual override reinitializer(1) {
_reinit();
}
function _reinit() internal virtual {}
function version() external view override returns (uint8) {
return _getInitializedVersion();
}
function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}
// Receive eth
receive() external payable {}
// ------------ getter ------------
function getUnclaimedWithdrawalsOfUser(address user) external view override returns (uint256[] memory) {
uint256 length = unclaimedWithdrawalsOfUser[user].length();
uint256[] memory withdrawals = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
withdrawals[i] = (unclaimedWithdrawalsOfUser[user].at(i));
}
return withdrawals;
}
function getEjectedValidatorsAtCycle(uint256 cycle) external view override returns (uint256[] memory) {
return ejectedValidatorsAtCycle[cycle];
}
function currentWithdrawCycle() public view returns (uint256) {
return block.timestamp / withdrawCycleSeconds;
}
// ------------ settings ------------
function setWithdrawCycleSeconds(uint256 _withdrawCycleSeconds) external onlyAdmin {
if (_withdrawCycleSeconds < 28800) { // 8 hours
revert TooLow(28800);
}
withdrawCycleSeconds = _withdrawCycleSeconds;
emit SetWithdrawCycleSeconds(_withdrawCycleSeconds);
}
function setNodeClaimEnabled(bool _value) external onlyAdmin {
nodeClaimEnabled = _value;
}
function platformClaim(address _recipient) external onlyAdmin {
uint256 shouldClaimAmount = totalPlatformCommission - totalPlatformClaimedAmount;
totalPlatformClaimedAmount = totalPlatformCommission;
(bool success,) = _recipient.call{value: shouldClaimAmount}("");
if (!success) {
revert FailedToCall();
}
}
function setStackCommissionRate(uint256 _stackCommissionRate) external onlyAdmin {
if (_stackCommissionRate > 1e18) {
revert CommissionRateInvalid();
}
stackCommissionRate = _stackCommissionRate;
}
function setPlatformAndNodeCommissionRate(uint256 _platformCommissionRate, uint256 _nodeCommissionRate)
external
onlyAdmin
{
if (_platformCommissionRate + _nodeCommissionRate > 1e18) {
revert CommissionRateInvalid();
}
platformCommissionRate = _platformCommissionRate;
nodeCommissionRate = _nodeCommissionRate;
}
// ------------ user unstake ------------
function unstake(uint256 _lsdTokenAmount) external override {
uint256 ethAmount = _processWithdraw(_lsdTokenAmount);
IUserDeposit userDeposit = IUserDeposit(userDepositAddress);
uint256 stakePoolBalance = userDeposit.getBalance();
uint256 totalMissingAmount = totalMissingAmountForWithdraw + ethAmount;
if (stakePoolBalance != 0) {
uint256 mvAmount = totalMissingAmount;
if (stakePoolBalance < mvAmount) {
mvAmount = stakePoolBalance;
}
userDeposit.withdrawExcessBalance(mvAmount);
totalMissingAmount -= mvAmount;
}
totalMissingAmountForWithdraw = totalMissingAmount;
bool unstakeInstantly = totalMissingAmount == 0;
uint256 willUseWithdrawalIndex = nextWithdrawIndex;
withdrawalAtIndex[willUseWithdrawalIndex] = Withdrawal({_address: msg.sender, _amount: ethAmount});
nextWithdrawIndex = willUseWithdrawalIndex + 1;
emit Unstake(msg.sender, _lsdTokenAmount, ethAmount, willUseWithdrawalIndex, unstakeInstantly);
if (unstakeInstantly) {
maxClaimableWithdrawIndex = willUseWithdrawalIndex;
(bool success,) = msg.sender.call{value: ethAmount}("");
if (!success) {
revert FailedToCall();
}
} else {
unclaimedWithdrawalsOfUser[msg.sender].add(willUseWithdrawalIndex);
}
}
function withdraw(uint256[] calldata _withdrawalIndexList) external override {
if (_withdrawalIndexList.length == 0) {
revert WithdrawIndexEmpty();
}
uint256 totalAmount;
for (uint256 i = 0; i < _withdrawalIndexList.length; i++) {
uint256 withdrawalIndex = _withdrawalIndexList[i];
if (withdrawalIndex > maxClaimableWithdrawIndex) {
revert NotClaimable();
}
if (!unclaimedWithdrawalsOfUser[msg.sender].remove(withdrawalIndex)) {
revert AlreadyClaimed();
}
totalAmount = totalAmount + withdrawalAtIndex[withdrawalIndex]._amount;
}
if (totalAmount != 0) {
(bool success,) = msg.sender.call{value: totalAmount}("");
if (!success) {
revert FailedToCall();
}
}
emit Withdraw(msg.sender, _withdrawalIndexList);
}
// ----- node claim --------------
function nodeClaim(
uint256 _index,
address _account,
uint256 _totalRewardAmount,
uint256 _totalExitDepositAmount,
bytes32[] calldata _merkleProof,
ClaimType _claimType
) external {
if (!nodeClaimEnabled) {
revert NodeNotClaimable();
}
uint256 claimableReward = _totalRewardAmount - totalClaimedRewardOfNode[_account];
uint256 claimableDeposit = _totalExitDepositAmount - totalClaimedDepositOfNode[_account];
// Verify the merkle proof.
if (
!MerkleProof.verify(
_merkleProof,
merkleRoot,
keccak256(abi.encodePacked(_index, _account, _totalRewardAmount, _totalExitDepositAmount))
)
) {
revert InvalidMerkleProof();
}
uint256 willClaimAmount;
if (_claimType == ClaimType.ClaimReward) {
if (claimableReward == 0) {
revert ClaimableRewardZero();
}
totalClaimedRewardOfNode[_account] = _totalRewardAmount;
willClaimAmount = claimableReward;
} else if (_claimType == ClaimType.ClaimDeposit) {
if (claimableDeposit == 0) {
revert ClaimableDepositZero();
}
totalClaimedDepositOfNode[_account] = _totalExitDepositAmount;
willClaimAmount = claimableDeposit;
} else if (_claimType == ClaimType.ClaimTotal) {
willClaimAmount = claimableReward + claimableDeposit;
if (willClaimAmount == 0) {
revert ClaimableAmountZero();
}
totalClaimedRewardOfNode[_account] = _totalRewardAmount;
totalClaimedDepositOfNode[_account] = _totalExitDepositAmount;
} else {
revert UnknownClaimType();
}
(bool success,) = _account.call{value: willClaimAmount}("");
if (!success) {
revert FailedToCall();
}
emit NodeClaimed(_index, _account, claimableReward, claimableDeposit, _claimType);
}
// ------------ voter ------------
function distribute(
DistributeType _distributeType,
uint256 _dealedHeight,
uint256 _userAmount,
uint256 _nodeAmount,
uint256 _platformAmount,
uint256 _maxClaimableWithdrawIndex
) external override onlyNetworkProposal {
uint256 totalAmount = _userAmount + _nodeAmount + _platformAmount;
uint256 latestDistributeHeight;
if (_distributeType == DistributeType.DistributePriorityFee) {
latestDistributeHeight = latestDistributePriorityFeeHeight;
latestDistributePriorityFeeHeight = _dealedHeight;
if (totalAmount != 0) {
IFeePool(feePoolAddress).withdrawEther(totalAmount);
}
} else if (_distributeType == DistributeType.DistributeWithdrawals) {
latestDistributeHeight = latestDistributeWithdrawalsHeight;
latestDistributeWithdrawalsHeight = _dealedHeight;
} else {
revert UnknownDistributeType();
}
if (_dealedHeight <= latestDistributeHeight) {
revert AlreadyDealedHeight();
}
if (_maxClaimableWithdrawIndex >= nextWithdrawIndex) {
revert ClaimableWithdrawIndexOverflow();
}
if (totalAmount > address(this).balance) {
revert BalanceNotEnough();
}
if (_maxClaimableWithdrawIndex > maxClaimableWithdrawIndex) {
maxClaimableWithdrawIndex = _maxClaimableWithdrawIndex;
}
uint256 mvAmount = _userAmount;
if (totalMissingAmountForWithdraw < _userAmount) {
mvAmount = _userAmount - totalMissingAmountForWithdraw;
totalMissingAmountForWithdraw = 0;
} else {
mvAmount = 0;
totalMissingAmountForWithdraw = totalMissingAmountForWithdraw - _userAmount;
}
if (mvAmount != 0) {
IUserDeposit(userDepositAddress).recycleNetworkWithdrawDeposit{value: mvAmount}();
}
distributeCommission(_platformAmount);
emit DistributeRewards(
_distributeType,
_dealedHeight,
_userAmount,
_nodeAmount,
_platformAmount,
_maxClaimableWithdrawIndex,
mvAmount
);
}
function notifyValidatorExit(
uint256 _withdrawCycle,
uint256 _ejectedStartCycle,
uint256[] calldata _validatorIndexList
) external override onlyNetworkProposal {
if (_validatorIndexList.length == 0) {
revert LengthNotMatch();
}
if (_ejectedStartCycle >= _withdrawCycle || _withdrawCycle + 1 != currentWithdrawCycle()) {
revert CycleNotMatch();
}
if (ejectedValidatorsAtCycle[_withdrawCycle].length != 0) {
revert AlreadyNotifiedCycle();
}
ejectedValidatorsAtCycle[_withdrawCycle] = _validatorIndexList;
ejectedStartCycle = _ejectedStartCycle;
emit NotifyValidatorExit(_withdrawCycle, _ejectedStartCycle, _validatorIndexList);
}
function setMerkleRoot(uint256 _dealedEpoch, bytes32 _merkleRoot, string calldata _nodeRewardsFileCid)
external
onlyNetworkProposal
{
if (_dealedEpoch <= latestMerkleRootEpoch) {
revert AlreadyDealedEpoch();
}
merkleRoot = _merkleRoot;
latestMerkleRootEpoch = _dealedEpoch;
nodeRewardsFileCid = _nodeRewardsFileCid;
emit SetMerkleRoot(_dealedEpoch, _merkleRoot, _nodeRewardsFileCid);
}
// ----- network --------------
// Deposit ETH from deposit pool
function depositEth() external payable override {
// Emit ether deposited event
emit EtherDeposited(msg.sender, msg.value, block.timestamp);
}
// Deposit ETH from deposit pool and update totalMissingAmountForWithdraw
function depositEthAndUpdateTotalMissingAmount() external payable override {
totalMissingAmountForWithdraw = totalMissingAmountForWithdraw - msg.value;
// Emit ether deposited event
emit EtherDeposited(msg.sender, msg.value, block.timestamp);
}
// ------------ helper ------------
// check:
// 1 cycle limit
// 2 user limit
// burn lsdToken from user
// return:
// 1 eth withdraw amount
function _processWithdraw(uint256 _lsdTokenAmount) private returns (uint256) {
if (_lsdTokenAmount == 0) {
revert LsdTokenAmountZero();
}
uint256 ethAmount = INetworkBalances(networkBalancesAddress).getEthValue(_lsdTokenAmount);
if (ethAmount == 0) {
revert EthAmountZero();
}
ERC20Burnable(lsdTokenAddress).burnFrom(msg.sender, _lsdTokenAmount);
return ethAmount;
}
function distributeCommission(uint256 _amount) private {
if (_amount == 0) {
return;
}
uint256 stackFee = (_amount * stackCommissionRate) / 1e18;
uint256 platformAmount = _amount - stackFee;
totalPlatformCommission = totalPlatformCommission + platformAmount;
(bool success,) = factoryAddress.call{value: stackFee}("");
if (!success) {
revert FailedToCall();
}
}
}
@openzeppelin/contracts/interfaces/IERC1967.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}
contracts/interfaces/IRateProvider.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
interface IRateProvider {
function getRate() external view returns (uint256);
}
contracts/interfaces/IUpgrade.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
interface IUpgrade {
function reinit() external;
function version() external returns (uint8);
}
@openzeppelin/contracts/interfaces/draft-IERC1822.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967Upgrade is IERC1967 {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}
@openzeppelin/contracts/proxy/beacon/IBeacon.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
@openzeppelin/contracts/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/Address.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]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev 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.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
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.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822.sol";
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeTo(address newImplementation) public virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
}
@openzeppelin/contracts/token/ERC20/ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)
pragma solidity ^0.8.0;
import "../ERC20.sol";
import "../../../utils/Context.sol";
/**
* @dev Extension of {ERC20} that allows token holders to destroy both their own
* tokens and those that they have an allowance for, in a way that can be
* recognized off-chain (via event analysis).
*/
abstract contract ERC20Burnable is Context, ERC20 {
/**
* @dev Destroys `amount` tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
/**
* @dev Destroys `amount` tokens from `account`, deducting from the caller's
* allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `amount`.
*/
function burnFrom(address account, uint256 amount) public virtual {
_spendAllowance(account, _msgSender(), amount);
_burn(account, amount);
}
}
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
@openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or 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 {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
contracts/interfaces/IUserDeposit.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
import "./IRateProvider.sol";
import "./Errors.sol";
import "./IUpgrade.sol";
interface IUserDeposit is IRateProvider, Errors, IUpgrade {
event DepositReceived(address indexed from, uint256 amount, uint256 time);
event DepositRecycled(address indexed from, uint256 amount, uint256 time);
event ExcessWithdrawn(address indexed to, uint256 amount, uint256 time);
function init(
address _lsdTokenAddress,
address _nodeDepositAddress,
address _networkWithdrawAddress,
address _networkProposalAddress,
address _networkBalancesAddress
) external;
function deposit() external payable;
function getBalance() external view returns (uint256);
function withdrawExcessBalance(uint256 _amount) external;
function recycleNetworkWithdrawDeposit() external payable;
}
@openzeppelin/contracts/utils/StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}
@openzeppelin/contracts/utils/cryptography/MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates merkle trees that are safe
* against this attack out of the box.
*/
library MerkleProof {
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*
* _Available since v4.7._
*/
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*
* _Available since v4.7._
*/
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*
* _Available since v4.7._
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
require(proofPos == proofLen, "MerkleProof: invalid multiproof");
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
require(proofPos == proofLen, "MerkleProof: invalid multiproof");
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
@openzeppelin/contracts/utils/structs/EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
contracts/interfaces/Errors.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
interface Errors {
error FailedToCall();
error AddressNotAllowed();
error CallerNotAllowed();
error AmountUnmatch();
error AmountZero();
error AmountNotZero();
error AlreadyInitialized();
error NotAuthorizedLsdToken();
error LsdTokenCanOnlyUseOnce();
error EmptyEntrustedVoters();
error SubmitBalancesDisabled();
error BlockNotMatch();
error RateChangeOverLimit();
error InvalidThreshold();
error VotersNotEnough();
error VotersDuplicate();
error VotersNotExist();
error ProposalExecFailed();
error AlreadyVoted();
error WithdrawIndexEmpty();
error NotClaimable();
error AlreadyClaimed();
error InvalidMerkleProof();
error ClaimableRewardZero();
error ClaimableDepositZero();
error ClaimableAmountZero();
error AlreadyDealedHeight();
error ClaimableWithdrawIndexOverflow();
error BalanceNotEnough();
error LengthNotMatch();
error CycleNotMatch();
error AlreadyNotifiedCycle();
error AlreadyDealedEpoch();
error LsdTokenAmountZero();
error EthAmountZero();
error TooLow(uint256 min);
error NodeNotClaimable();
error CommissionRateInvalid();
error PubkeyNotExist();
error PubkeyAlreadyExist();
error PubkeyStatusUnmatch();
error NodeAlreadyExist();
error NotTrustNode();
error NodeAlreadyRemoved();
error TrustNodeDepositDisabled();
error SoloNodeDepositDisabled();
error SoloNodeDepositAmountZero();
error PubkeyNumberOverLimit();
error NotPubkeyOwner();
error UserDepositDisabled();
error DepositAmountLTMinAmount();
error DepositAmountGTMaxAmount();
error UnknownClaimType();
error UnknownDistributeType();
error UnknownNodeType();
}
contracts/interfaces/IDepositEth.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
interface IDepositEth {
function depositEth() external payable;
}
contracts/interfaces/IFeePool.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
import "./Errors.sol";
import "./IUpgrade.sol";
interface IFeePool is Errors, IUpgrade {
event EtherWithdrawn(uint256 amount, uint256 time);
function init(address _networkWithdrawAddress, address _networkProposalAddress) external;
function withdrawEther(uint256 _amount) external;
}
contracts/interfaces/ILsdToken.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
import "./IRateProvider.sol";
import "./Errors.sol";
interface ILsdToken is IRateProvider, Errors {
function initMinter(address) external;
function mint(address, uint256) external;
function updateMinter(address _newMinter) external;
}
contracts/interfaces/INetworkBalances.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
import "./Errors.sol";
import "./IUpgrade.sol";
interface INetworkBalances is Errors, IUpgrade {
struct BalancesSnapshot {
uint256 _block;
uint256 _totalEth;
uint256 _totalLsdToken;
}
event BalancesUpdated(uint256 block, uint256 totalEth, uint256 lsdTokenSupply, uint256 time);
function init(address _networkProposalAddress) external;
function getEthValue(uint256 _lsdTokenAmount) external view returns (uint256);
function getLsdTokenValue(uint256 _ethAmount) external view returns (uint256);
function getExchangeRate() external view returns (uint256);
function submitBalances(uint256 _block, uint256 _totalEth, uint256 _totalLsdToken) external;
}
contracts/interfaces/INetworkProposal.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
import "./Errors.sol";
import "./IUpgrade.sol";
interface INetworkProposal is Errors, IUpgrade {
enum ProposalStatus {
Inactive,
Active,
Executed
}
struct Proposal {
ProposalStatus _status;
uint16 _yesVotes; // bitmap, 16 maximum votes
uint8 _yesVotesTotal;
}
event VoteProposal(bytes32 indexed _proposalId, address _voter);
event ProposalExecuted(bytes32 indexed _proposalId);
event VoterManagementTakenOver(address indexed _oldManager, address indexed _newManager);
function init(address[] memory _voters, uint256 _initialThreshold, address _adminAddress, address _voterManagerAddress) external;
function isAdmin(address _sender) external view returns (bool);
}
contracts/interfaces/INetworkWithdraw.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.19;
import "./IDepositEth.sol";
import "./Errors.sol";
import "./IUpgrade.sol";
interface INetworkWithdraw is IDepositEth, Errors, IUpgrade {
enum ClaimType {
None,
ClaimReward,
ClaimDeposit,
ClaimTotal
}
enum DistributeType {
None,
DistributeWithdrawals,
DistributePriorityFee
}
struct Withdrawal {
address _address;
uint256 _amount;
}
event NodeClaimed(
uint256 index, address account, uint256 claimableReward, uint256 claimableDeposit, ClaimType claimType
);
event SetWithdrawCycleSeconds(uint256 cycleSeconds);
event SetMerkleRoot(uint256 indexed dealedEpoch, bytes32 merkleRoot, string nodeRewardsFileCid);
event EtherDeposited(address indexed from, uint256 amount, uint256 time);
event Unstake(
address indexed from, uint256 lsdTokenAmount, uint256 ethAmount, uint256 withdrawIndex, bool instantly
);
event Withdraw(address indexed from, uint256[] withdrawIndexList);
event DistributeRewards(
DistributeType distributeType,
uint256 dealedHeight,
uint256 userAmount,
uint256 nodeAmount,
uint256 platformAmount,
uint256 maxClaimableWithdrawIndex,
uint256 mvAmount
);
event NotifyValidatorExit(uint256 withdrawCycle, uint256 ejectedStartWithdrawCycle, uint256[] ejectedValidators);
function init(
address _lsdTokenAddress,
address _userDepositAddress,
address _networkProposalAddress,
address _networkBalancesAddress,
address _feePoolAddress,
address _factoryAddress
) external;
// getter
function getUnclaimedWithdrawalsOfUser(address _user) external view returns (uint256[] memory);
function getEjectedValidatorsAtCycle(uint256 _cycle) external view returns (uint256[] memory);
function totalMissingAmountForWithdraw() external view returns (uint256);
// user
function unstake(uint256 _lsdTokenAmount) external;
function withdraw(uint256[] calldata _withdrawIndexList) external;
// ejector
function notifyValidatorExit(
uint256 _withdrawCycle,
uint256 _ejectedStartWithdrawCycle,
uint256[] calldata _validatorIndex
) external;
// voter
function distribute(
DistributeType _distributeType,
uint256 _dealedHeight,
uint256 _userAmount,
uint256 _nodeAmount,
uint256 _platformAmount,
uint256 _maxClaimableWithdrawIndex
) external;
function depositEthAndUpdateTotalMissingAmount() external payable;
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"error","name":"AddressNotAllowed","inputs":[]},{"type":"error","name":"AlreadyClaimed","inputs":[]},{"type":"error","name":"AlreadyDealedEpoch","inputs":[]},{"type":"error","name":"AlreadyDealedHeight","inputs":[]},{"type":"error","name":"AlreadyInitialized","inputs":[]},{"type":"error","name":"AlreadyNotifiedCycle","inputs":[]},{"type":"error","name":"AlreadyVoted","inputs":[]},{"type":"error","name":"AmountNotZero","inputs":[]},{"type":"error","name":"AmountUnmatch","inputs":[]},{"type":"error","name":"AmountZero","inputs":[]},{"type":"error","name":"BalanceNotEnough","inputs":[]},{"type":"error","name":"BlockNotMatch","inputs":[]},{"type":"error","name":"CallerNotAllowed","inputs":[]},{"type":"error","name":"ClaimableAmountZero","inputs":[]},{"type":"error","name":"ClaimableDepositZero","inputs":[]},{"type":"error","name":"ClaimableRewardZero","inputs":[]},{"type":"error","name":"ClaimableWithdrawIndexOverflow","inputs":[]},{"type":"error","name":"CommissionRateInvalid","inputs":[]},{"type":"error","name":"CycleNotMatch","inputs":[]},{"type":"error","name":"DepositAmountGTMaxAmount","inputs":[]},{"type":"error","name":"DepositAmountLTMinAmount","inputs":[]},{"type":"error","name":"EmptyEntrustedVoters","inputs":[]},{"type":"error","name":"EthAmountZero","inputs":[]},{"type":"error","name":"FailedToCall","inputs":[]},{"type":"error","name":"InvalidMerkleProof","inputs":[]},{"type":"error","name":"InvalidThreshold","inputs":[]},{"type":"error","name":"LengthNotMatch","inputs":[]},{"type":"error","name":"LsdTokenAmountZero","inputs":[]},{"type":"error","name":"LsdTokenCanOnlyUseOnce","inputs":[]},{"type":"error","name":"NodeAlreadyExist","inputs":[]},{"type":"error","name":"NodeAlreadyRemoved","inputs":[]},{"type":"error","name":"NodeNotClaimable","inputs":[]},{"type":"error","name":"NotAuthorizedLsdToken","inputs":[]},{"type":"error","name":"NotClaimable","inputs":[]},{"type":"error","name":"NotPubkeyOwner","inputs":[]},{"type":"error","name":"NotTrustNode","inputs":[]},{"type":"error","name":"ProposalExecFailed","inputs":[]},{"type":"error","name":"PubkeyAlreadyExist","inputs":[]},{"type":"error","name":"PubkeyNotExist","inputs":[]},{"type":"error","name":"PubkeyNumberOverLimit","inputs":[]},{"type":"error","name":"PubkeyStatusUnmatch","inputs":[]},{"type":"error","name":"RateChangeOverLimit","inputs":[]},{"type":"error","name":"SoloNodeDepositAmountZero","inputs":[]},{"type":"error","name":"SoloNodeDepositDisabled","inputs":[]},{"type":"error","name":"SubmitBalancesDisabled","inputs":[]},{"type":"error","name":"TooLow","inputs":[{"type":"uint256","name":"min","internalType":"uint256"}]},{"type":"error","name":"TrustNodeDepositDisabled","inputs":[]},{"type":"error","name":"UnknownClaimType","inputs":[]},{"type":"error","name":"UnknownDistributeType","inputs":[]},{"type":"error","name":"UnknownNodeType","inputs":[]},{"type":"error","name":"UserDepositDisabled","inputs":[]},{"type":"error","name":"VotersDuplicate","inputs":[]},{"type":"error","name":"VotersNotEnough","inputs":[]},{"type":"error","name":"VotersNotExist","inputs":[]},{"type":"error","name":"WithdrawIndexEmpty","inputs":[]},{"type":"event","name":"AdminChanged","inputs":[{"type":"address","name":"previousAdmin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BeaconUpgraded","inputs":[{"type":"address","name":"beacon","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"DistributeRewards","inputs":[{"type":"uint8","name":"distributeType","internalType":"enum INetworkWithdraw.DistributeType","indexed":false},{"type":"uint256","name":"dealedHeight","internalType":"uint256","indexed":false},{"type":"uint256","name":"userAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"nodeAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"platformAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"maxClaimableWithdrawIndex","internalType":"uint256","indexed":false},{"type":"uint256","name":"mvAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EtherDeposited","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"time","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"NodeClaimed","inputs":[{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"address","name":"account","internalType":"address","indexed":false},{"type":"uint256","name":"claimableReward","internalType":"uint256","indexed":false},{"type":"uint256","name":"claimableDeposit","internalType":"uint256","indexed":false},{"type":"uint8","name":"claimType","internalType":"enum INetworkWithdraw.ClaimType","indexed":false}],"anonymous":false},{"type":"event","name":"NotifyValidatorExit","inputs":[{"type":"uint256","name":"withdrawCycle","internalType":"uint256","indexed":false},{"type":"uint256","name":"ejectedStartWithdrawCycle","internalType":"uint256","indexed":false},{"type":"uint256[]","name":"ejectedValidators","internalType":"uint256[]","indexed":false}],"anonymous":false},{"type":"event","name":"SetMerkleRoot","inputs":[{"type":"uint256","name":"dealedEpoch","internalType":"uint256","indexed":true},{"type":"bytes32","name":"merkleRoot","internalType":"bytes32","indexed":false},{"type":"string","name":"nodeRewardsFileCid","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"SetWithdrawCycleSeconds","inputs":[{"type":"uint256","name":"cycleSeconds","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Unstake","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"uint256","name":"lsdTokenAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"ethAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"withdrawIndex","internalType":"uint256","indexed":false},{"type":"bool","name":"instantly","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"implementation","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Withdraw","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"uint256[]","name":"withdrawIndexList","internalType":"uint256[]","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentWithdrawCycle","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"depositEth","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"depositEthAndUpdateTotalMissingAmount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"distribute","inputs":[{"type":"uint8","name":"_distributeType","internalType":"enum INetworkWithdraw.DistributeType"},{"type":"uint256","name":"_dealedHeight","internalType":"uint256"},{"type":"uint256","name":"_userAmount","internalType":"uint256"},{"type":"uint256","name":"_nodeAmount","internalType":"uint256"},{"type":"uint256","name":"_platformAmount","internalType":"uint256"},{"type":"uint256","name":"_maxClaimableWithdrawIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ejectedStartCycle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ejectedValidatorsAtCycle","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"factoryAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feePoolAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getEjectedValidatorsAtCycle","inputs":[{"type":"uint256","name":"cycle","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getUnclaimedWithdrawalsOfUser","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"init","inputs":[{"type":"address","name":"_lsdTokenAddress","internalType":"address"},{"type":"address","name":"_userDepositAddress","internalType":"address"},{"type":"address","name":"_networkProposalAddress","internalType":"address"},{"type":"address","name":"_networkBalancesAddress","internalType":"address"},{"type":"address","name":"_feePoolAddress","internalType":"address"},{"type":"address","name":"_factoryAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestDistributePriorityFeeHeight","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestDistributeWithdrawalsHeight","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestMerkleRootEpoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"lsdTokenAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxClaimableWithdrawIndex","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"merkleRoot","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"networkBalancesAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"networkProposalAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nextWithdrawIndex","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nodeClaim","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"},{"type":"address","name":"_account","internalType":"address"},{"type":"uint256","name":"_totalRewardAmount","internalType":"uint256"},{"type":"uint256","name":"_totalExitDepositAmount","internalType":"uint256"},{"type":"bytes32[]","name":"_merkleProof","internalType":"bytes32[]"},{"type":"uint8","name":"_claimType","internalType":"enum INetworkWithdraw.ClaimType"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"nodeClaimEnabled","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nodeCommissionRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"nodeRewardsFileCid","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"notifyValidatorExit","inputs":[{"type":"uint256","name":"_withdrawCycle","internalType":"uint256"},{"type":"uint256","name":"_ejectedStartCycle","internalType":"uint256"},{"type":"uint256[]","name":"_validatorIndexList","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"platformClaim","inputs":[{"type":"address","name":"_recipient","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"platformCommissionRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"proxiableUUID","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"reinit","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMerkleRoot","inputs":[{"type":"uint256","name":"_dealedEpoch","internalType":"uint256"},{"type":"bytes32","name":"_merkleRoot","internalType":"bytes32"},{"type":"string","name":"_nodeRewardsFileCid","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setNodeClaimEnabled","inputs":[{"type":"bool","name":"_value","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPlatformAndNodeCommissionRate","inputs":[{"type":"uint256","name":"_platformCommissionRate","internalType":"uint256"},{"type":"uint256","name":"_nodeCommissionRate","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setStackCommissionRate","inputs":[{"type":"uint256","name":"_stackCommissionRate","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setWithdrawCycleSeconds","inputs":[{"type":"uint256","name":"_withdrawCycleSeconds","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stackCommissionRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalClaimedDepositOfNode","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalClaimedRewardOfNode","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalMissingAmountForWithdraw","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalPlatformClaimedAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalPlatformCommission","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unstake","inputs":[{"type":"uint256","name":"_lsdTokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgradeTo","inputs":[{"type":"address","name":"newImplementation","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToAndCall","inputs":[{"type":"address","name":"newImplementation","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"userDepositAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"version","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256[]","name":"_withdrawalIndexList","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdrawCycleSeconds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_address","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}],"name":"withdrawalAtIndex","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x60a0604052306080523480156200001557600080fd5b506200002062000026565b620000e7565b600054610100900460ff1615620000935760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e5576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60805161313c6200011f60003960008181610d2201528181610d6b01528181610e4701528181610e870152610f1a015261313c6000f3fe6080604052600436106102975760003560e01c80638a6998281161015a578063bb2d840c116100c1578063db17815b1161007a578063db17815b146107b5578063ea8532fb146107ca578063f1583c08146107ea578063fd6b5a491461080a578063fdf435e91461082a578063fef25c0d1461084a57600080fd5b8063bb2d840c146106f1578063c482ceaf1461071e578063c980ba8914610733578063d3638c7e14610753578063d57dc8241461077d578063d65143041461079f57600080fd5b80639fa1f5ba116101135780639fa1f5ba14610610578063a8e1b8ef14610626578063aaf8277014610685578063b3594059146106a5578063b4701c09146106bb578063b5ca7410146106db57600080fd5b80638a69982814610572578063939d1ee414610588578063966dae0e146105a8578063983d95ce146105c857806399e133f9146105e85780639d2f846e1461060857600080fd5b8063439370b1116101fe57806352d1902d116101b757806352d1902d146104b257806354fd4d50146104c75780636c570dc1146104e95780637a1a934d146105165780637e4dc15c1461053657806387505b9d1461054c57600080fd5b8063439370b1146104355780634636e4e51461043d57806346773830146104535780634a4b061b146104735780634dff8430146104895780634f1ef2861461049f57600080fd5b80632e17de78116102505780632e17de78146103715780632eb4a7ab146103915780633659cfe6146103a757806338fcf092146103c75780633c677dbe146103ff5780634319ebe41461041557600080fd5b80630a64041b146102a357806312b81931146102cc5780631da4dd0d146102ee5780631e0f4aae14610304578063261a792d146103245780632c0f41661461034457600080fd5b3661029e57005b600080fd5b3480156102af57600080fd5b506102b960075481565b6040519081526020015b60405180910390f35b3480156102d857600080fd5b506102ec6102e7366004612787565b610860565b005b3480156102fa57600080fd5b506102b9600e5481565b34801561031057600080fd5b506102ec61031f366004612853565b610907565b34801561033057600080fd5b506102b961033f3660046128a6565b610a22565b34801561035057600080fd5b5061036461035f3660046128c8565b610a53565b6040516102c391906128e1565b34801561037d57600080fd5b506102ec61038c3660046128c8565b610ab5565b34801561039d57600080fd5b506102b960135481565b3480156103b357600080fd5b506102ec6103c2366004612941565b610d18565b3480156103d357600080fd5b506003546103e7906001600160a01b031681565b6040516001600160a01b0390911681526020016102c3565b34801561040b57600080fd5b506102b9600b5481565b34801561042157600080fd5b506004546103e7906001600160a01b031681565b6102ec610e00565b34801561044957600080fd5b506102b9600f5481565b34801561045f57600080fd5b506001546103e7906001600160a01b031681565b34801561047f57600080fd5b506102b9600c5481565b34801561049557600080fd5b506102b9600a5481565b6102ec6104ad366004612972565b610e3d565b3480156104be57600080fd5b506102b9610f0d565b3480156104d357600080fd5b5060005460405160ff90911681526020016102c3565b3480156104f557600080fd5b506102b9610504366004612941565b601a6020526000908152604090205481565b34801561052257600080fd5b506102ec6105313660046128a6565b610fc5565b34801561054257600080fd5b506102b960065481565b34801561055857600080fd5b506000546103e7906201000090046001600160a01b031681565b34801561057e57600080fd5b506102b960085481565b34801561059457600080fd5b506102ec6105a33660046128c8565b61108b565b3480156105b457600080fd5b506005546103e7906001600160a01b031681565b3480156105d457600080fd5b506102ec6105e3366004612a34565b611177565b3480156105f457600080fd5b506102ec610603366004612a76565b611307565b6102ec611474565b34801561061c57600080fd5b506102b960095481565b34801561063257600080fd5b506106666106413660046128c8565b601660205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b0390931683526020830191909152016102c3565b34801561069157600080fd5b506102ec6106a0366004612941565b6114bc565b3480156106b157600080fd5b506102b960115481565b3480156106c757600080fd5b506002546103e7906001600160a01b031681565b3480156106e757600080fd5b506102b960125481565b3480156106fd57600080fd5b506102b961070c366004612941565b60196020526000908152604090205481565b34801561072a57600080fd5b506102ec6115d7565b34801561073f57600080fd5b506102ec61074e366004612aea565b611661565b34801561075f57600080fd5b5060155461076d9060ff1681565b60405190151581526020016102c3565b34801561078957600080fd5b506107926118e6565b6040516102c39190612b5e565b3480156107ab57600080fd5b506102b9600d5481565b3480156107c157600080fd5b506102b9611974565b3480156107d657600080fd5b506102ec6107e53660046128c8565b611984565b3480156107f657600080fd5b506102ec610805366004612b9f565b611a3b565b34801561081657600080fd5b50610364610825366004612941565b611ad7565b34801561083657600080fd5b506102ec610845366004612bc3565b611ba9565b34801561085657600080fd5b506102b960105481565b6002546001600160a01b0316331461088b5760405163015783e960e51b815260040160405180910390fd5b60125484116108ad5760405163e602012760e01b815260040160405180910390fd5b6013839055601284905560146108c4828483612cd4565b50837fec43b2424d0504da473794ad49016df3e06fb0d772bb403d724c9e5d53d8afb88484846040516108f993929190612d95565b60405180910390a250505050565b6002546001600160a01b031633146109325760405163015783e960e51b815260040160405180910390fd5b600081900361095457604051631985132360e31b815260040160405180910390fd5b83831015806109745750610966611974565b610971856001612de1565b14155b1561099257604051632d072a4760e21b815260040160405180910390fd5b600084815260186020526040902054156109bf5760405163fc0aca3960e01b815260040160405180910390fd5b60008481526018602052604090206109d8908383612727565b5060088390556040517fb83477449e27b4bab4f28c938d033b953557d6a1b9b4469a43d229f78ed6e55c90610a14908690869086908690612e26565b60405180910390a150505050565b60186020528160005260406000208181548110610a3e57600080fd5b90600052602060002001600091509150505481565b600081815260186020908152604091829020805483518184028101840190945280845260609392830182828015610aa957602002820191906000526020600020905b815481526020019060010190808311610a95575b50505050509050919050565b6000610ac082611ed0565b90506000600160009054906101000a90046001600160a01b031690506000816001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b409190612e46565b9050600083600b54610b529190612de1565b90508115610bd0578080831015610b665750815b6040516331d2edcf60e11b8152600481018290526001600160a01b038516906363a5db9e90602401600060405180830381600087803b158015610ba857600080fd5b505af1158015610bbc573d6000803e3d6000fd5b505050508082610bcc9190612e5f565b9150505b600b819055600654604080518082018252338152602080820188815260008581526016909252929020905181546001600160a01b0319166001600160a01b03909116178155905160019182015582159190610c2c908290612de1565b6006556040805188815260208101889052908101829052821515606082015233907fc7ccdcb2d25f572c6814e377dbb34ea4318a4b7d3cd890f5cfad699d75327c7c9060800160405180910390a28115610cf4576007819055604051600090339088908381818185875af1925050503d8060008114610cc7576040519150601f19603f3d011682016040523d82523d6000602084013e610ccc565b606091505b5050905080610cee57604051635cc4532160e01b815260040160405180910390fd5b50610d0f565b336000908152601760205260409020610d0d9082611ff4565b505b50505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610d695760405162461bcd60e51b8152600401610d6090612e72565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610db26000805160206130c0833981519152546001600160a01b031690565b6001600160a01b031614610dd85760405162461bcd60e51b8152600401610d6090612ebe565b610de181612009565b60408051600080825260208201909252610dfd91839190612092565b50565b6040805134815242602082015233917fef51b4c870b8b0100eae2072e91db01222a303072af3728e58c9d4d2da33127f91015b60405180910390a2565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610e855760405162461bcd60e51b8152600401610d6090612e72565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610ece6000805160206130c0833981519152546001600160a01b031690565b6001600160a01b031614610ef45760405162461bcd60e51b8152600401610d6090612ebe565b610efd82612009565b610f0982826001612092565b5050565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610fad5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610d60565b506000805160206130c083398151915290565b905090565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa15801561100d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110319190612f0a565b61104e5760405163015783e960e51b815260040160405180910390fd5b670de0b6b3a76400006110618284612de1565b11156110805760405163acc9c01b60e01b815260040160405180910390fd5b600e91909155600f55565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa1580156110d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f79190612f0a565b6111145760405163015783e960e51b815260040160405180910390fd5b61708081101561113b576040516305cac26160e21b81526170806004820152602401610d60565b600c8190556040518181527fa8bf31f5ff469d988ee50031edcb6b8a44b1cd010a1561d9a7a06d71c2193e6c906020015b60405180910390a150565b600081900361119957604051632f57e75d60e01b815260040160405180910390fd5b6000805b8281101561124d5760008484838181106111b9576111b9612f27565b9050602002013590506007548111156111e557604051633123d42760e11b815260040160405180910390fd5b3360009081526017602052604090206111fe90826121fd565b61121b57604051630c8d9eab60e31b815260040160405180910390fd5b6000818152601660205260409020600101546112379084612de1565b925050808061124590612f3d565b91505061119d565b5080156112bf57604051600090339083908381818185875af1925050503d8060008114611296576040519150601f19603f3d011682016040523d82523d6000602084013e61129b565b606091505b50509050806112bd57604051635cc4532160e01b815260040160405180910390fd5b505b336001600160a01b03167f67e9df8b3c7743c9f1b625ba4f2b4e601206dbd46ed5c33c85a1242e4d23a2d184846040516112fa929190612f56565b60405180910390a2505050565b600054610100900460ff16158080156113275750600054600160ff909116105b806113415750303b158015611341575060005460ff166001145b61135d5760405162461bcd60e51b8152600401610d6090612f6a565b6000805460ff191660011790558015611380576000805461ff0019166101001790555b62015180600c5567016345785d8a0000600d5566b1a2bc2ec50000600e819055600f55600160068190556015805460ff1916821790556000805462010000600160b01b031916620100006001600160a01b038b8116919091029190911790915581546001600160a01b031990811689831617909255600280548316888316179055600380548316878316179055600480548316868316179055600580549092169084161790558015610d0f576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b34600b546114829190612e5f565b600b556040805134815242602082015233917fef51b4c870b8b0100eae2072e91db01222a303072af3728e58c9d4d2da33127f9101610e33565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa158015611504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115289190612f0a565b6115455760405163015783e960e51b815260040160405180910390fd5b60006011546010546115579190612e5f565b6010546011556040519091506000906001600160a01b0384169083908381818185875af1925050503d80600081146115ab576040519150601f19603f3d011682016040523d82523d6000602084013e6115b0565b606091505b50509050806115d257604051635cc4532160e01b815260040160405180910390fd5b505050565b600054600190610100900460ff161580156115f9575060005460ff8083169116105b6116155760405162461bcd60e51b8152600401610d6090612f6a565b6000805461ffff191660ff83169081176101001761ff0019169091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161116c565b6002546001600160a01b0316331461168c5760405163015783e960e51b815260040160405180910390fd5b6000826116998587612de1565b6116a39190612de1565b9050600060028860028111156116bb576116bb612fb8565b036117315750600a805490879055811561172c5760048054604051631df699e760e11b81529182018490526001600160a01b031690633bed33ce90602401600060405180830381600087803b15801561171357600080fd5b505af1158015611727573d6000803e3d6000fd5b505050505b611771565b600188600281111561174557611745612fb8565b0361175857506009805490879055611771565b60405163b9154be560e01b815260040160405180910390fd5b808711611791576040516375d63e5b60e01b815260040160405180910390fd5b60065483106117b357604051637bb1a1ef60e11b815260040160405180910390fd5b478211156117d457604051639882883560e01b815260040160405180910390fd5b6007548311156117e45760078390555b600b54869081111561180957600b546117fd9088612e5f565b6000600b55905061181f565b6000905086600b5461181b9190612e5f565b600b555b801561188f57600160009054906101000a90046001600160a01b03166001600160a01b0316633d0062f8826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561187557600080fd5b505af1158015611889573d6000803e3d6000fd5b50505050505b61189885612209565b7ff10021cf129ec9c5003084ae330dba6d0bd143c47a2677c4d68939a19423206b898989898989876040516118d39796959493929190612fce565b60405180910390a1505050505050505050565b601480546118f390612c4c565b80601f016020809104026020016040519081016040528092919081815260200182805461191f90612c4c565b801561196c5780601f106119415761010080835404028352916020019161196c565b820191906000526020600020905b81548152906001019060200180831161194f57829003601f168201915b505050505081565b6000600c5442610fc09190613010565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa1580156119cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f09190612f0a565b611a0d5760405163015783e960e51b815260040160405180910390fd5b670de0b6b3a7640000811115611a365760405163acc9c01b60e01b815260040160405180910390fd5b600d55565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa158015611a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa79190612f0a565b611ac45760405163015783e960e51b815260040160405180910390fd5b6015805460ff1916911515919091179055565b6001600160a01b038116600090815260176020526040812060609190611afc906122d2565b905060008167ffffffffffffffff811115611b1957611b1961295c565b604051908082528060200260200182016040528015611b42578160200160208202803683370190505b50905060005b82811015611ba1576001600160a01b0385166000908152601760205260409020611b7290826122dc565b828281518110611b8457611b84612f27565b602090810291909101015280611b9981612f3d565b915050611b48565b509392505050565b60155460ff16611bcc57604051631a77d2c360e01b815260040160405180910390fd5b6001600160a01b038616600090815260196020526040812054611bef9087612e5f565b6001600160a01b0388166000908152601a602052604081205491925090611c169087612e5f565b9050611cad85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601354604051909250611c9291508d908d908d908d9060200193845260609290921b6bffffffffffffffffffffffff191660208401526034830152605482015260740190565b604051602081830303815290604052805190602001206122e8565b611cca5760405163582f497d60e11b815260040160405180910390fd5b60006001846003811115611ce057611ce0612fb8565b03611d285782600003611d0657604051631eac4ecb60e11b815260040160405180910390fd5b506001600160a01b038816600090815260196020526040902087905581611e10565b6002846003811115611d3c57611d3c612fb8565b03611d845781600003611d62576040516353ccfa3f60e11b815260040160405180910390fd5b506001600160a01b0388166000908152601a6020526040902086905580611e10565b6003846003811115611d9857611d98612fb8565b03611df757611da78284612de1565b905080600003611dca576040516317b7bd2b60e31b815260040160405180910390fd5b6001600160a01b03891660009081526019602090815260408083208b9055601a9091529020879055611e10565b604051636db370e760e01b815260040160405180910390fd5b6000896001600160a01b03168260405160006040518083038185875af1925050503d8060008114611e5d576040519150601f19603f3d011682016040523d82523d6000602084013e611e62565b606091505b5050905080611e8457604051635cc4532160e01b815260040160405180910390fd5b7f659e842f0209726671f562e8d7ee3a25d2cef92c2b85dcd268af93ef5d13582c8b8b868689604051611ebb959493929190613032565b60405180910390a15050505050505050505050565b600081600003611ef35760405163a6e0892360e01b815260040160405180910390fd5b600354604051638b32fa2360e01b8152600481018490526000916001600160a01b031690638b32fa2390602401602060405180830381865afa158015611f3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f619190612e46565b905080600003611f8457604051633419d2dd60e21b815260040160405180910390fd5b60005460405163079cc67960e41b815233600482015260248101859052620100009091046001600160a01b0316906379cc679090604401600060405180830381600087803b158015611fd557600080fd5b505af1158015611fe9573d6000803e3d6000fd5b509295945050505050565b600061200083836122fe565b90505b92915050565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa158015612051573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120759190612f0a565b610dfd5760405163015783e960e51b815260040160405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156120c5576115d28361234d565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561211f575060408051601f3d908101601f1916820190925261211c91810190612e46565b60015b6121825760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610d60565b6000805160206130c083398151915281146121f15760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610d60565b506115d28383836123e9565b6000612000838361240e565b806000036122145750565b6000670de0b6b3a7640000600d548361222d9190613076565b6122379190613010565b905060006122458284612e5f565b9050806010546122559190612de1565b6010556005546040516000916001600160a01b03169084908381818185875af1925050503d80600081146122a5576040519150601f19603f3d011682016040523d82523d6000602084013e6122aa565b606091505b50509050806122cc57604051635cc4532160e01b815260040160405180910390fd5b50505050565b6000612003825490565b60006120008383612501565b6000826122f5858461252b565b14949350505050565b600081815260018301602052604081205461234557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612003565b506000612003565b6001600160a01b0381163b6123ba5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610d60565b6000805160206130c083398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6123f283612570565b6000825111806123ff5750805b156115d2576122cc83836125b0565b600081815260018301602052604081205480156124f7576000612432600183612e5f565b855490915060009061244690600190612e5f565b90508181146124ab57600086600001828154811061246657612466612f27565b906000526020600020015490508087600001848154811061248957612489612f27565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806124bc576124bc61308d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612003565b6000915050612003565b600082600001828154811061251857612518612f27565b9060005260206000200154905092915050565b600081815b8451811015611ba15761255c8286838151811061254f5761254f612f27565b60200260200101516125d5565b91508061256881612f3d565b915050612530565b6125798161234d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061200083836040518060600160405280602781526020016130e060279139612604565b60008183106125f1576000828152602084905260409020612000565b6000838152602083905260409020612000565b6060600080856001600160a01b03168560405161262191906130a3565b600060405180830381855af49150503d806000811461265c576040519150601f19603f3d011682016040523d82523d6000602084013e612661565b606091505b50915091506126728683838761267c565b9695505050505050565b606083156126eb5782516000036126e4576001600160a01b0385163b6126e45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d60565b50816126f5565b6126f583836126fd565b949350505050565b81511561270d5781518083602001fd5b8060405162461bcd60e51b8152600401610d609190612b5e565b828054828255906000526020600020908101928215612762579160200282015b82811115612762578235825591602001919060010190612747565b5061276e929150612772565b5090565b5b8082111561276e5760008155600101612773565b6000806000806060858703121561279d57600080fd5b8435935060208501359250604085013567ffffffffffffffff808211156127c357600080fd5b818701915087601f8301126127d757600080fd5b8135818111156127e657600080fd5b8860208285010111156127f857600080fd5b95989497505060200194505050565b60008083601f84011261281957600080fd5b50813567ffffffffffffffff81111561283157600080fd5b6020830191508360208260051b850101111561284c57600080fd5b9250929050565b6000806000806060858703121561286957600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561288e57600080fd5b61289a87828801612807565b95989497509550505050565b600080604083850312156128b957600080fd5b50508035926020909101359150565b6000602082840312156128da57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015612919578351835292840192918401916001016128fd565b50909695505050505050565b80356001600160a01b038116811461293c57600080fd5b919050565b60006020828403121561295357600080fd5b61200082612925565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561298557600080fd5b61298e83612925565b9150602083013567ffffffffffffffff808211156129ab57600080fd5b818501915085601f8301126129bf57600080fd5b8135818111156129d1576129d161295c565b604051601f8201601f19908116603f011681019083821181831017156129f9576129f961295c565b81604052828152886020848701011115612a1257600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008060208385031215612a4757600080fd5b823567ffffffffffffffff811115612a5e57600080fd5b612a6a85828601612807565b90969095509350505050565b60008060008060008060c08789031215612a8f57600080fd5b612a9887612925565b9550612aa660208801612925565b9450612ab460408801612925565b9350612ac260608801612925565b9250612ad060808801612925565b9150612ade60a08801612925565b90509295509295509295565b60008060008060008060c08789031215612b0357600080fd5b863560038110612b1257600080fd5b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b60005b83811015612b55578181015183820152602001612b3d565b50506000910152565b6020815260008251806020840152612b7d816040850160208701612b3a565b601f01601f19169190910160400192915050565b8015158114610dfd57600080fd5b600060208284031215612bb157600080fd5b8135612bbc81612b91565b9392505050565b600080600080600080600060c0888a031215612bde57600080fd5b87359650612bee60208901612925565b95506040880135945060608801359350608088013567ffffffffffffffff811115612c1857600080fd5b612c248a828b01612807565b90945092505060a088013560048110612c3c57600080fd5b8091505092959891949750929550565b600181811c90821680612c6057607f821691505b602082108103612c8057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156115d257600081815260208120601f850160051c81016020861015612cad5750805b601f850160051c820191505b81811015612ccc57828155600101612cb9565b505050505050565b67ffffffffffffffff831115612cec57612cec61295c565b612d0083612cfa8354612c4c565b83612c86565b6000601f841160018114612d345760008515612d1c5750838201355b600019600387901b1c1916600186901b178355612d8e565b600083815260209020601f19861690835b82811015612d655786850135825560209485019460019092019101612d45565b5086821015612d825760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561200357612003612dcb565b81835260006001600160fb1b03831115612e0d57600080fd5b8260051b80836020870137939093016020019392505050565b848152836020820152606060408201526000612672606083018486612df4565b600060208284031215612e5857600080fd5b5051919050565b8181038181111561200357612003612dcb565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600060208284031215612f1c57600080fd5b8151612bbc81612b91565b634e487b7160e01b600052603260045260246000fd5b600060018201612f4f57612f4f612dcb565b5060010190565b6020815260006126f5602083018486612df4565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b634e487b7160e01b600052602160045260246000fd5b60e0810160038910612fe257612fe2612fb8565b978152602081019690965260408601949094526060850192909252608084015260a083015260c09091015290565b60008261302d57634e487b7160e01b600052601260045260246000fd5b500490565b8581526001600160a01b0385166020820152604081018490526060810183905260a081016004831061306657613066612fb8565b8260808301529695505050505050565b808202811582820484141761200357612003612dcb565b634e487b7160e01b600052603160045260246000fd5b600082516130b5818460208701612b3a565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207549580d157f75193473f686c87ad2d3d8371e2f34551ea174dc13f51b8b871664736f6c63430008130033
Deployed ByteCode
0x6080604052600436106102975760003560e01c80638a6998281161015a578063bb2d840c116100c1578063db17815b1161007a578063db17815b146107b5578063ea8532fb146107ca578063f1583c08146107ea578063fd6b5a491461080a578063fdf435e91461082a578063fef25c0d1461084a57600080fd5b8063bb2d840c146106f1578063c482ceaf1461071e578063c980ba8914610733578063d3638c7e14610753578063d57dc8241461077d578063d65143041461079f57600080fd5b80639fa1f5ba116101135780639fa1f5ba14610610578063a8e1b8ef14610626578063aaf8277014610685578063b3594059146106a5578063b4701c09146106bb578063b5ca7410146106db57600080fd5b80638a69982814610572578063939d1ee414610588578063966dae0e146105a8578063983d95ce146105c857806399e133f9146105e85780639d2f846e1461060857600080fd5b8063439370b1116101fe57806352d1902d116101b757806352d1902d146104b257806354fd4d50146104c75780636c570dc1146104e95780637a1a934d146105165780637e4dc15c1461053657806387505b9d1461054c57600080fd5b8063439370b1146104355780634636e4e51461043d57806346773830146104535780634a4b061b146104735780634dff8430146104895780634f1ef2861461049f57600080fd5b80632e17de78116102505780632e17de78146103715780632eb4a7ab146103915780633659cfe6146103a757806338fcf092146103c75780633c677dbe146103ff5780634319ebe41461041557600080fd5b80630a64041b146102a357806312b81931146102cc5780631da4dd0d146102ee5780631e0f4aae14610304578063261a792d146103245780632c0f41661461034457600080fd5b3661029e57005b600080fd5b3480156102af57600080fd5b506102b960075481565b6040519081526020015b60405180910390f35b3480156102d857600080fd5b506102ec6102e7366004612787565b610860565b005b3480156102fa57600080fd5b506102b9600e5481565b34801561031057600080fd5b506102ec61031f366004612853565b610907565b34801561033057600080fd5b506102b961033f3660046128a6565b610a22565b34801561035057600080fd5b5061036461035f3660046128c8565b610a53565b6040516102c391906128e1565b34801561037d57600080fd5b506102ec61038c3660046128c8565b610ab5565b34801561039d57600080fd5b506102b960135481565b3480156103b357600080fd5b506102ec6103c2366004612941565b610d18565b3480156103d357600080fd5b506003546103e7906001600160a01b031681565b6040516001600160a01b0390911681526020016102c3565b34801561040b57600080fd5b506102b9600b5481565b34801561042157600080fd5b506004546103e7906001600160a01b031681565b6102ec610e00565b34801561044957600080fd5b506102b9600f5481565b34801561045f57600080fd5b506001546103e7906001600160a01b031681565b34801561047f57600080fd5b506102b9600c5481565b34801561049557600080fd5b506102b9600a5481565b6102ec6104ad366004612972565b610e3d565b3480156104be57600080fd5b506102b9610f0d565b3480156104d357600080fd5b5060005460405160ff90911681526020016102c3565b3480156104f557600080fd5b506102b9610504366004612941565b601a6020526000908152604090205481565b34801561052257600080fd5b506102ec6105313660046128a6565b610fc5565b34801561054257600080fd5b506102b960065481565b34801561055857600080fd5b506000546103e7906201000090046001600160a01b031681565b34801561057e57600080fd5b506102b960085481565b34801561059457600080fd5b506102ec6105a33660046128c8565b61108b565b3480156105b457600080fd5b506005546103e7906001600160a01b031681565b3480156105d457600080fd5b506102ec6105e3366004612a34565b611177565b3480156105f457600080fd5b506102ec610603366004612a76565b611307565b6102ec611474565b34801561061c57600080fd5b506102b960095481565b34801561063257600080fd5b506106666106413660046128c8565b601660205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b0390931683526020830191909152016102c3565b34801561069157600080fd5b506102ec6106a0366004612941565b6114bc565b3480156106b157600080fd5b506102b960115481565b3480156106c757600080fd5b506002546103e7906001600160a01b031681565b3480156106e757600080fd5b506102b960125481565b3480156106fd57600080fd5b506102b961070c366004612941565b60196020526000908152604090205481565b34801561072a57600080fd5b506102ec6115d7565b34801561073f57600080fd5b506102ec61074e366004612aea565b611661565b34801561075f57600080fd5b5060155461076d9060ff1681565b60405190151581526020016102c3565b34801561078957600080fd5b506107926118e6565b6040516102c39190612b5e565b3480156107ab57600080fd5b506102b9600d5481565b3480156107c157600080fd5b506102b9611974565b3480156107d657600080fd5b506102ec6107e53660046128c8565b611984565b3480156107f657600080fd5b506102ec610805366004612b9f565b611a3b565b34801561081657600080fd5b50610364610825366004612941565b611ad7565b34801561083657600080fd5b506102ec610845366004612bc3565b611ba9565b34801561085657600080fd5b506102b960105481565b6002546001600160a01b0316331461088b5760405163015783e960e51b815260040160405180910390fd5b60125484116108ad5760405163e602012760e01b815260040160405180910390fd5b6013839055601284905560146108c4828483612cd4565b50837fec43b2424d0504da473794ad49016df3e06fb0d772bb403d724c9e5d53d8afb88484846040516108f993929190612d95565b60405180910390a250505050565b6002546001600160a01b031633146109325760405163015783e960e51b815260040160405180910390fd5b600081900361095457604051631985132360e31b815260040160405180910390fd5b83831015806109745750610966611974565b610971856001612de1565b14155b1561099257604051632d072a4760e21b815260040160405180910390fd5b600084815260186020526040902054156109bf5760405163fc0aca3960e01b815260040160405180910390fd5b60008481526018602052604090206109d8908383612727565b5060088390556040517fb83477449e27b4bab4f28c938d033b953557d6a1b9b4469a43d229f78ed6e55c90610a14908690869086908690612e26565b60405180910390a150505050565b60186020528160005260406000208181548110610a3e57600080fd5b90600052602060002001600091509150505481565b600081815260186020908152604091829020805483518184028101840190945280845260609392830182828015610aa957602002820191906000526020600020905b815481526020019060010190808311610a95575b50505050509050919050565b6000610ac082611ed0565b90506000600160009054906101000a90046001600160a01b031690506000816001600160a01b03166312065fe06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b409190612e46565b9050600083600b54610b529190612de1565b90508115610bd0578080831015610b665750815b6040516331d2edcf60e11b8152600481018290526001600160a01b038516906363a5db9e90602401600060405180830381600087803b158015610ba857600080fd5b505af1158015610bbc573d6000803e3d6000fd5b505050508082610bcc9190612e5f565b9150505b600b819055600654604080518082018252338152602080820188815260008581526016909252929020905181546001600160a01b0319166001600160a01b03909116178155905160019182015582159190610c2c908290612de1565b6006556040805188815260208101889052908101829052821515606082015233907fc7ccdcb2d25f572c6814e377dbb34ea4318a4b7d3cd890f5cfad699d75327c7c9060800160405180910390a28115610cf4576007819055604051600090339088908381818185875af1925050503d8060008114610cc7576040519150601f19603f3d011682016040523d82523d6000602084013e610ccc565b606091505b5050905080610cee57604051635cc4532160e01b815260040160405180910390fd5b50610d0f565b336000908152601760205260409020610d0d9082611ff4565b505b50505050505050565b6001600160a01b037f000000000000000000000000d495dba37abdb338343cc9ec4b21ab91024f4206163003610d695760405162461bcd60e51b8152600401610d6090612e72565b60405180910390fd5b7f000000000000000000000000d495dba37abdb338343cc9ec4b21ab91024f42066001600160a01b0316610db26000805160206130c0833981519152546001600160a01b031690565b6001600160a01b031614610dd85760405162461bcd60e51b8152600401610d6090612ebe565b610de181612009565b60408051600080825260208201909252610dfd91839190612092565b50565b6040805134815242602082015233917fef51b4c870b8b0100eae2072e91db01222a303072af3728e58c9d4d2da33127f91015b60405180910390a2565b6001600160a01b037f000000000000000000000000d495dba37abdb338343cc9ec4b21ab91024f4206163003610e855760405162461bcd60e51b8152600401610d6090612e72565b7f000000000000000000000000d495dba37abdb338343cc9ec4b21ab91024f42066001600160a01b0316610ece6000805160206130c0833981519152546001600160a01b031690565b6001600160a01b031614610ef45760405162461bcd60e51b8152600401610d6090612ebe565b610efd82612009565b610f0982826001612092565b5050565b6000306001600160a01b037f000000000000000000000000d495dba37abdb338343cc9ec4b21ab91024f42061614610fad5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610d60565b506000805160206130c083398151915290565b905090565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa15801561100d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110319190612f0a565b61104e5760405163015783e960e51b815260040160405180910390fd5b670de0b6b3a76400006110618284612de1565b11156110805760405163acc9c01b60e01b815260040160405180910390fd5b600e91909155600f55565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa1580156110d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f79190612f0a565b6111145760405163015783e960e51b815260040160405180910390fd5b61708081101561113b576040516305cac26160e21b81526170806004820152602401610d60565b600c8190556040518181527fa8bf31f5ff469d988ee50031edcb6b8a44b1cd010a1561d9a7a06d71c2193e6c906020015b60405180910390a150565b600081900361119957604051632f57e75d60e01b815260040160405180910390fd5b6000805b8281101561124d5760008484838181106111b9576111b9612f27565b9050602002013590506007548111156111e557604051633123d42760e11b815260040160405180910390fd5b3360009081526017602052604090206111fe90826121fd565b61121b57604051630c8d9eab60e31b815260040160405180910390fd5b6000818152601660205260409020600101546112379084612de1565b925050808061124590612f3d565b91505061119d565b5080156112bf57604051600090339083908381818185875af1925050503d8060008114611296576040519150601f19603f3d011682016040523d82523d6000602084013e61129b565b606091505b50509050806112bd57604051635cc4532160e01b815260040160405180910390fd5b505b336001600160a01b03167f67e9df8b3c7743c9f1b625ba4f2b4e601206dbd46ed5c33c85a1242e4d23a2d184846040516112fa929190612f56565b60405180910390a2505050565b600054610100900460ff16158080156113275750600054600160ff909116105b806113415750303b158015611341575060005460ff166001145b61135d5760405162461bcd60e51b8152600401610d6090612f6a565b6000805460ff191660011790558015611380576000805461ff0019166101001790555b62015180600c5567016345785d8a0000600d5566b1a2bc2ec50000600e819055600f55600160068190556015805460ff1916821790556000805462010000600160b01b031916620100006001600160a01b038b8116919091029190911790915581546001600160a01b031990811689831617909255600280548316888316179055600380548316878316179055600480548316868316179055600580549092169084161790558015610d0f576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b34600b546114829190612e5f565b600b556040805134815242602082015233917fef51b4c870b8b0100eae2072e91db01222a303072af3728e58c9d4d2da33127f9101610e33565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa158015611504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115289190612f0a565b6115455760405163015783e960e51b815260040160405180910390fd5b60006011546010546115579190612e5f565b6010546011556040519091506000906001600160a01b0384169083908381818185875af1925050503d80600081146115ab576040519150601f19603f3d011682016040523d82523d6000602084013e6115b0565b606091505b50509050806115d257604051635cc4532160e01b815260040160405180910390fd5b505050565b600054600190610100900460ff161580156115f9575060005460ff8083169116105b6116155760405162461bcd60e51b8152600401610d6090612f6a565b6000805461ffff191660ff83169081176101001761ff0019169091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200161116c565b6002546001600160a01b0316331461168c5760405163015783e960e51b815260040160405180910390fd5b6000826116998587612de1565b6116a39190612de1565b9050600060028860028111156116bb576116bb612fb8565b036117315750600a805490879055811561172c5760048054604051631df699e760e11b81529182018490526001600160a01b031690633bed33ce90602401600060405180830381600087803b15801561171357600080fd5b505af1158015611727573d6000803e3d6000fd5b505050505b611771565b600188600281111561174557611745612fb8565b0361175857506009805490879055611771565b60405163b9154be560e01b815260040160405180910390fd5b808711611791576040516375d63e5b60e01b815260040160405180910390fd5b60065483106117b357604051637bb1a1ef60e11b815260040160405180910390fd5b478211156117d457604051639882883560e01b815260040160405180910390fd5b6007548311156117e45760078390555b600b54869081111561180957600b546117fd9088612e5f565b6000600b55905061181f565b6000905086600b5461181b9190612e5f565b600b555b801561188f57600160009054906101000a90046001600160a01b03166001600160a01b0316633d0062f8826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561187557600080fd5b505af1158015611889573d6000803e3d6000fd5b50505050505b61189885612209565b7ff10021cf129ec9c5003084ae330dba6d0bd143c47a2677c4d68939a19423206b898989898989876040516118d39796959493929190612fce565b60405180910390a1505050505050505050565b601480546118f390612c4c565b80601f016020809104026020016040519081016040528092919081815260200182805461191f90612c4c565b801561196c5780601f106119415761010080835404028352916020019161196c565b820191906000526020600020905b81548152906001019060200180831161194f57829003601f168201915b505050505081565b6000600c5442610fc09190613010565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa1580156119cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f09190612f0a565b611a0d5760405163015783e960e51b815260040160405180910390fd5b670de0b6b3a7640000811115611a365760405163acc9c01b60e01b815260040160405180910390fd5b600d55565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa158015611a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa79190612f0a565b611ac45760405163015783e960e51b815260040160405180910390fd5b6015805460ff1916911515919091179055565b6001600160a01b038116600090815260176020526040812060609190611afc906122d2565b905060008167ffffffffffffffff811115611b1957611b1961295c565b604051908082528060200260200182016040528015611b42578160200160208202803683370190505b50905060005b82811015611ba1576001600160a01b0385166000908152601760205260409020611b7290826122dc565b828281518110611b8457611b84612f27565b602090810291909101015280611b9981612f3d565b915050611b48565b509392505050565b60155460ff16611bcc57604051631a77d2c360e01b815260040160405180910390fd5b6001600160a01b038616600090815260196020526040812054611bef9087612e5f565b6001600160a01b0388166000908152601a602052604081205491925090611c169087612e5f565b9050611cad85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050601354604051909250611c9291508d908d908d908d9060200193845260609290921b6bffffffffffffffffffffffff191660208401526034830152605482015260740190565b604051602081830303815290604052805190602001206122e8565b611cca5760405163582f497d60e11b815260040160405180910390fd5b60006001846003811115611ce057611ce0612fb8565b03611d285782600003611d0657604051631eac4ecb60e11b815260040160405180910390fd5b506001600160a01b038816600090815260196020526040902087905581611e10565b6002846003811115611d3c57611d3c612fb8565b03611d845781600003611d62576040516353ccfa3f60e11b815260040160405180910390fd5b506001600160a01b0388166000908152601a6020526040902086905580611e10565b6003846003811115611d9857611d98612fb8565b03611df757611da78284612de1565b905080600003611dca576040516317b7bd2b60e31b815260040160405180910390fd5b6001600160a01b03891660009081526019602090815260408083208b9055601a9091529020879055611e10565b604051636db370e760e01b815260040160405180910390fd5b6000896001600160a01b03168260405160006040518083038185875af1925050503d8060008114611e5d576040519150601f19603f3d011682016040523d82523d6000602084013e611e62565b606091505b5050905080611e8457604051635cc4532160e01b815260040160405180910390fd5b7f659e842f0209726671f562e8d7ee3a25d2cef92c2b85dcd268af93ef5d13582c8b8b868689604051611ebb959493929190613032565b60405180910390a15050505050505050505050565b600081600003611ef35760405163a6e0892360e01b815260040160405180910390fd5b600354604051638b32fa2360e01b8152600481018490526000916001600160a01b031690638b32fa2390602401602060405180830381865afa158015611f3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f619190612e46565b905080600003611f8457604051633419d2dd60e21b815260040160405180910390fd5b60005460405163079cc67960e41b815233600482015260248101859052620100009091046001600160a01b0316906379cc679090604401600060405180830381600087803b158015611fd557600080fd5b505af1158015611fe9573d6000803e3d6000fd5b509295945050505050565b600061200083836122fe565b90505b92915050565b600254604051630935e01b60e21b81523360048201526001600160a01b03909116906324d7806c90602401602060405180830381865afa158015612051573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120759190612f0a565b610dfd5760405163015783e960e51b815260040160405180910390fd5b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156120c5576115d28361234d565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561211f575060408051601f3d908101601f1916820190925261211c91810190612e46565b60015b6121825760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610d60565b6000805160206130c083398151915281146121f15760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610d60565b506115d28383836123e9565b6000612000838361240e565b806000036122145750565b6000670de0b6b3a7640000600d548361222d9190613076565b6122379190613010565b905060006122458284612e5f565b9050806010546122559190612de1565b6010556005546040516000916001600160a01b03169084908381818185875af1925050503d80600081146122a5576040519150601f19603f3d011682016040523d82523d6000602084013e6122aa565b606091505b50509050806122cc57604051635cc4532160e01b815260040160405180910390fd5b50505050565b6000612003825490565b60006120008383612501565b6000826122f5858461252b565b14949350505050565b600081815260018301602052604081205461234557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612003565b506000612003565b6001600160a01b0381163b6123ba5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610d60565b6000805160206130c083398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6123f283612570565b6000825111806123ff5750805b156115d2576122cc83836125b0565b600081815260018301602052604081205480156124f7576000612432600183612e5f565b855490915060009061244690600190612e5f565b90508181146124ab57600086600001828154811061246657612466612f27565b906000526020600020015490508087600001848154811061248957612489612f27565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806124bc576124bc61308d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612003565b6000915050612003565b600082600001828154811061251857612518612f27565b9060005260206000200154905092915050565b600081815b8451811015611ba15761255c8286838151811061254f5761254f612f27565b60200260200101516125d5565b91508061256881612f3d565b915050612530565b6125798161234d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061200083836040518060600160405280602781526020016130e060279139612604565b60008183106125f1576000828152602084905260409020612000565b6000838152602083905260409020612000565b6060600080856001600160a01b03168560405161262191906130a3565b600060405180830381855af49150503d806000811461265c576040519150601f19603f3d011682016040523d82523d6000602084013e612661565b606091505b50915091506126728683838761267c565b9695505050505050565b606083156126eb5782516000036126e4576001600160a01b0385163b6126e45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d60565b50816126f5565b6126f583836126fd565b949350505050565b81511561270d5781518083602001fd5b8060405162461bcd60e51b8152600401610d609190612b5e565b828054828255906000526020600020908101928215612762579160200282015b82811115612762578235825591602001919060010190612747565b5061276e929150612772565b5090565b5b8082111561276e5760008155600101612773565b6000806000806060858703121561279d57600080fd5b8435935060208501359250604085013567ffffffffffffffff808211156127c357600080fd5b818701915087601f8301126127d757600080fd5b8135818111156127e657600080fd5b8860208285010111156127f857600080fd5b95989497505060200194505050565b60008083601f84011261281957600080fd5b50813567ffffffffffffffff81111561283157600080fd5b6020830191508360208260051b850101111561284c57600080fd5b9250929050565b6000806000806060858703121561286957600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561288e57600080fd5b61289a87828801612807565b95989497509550505050565b600080604083850312156128b957600080fd5b50508035926020909101359150565b6000602082840312156128da57600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015612919578351835292840192918401916001016128fd565b50909695505050505050565b80356001600160a01b038116811461293c57600080fd5b919050565b60006020828403121561295357600080fd5b61200082612925565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561298557600080fd5b61298e83612925565b9150602083013567ffffffffffffffff808211156129ab57600080fd5b818501915085601f8301126129bf57600080fd5b8135818111156129d1576129d161295c565b604051601f8201601f19908116603f011681019083821181831017156129f9576129f961295c565b81604052828152886020848701011115612a1257600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008060208385031215612a4757600080fd5b823567ffffffffffffffff811115612a5e57600080fd5b612a6a85828601612807565b90969095509350505050565b60008060008060008060c08789031215612a8f57600080fd5b612a9887612925565b9550612aa660208801612925565b9450612ab460408801612925565b9350612ac260608801612925565b9250612ad060808801612925565b9150612ade60a08801612925565b90509295509295509295565b60008060008060008060c08789031215612b0357600080fd5b863560038110612b1257600080fd5b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b60005b83811015612b55578181015183820152602001612b3d565b50506000910152565b6020815260008251806020840152612b7d816040850160208701612b3a565b601f01601f19169190910160400192915050565b8015158114610dfd57600080fd5b600060208284031215612bb157600080fd5b8135612bbc81612b91565b9392505050565b600080600080600080600060c0888a031215612bde57600080fd5b87359650612bee60208901612925565b95506040880135945060608801359350608088013567ffffffffffffffff811115612c1857600080fd5b612c248a828b01612807565b90945092505060a088013560048110612c3c57600080fd5b8091505092959891949750929550565b600181811c90821680612c6057607f821691505b602082108103612c8057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156115d257600081815260208120601f850160051c81016020861015612cad5750805b601f850160051c820191505b81811015612ccc57828155600101612cb9565b505050505050565b67ffffffffffffffff831115612cec57612cec61295c565b612d0083612cfa8354612c4c565b83612c86565b6000601f841160018114612d345760008515612d1c5750838201355b600019600387901b1c1916600186901b178355612d8e565b600083815260209020601f19861690835b82811015612d655786850135825560209485019460019092019101612d45565b5086821015612d825760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561200357612003612dcb565b81835260006001600160fb1b03831115612e0d57600080fd5b8260051b80836020870137939093016020019392505050565b848152836020820152606060408201526000612672606083018486612df4565b600060208284031215612e5857600080fd5b5051919050565b8181038181111561200357612003612dcb565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600060208284031215612f1c57600080fd5b8151612bbc81612b91565b634e487b7160e01b600052603260045260246000fd5b600060018201612f4f57612f4f612dcb565b5060010190565b6020815260006126f5602083018486612df4565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b634e487b7160e01b600052602160045260246000fd5b60e0810160038910612fe257612fe2612fb8565b978152602081019690965260408601949094526060850192909252608084015260a083015260c09091015290565b60008261302d57634e487b7160e01b600052601260045260246000fd5b500490565b8581526001600160a01b0385166020820152604081018490526060810183905260a081016004831061306657613066612fb8565b8260808301529695505050505050565b808202811582820484141761200357612003612dcb565b634e487b7160e01b600052603160045260246000fd5b600082516130b5818460208701612b3a565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207549580d157f75193473f686c87ad2d3d8371e2f34551ea174dc13f51b8b871664736f6c63430008130033