Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
StakefishTransactionFeePoolV3
Compiler Version
v0.8.7+commit.e28d00a7
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "Address.sol";
import "ReentrancyGuard.sol";
import "Initializable.sol";
import "UUPSUpgradeable.sol";
import "IStakefishTransactionFeePoolV3.sol";
import "IStakefishNFTManager.sol";
import "StakefishTransactionStorageV3.sol";
import "StakefishTransactionStorageV3Additional.sol";
contract StakefishTransactionFeePoolV3 is
IStakefishTransactionFeePoolV3,
StakefishTransactionStorageV3,
Initializable,
UUPSUpgradeable,
ReentrancyGuard,
StakefishTransactionStorageV3Additional
{
using Address for address payable;
// Upgradable contract.
constructor() initializer {
}
function initialize(address operatorAddress_, address adminAddress_) initializer external {
require(operatorAddress_ != address(0));
require(adminAddress_ != address(0));
adminAddress = adminAddress_;
operatorAddress = operatorAddress_;
validatorCount = 0;
stakefishCommissionRateBasisPoints = 2000;
isOpenForWithdrawal = true;
// V3 storage variables
accRewardPerValidator = 0;
accLifetimeStakefishCommission = 0;
amountTransferredToColdWallet = 0;
nftManagerAddress = address(0x0);
lastRewardUpdateBlock = block.number;
lastLifetimeReward = getLifetimeReward();
}
function initialize_version3() initializer external {
amountTransferredToColdWallet = 0;
}
// If the pool starts from scratch, accLifetimeStakefishCommission correctly starts from 0.
// However, the fee pool is upgraded from a simpler commission accounting logic, and we need
// to initialize accLifetimeStakefishCommission to the correct value.
// This function is idempotent and can be call many times without issues.
// TODO(yz): clean up this code after use.
function initializeAccLifetimeStakefishComission() external adminOnly {
// We updated commission from 20% to 25% in this transaction:j
// https://etherscan.io/tx/0x879c4eb3975d58e258626df9a50eaf51d92fb60feb6e82643a263dc1f5348001
// This is the getLifetimeReward as of block 17020824
uint256 preChangeLifetimeReward = 2960947228478966516822;
updatePool();
uint256 curLifetimeReward = getLifetimeReward();
accLifetimeStakefishCommission =
1e6 * // scale up by 1e6 to avoid precision loss due to divisions.
(
preChangeLifetimeReward * 2000 / 10000 +
(curLifetimeReward - preChangeLifetimeReward) * stakefishCommissionRateBasisPoints / 10000
);
}
// IMPORTANT CODE! ONLY DEV ACCOUNT CAN UPGRADE CONTRACT
function _authorizeUpgrade(address) internal override adminOnly {}
// Used to upgrade in place from V2 to V3.
function migrateFromV2(address[] calldata userlist) external nonReentrant operatorOnly {
// This check serves two purposes:
// 1. It ensures that contract state does not change during migration.
// 2. It requires the admin to close pool before this can be called, even though this function is operatorOnly.
require(isOpenForWithdrawal == false, "Pool must be closed for withdrawal");
// Note that UserSummary is repurposed from V2 and the fields:
// - validatorCount and collectedReward contain values we want to keep from V2.
// - lifetimeCredit and debit have junk values after upgrade.
// We must re-write the lifetimeCredit and debit fields for every users during the v2->v3 upgrade.
// To simplify calculations, we assume that all validators joined at the same time upon Ethereum merge.
for (uint256 i = 0; i < userlist.length; i++) {
// user.lifetimeCredit contains user.totalStartTimestamps from V2. Need to erase it.
// user.debit contains user.partedUptime from V2. Need to erase it.
users[userlist[i]].lifetimeCredit = 0;
users[userlist[i]].debit = 0;
// If we call accruePayout, it would eagerly update the user's lifetimeCredit and debit fields.
// However, this is unnecessary because validator count did not change for any user.
// accruePayout(userlist[i]);
}
updatePool();
}
function decodeValidatorInfo(uint256 data) public pure returns (address, uint256) {
address ownerAddress = address(uint160(data));
uint256 joinPoolTimestamp = data >> 224;
return (ownerAddress, joinPoolTimestamp);
}
function encodeValidatorInfo(address ownerAddress, uint256 joinPoolTimestamp) public pure returns (uint256) {
return uint256(uint160(ownerAddress)) | (joinPoolTimestamp << 224);
}
// Total rewards that have been sent into this contract since contract creation.
function getLifetimeReward() public view returns (uint256) {
return address(this).balance
+ amountTransferredToColdWallet // this amount is saved to cold wallet
+ lifetimePaidUserRewards // this amount is paid to users
+ lifetimeCollectedCommission; // this amount is paid to stakefish
}
// Reference: pancake swap updatePool function
// https://github.com/pancakeswap/pancake-smart-contracts/blob/master/projects/farms-pools/contracts/MasterChef.sol#L209
// This concludes a time period and updates accRewardPerValidator.
function updatePool() internal {
if (block.number <= lastRewardUpdateBlock || validatorCount == 0) {
return;
}
uint256 curLifetimeReward = getLifetimeReward();
accRewardPerValidator +=
1e6 * // scale up by 1e6 to avoid precision loss due to divisions.
(curLifetimeReward - lastLifetimeReward) / validatorCount // add in the new reward from last period
* (10000 - stakefishCommissionRateBasisPoints) / 10000; // adjust for stakefish commission
accLifetimeStakefishCommission +=
1e6 * // scale up by 1e6 to avoid precision loss due to divisions.
(curLifetimeReward - lastLifetimeReward) // add in the new reward from last period
* stakefishCommissionRateBasisPoints / 10000; // multiply by stakefish commission rate
lastRewardUpdateBlock = block.number;
lastLifetimeReward = curLifetimeReward;
}
function getAccRewardPerValidator() public view returns (uint256) {
return accRewardPerValidator / 1e6; // scale down by 1e6, which was multiplied to avoid precision loss.
}
// Used by stakefish to check how much commission they have earned.
// Read-only function without having to call updatePool().
function getAccLifetimeStakefishCommission() public view returns (uint256) {
uint256 curLifetimeReward = getLifetimeReward();
// we cannot call update pool in a view function, so we add in new commission from the last period manually.
return (
accLifetimeStakefishCommission
+ 1e6 * (curLifetimeReward - lastLifetimeReward) * stakefishCommissionRateBasisPoints / 10000
) / 1e6;
}
// Simulate a payout by adding pending payout to user lifetimeCredits
function accruePayout(address depositor) internal {
uint256 userValidatorCount = users[depositor].validatorCount;
if (userValidatorCount > 0) {
uint256 pending = userValidatorCount * getAccRewardPerValidator() - users[depositor].debit;
users[depositor].lifetimeCredit += uint128(pending); // simulate a payout
}
}
// Reference: pancake swap deposit function
// https://github.com/pancakeswap/pancake-smart-contracts/blob/master/projects/farms-pools/contracts/MasterChef.sol#L228
/**
* Operator Functions
*/
function joinPool(
bytes calldata validatorPubKey,
address depositor
) external nonReentrant operatorOnly {
// One validator joined, the previous time period ends.
updatePool();
_joinPool(validatorPubKey, depositor);
emit ValidatorJoined(validatorPubKey, depositor, block.timestamp);
}
// This function implementation references:
// https://github.com/pancakeswap/pancake-smart-contracts/blob/master/projects/farms-pools/contracts/MasterChef.sol#L228
function _joinPool(
bytes calldata validatorPubKey,
address depositor
) internal {
require(
validatorOwnerAndJoinTime[validatorPubKey] == 0,
"Validator already in pool"
);
require(
depositor != address(0),
"depositorAddress must be set"
);
// If the user already has some validators in the pool, we simulate a payout for existing validators.
accruePayout(depositor);
// Add the given validator to the UserSummary.
users[depositor].validatorCount += 1;
validatorCount += 1;
validatorOwnerAndJoinTime[validatorPubKey] = encodeValidatorInfo(depositor, block.timestamp);
users[depositor].debit = uint128(users[depositor].validatorCount * getAccRewardPerValidator());
}
function partPool(
bytes calldata validatorPubKey
) external nonReentrant operatorOnly {
// One validator left, the previous time period ends.
updatePool();
address depositor = _partPool(validatorPubKey);
emit ValidatorParted(validatorPubKey, depositor, block.timestamp);
}
function _partPool(
bytes calldata validatorPubKey
) internal returns (address depositorAddress) {
(address depositor, ) = decodeValidatorInfo(validatorOwnerAndJoinTime[validatorPubKey]);
require(
depositor != address(0),
"Validator not in pool"
);
// Simulate a payout for the existing validators.
accruePayout(depositor);
validatorCount -= 1;
users[depositor].validatorCount -= 1;
delete validatorOwnerAndJoinTime[validatorPubKey];
users[depositor].debit = uint128(users[depositor].validatorCount * getAccRewardPerValidator());
return depositor;
}
// These two functions are added for V2 compatibility--they allow the oracle to call joinPool and partPool with the V2 abi.
// These two functions are not in the interface and are only used by the oracle for backward compatibility purposes.
function joinPool(bytes calldata validatorPubKey, address depositor, uint256)
external override nonReentrant operatorOnly
{
updatePool();
_joinPool(validatorPubKey, depositor);
emit ValidatorJoined(validatorPubKey, depositor, block.timestamp);
}
function partPool(bytes calldata validatorPubKey, uint256) external override nonReentrant operatorOnly {
updatePool();
address depositor = _partPool(validatorPubKey);
emit ValidatorParted(validatorPubKey, depositor, block.timestamp);
}
function bulkJoinPool(
bytes calldata validatorPubkeyArray,
address[] calldata depositorAddresses,
uint256
) external override nonReentrant operatorOnly {
require(depositorAddresses.length == 1 || depositorAddresses.length * 48 == validatorPubkeyArray.length, "Invalid depositorAddresses length");
updatePool();
uint256 validatorCount = validatorPubkeyArray.length / 48;
if (depositorAddresses.length == 1) {
for(uint256 i = 0; i < validatorCount; i++) {
_joinPool(validatorPubkeyArray[i*48:(i+1)*48], depositorAddresses[0]);
emit ValidatorJoined(validatorPubkeyArray[i*48:(i+1)*48], depositorAddresses[0], block.timestamp);
}
} else {
for(uint256 i = 0; i < validatorCount; i++) {
_joinPool(validatorPubkeyArray[i*48:(i+1)*48], depositorAddresses[i]);
emit ValidatorJoined(validatorPubkeyArray[i*48:(i+1)*48], depositorAddresses[i], block.timestamp);
}
}
}
function bulkPartPool(
bytes calldata validatorPubkeyArray,
uint256
) external override nonReentrant operatorOnly {
require(validatorPubkeyArray.length % 48 == 0, "pubKeyArray length not multiple of 48");
updatePool();
uint256 validatorCount = validatorPubkeyArray.length / 48;
for(uint256 i = 0; i < validatorCount; i++) {
address depositor = _partPool(validatorPubkeyArray[i*48:(i+1)*48]);
emit ValidatorParted(validatorPubkeyArray[i*48:(i+1)*48], depositor, block.timestamp);
}
}
// @return (pendingRewards, collectedRewards)
function computePayout(address depositor) internal view returns (uint256, uint256) {
// this is a view function so we cannot call updatePool() or accruePayout().
uint256 accRewardPerValidatorWithCurPeriod = getAccRewardPerValidator();
if (block.number > lastRewardUpdateBlock && validatorCount > 0) {
// If the accRewardPerValidator is not up-to-date, we need to include rewards from the current time period.
uint256 curLifetimeReward = getLifetimeReward();
accRewardPerValidatorWithCurPeriod +=
(curLifetimeReward - lastLifetimeReward) / validatorCount * (10000 - stakefishCommissionRateBasisPoints) / 10000;
}
uint256 totalPayout = users[depositor].validatorCount * accRewardPerValidatorWithCurPeriod
+ users[depositor].lifetimeCredit - users[depositor].debit;
if (totalPayout > users[depositor].collectedReward) {
return (totalPayout - users[depositor].collectedReward, users[depositor].collectedReward);
} else {
return (0, users[depositor].collectedReward);
}
}
// This function estimates user pending reward based on the latest block timestamp.
// In order to keep this function to be a view function, it does not update the computation cache.
function pendingReward(address depositorAddress) external override view returns (uint256, uint256) {
require(depositorAddress != address(0), "depositorAddress must be set");
return computePayout(depositorAddress);
}
// Reference: Pancake swap withdraw function
// https://github.com/pancakeswap/pancake-smart-contracts/blob/master/projects/farms-pools/contracts/MasterChef.sol#L249
function _collectReward(
address depositorAddress,
address payable beneficiary,
uint256 amountRequested
) internal {
if (beneficiary == address(0)) {
beneficiary = payable(depositorAddress);
}
accruePayout(depositorAddress);
users[depositorAddress].debit = uint128(users[depositorAddress].validatorCount * getAccRewardPerValidator());
uint256 pending = users[depositorAddress].lifetimeCredit - users[depositorAddress].collectedReward;
if (amountRequested == 0) {
users[depositorAddress].collectedReward += uint128(pending);
lifetimePaidUserRewards += pending;
emit ValidatorRewardCollected(depositorAddress, beneficiary, pending, msg.sender);
require(pending <= address(this).balance, "Contact [email protected] to top up the contract");
beneficiary.sendValue(pending);
} else {
require(amountRequested <= pending, "Not enough pending rewards");
users[depositorAddress].collectedReward += uint128(amountRequested);
lifetimePaidUserRewards += amountRequested;
emit ValidatorRewardCollected(depositorAddress, beneficiary, amountRequested, msg.sender);
require(amountRequested <= address(this).balance, "Contact [email protected] to top up the contract");
beneficiary.sendValue(amountRequested);
}
}
// collect rewards from the tip pool, up to amountRequested.
// If amountRequested is unspecified, collect all rewards.
function collectReward(address payable beneficiary, uint256 amountRequested) external override nonReentrant {
require(isOpenForWithdrawal, "Pool is not open for withdrawal right now");
updatePool();
_collectReward(msg.sender, beneficiary, amountRequested);
}
function collectRewardForNFT(
address payable beneficiary,
address nftWallet,
uint256 amountRequested)
external override nonReentrant {
IStakefishNFTManager nftManager = IStakefishNFTManager(nftManagerAddress);
require(msg.sender == nftManager.validatorOwner(nftWallet), "Only validator NFT owner can collect reward");
if (beneficiary == address(0)) {
beneficiary = payable(msg.sender);
}
updatePool();
_collectReward(nftWallet, beneficiary, amountRequested);
}
function batchCollectReward(
address payable beneficiary,
address[] calldata wallet,
uint256[] calldata amountRequested)
external override nonReentrant {
require(wallet.length == amountRequested.length, "wallet and amountRequested must have the same length");
if (beneficiary == address(0)) {
beneficiary = payable(msg.sender);
}
IStakefishNFTManager nftManager = IStakefishNFTManager(nftManagerAddress);
updatePool();
for (uint256 i = 0; i < wallet.length; i++) {
if(msg.sender == wallet[i] || msg.sender == nftManager.validatorOwner(wallet[i])) {
_collectReward(wallet[i], beneficiary, amountRequested[i]);
} else {
revert("Only validator or NFT owner can collect reward");
}
}
}
function _transferValidator(bytes calldata validatorPubKey, address to) internal {
(address validatorOwner, ) = decodeValidatorInfo(validatorOwnerAndJoinTime[validatorPubKey]);
require(validatorOwner != address(0), "Validator not in pool");
require(to != address(0), "to address must be set to nonzero");
require(to != validatorOwner, "cannot transfer validator owner to oneself");
_partPool(validatorPubKey);
_joinPool(validatorPubKey, to);
emit ValidatorTransferred(validatorPubKey, validatorOwner, to, block.timestamp);
}
/*
// This function is not enabled for now to keep the current product simple.
function transferValidatorByOwner(bytes calldata validatorPubKey, address to) external override nonReentrant {
(address validatorOwner, ) = decodeValidatorInfo(validatorOwnerAndJoinTime[validatorPubKey]);
require(validatorOwner == msg.sender, "Only the validator owner can transfer the validator");
_transferValidator(validatorPubKey, to, block.timestamp);
}
*/
/**
* Admin Functions
*/
function setCommissionRate(uint256 commissionRate) external override nonReentrant adminOnly {
updatePool();
stakefishCommissionRateBasisPoints = commissionRate;
emit CommissionRateChanged(stakefishCommissionRateBasisPoints);
}
// Collect accumulated commission fees, up to amountRequested.
// If amountRequested is unspecified, collect all fees.
function collectPoolCommission(address payable beneficiary, uint256 amountRequested)
external
override
nonReentrant
adminOnly
{
updatePool();
uint256 totalCommission = accLifetimeStakefishCommission / 1e6;
uint256 pendingCommission = totalCommission - lifetimeCollectedCommission;
if (amountRequested == 0) {
lifetimeCollectedCommission += pendingCommission;
emit CommissionCollected(beneficiary, pendingCommission);
beneficiary.sendValue(pendingCommission);
} else {
require(amountRequested <= pendingCommission, "Not enough pending commission");
lifetimeCollectedCommission += amountRequested;
emit CommissionCollected(beneficiary, amountRequested);
beneficiary.sendValue(amountRequested);
}
}
function transferValidatorByAdmin(
bytes calldata validatorPubkeys,
address[] calldata toAddresses
) external override nonReentrant adminOnly {
require(validatorPubkeys.length == toAddresses.length * 48, "validatorPubkeys byte array length incorrect");
for (uint256 i = 0; i < toAddresses.length; i++) {
_transferValidator(
validatorPubkeys[i * 48 : (i + 1) * 48],
toAddresses[i]
);
}
}
// Used to transfer claim history from another contract into this one.
// @param addresses: array of user addresses
// @param claimAmount: amount paid to the user outside of the contract
// Warning: the balance from the previous contract must be transferred over as well.
function transferClaimHistory(address[] calldata addresses, uint256[] calldata claimAmount)
external
override
adminOnly
{
for (uint256 i = 0; i < addresses.length; i++) {
lifetimePaidUserRewards += claimAmount[i];
users[addresses[i]].collectedReward += uint128(claimAmount[i]);
}
}
function setNFTManager(address nftManager) external override nonReentrant adminOnly {
require(nftManager != address(0), "NFT manager address must be set to nonzero");
nftManagerAddress = nftManager;
}
// Used by admins to handle emergency situations where we want to temporarily pause all withdrawals.
function closePoolForWithdrawal() external override nonReentrant adminOnly {
require(isOpenForWithdrawal, "Pool is already closed for withdrawal");
isOpenForWithdrawal = false;
}
function openPoolForWithdrawal() external override nonReentrant adminOnly {
require(!isOpenForWithdrawal, "Pool is already open for withdrawal");
isOpenForWithdrawal = true;
}
function changeOperator(address newOperator) external override nonReentrant adminOnly {
require(newOperator != address(0));
operatorAddress = newOperator;
emit OperatorChanged(operatorAddress);
}
function emergencyWithdraw (
address[] calldata depositorAddresses,
address[] calldata beneficiaries,
uint256 maxAmount
)
external
override
nonReentrant
adminOnly
{
require(beneficiaries.length == depositorAddresses.length || beneficiaries.length == 1, "beneficiaries length incorrect");
updatePool();
if (beneficiaries.length == 1) {
for (uint256 i = 0; i < depositorAddresses.length; i++) {
_collectReward(depositorAddresses[i], payable(beneficiaries[0]), maxAmount);
}
} else {
for (uint256 i = 0; i < depositorAddresses.length; i++) {
_collectReward(depositorAddresses[i], payable(beneficiaries[i]), maxAmount);
}
}
}
function saveToColdWallet(address wallet, uint256 amount) external nonReentrant override adminOnly {
require(amount <= address(this).balance, "Not enough balance");
amountTransferredToColdWallet += amount;
payable(wallet).sendValue(amount);
}
function loadFromColdWallet() external payable nonReentrant override adminOnly {
require(msg.value <= amountTransferredToColdWallet, "Too much transferred from cold wallet");
amountTransferredToColdWallet -= msg.value;
}
function totalValidators() external override view returns (uint256) {
return validatorCount;
}
function getPoolState() external override view returns (uint256, uint256, uint256, uint256, uint256, uint256, bool) {
return (
lastRewardUpdateBlock,
getAccRewardPerValidator(),
validatorCount,
lifetimeCollectedCommission,
lifetimePaidUserRewards,
amountTransferredToColdWallet,
isOpenForWithdrawal
);
}
function getUserState(address user) external override view returns (uint256, uint256, uint256, uint256) {
return (
users[user].validatorCount,
users[user].lifetimeCredit,
users[user].debit,
users[user].collectedReward
);
}
/**
* Modifiers
*/
modifier operatorOnly() {
require(
msg.sender == operatorAddress,
"Only stakefish operator allowed"
);
_;
}
modifier adminOnly() {
require(
msg.sender == adminAddress,
"Only stakefish admin allowed"
);
_;
}
// This contract should not receive value directly.
// All value should be sent to the proxy contract.
// receive() external override payable { }
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "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]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = _setInitializedVersion(1);
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
bool isTopLevelCall = _setInitializedVersion(version);
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(version);
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
_setInitializedVersion(type(uint8).max);
}
function _setInitializedVersion(uint8 version) private returns (bool) {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, and for the lowest level
// of initializers, because in other contexts the contract may have been reentered.
if (_initializing) {
require(
version == 1 && !Address.isContract(address(this)),
"Initializable: contract is already initialized"
);
return false;
} else {
require(_initialized < version, "Initializable: contract is already initialized");
_initialized = version;
return true;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "draft-IERC1822.sol";
import "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 that the this implementation remains valid after 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.
*/
function upgradeTo(address newImplementation) external 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.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) external 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;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "IBeacon.sol";
import "draft-IERC1822.sol";
import "Address.sol";
import "StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
/**
* IStakefishTransactionFeePoolV3
* This contract collects transaction fees from a pool of validators, and shares the income with their delegators (depositors).
* Important notes compared to V2:
* - The ability to retroactively specify join and part pool time is no longer present.
* - joinPool and partPool no longer take timestamps--they are effective as of the transaction.
* - We no longer emit bulkJoinPool and bulkPartPool events.
*/
interface IStakefishTransactionFeePoolV3 {
event ValidatorJoined(bytes indexed validatorPubkey, address indexed depositorAddress, uint256 ts);
event ValidatorParted(bytes indexed validatorPubkey, address indexed depositorAddress, uint256 ts);
event ValidatorBulkJoined(bytes validatorPubkeyArray, address[] depositorAddress, uint256 time);
event ValidatorBulkParted(bytes validatorPubkeyArray, address[] depositorAddress, uint256 time);
event ValidatorRewardCollected(address indexed depositorAddress, address beneficiary, uint256 rewardAmount, address requester);
event ValidatorTransferred(bytes indexed validatorPubkey, address indexed from, address indexed to, uint256 ts);
event OperatorChanged(address newOperator);
event CommissionRateChanged(uint256 newRate);
event CommissionCollected(address beneficiary, uint256 collectedAmount);
// Operator Only
/**
* @notice Add a validator to the pool
* @dev operatorOnly.
* Emits an {ValidatorJoined} event.
* Requirements:
* `validatorPubkey` cannot double join (Validator already in pool).
* `depositorAddress` is not nullable (depositorAddress must be set).
* @param validatorPubKey The validator's public key
* @param depositorAddress The delegator that is associated with the validator
*/
function joinPool(bytes calldata validatorPubKey, address depositorAddress, uint256 unused) external;
/**
* @notice Remove a validator from the pool
* @dev operatorOnly.
* Emits an {ValidatorParted} event.
* Requirements:
* `validatorPubKey` must be in the pool (Validator not in pool).
* @param validatorPubKey The validator's public key
*/
function partPool(bytes calldata validatorPubKey, uint256 unused) external;
/**
* @notice Add many validators to the pool
* @dev operatorOnly.
* @param validatorPubKeys The list of validator public keys to add (must be a multiple of 48)
* @param depositorAddresses The depositor addresses to associate with the validators.
*/
function bulkJoinPool(bytes calldata validatorPubKeys, address[] calldata depositorAddresses, uint256 unused) external;
/**
* @notice Remove many validators from the pool
* @dev operatorOnly.
* @param validatorPubKeys The list of validator public keys to remove (must be a multiple of 48)
*/
function bulkPartPool(bytes calldata validatorPubKeys, uint256 unused) external;
// Admin Only
/**
* @notice Set the contract commission rate
* @dev adminOnly.
* Emits an {CommissionRateChanged} event.
* @param commissionRate The new commission rate
*/
function setCommissionRate(uint256 commissionRate) external;
/**
* @notice Collect new commission fees up to `amountRequested`.
* @dev adminOnly.
* Emits an {CommissionCollected} event.
* Requirements:
* `amountRequested` cannot be greater than the available balance (Not enough pending commission).
* @param beneficiary The address that the `amountRequested` will be sent to
* @param amountRequested The amount that will be sent to the `beneficiary`. If 0, collect all fees.
*/
function collectPoolCommission(address payable beneficiary, uint256 amountRequested) external;
/**
* @notice Change the contract operator
* @dev adminOnly.
* Emits an {OperatorChanged} event.
* Requirements:
* `newOperator` is not nullable ().
* @param newOperator The new operator
*/
function changeOperator(address newOperator) external;
/**
* @notice Temporarily disable reward collection during a contract maintenance window
* @dev adminOnly.
* Requirements:
* `isOpenForWithdrawal` must be true (Pool is already closed for withdrawal).
*/
function closePoolForWithdrawal() external;
/**
* @notice Enable reward collection after a temporary contract maintenance window
* @dev adminOnly.
* Requirements:
* `isOpenForWithdrawal` must be false (Pool is already open for withdrawal).
*/
function openPoolForWithdrawal() external;
/**
* @notice Set the NFT manager contract address.
*/
function setNFTManager(address nftManager) external;
/**
* @notice Transfer one or more validators to new fee pool owners.
* @dev adminOnly.
* Emits many {ValidatorParted}, {ValidatorJoined} and {ValidatorTransferred} events.
* Requirements:
* `validatorPubKeys`.length must equal `toAddresses`.length * 48 (validatorPubKeys byte array length incorrect).
* Every `validatorPubKey` must be in the pool (Validator not in pool).
* No `toAddress` is nullable (to address must be set to nonzero).
* No `toAddress` can be equal to the validator's depositor (cannot transfer validator owner to oneself).
* `transferTimestamp` must be before every validator's `joinTime` (Validator transferTimestamp is before join pool time).
* `transferTimestamp` must not be in the future (Validator transferTimestamp is in the future).
* @param validatorPubKeys The list of validators that will be transferred
* @param toAddresses The list of addresses that the validators will be transferred to
*/
function transferValidatorByAdmin(bytes calldata validatorPubKeys, address[] calldata toAddresses) external;
/**
* @notice Transfer historical claim amounts into this contract
* @dev adminOnly (used during contract migration) (not idempotent!)
* @param addresses The list of depositor addresses that collected
* @param claimedAmounts The total amount collected by each depositor
*/
function transferClaimHistory(address[] calldata addresses, uint256[] calldata claimedAmounts) external;
/**
* @notice Admin function to help users recover funds from a lost or stolen wallet
* @dev adminOnly.
* Emits an {ValidatorRewardCollected} event.
* Requirements:
* `beneficiaries`.length must equal 1 or `depositorAddresses`.length (beneficiaries length incorrect).
* The pool must be open for withdrawals (Pool is not open for withdrawal right now).
* `amountRequested` cannot be greater than the available balance (Not enough pending rewards).
* @param depositorAddresses The list of depositors to withdraw rewards from
* @param beneficiaries The list of addresses that will be sent the depositors' rewards
* @param amountRequested The max amount to be withdrawn. If 0, all depositors' pending rewards will be withdrawn.
*/
function emergencyWithdraw(address[] calldata depositorAddresses, address[] calldata beneficiaries, uint256 amountRequested) external;
/**
* @notice Admin function to transfer excess balance into a cold wallet for safekeeping.
* @dev adminOnly.
* @param wallet the cold wallet to transfer to
* @param amount the amount to transfer
*/
function saveToColdWallet(address wallet, uint256 amount) external;
/**
* @notice Admin function to transfer balance back from a cold wallet. Please do not send value from the cold
* wallet directly into this contract. This function needs to do accounting to track the transferred balance.
* @dev adminOnly.
*/
function loadFromColdWallet() external payable;
// Public
/**
* @notice The amount of rewards a depositor can withdraw, and all rewards they have ever withdrawn
* @dev Reverts if `depositorAddress` is not set (depositorAddress must be set).
* @param depositorAddress The depositor address
* @return pendingRewards The current amount available for withdrawal by the depositor
* @return collectedRewards The total amount ever withdrawn by the depositor
*/
function pendingReward(address depositorAddress) external view returns (
uint256 pendingRewards,
uint256 collectedRewards
);
/**
* @notice Allow a depositor (`msg.sender`) to collect their tip rewards from the pool.
* @dev Emits an {ValidatorRewardCollected} event.
* Requirements:
* The pool must be open for withdrawals (Pool is not open for withdrawal right now).
* `amountRequested` cannot be greater than the available balance (Not enough pending rewards).
* @param beneficiary The address that the `amountRequested` will be sent to. If not set, send to `msg.sender`.
* @param amountRequested The amount that will be sent to the `beneficiary`. If 0, send all pending rewards.
*/
function collectReward(address payable beneficiary, uint256 amountRequested) external;
/**
* Collect rewards for a NFT validator. The msg.sender must own the corresponding NFT for the given validator.
* @param beneficiary The address that the `amountRequested` will be sent to. If not set, send to `msg.sender`.
* @param nftWallet The address of the NFT validator wallet.
* @param amountRequested The amount that will be sent to the `beneficiary`. If 0, send all pending rewards.
*/
function collectRewardForNFT(address payable beneficiary, address nftWallet, uint256 amountRequested) external;
/**
* Batched version of collectRewardForNFT and collectReward.
* This can be used to collect reward for NFT and non-NFT validators in a single transaction.
* @param wallet The list of validator wallets. A wallet must either be the msg.sender
* or an NFT validator wallet owned by the msg.sender.
* @param amountRequested The amount to collect from each of the above wallets.
* The length must be equal to wallet.length.
*/
function batchCollectReward(
address payable beneficiary,
address[] calldata wallet,
uint256[] calldata amountRequested) external;
/**
* @notice The count of all validators in the pool
* @return validatorCount_ The count of all validators in the pool
*/
function totalValidators() external view returns (
uint256 validatorCount_
);
/**
* @notice A summary of the pool's current state
*/
function getPoolState() external view returns (
uint256 lastRewardUpdateBlock,
uint256 accRewardPerValidator,
uint256 validatorCount,
uint256 lifetimeCollectedCommission,
uint256 lifetimePaidUserRewards,
uint256 amountInColdWallet,
bool isPoolOpenForWithdrawal
);
/**
* @notice A summary of the depositor's activity in the pool
* @param user The depositor's address
*/
function getUserState(address user) external view returns (
uint256 validatorCount,
uint256 lifetimeCredit,
uint256 debit,
uint256 collectedReward
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
// This function signature is copied from:
// https://github.com/stakefish/eth2-nft-validator-contract/blob/v0.5.5/interfaces/IStakefishNFTManager.sol
interface IStakefishNFTManager {
function validatorOwner(address validator) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract StakefishTransactionStorageV3 {
// Note that the UserSummary definition changed, but the struct layout remains the same in storage.
// The old definition is included here for reference.
// struct UserSummary {
// uint128 validatorCount;
// uint128 totalStartTimestamps;
// uint128 partedUptime;
// uint128 collectedReward;
// }
struct UserSummary {
uint128 validatorCount;
uint128 lifetimeCredit;
uint128 debit;
uint128 collectedReward;
}
// Carried over from v2, no longer used.
struct DEPRECATED_ComputationCache {
uint256 lastCacheUpdateTime;
uint256 totalValidatorUptime;
}
/////////////////////////////////////////////////////////////
// V2 storage preserved to allow in place upgrade. //
// Some are deprecated and no longer used. //
/////////////////////////////////////////////////////////////
address internal adminAddress;
address internal operatorAddress;
uint256 internal validatorCount;
uint256 public stakefishCommissionRateBasisPoints;
uint256 public lifetimeCollectedCommission;
uint256 public lifetimePaidUserRewards;
bool public isOpenForWithdrawal;
mapping(address => UserSummary) internal users;
mapping(bytes => uint256) internal validatorOwnerAndJoinTime;
DEPRECATED_ComputationCache internal DEPRECATED_cache;
/////////////////////////////////////////////////////////////
// End of V2 data structures //
/////////////////////////////////////////////////////////////
// The below are storage variables introduced by V3
uint256 public amountTransferredToColdWallet;
uint256 internal accRewardPerValidator;
uint256 internal lastRewardUpdateBlock;
uint256 internal lastLifetimeReward;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
// Additional storage added to avoid changing the storage layout during upgrades.
contract StakefishTransactionStorageV3Additional {
// Added in January 2023 update to support tip collection for NFT validators.
address internal nftManagerAddress;
// Total commission accumulated since the beginning of the lifetime of the contract.
uint256 internal accLifetimeStakefishCommission;
}{
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 200
},
"libraries": {
"StakefishTransactionFeePoolV3.sol": {}
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"collectedAmount","type":"uint256"}],"name":"CommissionCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"CommissionRateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOperator","type":"address"}],"name":"OperatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"validatorPubkeyArray","type":"bytes"},{"indexed":false,"internalType":"address[]","name":"depositorAddress","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ValidatorBulkJoined","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"validatorPubkeyArray","type":"bytes"},{"indexed":false,"internalType":"address[]","name":"depositorAddress","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ValidatorBulkParted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"validatorPubkey","type":"bytes"},{"indexed":true,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"ValidatorJoined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"validatorPubkey","type":"bytes"},{"indexed":true,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"ValidatorParted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositorAddress","type":"address"},{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"requester","type":"address"}],"name":"ValidatorRewardCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"validatorPubkey","type":"bytes"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"ts","type":"uint256"}],"name":"ValidatorTransferred","type":"event"},{"inputs":[],"name":"amountTransferredToColdWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"address[]","name":"wallet","type":"address[]"},{"internalType":"uint256[]","name":"amountRequested","type":"uint256[]"}],"name":"batchCollectReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubkeyArray","type":"bytes"},{"internalType":"address[]","name":"depositorAddresses","type":"address[]"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"bulkJoinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubkeyArray","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"bulkPartPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOperator","type":"address"}],"name":"changeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closePoolForWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"amountRequested","type":"uint256"}],"name":"collectPoolCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"amountRequested","type":"uint256"}],"name":"collectReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"address","name":"nftWallet","type":"address"},{"internalType":"uint256","name":"amountRequested","type":"uint256"}],"name":"collectRewardForNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"data","type":"uint256"}],"name":"decodeValidatorInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"depositorAddresses","type":"address[]"},{"internalType":"address[]","name":"beneficiaries","type":"address[]"},{"internalType":"uint256","name":"maxAmount","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ownerAddress","type":"address"},{"internalType":"uint256","name":"joinPoolTimestamp","type":"uint256"}],"name":"encodeValidatorInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getAccLifetimeStakefishCommission","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAccRewardPerValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLifetimeReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolState","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserState","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operatorAddress_","type":"address"},{"internalType":"address","name":"adminAddress_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initializeAccLifetimeStakefishComission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize_version3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isOpenForWithdrawal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubKey","type":"bytes"},{"internalType":"address","name":"depositor","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"joinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubKey","type":"bytes"},{"internalType":"address","name":"depositor","type":"address"}],"name":"joinPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lifetimeCollectedCommission","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lifetimePaidUserRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"loadFromColdWallet","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"userlist","type":"address[]"}],"name":"migrateFromV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"openPoolForWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubKey","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"partPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubKey","type":"bytes"}],"name":"partPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositorAddress","type":"address"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"saveToColdWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"commissionRate","type":"uint256"}],"name":"setCommissionRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftManager","type":"address"}],"name":"setNFTManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakefishCommissionRateBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalValidators","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"uint256[]","name":"claimAmount","type":"uint256[]"}],"name":"transferClaimHistory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubkeys","type":"bytes"},{"internalType":"address[]","name":"toAddresses","type":"address[]"}],"name":"transferValidatorByAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60a06040523060601b6080523480156200001857600080fd5b50600160108190556000906200002e9062000095565b905080156200004757600f805461ff0019166101001790555b80156200008e57600f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50620001b8565b600f54600090610100900460ff161562000130578160ff166001148015620000d05750620000ce30620001a960201b6200262b1760201c565b155b620001285760405162461bcd60e51b815260206004820152602e60248201526000805160206200435d83398151915260448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b506000919050565b600f5460ff8084169116106200018f5760405162461bcd60e51b815260206004820152602e60248201526000805160206200435d83398151915260448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016200011f565b50600f805460ff191660ff92909216919091179055600190565b6001600160a01b03163b151590565b60805160601c61416a620001f360003960008181610d2e01528181610d6e015281816115110152818161155101526115e4015261416a6000f3fe6080604052600436106102465760003560e01c806358f2b96411610139578063c81b356b116100b6578063d75f8b051161007a578063d75f8b05146106f4578063e8c080d714610709578063eb2f385d1461071e578063f178ad7a14610726578063f40f0f5214610746578063fa45d9701461077b57600080fd5b8063c81b356b14610646578063ca599e4c1461065b578063cbc8c8a71461067b578063cf5bc5e414610691578063d1d59fd0146106b157600080fd5b8063a3a7ca94116100fd578063a3a7ca94146105a7578063aa6425c1146105c7578063ad0b13eb146105e7578063b2d3963414610607578063b5a130951461061c57600080fd5b806358f2b96414610507578063704653aa1461052757806383c711901461054757806385e6062e146105675780638ec2cab61461058757600080fd5b806336ec1fe8116101c7578063485cc9551161018b578063485cc9551461049457806349cd4255146104b45780634ebf9b99146104c95780634f1ef286146104df57806352d1902d146104f257600080fd5b806336ec1fe8146103a15780633ec0c7b5146103c1578063416ae768146103e1578063448c4bd61461045e57806346b50d261461047457600080fd5b80631bc1f6e11161020e5780631bc1f6e1146102d75780631cfc6055146102f7578063217ac2371461031f5780632382c6ff1461036b5780633659cfe61461038157600080fd5b8063044864101461024b57806306394c9b1461026d57806307996dae1461028d57806319f344ba146102a257806319fac8fd146102b7575b600080fd5b34801561025757600080fd5b5061026b610266366004613c8c565b6107a9565b005b34801561027957600080fd5b5061026b6102883660046137d4565b61096b565b34801561029957600080fd5b5061026b610a2a565b3480156102ae57600080fd5b5061026b610acf565b3480156102c357600080fd5b5061026b6102d2366004613cd7565b610b95565b3480156102e357600080fd5b5061026b6102f23660046138d1565b610c24565b34801561030357600080fd5b5061030c610ccc565b6040519081526020015b60405180910390f35b34801561032b57600080fd5b50610334610ce4565b604080519788526020880196909652948601939093526060850191909152608084015260a0830152151560c082015260e001610316565b34801561037757600080fd5b5061030c600b5481565b34801561038d57600080fd5b5061026b61039c3660046137d4565b610d23565b3480156103ad57600080fd5b5061026b6103bc366004613a3a565b610e03565b3480156103cd57600080fd5b5061026b6103dc36600461384f565b610fa1565b3480156103ed57600080fd5b5061043e6103fc3660046137d4565b6001600160a01b0316600090815260076020526040902080546001909101546001600160801b0380831693600160801b93849004821693828416930490911690565b604080519485526020850193909352918301526060820152608001610316565b34801561046a57600080fd5b5061030c60045481565b34801561048057600080fd5b5061026b61048f3660046139f9565b61123b565b3480156104a057600080fd5b5061026b6104af3660046138fd565b6113d9565b3480156104c057600080fd5b5061030c6114dc565b3480156104d557600080fd5b5061030c60035481565b61026b6104ed366004613936565b611506565b3480156104fe57600080fd5b5061030c6115d7565b34801561051357600080fd5b5061026b61052236600461380e565b61168a565b34801561053357600080fd5b5061026b610542366004613c51565b6117d5565b34801561055357600080fd5b5061026b610562366004613c8c565b611acb565b34801561057357600080fd5b5061026b610582366004613b31565b611b93565b34801561059357600080fd5b5061026b6105a2366004613bbc565b611c5a565b3480156105b357600080fd5b5061026b6105c2366004613b66565b611cfe565b3480156105d357600080fd5b5061026b6105e2366004613aad565b611da2565b3480156105f357600080fd5b5061026b6106023660046138d1565b611ec5565b34801561061357600080fd5b5061026b611f87565b34801561062857600080fd5b506006546106369060ff1681565b6040519015158152602001610316565b34801561065257600080fd5b5060025461030c565b34801561066757600080fd5b5061026b6106763660046138d1565b61204a565b34801561068757600080fd5b5061030c60055481565b34801561069d57600080fd5b5061026b6106ac366004613c18565b6121fd565b3480156106bd57600080fd5b506106d56106cc366004613cd7565b9060e082901c90565b604080516001600160a01b039093168352602083019190915201610316565b34801561070057600080fd5b5061026b61233a565b34801561071557600080fd5b5061030c6123ab565b61026b61240e565b34801561073257600080fd5b5061026b6107413660046137d4565b6124de565b34801561075257600080fd5b506107666107613660046137d4565b6125c0565b60408051928352602083019190915201610316565b34801561078757600080fd5b5061030c6107963660046138d1565b60e01b6001600160a01b03919091161790565b600260105414156107d55760405162461bcd60e51b81526004016107cc90613eef565b60405180910390fd5b60026010556001546001600160a01b031633146108045760405162461bcd60e51b81526004016107cc90613eb8565b61080f60308361404c565b1561086a5760405162461bcd60e51b815260206004820152602560248201527f7075624b65794172726179206c656e677468206e6f74206d756c7469706c65206044820152640decc4068760db1b60648201526084016107cc565b61087261263a565b600061087f603084613f93565b905060005b8181101561095f5760006108c7868661089e856030613fa7565b906108aa866001613f7b565b6108b5906030613fa7565b926108c293929190613f26565b612717565b90506001600160a01b03811686866108e0856030613fa7565b906108ec866001613f7b565b6108f7906030613fa7565b9261090493929190613f26565b604051610912929190613cf0565b604051908190038120428252907f202ad6fc2d3f4272cf4232d1c3bd583211957c8f884eac1f9de1f94c5cd18a249060200160405180910390a3508061095781614031565b915050610884565b50506001601055505050565b6002601054141561098e5760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b031633146109bd5760405162461bcd60e51b81526004016107cc90613d4f565b6001600160a01b0381166109d057600080fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f4721129e0e676ed6a92909bb24e853ccdd63ad72280cc2e974e38e480e0e6e54906020015b60405180910390a1506001601055565b6000546001600160a01b03163314610a545760405162461bcd60e51b81526004016107cc90613d4f565b68a08365b887e62ecc56610a6661263a565b6000610a706114dc565b90506127106003548383610a849190613fee565b610a8e9190613fa7565b610a989190613f93565b612710610aa7846107d0613fa7565b610ab19190613f93565b610abb9190613f7b565b610ac890620f4240613fa7565b6012555050565b60026010541415610af25760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314610b215760405162461bcd60e51b81526004016107cc90613d4f565b60065460ff1615610b805760405162461bcd60e51b815260206004820152602360248201527f506f6f6c20697320616c7265616479206f70656e20666f7220776974686472616044820152621dd85b60ea1b60648201526084016107cc565b6006805460ff19166001908117909155601055565b60026010541415610bb85760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314610be75760405162461bcd60e51b81526004016107cc90613d4f565b610bef61263a565b60038190556040518181527f7944cc49dc8637e3cacb75b6261e778f93a87026e0357ae7c3b0e434324afa3590602001610a1a565b60026010541415610c475760405162461bcd60e51b81526004016107cc90613eef565b600260105560065460ff16610cb05760405162461bcd60e51b815260206004820152602960248201527f506f6f6c206973206e6f74206f70656e20666f72207769746864726177616c206044820152687269676874206e6f7760b81b60648201526084016107cc565b610cb861263a565b610cc33383836128a7565b50506001601055565b6000620f4240600c54610cdf9190613f93565b905090565b6000806000806000806000600d54610cfa610ccc565b600254600454600554600b54600654959d949c50929a509098509650945060ff90911692509050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415610d6c5760405162461bcd60e51b81526004016107cc90613dd2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610db56000805160206140ee833981519152546001600160a01b031690565b6001600160a01b031614610ddb5760405162461bcd60e51b81526004016107cc90613e1e565b610de481612ba7565b60408051600080825260208201909252610e0091839190612bd1565b50565b60026010541415610e265760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314610e555760405162461bcd60e51b81526004016107cc90613d4f565b81841480610e635750600182145b610eaf5760405162461bcd60e51b815260206004820152601e60248201527f62656e65666963696172696573206c656e67746820696e636f7272656374000060448201526064016107cc565b610eb761263a565b6001821415610f3b5760005b84811015610f3557610f23868683818110610ee057610ee061408c565b9050602002016020810190610ef591906137d4565b85856000818110610f0857610f0861408c565b9050602002016020810190610f1d91906137d4565b846128a7565b80610f2d81614031565b915050610ec3565b5061095f565b60005b84811015610f9457610f82868683818110610f5b57610f5b61408c565b9050602002016020810190610f7091906137d4565b858584818110610f0857610f0861408c565b80610f8c81614031565b915050610f3e565b5050506001601055505050565b60026010541415610fc45760405162461bcd60e51b81526004016107cc90613eef565b60026010558281146110355760405162461bcd60e51b815260206004820152603460248201527f77616c6c657420616e6420616d6f756e74526571756573746564206d757374206044820152730d0c2ecca40e8d0ca40e6c2daca40d8cadccee8d60631b60648201526084016107cc565b6001600160a01b038516611047573394505b6011546001600160a01b031661105b61263a565b60005b8481101561122d578585828181106110785761107861408c565b905060200201602081019061108d91906137d4565b6001600160a01b0316336001600160a01b031614806111695750816001600160a01b0316632944aedc8787848181106110c8576110c861408c565b90506020020160208101906110dd91906137d4565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b15801561111c57600080fd5b505afa158015611130573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115491906137f1565b6001600160a01b0316336001600160a01b0316145b156111bc576111b78686838181106111835761118361408c565b905060200201602081019061119891906137d4565b888686858181106111ab576111ab61408c565b905060200201356128a7565b61121b565b60405162461bcd60e51b815260206004820152602e60248201527f4f6e6c792076616c696461746f72206f72204e4654206f776e65722063616e2060448201526d18dbdb1b1958dd081c995dd85c9960921b60648201526084016107cc565b8061122581614031565b91505061105e565b505060016010555050505050565b6002601054141561125e5760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b0316331461128d5760405162461bcd60e51b81526004016107cc90613eb8565b60065460ff16156112eb5760405162461bcd60e51b815260206004820152602260248201527f506f6f6c206d75737420626520636c6f73656420666f72207769746864726177604482015261185b60f21b60648201526084016107cc565b60005b818110156113d05760006007600085858581811061130e5761130e61408c565b905060200201602081019061132391906137d4565b6001600160a01b031681526020810191909152604001600090812080546001600160801b03938416600160801b0293169290921790915560078185858581811061136f5761136f61408c565b905060200201602081019061138491906137d4565b6001600160a01b03168152602081019190915260400160002060010180546001600160801b0319166001600160801b0392909216919091179055806113c881614031565b9150506112ee565b50610cc361263a565b60006113e56001612d4b565b905080156113fd57600f805461ff0019166101001790555b6001600160a01b03831661141057600080fd5b6001600160a01b03821661142357600080fd5b600080546001600160a01b038085166001600160a01b03199283161783556001805491871691831691909117815560028390556107d06003556006805460ff19169091179055600c8290556012829055600b9190915560118054909116905543600d5561148e6114dc565b600e5580156114d757600f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000600454600554600b54476114f29190613f7b565b6114fc9190613f7b565b610cdf9190613f7b565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141561154f5760405162461bcd60e51b81526004016107cc90613dd2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166115986000805160206140ee833981519152546001600160a01b031690565b6001600160a01b0316146115be5760405162461bcd60e51b81526004016107cc90613e1e565b6115c782612ba7565b6115d382826001612bd1565b5050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116775760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016107cc565b506000805160206140ee83398151915290565b600260105414156116ad5760405162461bcd60e51b81526004016107cc90613eef565b6002601055601154604051630a512bb760e21b81526001600160a01b038481166004830152909116908190632944aedc9060240160206040518083038186803b1580156116f957600080fd5b505afa15801561170d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173191906137f1565b6001600160a01b0316336001600160a01b0316146117a55760405162461bcd60e51b815260206004820152602b60248201527f4f6e6c792076616c696461746f72204e4654206f776e65722063616e20636f6c60448201526a1b1958dd081c995dd85c9960aa1b60648201526084016107cc565b6001600160a01b0384166117b7573393505b6117bf61263a565b6117ca8385846128a7565b505060016010555050565b600260105414156117f85760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b031633146118275760405162461bcd60e51b81526004016107cc90613eb8565b600182148061183f57508361183d836030613fa7565b145b6118955760405162461bcd60e51b815260206004820152602160248201527f496e76616c6964206465706f7369746f72416464726573736573206c656e67746044820152600d60fb1b60648201526084016107cc565b61189d61263a565b60006118aa603086613f93565b905060018314156119d15760005b818110156119cb5761192187876118d0846030613fa7565b906118dc856001613f7b565b6118e7906030613fa7565b926118f493929190613f26565b878760008181106119075761190761408c565b905060200201602081019061191c91906137d4565b612dd5565b848460008181106119345761193461408c565b905060200201602081019061194991906137d4565b6001600160a01b0316878761195f846030613fa7565b9061196b856001613f7b565b611976906030613fa7565b9261198393929190613f26565b604051611991929190613cf0565b604051908190038120428252906000805160206140ce8339815191529060200160405180910390a3806119c381614031565b9150506118b8565b50610f94565b60005b8181101561122d57611a2287876119ec846030613fa7565b906119f8856001613f7b565b611a03906030613fa7565b92611a1093929190613f26565b8787858181106119075761190761408c565b848482818110611a3457611a3461408c565b9050602002016020810190611a4991906137d4565b6001600160a01b03168787611a5f846030613fa7565b90611a6b856001613f7b565b611a76906030613fa7565b92611a8393929190613f26565b604051611a91929190613cf0565b604051908190038120428252906000805160206140ce8339815191529060200160405180910390a380611ac381614031565b9150506119d4565b60026010541415611aee5760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b03163314611b1d5760405162461bcd60e51b81526004016107cc90613eb8565b611b2561263a565b6000611b318484612717565b9050806001600160a01b03168484604051611b4d929190613cf0565b604051908190038120428252907f202ad6fc2d3f4272cf4232d1c3bd583211957c8f884eac1f9de1f94c5cd18a24906020015b60405180910390a3505060016010555050565b60026010541415611bb65760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b03163314611be55760405162461bcd60e51b81526004016107cc90613eb8565b611bed61263a565b6000611bf98383612717565b9050806001600160a01b03168383604051611c15929190613cf0565b604051908190038120428252907f202ad6fc2d3f4272cf4232d1c3bd583211957c8f884eac1f9de1f94c5cd18a24906020015b60405180910390a35050600160105550565b60026010541415611c7d5760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b03163314611cac5760405162461bcd60e51b81526004016107cc90613eb8565b611cb461263a565b611cbf848484612dd5565b816001600160a01b03168484604051611cd9929190613cf0565b604051908190038120428252906000805160206140ce83398151915290602001611b80565b60026010541415611d215760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b03163314611d505760405162461bcd60e51b81526004016107cc90613eb8565b611d5861263a565b611d63838383612dd5565b806001600160a01b03168383604051611d7d929190613cf0565b604051908190038120428252906000805160206140ce83398151915290602001611c48565b6000546001600160a01b03163314611dcc5760405162461bcd60e51b81526004016107cc90613d4f565b60005b83811015611ebe57828282818110611de957611de961408c565b9050602002013560056000828254611e019190613f7b565b909155508390508282818110611e1957611e1961408c565b9050602002013560076000878785818110611e3657611e3661408c565b9050602002016020810190611e4b91906137d4565b6001600160a01b0316815260208101919091526040016000206001018054601090611e87908490600160801b90046001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508080611eb690614031565b915050611dcf565b5050505050565b60026010541415611ee85760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314611f175760405162461bcd60e51b81526004016107cc90613d4f565b47811115611f5c5760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f7567682062616c616e636560701b60448201526064016107cc565b80600b6000828254611f6e9190613f7b565b90915550610cc390506001600160a01b03831682612fb5565b60026010541415611faa5760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314611fd95760405162461bcd60e51b81526004016107cc90613d4f565b60065460ff166120395760405162461bcd60e51b815260206004820152602560248201527f506f6f6c20697320616c726561647920636c6f73656420666f722077697468646044820152641c985dd85b60da1b60648201526084016107cc565b6006805460ff191690556001601055565b6002601054141561206d5760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b0316331461209c5760405162461bcd60e51b81526004016107cc90613d4f565b6120a461263a565b6000620f42406012546120b79190613f93565b90506000600454826120c99190613fee565b9050826121415780600460008282546120e29190613f7b565b9091555050604080516001600160a01b0386168152602081018390527ff67ff1ef3bd2c37e685ec22f149d7776849fb804e098303936350bb3719721bc910160405180910390a161213c6001600160a01b03851682612fb5565b6117ca565b808311156121915760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f7567682070656e64696e6720636f6d6d697373696f6e00000060448201526064016107cc565b82600460008282546121a39190613f7b565b9091555050604080516001600160a01b0386168152602081018590527ff67ff1ef3bd2c37e685ec22f149d7776849fb804e098303936350bb3719721bc910160405180910390a16117ca6001600160a01b03851684612fb5565b600260105414156122205760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b0316331461224f5760405162461bcd60e51b81526004016107cc90613d4f565b61225a816030613fa7565b83146122bd5760405162461bcd60e51b815260206004820152602c60248201527f76616c696461746f725075626b6579732062797465206172726179206c656e6760448201526b1d1a081a5b98dbdc9c9958dd60a21b60648201526084016107cc565b60005b8181101561095f5761232885856122d8846030613fa7565b906122e4856001613f7b565b6122ef906030613fa7565b926122fc93929190613f26565b85858581811061230e5761230e61408c565b905060200201602081019061232391906137d4565b6130ce565b8061233281614031565b9150506122c0565b60006123466001612d4b565b9050801561235e57600f805461ff0019166101001790555b6000600b558015610e0057600f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000806123b66114dc565b9050620f4240612710600354600e54846123d09190613fee565b6123dd90620f4240613fa7565b6123e79190613fa7565b6123f19190613f93565b6012546123fe9190613f7b565b6124089190613f93565b91505090565b600260105414156124315760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b031633146124605760405162461bcd60e51b81526004016107cc90613d4f565b600b543411156124c05760405162461bcd60e51b815260206004820152602560248201527f546f6f206d756368207472616e736665727265642066726f6d20636f6c642077604482015264185b1b195d60da1b60648201526084016107cc565b34600b60008282546124d29190613fee565b90915550506001601055565b600260105414156125015760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b031633146125305760405162461bcd60e51b81526004016107cc90613d4f565b6001600160a01b0381166125995760405162461bcd60e51b815260206004820152602a60248201527f4e4654206d616e616765722061646472657373206d7573742062652073657420604482015269746f206e6f6e7a65726f60b01b60648201526084016107cc565b601180546001600160a01b0319166001600160a01b03929092169190911790556001601055565b6000806001600160a01b0383166126195760405162461bcd60e51b815260206004820152601c60248201527f6465706f7369746f7241646472657373206d757374206265207365740000000060448201526064016107cc565b61262283613285565b91509150915091565b6001600160a01b03163b151590565b600d544311158061264b5750600254155b1561265257565b600061265c6114dc565b90506127106003546127106126719190613fee565b600254600e546126819085613fee565b61268e90620f4240613fa7565b6126989190613f93565b6126a29190613fa7565b6126ac9190613f93565b600c60008282546126bd9190613f7b565b9091555050600354600e5461271091906126d79084613fee565b6126e490620f4240613fa7565b6126ee9190613fa7565b6126f89190613f93565b601260008282546127099190613f7b565b909155505043600d55600e55565b6000806127476008858560405161272f929190613cf0565b9081526020016040518091039020549060e082901c90565b5090506001600160a01b0381166127985760405162461bcd60e51b815260206004820152601560248201527415985b1a59185d1bdc881b9bdd081a5b881c1bdbdb605a1b60448201526064016107cc565b6127a181613436565b6001600260008282546127b49190613fee565b90915550506001600160a01b03811660009081526007602052604081208054600192906127eb9084906001600160801b0316613fc6565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555060088484604051612821929190613cf0565b90815260200160405180910390206000905561283b610ccc565b6001600160a01b03821660009081526007602052604090205461286791906001600160801b0316613fa7565b6001600160a01b038216600090815260076020526040902060010180546001600160801b0319166001600160801b03929092169190911790559392505050565b6001600160a01b0382166128b9578291505b6128c283613436565b6128ca610ccc565b6001600160a01b0384166000908152600760205260409020546128f691906001600160801b0316613fa7565b6001600160a01b03841660009081526007602052604081206001810180546001600160801b0319166001600160801b0394851617908190559054919261294a92600160801b92839004821692900416613fc6565b6001600160801b0316905081612a58576001600160a01b03841660009081526007602052604090206001018054829190601090612998908490600160801b90046001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555080600560008282546129ce9190613f7b565b9091555050604080516001600160a01b0385811682526020820184905233828401529151918616917f7916d844d976746a43b9efc42cf4339ebe50001364a8790d4aec7bbd9a2b599e9181900360600190a247811115612a405760405162461bcd60e51b81526004016107cc90613d86565b612a536001600160a01b03841682612fb5565b612ba1565b80821115612aa85760405162461bcd60e51b815260206004820152601a60248201527f4e6f7420656e6f7567682070656e64696e67207265776172647300000000000060448201526064016107cc565b6001600160a01b03841660009081526007602052604090206001018054839190601090612ae6908490600160801b90046001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508160056000828254612b1c9190613f7b565b9091555050604080516001600160a01b0385811682526020820185905233828401529151918616917f7916d844d976746a43b9efc42cf4339ebe50001364a8790d4aec7bbd9a2b599e9181900360600190a247821115612b8e5760405162461bcd60e51b81526004016107cc90613d86565b612ba16001600160a01b03841683612fb5565b50505050565b6000546001600160a01b03163314610e005760405162461bcd60e51b81526004016107cc90613d4f565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612c04576114d783613505565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c3d57600080fd5b505afa925050508015612c6d575060408051601f3d908101601f19168201909252612c6a91810190613b18565b60015b612cd05760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016107cc565b6000805160206140ee8339815191528114612d3f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016107cc565b506114d78383836135a1565b600f54600090610100900460ff1615612d94578160ff166001148015612d705750303b155b612d8c5760405162461bcd60e51b81526004016107cc90613e6a565b506000919050565b600f5460ff808416911610612dbb5760405162461bcd60e51b81526004016107cc90613e6a565b50600f805460ff191660ff92909216919091179055600190565b60088383604051612de7929190613cf0565b908152602001604051809103902054600014612e455760405162461bcd60e51b815260206004820152601960248201527f56616c696461746f7220616c726561647920696e20706f6f6c0000000000000060448201526064016107cc565b6001600160a01b038116612e9b5760405162461bcd60e51b815260206004820152601c60248201527f6465706f7369746f7241646472657373206d757374206265207365740000000060448201526064016107cc565b612ea481613436565b6001600160a01b0381166000908152600760205260408120805460019290612ed69084906001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550600160026000828254612f0d9190613f7b565b90915550506001600160a01b0381164260e01b1760088484604051612f33929190613cf0565b90815260405190819003602001902055612f4b610ccc565b6001600160a01b038216600090815260076020526040902054612f7791906001600160801b0316613fa7565b6001600160a01b0391909116600090815260076020526040902060010180546001600160801b0319166001600160801b039092169190911790555050565b804710156130055760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016107cc565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613052576040519150601f19603f3d011682016040523d82523d6000602084013e613057565b606091505b50509050806114d75760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016107cc565b60006130e56008858560405161272f929190613cf0565b5090506001600160a01b0381166131365760405162461bcd60e51b815260206004820152601560248201527415985b1a59185d1bdc881b9bdd081a5b881c1bdbdb605a1b60448201526064016107cc565b6001600160a01b0382166131965760405162461bcd60e51b815260206004820152602160248201527f746f2061646472657373206d7573742062652073657420746f206e6f6e7a65726044820152606f60f81b60648201526084016107cc565b806001600160a01b0316826001600160a01b0316141561320b5760405162461bcd60e51b815260206004820152602a60248201527f63616e6e6f74207472616e736665722076616c696461746f72206f776e6572206044820152693a379037b732b9b2b63360b11b60648201526084016107cc565b6132158484612717565b50613221848484612dd5565b816001600160a01b0316816001600160a01b03168585604051613245929190613cf0565b604051908190038120428252907fae24802f5dcf9eb23697e34d9f536295d24fc5a2684ed27559aa35ae878138269060200160405180910390a450505050565b6000806000613292610ccc565b9050600d54431180156132a757506000600254115b156133075760006132b66114dc565b90506127106003546127106132cb9190613fee565b600254600e546132db9085613fee565b6132e59190613f93565b6132ef9190613fa7565b6132f99190613f93565b6133039083613f7b565b9150505b6001600160a01b0384166000908152600760205260408120600181015490546001600160801b0391821691600160801b820481169161334891869116613fa7565b6133529190613f7b565b61335c9190613fee565b6001600160a01b038616600090815260076020526040902060010154909150600160801b90046001600160801b0316811115613401576001600160a01b0385166000908152600760205260409020600101546133c890600160801b90046001600160801b031682613fee565b6001600160a01b03959095166000908152600760205260409020600101549495600160801b9095046001600160801b0316949350505050565b505050506001600160a01b03166000908152600760205260408120600101549091600160801b9091046001600160801b031690565b6001600160a01b0381166000908152600760205260409020546001600160801b031680156115d3576001600160a01b0382166000908152600760205260408120600101546001600160801b031661348b610ccc565b6134959084613fa7565b61349f9190613fee565b6001600160a01b0384166000908152600760205260409020805491925082916010906134dc908490600160801b90046001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505050565b6001600160a01b0381163b6135725760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016107cc565b6000805160206140ee83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6135aa836135c6565b6000825111806135b75750805b156114d757612ba18383613606565b6135cf81613505565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061362b838360405180606001604052806027815260200161410e60279139613632565b9392505050565b60606001600160a01b0384163b61369a5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016107cc565b600080856001600160a01b0316856040516136b59190613d00565b600060405180830381855af49150503d80600081146136f0576040519150601f19603f3d011682016040523d82523d6000602084013e6136f5565b606091505b509150915061370582828661370f565b9695505050505050565b6060831561371e57508161362b565b82511561372e5782518084602001fd5b8160405162461bcd60e51b81526004016107cc9190613d1c565b60008083601f84011261375a57600080fd5b5081356001600160401b0381111561377157600080fd5b6020830191508360208260051b850101111561378c57600080fd5b9250929050565b60008083601f8401126137a557600080fd5b5081356001600160401b038111156137bc57600080fd5b60208301915083602082850101111561378c57600080fd5b6000602082840312156137e657600080fd5b813561362b816140b8565b60006020828403121561380357600080fd5b815161362b816140b8565b60008060006060848603121561382357600080fd5b833561382e816140b8565b9250602084013561383e816140b8565b929592945050506040919091013590565b60008060008060006060868803121561386757600080fd5b8535613872816140b8565b945060208601356001600160401b038082111561388e57600080fd5b61389a89838a01613748565b909650945060408801359150808211156138b357600080fd5b506138c088828901613748565b969995985093965092949392505050565b600080604083850312156138e457600080fd5b82356138ef816140b8565b946020939093013593505050565b6000806040838503121561391057600080fd5b823561391b816140b8565b9150602083013561392b816140b8565b809150509250929050565b6000806040838503121561394957600080fd5b8235613954816140b8565b915060208301356001600160401b038082111561397057600080fd5b818501915085601f83011261398457600080fd5b813581811115613996576139966140a2565b604051601f8201601f19908116603f011681019083821181831017156139be576139be6140a2565b816040528281528860208487010111156139d757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008060208385031215613a0c57600080fd5b82356001600160401b03811115613a2257600080fd5b613a2e85828601613748565b90969095509350505050565b600080600080600060608688031215613a5257600080fd5b85356001600160401b0380821115613a6957600080fd5b613a7589838a01613748565b90975095506020880135915080821115613a8e57600080fd5b50613a9b88828901613748565b96999598509660400135949350505050565b60008060008060408587031215613ac357600080fd5b84356001600160401b0380821115613ada57600080fd5b613ae688838901613748565b90965094506020870135915080821115613aff57600080fd5b50613b0c87828801613748565b95989497509550505050565b600060208284031215613b2a57600080fd5b5051919050565b60008060208385031215613b4457600080fd5b82356001600160401b03811115613b5a57600080fd5b613a2e85828601613793565b600080600060408486031215613b7b57600080fd5b83356001600160401b03811115613b9157600080fd5b613b9d86828701613793565b9094509250506020840135613bb1816140b8565b809150509250925092565b60008060008060608587031215613bd257600080fd5b84356001600160401b03811115613be857600080fd5b613bf487828801613793565b9095509350506020850135613c08816140b8565b9396929550929360400135925050565b60008060008060408587031215613c2e57600080fd5b84356001600160401b0380821115613c4557600080fd5b613ae688838901613793565b600080600080600060608688031215613c6957600080fd5b85356001600160401b0380821115613c8057600080fd5b613a7589838a01613793565b600080600060408486031215613ca157600080fd5b83356001600160401b03811115613cb757600080fd5b613cc386828701613793565b909790965060209590950135949350505050565b600060208284031215613ce957600080fd5b5035919050565b8183823760009101908152919050565b60008251613d12818460208701614005565b9190910192915050565b6020815260008251806020840152613d3b816040850160208701614005565b601f01601f19169190910160400192915050565b6020808252601c908201527f4f6e6c79207374616b65666973682061646d696e20616c6c6f77656400000000604082015260600190565b6020808252602c908201527f436f6e74616374206869407374616b652e6669736820746f20746f702075702060408201526b1d1a194818dbdb9d1c9858dd60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252601f908201527f4f6e6c79207374616b6566697368206f70657261746f7220616c6c6f77656400604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008085851115613f3657600080fd5b83861115613f4357600080fd5b5050820193919092039150565b60006001600160801b03808316818516808303821115613f7257613f72614060565b01949350505050565b60008219821115613f8e57613f8e614060565b500190565b600082613fa257613fa2614076565b500490565b6000816000190483118215151615613fc157613fc1614060565b500290565b60006001600160801b0383811690831681811015613fe657613fe6614060565b039392505050565b60008282101561400057614000614060565b500390565b60005b83811015614020578181015183820152602001614008565b83811115612ba15750506000910152565b600060001982141561404557614045614060565b5060010190565b60008261405b5761405b614076565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610e0057600080fdfec27226fe0e3257ae8f994a67664da5b3ba69bbf54bc8f131138b87035ff86744360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220598689637565d3ed39c30aa1833d43c54169e963e4f70c7426d9f41d95c226e664736f6c63430008070033496e697469616c697a61626c653a20636f6e747261637420697320616c726561
Deployed Bytecode
0x6080604052600436106102465760003560e01c806358f2b96411610139578063c81b356b116100b6578063d75f8b051161007a578063d75f8b05146106f4578063e8c080d714610709578063eb2f385d1461071e578063f178ad7a14610726578063f40f0f5214610746578063fa45d9701461077b57600080fd5b8063c81b356b14610646578063ca599e4c1461065b578063cbc8c8a71461067b578063cf5bc5e414610691578063d1d59fd0146106b157600080fd5b8063a3a7ca94116100fd578063a3a7ca94146105a7578063aa6425c1146105c7578063ad0b13eb146105e7578063b2d3963414610607578063b5a130951461061c57600080fd5b806358f2b96414610507578063704653aa1461052757806383c711901461054757806385e6062e146105675780638ec2cab61461058757600080fd5b806336ec1fe8116101c7578063485cc9551161018b578063485cc9551461049457806349cd4255146104b45780634ebf9b99146104c95780634f1ef286146104df57806352d1902d146104f257600080fd5b806336ec1fe8146103a15780633ec0c7b5146103c1578063416ae768146103e1578063448c4bd61461045e57806346b50d261461047457600080fd5b80631bc1f6e11161020e5780631bc1f6e1146102d75780631cfc6055146102f7578063217ac2371461031f5780632382c6ff1461036b5780633659cfe61461038157600080fd5b8063044864101461024b57806306394c9b1461026d57806307996dae1461028d57806319f344ba146102a257806319fac8fd146102b7575b600080fd5b34801561025757600080fd5b5061026b610266366004613c8c565b6107a9565b005b34801561027957600080fd5b5061026b6102883660046137d4565b61096b565b34801561029957600080fd5b5061026b610a2a565b3480156102ae57600080fd5b5061026b610acf565b3480156102c357600080fd5b5061026b6102d2366004613cd7565b610b95565b3480156102e357600080fd5b5061026b6102f23660046138d1565b610c24565b34801561030357600080fd5b5061030c610ccc565b6040519081526020015b60405180910390f35b34801561032b57600080fd5b50610334610ce4565b604080519788526020880196909652948601939093526060850191909152608084015260a0830152151560c082015260e001610316565b34801561037757600080fd5b5061030c600b5481565b34801561038d57600080fd5b5061026b61039c3660046137d4565b610d23565b3480156103ad57600080fd5b5061026b6103bc366004613a3a565b610e03565b3480156103cd57600080fd5b5061026b6103dc36600461384f565b610fa1565b3480156103ed57600080fd5b5061043e6103fc3660046137d4565b6001600160a01b0316600090815260076020526040902080546001909101546001600160801b0380831693600160801b93849004821693828416930490911690565b604080519485526020850193909352918301526060820152608001610316565b34801561046a57600080fd5b5061030c60045481565b34801561048057600080fd5b5061026b61048f3660046139f9565b61123b565b3480156104a057600080fd5b5061026b6104af3660046138fd565b6113d9565b3480156104c057600080fd5b5061030c6114dc565b3480156104d557600080fd5b5061030c60035481565b61026b6104ed366004613936565b611506565b3480156104fe57600080fd5b5061030c6115d7565b34801561051357600080fd5b5061026b61052236600461380e565b61168a565b34801561053357600080fd5b5061026b610542366004613c51565b6117d5565b34801561055357600080fd5b5061026b610562366004613c8c565b611acb565b34801561057357600080fd5b5061026b610582366004613b31565b611b93565b34801561059357600080fd5b5061026b6105a2366004613bbc565b611c5a565b3480156105b357600080fd5b5061026b6105c2366004613b66565b611cfe565b3480156105d357600080fd5b5061026b6105e2366004613aad565b611da2565b3480156105f357600080fd5b5061026b6106023660046138d1565b611ec5565b34801561061357600080fd5b5061026b611f87565b34801561062857600080fd5b506006546106369060ff1681565b6040519015158152602001610316565b34801561065257600080fd5b5060025461030c565b34801561066757600080fd5b5061026b6106763660046138d1565b61204a565b34801561068757600080fd5b5061030c60055481565b34801561069d57600080fd5b5061026b6106ac366004613c18565b6121fd565b3480156106bd57600080fd5b506106d56106cc366004613cd7565b9060e082901c90565b604080516001600160a01b039093168352602083019190915201610316565b34801561070057600080fd5b5061026b61233a565b34801561071557600080fd5b5061030c6123ab565b61026b61240e565b34801561073257600080fd5b5061026b6107413660046137d4565b6124de565b34801561075257600080fd5b506107666107613660046137d4565b6125c0565b60408051928352602083019190915201610316565b34801561078757600080fd5b5061030c6107963660046138d1565b60e01b6001600160a01b03919091161790565b600260105414156107d55760405162461bcd60e51b81526004016107cc90613eef565b60405180910390fd5b60026010556001546001600160a01b031633146108045760405162461bcd60e51b81526004016107cc90613eb8565b61080f60308361404c565b1561086a5760405162461bcd60e51b815260206004820152602560248201527f7075624b65794172726179206c656e677468206e6f74206d756c7469706c65206044820152640decc4068760db1b60648201526084016107cc565b61087261263a565b600061087f603084613f93565b905060005b8181101561095f5760006108c7868661089e856030613fa7565b906108aa866001613f7b565b6108b5906030613fa7565b926108c293929190613f26565b612717565b90506001600160a01b03811686866108e0856030613fa7565b906108ec866001613f7b565b6108f7906030613fa7565b9261090493929190613f26565b604051610912929190613cf0565b604051908190038120428252907f202ad6fc2d3f4272cf4232d1c3bd583211957c8f884eac1f9de1f94c5cd18a249060200160405180910390a3508061095781614031565b915050610884565b50506001601055505050565b6002601054141561098e5760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b031633146109bd5760405162461bcd60e51b81526004016107cc90613d4f565b6001600160a01b0381166109d057600080fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f4721129e0e676ed6a92909bb24e853ccdd63ad72280cc2e974e38e480e0e6e54906020015b60405180910390a1506001601055565b6000546001600160a01b03163314610a545760405162461bcd60e51b81526004016107cc90613d4f565b68a08365b887e62ecc56610a6661263a565b6000610a706114dc565b90506127106003548383610a849190613fee565b610a8e9190613fa7565b610a989190613f93565b612710610aa7846107d0613fa7565b610ab19190613f93565b610abb9190613f7b565b610ac890620f4240613fa7565b6012555050565b60026010541415610af25760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314610b215760405162461bcd60e51b81526004016107cc90613d4f565b60065460ff1615610b805760405162461bcd60e51b815260206004820152602360248201527f506f6f6c20697320616c7265616479206f70656e20666f7220776974686472616044820152621dd85b60ea1b60648201526084016107cc565b6006805460ff19166001908117909155601055565b60026010541415610bb85760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314610be75760405162461bcd60e51b81526004016107cc90613d4f565b610bef61263a565b60038190556040518181527f7944cc49dc8637e3cacb75b6261e778f93a87026e0357ae7c3b0e434324afa3590602001610a1a565b60026010541415610c475760405162461bcd60e51b81526004016107cc90613eef565b600260105560065460ff16610cb05760405162461bcd60e51b815260206004820152602960248201527f506f6f6c206973206e6f74206f70656e20666f72207769746864726177616c206044820152687269676874206e6f7760b81b60648201526084016107cc565b610cb861263a565b610cc33383836128a7565b50506001601055565b6000620f4240600c54610cdf9190613f93565b905090565b6000806000806000806000600d54610cfa610ccc565b600254600454600554600b54600654959d949c50929a509098509650945060ff90911692509050565b306001600160a01b037f000000000000000000000000bb328e08ac4015eed64e2738b97449797373eaf3161415610d6c5760405162461bcd60e51b81526004016107cc90613dd2565b7f000000000000000000000000bb328e08ac4015eed64e2738b97449797373eaf36001600160a01b0316610db56000805160206140ee833981519152546001600160a01b031690565b6001600160a01b031614610ddb5760405162461bcd60e51b81526004016107cc90613e1e565b610de481612ba7565b60408051600080825260208201909252610e0091839190612bd1565b50565b60026010541415610e265760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314610e555760405162461bcd60e51b81526004016107cc90613d4f565b81841480610e635750600182145b610eaf5760405162461bcd60e51b815260206004820152601e60248201527f62656e65666963696172696573206c656e67746820696e636f7272656374000060448201526064016107cc565b610eb761263a565b6001821415610f3b5760005b84811015610f3557610f23868683818110610ee057610ee061408c565b9050602002016020810190610ef591906137d4565b85856000818110610f0857610f0861408c565b9050602002016020810190610f1d91906137d4565b846128a7565b80610f2d81614031565b915050610ec3565b5061095f565b60005b84811015610f9457610f82868683818110610f5b57610f5b61408c565b9050602002016020810190610f7091906137d4565b858584818110610f0857610f0861408c565b80610f8c81614031565b915050610f3e565b5050506001601055505050565b60026010541415610fc45760405162461bcd60e51b81526004016107cc90613eef565b60026010558281146110355760405162461bcd60e51b815260206004820152603460248201527f77616c6c657420616e6420616d6f756e74526571756573746564206d757374206044820152730d0c2ecca40e8d0ca40e6c2daca40d8cadccee8d60631b60648201526084016107cc565b6001600160a01b038516611047573394505b6011546001600160a01b031661105b61263a565b60005b8481101561122d578585828181106110785761107861408c565b905060200201602081019061108d91906137d4565b6001600160a01b0316336001600160a01b031614806111695750816001600160a01b0316632944aedc8787848181106110c8576110c861408c565b90506020020160208101906110dd91906137d4565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b15801561111c57600080fd5b505afa158015611130573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115491906137f1565b6001600160a01b0316336001600160a01b0316145b156111bc576111b78686838181106111835761118361408c565b905060200201602081019061119891906137d4565b888686858181106111ab576111ab61408c565b905060200201356128a7565b61121b565b60405162461bcd60e51b815260206004820152602e60248201527f4f6e6c792076616c696461746f72206f72204e4654206f776e65722063616e2060448201526d18dbdb1b1958dd081c995dd85c9960921b60648201526084016107cc565b8061122581614031565b91505061105e565b505060016010555050505050565b6002601054141561125e5760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b0316331461128d5760405162461bcd60e51b81526004016107cc90613eb8565b60065460ff16156112eb5760405162461bcd60e51b815260206004820152602260248201527f506f6f6c206d75737420626520636c6f73656420666f72207769746864726177604482015261185b60f21b60648201526084016107cc565b60005b818110156113d05760006007600085858581811061130e5761130e61408c565b905060200201602081019061132391906137d4565b6001600160a01b031681526020810191909152604001600090812080546001600160801b03938416600160801b0293169290921790915560078185858581811061136f5761136f61408c565b905060200201602081019061138491906137d4565b6001600160a01b03168152602081019190915260400160002060010180546001600160801b0319166001600160801b0392909216919091179055806113c881614031565b9150506112ee565b50610cc361263a565b60006113e56001612d4b565b905080156113fd57600f805461ff0019166101001790555b6001600160a01b03831661141057600080fd5b6001600160a01b03821661142357600080fd5b600080546001600160a01b038085166001600160a01b03199283161783556001805491871691831691909117815560028390556107d06003556006805460ff19169091179055600c8290556012829055600b9190915560118054909116905543600d5561148e6114dc565b600e5580156114d757600f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000600454600554600b54476114f29190613f7b565b6114fc9190613f7b565b610cdf9190613f7b565b306001600160a01b037f000000000000000000000000bb328e08ac4015eed64e2738b97449797373eaf316141561154f5760405162461bcd60e51b81526004016107cc90613dd2565b7f000000000000000000000000bb328e08ac4015eed64e2738b97449797373eaf36001600160a01b03166115986000805160206140ee833981519152546001600160a01b031690565b6001600160a01b0316146115be5760405162461bcd60e51b81526004016107cc90613e1e565b6115c782612ba7565b6115d382826001612bd1565b5050565b6000306001600160a01b037f000000000000000000000000bb328e08ac4015eed64e2738b97449797373eaf316146116775760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016107cc565b506000805160206140ee83398151915290565b600260105414156116ad5760405162461bcd60e51b81526004016107cc90613eef565b6002601055601154604051630a512bb760e21b81526001600160a01b038481166004830152909116908190632944aedc9060240160206040518083038186803b1580156116f957600080fd5b505afa15801561170d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173191906137f1565b6001600160a01b0316336001600160a01b0316146117a55760405162461bcd60e51b815260206004820152602b60248201527f4f6e6c792076616c696461746f72204e4654206f776e65722063616e20636f6c60448201526a1b1958dd081c995dd85c9960aa1b60648201526084016107cc565b6001600160a01b0384166117b7573393505b6117bf61263a565b6117ca8385846128a7565b505060016010555050565b600260105414156117f85760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b031633146118275760405162461bcd60e51b81526004016107cc90613eb8565b600182148061183f57508361183d836030613fa7565b145b6118955760405162461bcd60e51b815260206004820152602160248201527f496e76616c6964206465706f7369746f72416464726573736573206c656e67746044820152600d60fb1b60648201526084016107cc565b61189d61263a565b60006118aa603086613f93565b905060018314156119d15760005b818110156119cb5761192187876118d0846030613fa7565b906118dc856001613f7b565b6118e7906030613fa7565b926118f493929190613f26565b878760008181106119075761190761408c565b905060200201602081019061191c91906137d4565b612dd5565b848460008181106119345761193461408c565b905060200201602081019061194991906137d4565b6001600160a01b0316878761195f846030613fa7565b9061196b856001613f7b565b611976906030613fa7565b9261198393929190613f26565b604051611991929190613cf0565b604051908190038120428252906000805160206140ce8339815191529060200160405180910390a3806119c381614031565b9150506118b8565b50610f94565b60005b8181101561122d57611a2287876119ec846030613fa7565b906119f8856001613f7b565b611a03906030613fa7565b92611a1093929190613f26565b8787858181106119075761190761408c565b848482818110611a3457611a3461408c565b9050602002016020810190611a4991906137d4565b6001600160a01b03168787611a5f846030613fa7565b90611a6b856001613f7b565b611a76906030613fa7565b92611a8393929190613f26565b604051611a91929190613cf0565b604051908190038120428252906000805160206140ce8339815191529060200160405180910390a380611ac381614031565b9150506119d4565b60026010541415611aee5760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b03163314611b1d5760405162461bcd60e51b81526004016107cc90613eb8565b611b2561263a565b6000611b318484612717565b9050806001600160a01b03168484604051611b4d929190613cf0565b604051908190038120428252907f202ad6fc2d3f4272cf4232d1c3bd583211957c8f884eac1f9de1f94c5cd18a24906020015b60405180910390a3505060016010555050565b60026010541415611bb65760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b03163314611be55760405162461bcd60e51b81526004016107cc90613eb8565b611bed61263a565b6000611bf98383612717565b9050806001600160a01b03168383604051611c15929190613cf0565b604051908190038120428252907f202ad6fc2d3f4272cf4232d1c3bd583211957c8f884eac1f9de1f94c5cd18a24906020015b60405180910390a35050600160105550565b60026010541415611c7d5760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b03163314611cac5760405162461bcd60e51b81526004016107cc90613eb8565b611cb461263a565b611cbf848484612dd5565b816001600160a01b03168484604051611cd9929190613cf0565b604051908190038120428252906000805160206140ce83398151915290602001611b80565b60026010541415611d215760405162461bcd60e51b81526004016107cc90613eef565b60026010556001546001600160a01b03163314611d505760405162461bcd60e51b81526004016107cc90613eb8565b611d5861263a565b611d63838383612dd5565b806001600160a01b03168383604051611d7d929190613cf0565b604051908190038120428252906000805160206140ce83398151915290602001611c48565b6000546001600160a01b03163314611dcc5760405162461bcd60e51b81526004016107cc90613d4f565b60005b83811015611ebe57828282818110611de957611de961408c565b9050602002013560056000828254611e019190613f7b565b909155508390508282818110611e1957611e1961408c565b9050602002013560076000878785818110611e3657611e3661408c565b9050602002016020810190611e4b91906137d4565b6001600160a01b0316815260208101919091526040016000206001018054601090611e87908490600160801b90046001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508080611eb690614031565b915050611dcf565b5050505050565b60026010541415611ee85760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314611f175760405162461bcd60e51b81526004016107cc90613d4f565b47811115611f5c5760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f7567682062616c616e636560701b60448201526064016107cc565b80600b6000828254611f6e9190613f7b565b90915550610cc390506001600160a01b03831682612fb5565b60026010541415611faa5760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b03163314611fd95760405162461bcd60e51b81526004016107cc90613d4f565b60065460ff166120395760405162461bcd60e51b815260206004820152602560248201527f506f6f6c20697320616c726561647920636c6f73656420666f722077697468646044820152641c985dd85b60da1b60648201526084016107cc565b6006805460ff191690556001601055565b6002601054141561206d5760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b0316331461209c5760405162461bcd60e51b81526004016107cc90613d4f565b6120a461263a565b6000620f42406012546120b79190613f93565b90506000600454826120c99190613fee565b9050826121415780600460008282546120e29190613f7b565b9091555050604080516001600160a01b0386168152602081018390527ff67ff1ef3bd2c37e685ec22f149d7776849fb804e098303936350bb3719721bc910160405180910390a161213c6001600160a01b03851682612fb5565b6117ca565b808311156121915760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f7567682070656e64696e6720636f6d6d697373696f6e00000060448201526064016107cc565b82600460008282546121a39190613f7b565b9091555050604080516001600160a01b0386168152602081018590527ff67ff1ef3bd2c37e685ec22f149d7776849fb804e098303936350bb3719721bc910160405180910390a16117ca6001600160a01b03851684612fb5565b600260105414156122205760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b0316331461224f5760405162461bcd60e51b81526004016107cc90613d4f565b61225a816030613fa7565b83146122bd5760405162461bcd60e51b815260206004820152602c60248201527f76616c696461746f725075626b6579732062797465206172726179206c656e6760448201526b1d1a081a5b98dbdc9c9958dd60a21b60648201526084016107cc565b60005b8181101561095f5761232885856122d8846030613fa7565b906122e4856001613f7b565b6122ef906030613fa7565b926122fc93929190613f26565b85858581811061230e5761230e61408c565b905060200201602081019061232391906137d4565b6130ce565b8061233281614031565b9150506122c0565b60006123466001612d4b565b9050801561235e57600f805461ff0019166101001790555b6000600b558015610e0057600f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b6000806123b66114dc565b9050620f4240612710600354600e54846123d09190613fee565b6123dd90620f4240613fa7565b6123e79190613fa7565b6123f19190613f93565b6012546123fe9190613f7b565b6124089190613f93565b91505090565b600260105414156124315760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b031633146124605760405162461bcd60e51b81526004016107cc90613d4f565b600b543411156124c05760405162461bcd60e51b815260206004820152602560248201527f546f6f206d756368207472616e736665727265642066726f6d20636f6c642077604482015264185b1b195d60da1b60648201526084016107cc565b34600b60008282546124d29190613fee565b90915550506001601055565b600260105414156125015760405162461bcd60e51b81526004016107cc90613eef565b60026010556000546001600160a01b031633146125305760405162461bcd60e51b81526004016107cc90613d4f565b6001600160a01b0381166125995760405162461bcd60e51b815260206004820152602a60248201527f4e4654206d616e616765722061646472657373206d7573742062652073657420604482015269746f206e6f6e7a65726f60b01b60648201526084016107cc565b601180546001600160a01b0319166001600160a01b03929092169190911790556001601055565b6000806001600160a01b0383166126195760405162461bcd60e51b815260206004820152601c60248201527f6465706f7369746f7241646472657373206d757374206265207365740000000060448201526064016107cc565b61262283613285565b91509150915091565b6001600160a01b03163b151590565b600d544311158061264b5750600254155b1561265257565b600061265c6114dc565b90506127106003546127106126719190613fee565b600254600e546126819085613fee565b61268e90620f4240613fa7565b6126989190613f93565b6126a29190613fa7565b6126ac9190613f93565b600c60008282546126bd9190613f7b565b9091555050600354600e5461271091906126d79084613fee565b6126e490620f4240613fa7565b6126ee9190613fa7565b6126f89190613f93565b601260008282546127099190613f7b565b909155505043600d55600e55565b6000806127476008858560405161272f929190613cf0565b9081526020016040518091039020549060e082901c90565b5090506001600160a01b0381166127985760405162461bcd60e51b815260206004820152601560248201527415985b1a59185d1bdc881b9bdd081a5b881c1bdbdb605a1b60448201526064016107cc565b6127a181613436565b6001600260008282546127b49190613fee565b90915550506001600160a01b03811660009081526007602052604081208054600192906127eb9084906001600160801b0316613fc6565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555060088484604051612821929190613cf0565b90815260200160405180910390206000905561283b610ccc565b6001600160a01b03821660009081526007602052604090205461286791906001600160801b0316613fa7565b6001600160a01b038216600090815260076020526040902060010180546001600160801b0319166001600160801b03929092169190911790559392505050565b6001600160a01b0382166128b9578291505b6128c283613436565b6128ca610ccc565b6001600160a01b0384166000908152600760205260409020546128f691906001600160801b0316613fa7565b6001600160a01b03841660009081526007602052604081206001810180546001600160801b0319166001600160801b0394851617908190559054919261294a92600160801b92839004821692900416613fc6565b6001600160801b0316905081612a58576001600160a01b03841660009081526007602052604090206001018054829190601090612998908490600160801b90046001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555080600560008282546129ce9190613f7b565b9091555050604080516001600160a01b0385811682526020820184905233828401529151918616917f7916d844d976746a43b9efc42cf4339ebe50001364a8790d4aec7bbd9a2b599e9181900360600190a247811115612a405760405162461bcd60e51b81526004016107cc90613d86565b612a536001600160a01b03841682612fb5565b612ba1565b80821115612aa85760405162461bcd60e51b815260206004820152601a60248201527f4e6f7420656e6f7567682070656e64696e67207265776172647300000000000060448201526064016107cc565b6001600160a01b03841660009081526007602052604090206001018054839190601090612ae6908490600160801b90046001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508160056000828254612b1c9190613f7b565b9091555050604080516001600160a01b0385811682526020820185905233828401529151918616917f7916d844d976746a43b9efc42cf4339ebe50001364a8790d4aec7bbd9a2b599e9181900360600190a247821115612b8e5760405162461bcd60e51b81526004016107cc90613d86565b612ba16001600160a01b03841683612fb5565b50505050565b6000546001600160a01b03163314610e005760405162461bcd60e51b81526004016107cc90613d4f565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612c04576114d783613505565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c3d57600080fd5b505afa925050508015612c6d575060408051601f3d908101601f19168201909252612c6a91810190613b18565b60015b612cd05760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016107cc565b6000805160206140ee8339815191528114612d3f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016107cc565b506114d78383836135a1565b600f54600090610100900460ff1615612d94578160ff166001148015612d705750303b155b612d8c5760405162461bcd60e51b81526004016107cc90613e6a565b506000919050565b600f5460ff808416911610612dbb5760405162461bcd60e51b81526004016107cc90613e6a565b50600f805460ff191660ff92909216919091179055600190565b60088383604051612de7929190613cf0565b908152602001604051809103902054600014612e455760405162461bcd60e51b815260206004820152601960248201527f56616c696461746f7220616c726561647920696e20706f6f6c0000000000000060448201526064016107cc565b6001600160a01b038116612e9b5760405162461bcd60e51b815260206004820152601c60248201527f6465706f7369746f7241646472657373206d757374206265207365740000000060448201526064016107cc565b612ea481613436565b6001600160a01b0381166000908152600760205260408120805460019290612ed69084906001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550600160026000828254612f0d9190613f7b565b90915550506001600160a01b0381164260e01b1760088484604051612f33929190613cf0565b90815260405190819003602001902055612f4b610ccc565b6001600160a01b038216600090815260076020526040902054612f7791906001600160801b0316613fa7565b6001600160a01b0391909116600090815260076020526040902060010180546001600160801b0319166001600160801b039092169190911790555050565b804710156130055760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016107cc565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613052576040519150601f19603f3d011682016040523d82523d6000602084013e613057565b606091505b50509050806114d75760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016107cc565b60006130e56008858560405161272f929190613cf0565b5090506001600160a01b0381166131365760405162461bcd60e51b815260206004820152601560248201527415985b1a59185d1bdc881b9bdd081a5b881c1bdbdb605a1b60448201526064016107cc565b6001600160a01b0382166131965760405162461bcd60e51b815260206004820152602160248201527f746f2061646472657373206d7573742062652073657420746f206e6f6e7a65726044820152606f60f81b60648201526084016107cc565b806001600160a01b0316826001600160a01b0316141561320b5760405162461bcd60e51b815260206004820152602a60248201527f63616e6e6f74207472616e736665722076616c696461746f72206f776e6572206044820152693a379037b732b9b2b63360b11b60648201526084016107cc565b6132158484612717565b50613221848484612dd5565b816001600160a01b0316816001600160a01b03168585604051613245929190613cf0565b604051908190038120428252907fae24802f5dcf9eb23697e34d9f536295d24fc5a2684ed27559aa35ae878138269060200160405180910390a450505050565b6000806000613292610ccc565b9050600d54431180156132a757506000600254115b156133075760006132b66114dc565b90506127106003546127106132cb9190613fee565b600254600e546132db9085613fee565b6132e59190613f93565b6132ef9190613fa7565b6132f99190613f93565b6133039083613f7b565b9150505b6001600160a01b0384166000908152600760205260408120600181015490546001600160801b0391821691600160801b820481169161334891869116613fa7565b6133529190613f7b565b61335c9190613fee565b6001600160a01b038616600090815260076020526040902060010154909150600160801b90046001600160801b0316811115613401576001600160a01b0385166000908152600760205260409020600101546133c890600160801b90046001600160801b031682613fee565b6001600160a01b03959095166000908152600760205260409020600101549495600160801b9095046001600160801b0316949350505050565b505050506001600160a01b03166000908152600760205260408120600101549091600160801b9091046001600160801b031690565b6001600160a01b0381166000908152600760205260409020546001600160801b031680156115d3576001600160a01b0382166000908152600760205260408120600101546001600160801b031661348b610ccc565b6134959084613fa7565b61349f9190613fee565b6001600160a01b0384166000908152600760205260409020805491925082916010906134dc908490600160801b90046001600160801b0316613f50565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505050565b6001600160a01b0381163b6135725760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016107cc565b6000805160206140ee83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6135aa836135c6565b6000825111806135b75750805b156114d757612ba18383613606565b6135cf81613505565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061362b838360405180606001604052806027815260200161410e60279139613632565b9392505050565b60606001600160a01b0384163b61369a5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016107cc565b600080856001600160a01b0316856040516136b59190613d00565b600060405180830381855af49150503d80600081146136f0576040519150601f19603f3d011682016040523d82523d6000602084013e6136f5565b606091505b509150915061370582828661370f565b9695505050505050565b6060831561371e57508161362b565b82511561372e5782518084602001fd5b8160405162461bcd60e51b81526004016107cc9190613d1c565b60008083601f84011261375a57600080fd5b5081356001600160401b0381111561377157600080fd5b6020830191508360208260051b850101111561378c57600080fd5b9250929050565b60008083601f8401126137a557600080fd5b5081356001600160401b038111156137bc57600080fd5b60208301915083602082850101111561378c57600080fd5b6000602082840312156137e657600080fd5b813561362b816140b8565b60006020828403121561380357600080fd5b815161362b816140b8565b60008060006060848603121561382357600080fd5b833561382e816140b8565b9250602084013561383e816140b8565b929592945050506040919091013590565b60008060008060006060868803121561386757600080fd5b8535613872816140b8565b945060208601356001600160401b038082111561388e57600080fd5b61389a89838a01613748565b909650945060408801359150808211156138b357600080fd5b506138c088828901613748565b969995985093965092949392505050565b600080604083850312156138e457600080fd5b82356138ef816140b8565b946020939093013593505050565b6000806040838503121561391057600080fd5b823561391b816140b8565b9150602083013561392b816140b8565b809150509250929050565b6000806040838503121561394957600080fd5b8235613954816140b8565b915060208301356001600160401b038082111561397057600080fd5b818501915085601f83011261398457600080fd5b813581811115613996576139966140a2565b604051601f8201601f19908116603f011681019083821181831017156139be576139be6140a2565b816040528281528860208487010111156139d757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008060208385031215613a0c57600080fd5b82356001600160401b03811115613a2257600080fd5b613a2e85828601613748565b90969095509350505050565b600080600080600060608688031215613a5257600080fd5b85356001600160401b0380821115613a6957600080fd5b613a7589838a01613748565b90975095506020880135915080821115613a8e57600080fd5b50613a9b88828901613748565b96999598509660400135949350505050565b60008060008060408587031215613ac357600080fd5b84356001600160401b0380821115613ada57600080fd5b613ae688838901613748565b90965094506020870135915080821115613aff57600080fd5b50613b0c87828801613748565b95989497509550505050565b600060208284031215613b2a57600080fd5b5051919050565b60008060208385031215613b4457600080fd5b82356001600160401b03811115613b5a57600080fd5b613a2e85828601613793565b600080600060408486031215613b7b57600080fd5b83356001600160401b03811115613b9157600080fd5b613b9d86828701613793565b9094509250506020840135613bb1816140b8565b809150509250925092565b60008060008060608587031215613bd257600080fd5b84356001600160401b03811115613be857600080fd5b613bf487828801613793565b9095509350506020850135613c08816140b8565b9396929550929360400135925050565b60008060008060408587031215613c2e57600080fd5b84356001600160401b0380821115613c4557600080fd5b613ae688838901613793565b600080600080600060608688031215613c6957600080fd5b85356001600160401b0380821115613c8057600080fd5b613a7589838a01613793565b600080600060408486031215613ca157600080fd5b83356001600160401b03811115613cb757600080fd5b613cc386828701613793565b909790965060209590950135949350505050565b600060208284031215613ce957600080fd5b5035919050565b8183823760009101908152919050565b60008251613d12818460208701614005565b9190910192915050565b6020815260008251806020840152613d3b816040850160208701614005565b601f01601f19169190910160400192915050565b6020808252601c908201527f4f6e6c79207374616b65666973682061646d696e20616c6c6f77656400000000604082015260600190565b6020808252602c908201527f436f6e74616374206869407374616b652e6669736820746f20746f702075702060408201526b1d1a194818dbdb9d1c9858dd60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252601f908201527f4f6e6c79207374616b6566697368206f70657261746f7220616c6c6f77656400604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008085851115613f3657600080fd5b83861115613f4357600080fd5b5050820193919092039150565b60006001600160801b03808316818516808303821115613f7257613f72614060565b01949350505050565b60008219821115613f8e57613f8e614060565b500190565b600082613fa257613fa2614076565b500490565b6000816000190483118215151615613fc157613fc1614060565b500290565b60006001600160801b0383811690831681811015613fe657613fe6614060565b039392505050565b60008282101561400057614000614060565b500390565b60005b83811015614020578181015183820152602001614008565b83811115612ba15750506000910152565b600060001982141561404557614045614060565b5060010190565b60008261405b5761405b614076565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610e0057600080fdfec27226fe0e3257ae8f994a67664da5b3ba69bbf54bc8f131138b87035ff86744360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220598689637565d3ed39c30aa1833d43c54169e963e4f70c7426d9f41d95c226e664736f6c63430008070033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.