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
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SDUtilityPool
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 10000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
import './library/UtilLib.sol';
import './interfaces/IStaderConfig.sol';
import './interfaces/ISDIncentiveController.sol';
import './interfaces/ISDUtilityPool.sol';
import './interfaces/SDCollateral/ISDCollateral.sol';
import './interfaces/IPoolUtils.sol';
import './interfaces/IOperatorRewardsCollector.sol';
import '@openzeppelin/contracts/utils/math/Math.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol';
contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgradeable {
using Math for uint256;
uint256 public constant DECIMAL = 1e18;
uint256 public constant MIN_SD_DELEGATE_LIMIT = 1e15;
uint256 public constant MIN_SD_WITHDRAW_LIMIT = 1e12;
uint256 public constant MAX_UTILIZATION_RATE_PER_BLOCK = 95129375951; // 25 % APR
uint256 public constant MAX_PROTOCOL_FEE = 1e17; // 10%
// State variables
/// @notice Percentage of protocol fee expressed in gwei
uint256 public protocolFee;
/// @notice Block number that fee was last accrued at
uint256 public accrualBlockNumber;
/// @notice Accumulator of the total earned interest rate since start of pool
uint256 public utilizeIndex;
/// @notice Total amount of outstanding SD utilized
uint256 public totalUtilizedSD;
/// @notice Total amount of protocol fee
uint256 public accumulatedProtocolFee;
/// @notice utilization rate per block
uint256 public utilizationRatePerBlock;
/// @notice value of cToken supply
uint256 public cTokenTotalSupply;
/// @notice upper cap on ETH worth of SD utilized per validator
uint256 public maxETHWorthOfSDPerValidator;
/// @notice request ID to be finalized next
uint256 public nextRequestIdToFinalize;
/// @notice request ID to be assigned to a next withdraw request
uint256 public nextRequestId;
/// @notice amount of SD requested for withdraw
uint256 public sdRequestedForWithdraw;
/// @notice batch limit on withdraw requests to be finalized in single txn
uint256 public finalizationBatchLimit;
/// @notice amount of SD reserved for claim request
uint256 public sdReservedForClaim;
/// @notice minimum block delay between requesting for withdraw and finalization of request
uint256 public minBlockDelayToFinalizeRequest;
/// @notice upper cap on user non redeemed withdraw request count
uint256 public maxNonRedeemedDelegatorRequestCount;
/// @notice address of staderConfig contract
IStaderConfig public staderConfig;
/// @notice risk configuration
RiskConfig public riskConfig;
/// @notice chronological collection of liquidations
OperatorLiquidation[] public liquidations;
// Mappings
mapping(address => UtilizerStruct) public override utilizerData;
mapping(address => uint256) public override delegatorCTokenBalance;
mapping(address => uint256) public override delegatorWithdrawRequestedCTokenCount;
mapping(uint256 => DelegatorWithdrawInfo) public override delegatorWithdrawRequests;
mapping(address => uint256[]) public override requestIdsByDelegatorAddress;
mapping(address => uint256) public override liquidationIndexByOperator;
uint256 public conservativeEthPerKey;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(address _admin, address _staderConfig) external initializer {
UtilLib.checkNonZeroAddress(_admin);
UtilLib.checkNonZeroAddress(_staderConfig);
__AccessControl_init_unchained();
__Pausable_init();
staderConfig = IStaderConfig(_staderConfig);
utilizeIndex = DECIMAL;
utilizationRatePerBlock = 38051750380; // 10% APR
protocolFee = 0;
nextRequestId = 1;
nextRequestIdToFinalize = 1;
finalizationBatchLimit = 50;
accrualBlockNumber = block.number;
minBlockDelayToFinalizeRequest = 50400; //7 days
maxNonRedeemedDelegatorRequestCount = 1000;
maxETHWorthOfSDPerValidator = 1 ether;
conservativeEthPerKey = 2 ether;
_updateRiskConfig(70, 30, 5, 50);
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
//delegate SD during initialization to avoid price inflation of cTokenShare
_delegate(1 ether);
emit UpdatedStaderConfig(_staderConfig);
}
/**
* @notice Sender delegate SD and cToken balance increases for sender
* @dev Accrues fee whether or not the operation succeeds, unless reverted
* @param sdAmount The amount of SD token to delegate
*/
function delegate(uint256 sdAmount) external override whenNotPaused {
if (sdAmount < MIN_SD_DELEGATE_LIMIT) {
revert InvalidInput();
}
accrueFee();
ISDIncentiveController(staderConfig.getSDIncentiveController()).updateRewardForAccount(msg.sender);
_delegate(sdAmount);
}
/**
* @notice auxiliary method to put a withdrawal request, takes in cToken amount as input
* @dev use this function to withdraw all SD from pool, pass delegatorCTokenBalance in the input for such cases
* @param _cTokenAmount amount of cToken
* @return _requestId generated request ID for withdrawal
*/
function requestWithdraw(uint256 _cTokenAmount) external override whenNotPaused returns (uint256 _requestId) {
if (_cTokenAmount > delegatorCTokenBalance[msg.sender]) {
revert InvalidAmountOfWithdraw();
}
accrueFee();
uint256 exchangeRate = _exchangeRateStored();
delegatorCTokenBalance[msg.sender] -= _cTokenAmount;
delegatorWithdrawRequestedCTokenCount[msg.sender] += _cTokenAmount;
uint256 sdRequested = (exchangeRate * _cTokenAmount) / DECIMAL;
if (sdRequested < MIN_SD_WITHDRAW_LIMIT) {
revert InvalidInput();
}
_requestId = _requestWithdraw(sdRequested, _cTokenAmount);
}
/**
* @notice auxiliary method to put a withdrawal request, takes SD amount as input
* @dev this function is not recommended to withdraw all balance as due to some elapsed block
* between calculating getDelegatorLatestSDBalance and then executing this function, some more SD rewards
* might accumulate, use 'requestWithdraw' function in such case by passing delegatorCTokenBalance in the input
* @param _sdAmount amount of SD to withdraw
* @return _requestId generated request ID for withdrawal
*/
function requestWithdrawWithSDAmount(uint256 _sdAmount)
external
override
whenNotPaused
returns (uint256 _requestId)
{
if (_sdAmount < MIN_SD_WITHDRAW_LIMIT) {
revert InvalidInput();
}
accrueFee();
uint256 exchangeRate = _exchangeRateStored();
uint256 cTokenToReduce = Math.ceilDiv((_sdAmount * DECIMAL), exchangeRate);
if (cTokenToReduce > delegatorCTokenBalance[msg.sender]) {
revert InvalidAmountOfWithdraw();
}
delegatorCTokenBalance[msg.sender] -= cTokenToReduce;
delegatorWithdrawRequestedCTokenCount[msg.sender] += cTokenToReduce;
_requestId = _requestWithdraw(_sdAmount, cTokenToReduce);
}
/**
* @notice finalize delegator's withdraw requests
*/
function finalizeDelegatorWithdrawalRequest() external override whenNotPaused {
accrueFee();
uint256 exchangeRate = _exchangeRateStored();
uint256 maxRequestIdToFinalize = Math.min(nextRequestId, nextRequestIdToFinalize + finalizationBatchLimit);
uint256 requestId;
uint256 sdToReserveToFinalizeRequests;
for (requestId = nextRequestIdToFinalize; requestId < maxRequestIdToFinalize; ) {
DelegatorWithdrawInfo memory delegatorWithdrawInfo = delegatorWithdrawRequests[requestId];
uint256 requiredSD = delegatorWithdrawInfo.sdExpected;
uint256 amountOfcToken = delegatorWithdrawInfo.amountOfCToken;
uint256 minSDRequiredToFinalizeRequest = Math.min(requiredSD, (amountOfcToken * exchangeRate) / DECIMAL);
if (
(sdToReserveToFinalizeRequests + minSDRequiredToFinalizeRequest + accumulatedProtocolFee >
getPoolAvailableSDBalance()) ||
(delegatorWithdrawInfo.requestBlock + minBlockDelayToFinalizeRequest > block.number)
) {
break;
}
ISDIncentiveController(staderConfig.getSDIncentiveController()).updateRewardForAccount(
delegatorWithdrawInfo.owner
);
delegatorWithdrawRequests[requestId].sdFinalized = minSDRequiredToFinalizeRequest;
sdRequestedForWithdraw -= requiredSD;
sdToReserveToFinalizeRequests += minSDRequiredToFinalizeRequest;
delegatorWithdrawRequestedCTokenCount[delegatorWithdrawInfo.owner] -= amountOfcToken;
cTokenTotalSupply -= amountOfcToken;
unchecked {
++requestId;
}
}
nextRequestIdToFinalize = requestId;
sdReservedForClaim += sdToReserveToFinalizeRequests;
emit FinalizedWithdrawRequest(nextRequestIdToFinalize);
}
/**
* @notice transfer the SD of finalized request to recipient and delete the request
* @param _requestId request id to claim
*/
function claim(uint256 _requestId) external override whenNotPaused {
if (_requestId >= nextRequestIdToFinalize) {
revert RequestIdNotFinalized(_requestId);
}
DelegatorWithdrawInfo memory delegatorRequest = delegatorWithdrawRequests[_requestId];
if (msg.sender != delegatorRequest.owner) {
revert CallerNotAuthorizedToRedeem();
}
uint256 sdToTransfer = delegatorRequest.sdFinalized;
sdReservedForClaim -= sdToTransfer;
_deleteRequestId(_requestId);
ISDIncentiveController(staderConfig.getSDIncentiveController()).claim(msg.sender);
if (!IERC20(staderConfig.getStaderToken()).transfer(msg.sender, sdToTransfer)) {
revert SDTransferFailed();
}
emit RequestRedeemed(msg.sender, sdToTransfer);
}
/**
* @notice Sender utilizes SD from the pool to add it as collateral to run validators
* @param utilizeAmount The amount of the SD token to utilize
*/
function utilize(uint256 utilizeAmount) external override whenNotPaused {
ISDCollateral sdCollateral = ISDCollateral(staderConfig.getSDCollateral());
(, , uint256 nonTerminalKeyCount) = sdCollateral.getOperatorInfo(msg.sender);
uint256 currentUtilizedSDCollateral = sdCollateral.operatorUtilizedSDBalance(msg.sender);
uint256 maxSDUtilizeValue = nonTerminalKeyCount * sdCollateral.convertETHToSD(maxETHWorthOfSDPerValidator);
if (currentUtilizedSDCollateral + utilizeAmount > maxSDUtilizeValue) {
revert SDUtilizeLimitReached();
}
accrueFee();
_utilize(msg.sender, utilizeAmount);
}
/**
* @notice utilize SD from the pool to add it as collateral for `operator` to run validators
* @dev only permissionless node registry contract can call
* @param operator address of an ETHx operator
* @param utilizeAmount The amount of the SD token to utilize
* @param nonTerminalKeyCount count of operator's non terminal keys
*
*/
function utilizeWhileAddingKeys(
address operator,
uint256 utilizeAmount,
uint256 nonTerminalKeyCount
) external override whenNotPaused {
UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.PERMISSIONLESS_NODE_REGISTRY());
ISDCollateral sdCollateral = ISDCollateral(staderConfig.getSDCollateral());
uint256 currentUtilizedSDCollateral = sdCollateral.operatorUtilizedSDBalance(operator);
uint256 maxSDUtilizeValue = nonTerminalKeyCount * sdCollateral.convertETHToSD(maxETHWorthOfSDPerValidator);
if (currentUtilizedSDCollateral + utilizeAmount > maxSDUtilizeValue) {
revert SDUtilizeLimitReached();
}
accrueFee();
_utilize(operator, utilizeAmount);
}
/**
* @notice Sender repays their utilized SD, returns actual repayment amount
* @param repayAmount The amount to repay
*/
function repay(uint256 repayAmount) external whenNotPaused returns (uint256 repaidAmount, uint256 feePaid) {
accrueFee();
(repaidAmount, feePaid) = _repay(msg.sender, repayAmount);
}
/**
* @notice Sender repays on behalf of utilizer, returns actual repayment amount
* @param repayAmount The amount to repay
*/
function repayOnBehalf(address utilizer, uint256 repayAmount)
external
override
whenNotPaused
returns (uint256 repaidAmount, uint256 feePaid)
{
accrueFee();
(repaidAmount, feePaid) = _repay(utilizer, repayAmount);
}
/**
* @notice Sender repays their full utilized SD position, this function is introduce to help
* utilizer not to worry about calculating exact SD repayment amount for clearing their entire position
*/
function repayFullAmount() external override whenNotPaused returns (uint256 repaidAmount, uint256 feePaid) {
accrueFee();
uint256 accountUtilizedPrev = _utilizerBalanceStoredInternal(msg.sender);
(repaidAmount, feePaid) = _repay(msg.sender, accountUtilizedPrev);
}
/**
* @notice call to withdraw protocol fee SD
* @dev only `MANAGER` role can call
* @param _amount amount of protocol fee in SD to withdraw
*/
function withdrawProtocolFee(uint256 _amount) external override whenNotPaused {
UtilLib.onlyManagerRole(msg.sender, staderConfig);
accrueFee();
if (_amount > accumulatedProtocolFee || _amount > getPoolAvailableSDBalance()) {
revert InvalidWithdrawAmount();
}
accumulatedProtocolFee -= _amount;
if (!IERC20(staderConfig.getStaderToken()).transfer(staderConfig.getStaderTreasury(), _amount)) {
revert SDTransferFailed();
}
emit WithdrawnProtocolFee(_amount);
}
/// @notice for max approval to SD collateral contract for spending SD tokens
function maxApproveSD() external override whenNotPaused {
UtilLib.onlyManagerRole(msg.sender, staderConfig);
address sdCollateral = staderConfig.getSDCollateral();
UtilLib.checkNonZeroAddress(sdCollateral);
IERC20(staderConfig.getStaderToken()).approve(sdCollateral, type(uint256).max);
}
/**
* @notice Applies accrued fee to total utilized and protocolFees
* @dev This calculates fee accrued from the last check pointed block
* up to the current block and writes new checkpoint to storage.
*/
function accrueFee() public override whenNotPaused {
/* Remember the initial block number */
uint256 currentBlockNumber = block.number;
/* Short-circuit accumulating 0 fee */
if (accrualBlockNumber == currentBlockNumber) {
return;
}
/* Calculate the number of blocks elapsed since the last accrual */
uint256 blockDelta = currentBlockNumber - accrualBlockNumber;
/*
* Calculate the fee accumulated into utilized and totalProtocolFee and the new index:
* simpleFeeFactor = utilizationRate * blockDelta
* feeAccumulated = simpleFeeFactor * totalUtilizedSD
* totalUtilizedSDNew = feeAccumulated + totalUtilizedSD
* totalProtocolFeeNew = feeAccumulated * protocolFeeFactor + totalProtocolFee
* utilizeIndexNew = simpleFeeFactor * utilizeIndex + utilizeIndex
*/
uint256 simpleFeeFactor = utilizationRatePerBlock * blockDelta;
uint256 feeAccumulated = (simpleFeeFactor * totalUtilizedSD) / DECIMAL;
totalUtilizedSD += feeAccumulated;
accumulatedProtocolFee += (protocolFee * feeAccumulated) / DECIMAL;
utilizeIndex += Math.ceilDiv((simpleFeeFactor * utilizeIndex), DECIMAL);
accrualBlockNumber = currentBlockNumber;
emit AccruedFees(feeAccumulated, accumulatedProtocolFee, totalUtilizedSD);
}
/**
* @notice Initiates the liquidation process for an account if its health factor is below the required threshold.
* @dev The function checks the health factor, accrues fees, updates utilized indices, and calculates liquidation amounts.
* It's important to note that this liquidation process does not touch the operator's self-bonded SD tokens,
* even if they could potentially be used for repayment.
* @param account The address of the account to be liquidated
*/
function liquidationCall(address account) external override whenNotPaused {
if (liquidationIndexByOperator[account] != 0) revert AlreadyLiquidated();
accrueFee();
UserData memory userData = getUserData(account);
if (userData.healthFactor > DECIMAL) {
revert NotLiquidatable();
}
_repay(account, userData.totalInterestSD);
uint256 totalInterestInEth = ISDCollateral(staderConfig.getSDCollateral()).convertSDToETH(
userData.totalInterestSD
);
uint256 liquidationBonusInEth = (totalInterestInEth * riskConfig.liquidationBonusPercent) / 100;
uint256 liquidationFeeInEth = (totalInterestInEth * riskConfig.liquidationFeePercent) / 100;
uint256 totalLiquidationAmountInEth = totalInterestInEth + liquidationBonusInEth + liquidationFeeInEth;
OperatorLiquidation memory liquidation = OperatorLiquidation({
totalAmountInEth: totalLiquidationAmountInEth,
totalBonusInEth: liquidationBonusInEth,
totalFeeInEth: liquidationFeeInEth,
isRepaid: false,
isClaimed: false,
liquidator: msg.sender
});
liquidations.push(liquidation);
liquidationIndexByOperator[account] = liquidations.length;
IPoolUtils(staderConfig.getPoolUtils()).processOperatorExit(account, totalLiquidationAmountInEth);
emit LiquidationCall(
account,
totalLiquidationAmountInEth,
liquidationBonusInEth,
liquidationFeeInEth,
msg.sender
);
}
/**
* @notice function used to clear utilizer's SD interest position in case when protocol does not have any ETH
* collateral left for SD interest due to all collateral ETH being used as liquidation fee, SD interest in this
* case will be from the moment of liquidationCall and claiming of liquidation
* @dev only ADMIN role can call, SD worth of interest is lost from the protocol
* @dev utilizer utilizedSD balance in SDCollateral contract should be 0
* @param _utilizer array of utilizer addresses
*/
function clearUtilizerInterest(address[] calldata _utilizer) external override onlyRole(DEFAULT_ADMIN_ROLE) {
accrueFee();
uint256 operatorCount = _utilizer.length;
for (uint256 i; i < operatorCount; ) {
address utilizer = _utilizer[i];
if (ISDCollateral(staderConfig.getSDCollateral()).operatorUtilizedSDBalance(utilizer) != 0) {
revert OperatorUtilizedSDBalanceNonZero();
}
uint256 accountUtilizedPrev = _utilizerBalanceStoredInternal(utilizer);
utilizerData[utilizer].principal = 0;
utilizerData[utilizer].utilizeIndex = utilizeIndex;
totalUtilizedSD = totalUtilizedSD > accountUtilizedPrev ? totalUtilizedSD - accountUtilizedPrev : 0;
emit ClearedUtilizerInterest(utilizer, accountUtilizedPrev);
unchecked {
++i;
}
}
}
/**
* @notice function used to move utilizedSD from SDCollateral to UtilityPool
* in such a way that utilizedSDBalance in SDCollateral contract becomes 0 and utilizer is left with only SD interest
* @dev only SDCollateral contract can call
*/
function repayUtilizedSDBalance(address _utilizer, uint256 amount) external override {
UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.SD_COLLATERAL());
accrueFee();
if (!IERC20(staderConfig.getStaderToken()).transferFrom(msg.sender, address(this), amount)) {
revert SDTransferFailed();
}
uint256 accountUtilizedPrev = _utilizerBalanceStoredInternal(_utilizer);
utilizerData[_utilizer].principal = accountUtilizedPrev - amount;
utilizerData[_utilizer].utilizeIndex = utilizeIndex;
totalUtilizedSD = totalUtilizedSD > amount ? totalUtilizedSD - amount : 0;
emit RepaidUtilizedSDBalance(_utilizer, amount);
}
/**
* @notice Accrue fee to updated utilizeIndex and then calculate account's utilized balance using the updated utilizeIndex
* @param account The address whose balance should be calculated after updating utilizeIndex
* @return The calculated balance
*/
function utilizerBalanceCurrent(address account) external override returns (uint256) {
accrueFee();
return _utilizerBalanceStoredInternal(account);
}
/**
* @notice Finishes the liquidation process
* @dev Both liquidator and treasury expected amounts should be transferred already from the Operator Reward Collector
* @param account The operator address
*/
function completeLiquidation(address account) external override whenNotPaused {
UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.OPERATOR_REWARD_COLLECTOR());
if (liquidationIndexByOperator[account] == 0) revert InvalidInput();
uint256 liquidationIndex = liquidationIndexByOperator[account];
liquidations[liquidationIndexByOperator[account] - 1].isRepaid = true;
liquidations[liquidationIndexByOperator[account] - 1].isClaimed = true;
liquidationIndexByOperator[account] = 0;
emit CompleteLiquidation(liquidationIndex);
}
/**
* @notice Accrue fee then return the up-to-date exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateCurrent() external override returns (uint256) {
accrueFee();
return _exchangeRateStored();
}
/**
* @dev Triggers stopped state.
* Contract must not be paused
*/
function pause() external {
UtilLib.onlyManagerRole(msg.sender, staderConfig);
_pause();
}
/**
* @dev Returns to normal state.
* Contract must be paused
*/
function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
//Setters
/**
* @notice updates protocol fee factor
* @dev only `MANAGER` role can call
* @param _protocolFee value of protocol fee percentage expressed in gwei
*/
function updateProtocolFee(uint256 _protocolFee) external override {
UtilLib.onlyManagerRole(msg.sender, staderConfig);
if (_protocolFee > MAX_PROTOCOL_FEE) {
revert InvalidInput();
}
accrueFee();
protocolFee = _protocolFee;
emit ProtocolFeeFactorUpdated(protocolFee);
}
/**
* @notice updates the utilization rate
* @dev only `MANAGER` role can call
* @param _utilizationRatePerBlock new value of utilization rate per block
*/
function updateUtilizationRatePerBlock(uint256 _utilizationRatePerBlock) external override {
UtilLib.onlyManagerRole(msg.sender, staderConfig);
if (_utilizationRatePerBlock > MAX_UTILIZATION_RATE_PER_BLOCK) {
revert InvalidInput();
}
accrueFee();
utilizationRatePerBlock = _utilizationRatePerBlock;
emit UtilizationRatePerBlockUpdated(utilizationRatePerBlock);
}
/**
* @notice updates the maximum ETH worth of SD utilized per validator
* @dev only `MANAGER` role can call
* @param _maxETHWorthOfSDPerValidator new value of maximum ETH worth of SD utilized per validator
*/
function updateMaxETHWorthOfSDPerValidator(uint256 _maxETHWorthOfSDPerValidator) external override {
UtilLib.onlyManagerRole(msg.sender, staderConfig);
maxETHWorthOfSDPerValidator = _maxETHWorthOfSDPerValidator;
emit UpdatedMaxETHWorthOfSDPerValidator(_maxETHWorthOfSDPerValidator);
}
/**
* @notice updates the batch limit to finalize withdraw request in a single txn
* @dev only `MANAGER` role can call
* @param _finalizationBatchLimit new value of batch limit
*/
function updateFinalizationBatchLimit(uint256 _finalizationBatchLimit) external override {
UtilLib.onlyManagerRole(msg.sender, staderConfig);
finalizationBatchLimit = _finalizationBatchLimit;
emit UpdatedFinalizationBatchLimit(finalizationBatchLimit);
}
/**
* @notice updates the value of minimum block delay to finalize withdraw requests
* @dev only `DEFAULT_ADMIN_ROLE` role can call
* @param _minBlockDelayToFinalizeRequest new value of minBlockDelayToFinalizeRequest
*/
function updateMinBlockDelayToFinalizeRequest(uint256 _minBlockDelayToFinalizeRequest)
external
override
onlyRole(DEFAULT_ADMIN_ROLE)
{
minBlockDelayToFinalizeRequest = _minBlockDelayToFinalizeRequest;
emit UpdatedMinBlockDelayToFinalizeRequest(minBlockDelayToFinalizeRequest);
}
/**
* @notice updates the value of `maxNonRedeemedDelegatorRequestCount`
* @dev only `ADMIN` role can call
* @param _count new count of maxNonRedeemedDelegatorRequest
*/
function updateMaxNonRedeemedDelegatorRequestCount(uint256 _count) external override onlyRole(DEFAULT_ADMIN_ROLE) {
maxNonRedeemedDelegatorRequestCount = _count;
emit UpdatedMaxNonRedeemedDelegatorRequestCount(_count);
}
/// @notice updates the address of staderConfig
function updateStaderConfig(address _staderConfig) external override onlyRole(DEFAULT_ADMIN_ROLE) {
UtilLib.checkNonZeroAddress(_staderConfig);
staderConfig = IStaderConfig(_staderConfig);
emit UpdatedStaderConfig(_staderConfig);
}
/// @notice updates the value of conservativeEthPerKey
/// @dev only `ADMIN` role can call
/// @param _newEthPerKey new value of conservativeEthPerKey
function updateConservativeEthPerKey(uint256 _newEthPerKey) external override onlyRole(DEFAULT_ADMIN_ROLE) {
if (_newEthPerKey == 0) revert InvalidInput();
conservativeEthPerKey = _newEthPerKey;
emit UpdatedConservativeEthPerKey(_newEthPerKey);
}
/**
* @notice Updates the risk configuration
* @param liquidationThreshold The new liquidation threshold percent (1 - 100)
* @param liquidationBonusPercent The new liquidation bonus percent (0 - 100)
* @param liquidationFeePercent The new liquidation fee percent (0 - 100)
* @param ltv The new loan-to-value ratio (1 - 100)
*/
function updateRiskConfig(
uint256 liquidationThreshold,
uint256 liquidationBonusPercent,
uint256 liquidationFeePercent,
uint256 ltv
) external onlyRole(DEFAULT_ADMIN_ROLE) {
_updateRiskConfig(liquidationThreshold, liquidationBonusPercent, liquidationFeePercent, ltv);
}
//Getters
/// @notice return the list of ongoing withdraw requestIds for a user
function getRequestIdsByDelegator(address _delegator) external view override returns (uint256[] memory) {
return requestIdsByDelegatorAddress[_delegator];
}
/**
* @notice Return the utilized balance of account based on stored data
* @param account The address whose balance should be calculated
* @return The calculated balance
*/
function utilizerBalanceStored(address account) external view override returns (uint256) {
return _utilizerBalanceStoredInternal(account);
}
/// @notice Calculates the current delegation rate per block
function getDelegationRatePerBlock() external view override returns (uint256) {
uint256 oneMinusProtocolFeeFactor = DECIMAL - protocolFee;
uint256 rateToPool = (utilizationRatePerBlock * oneMinusProtocolFeeFactor) / DECIMAL;
return (poolUtilization() * rateToPool) / DECIMAL;
}
/**
* @notice Calculates the exchange rate between SD token and corresponding cToken
* @dev This function does not accrue fee before calculating the exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateStored() external view override returns (uint256) {
return _exchangeRateStored();
}
/**
* @notice view function to get utilizer latest utilized balance
* @param _utilizer address of the utilizer
*/
function getUtilizerLatestBalance(address _utilizer) public view override returns (uint256) {
uint256 currentBlockNumber = block.number;
uint256 blockDelta = currentBlockNumber - accrualBlockNumber;
uint256 simpleFeeFactor = utilizationRatePerBlock * blockDelta;
uint256 utilizeIndexNew = Math.ceilDiv((simpleFeeFactor * utilizeIndex), DECIMAL) + utilizeIndex;
UtilizerStruct storage utilizeSnapshot = utilizerData[_utilizer];
if (utilizeSnapshot.principal == 0) {
return 0;
}
return (utilizeSnapshot.principal * utilizeIndexNew) / utilizeSnapshot.utilizeIndex;
}
/**
* @notice view function to get delegator latest SD balance
* @param _delegator address of the delegator
*/
function getDelegatorLatestSDBalance(address _delegator) external view override returns (uint256) {
uint256 latestExchangeRate = getLatestExchangeRate();
return (latestExchangeRate * delegatorCTokenBalance[_delegator]) / DECIMAL;
}
/**
* @notice view function to get latest exchange rate
*/
function getLatestExchangeRate() public view override returns (uint256) {
uint256 currentBlockNumber = block.number;
uint256 blockDelta = currentBlockNumber - accrualBlockNumber;
uint256 simpleFeeFactor = utilizationRatePerBlock * blockDelta;
uint256 feeAccumulated = (simpleFeeFactor * totalUtilizedSD) / DECIMAL;
uint256 totalUtilizedSDNew = feeAccumulated + totalUtilizedSD;
uint256 totalProtocolFeeNew = (protocolFee * feeAccumulated) / DECIMAL + accumulatedProtocolFee;
if (cTokenTotalSupply == 0) {
return DECIMAL;
} else {
uint256 poolBalancePlusUtilizedSDMinusReserves = getPoolAvailableSDBalance() +
totalUtilizedSDNew -
totalProtocolFeeNew;
uint256 exchangeRate = (poolBalancePlusUtilizedSDMinusReserves * DECIMAL) / cTokenTotalSupply;
return exchangeRate;
}
}
function getPoolAvailableSDBalance() public view override returns (uint256) {
return IERC20(staderConfig.getStaderToken()).balanceOf(address(this)) - sdReservedForClaim;
}
/// @notice Calculates the utilization of the utility pool
function poolUtilization() public view override returns (uint256) {
// Utilization is 0 when there are no utilized SD
if (totalUtilizedSD == 0) {
return 0;
}
return (totalUtilizedSD * DECIMAL) / (getPoolAvailableSDBalance() + totalUtilizedSD - accumulatedProtocolFee);
}
/**
* @notice Calculates and returns the user data for a given account
* @param account The address whose utilisation should be calculated
* @return UserData struct containing the user data
*/
function getUserData(address account) public view override returns (UserData memory) {
uint256 totalInterestSD = getUtilizerLatestBalance(account) -
ISDCollateral(staderConfig.getSDCollateral()).operatorUtilizedSDBalance(account);
uint256 totalCollateralInEth = getOperatorTotalEth(account);
uint256 totalCollateralInSD = ISDCollateral(staderConfig.getSDCollateral()).convertETHToSD(
totalCollateralInEth
);
uint256 healthFactor = (totalInterestSD == 0)
? type(uint256).max
: (totalCollateralInSD * riskConfig.liquidationThreshold * DECIMAL) / (totalInterestSD * 100);
return
UserData(
totalInterestSD,
totalCollateralInEth,
healthFactor,
liquidationIndexByOperator[account] == 0
? 0
: liquidations[liquidationIndexByOperator[account] - 1].totalAmountInEth
);
}
/**
* @notice
* @param operator Calculates and returns the conservative estimate of the total Ether (ETH) bonded by a given operator
* plus non claimed ETH from rewards collector.
* @return totalEth The total ETH bonded by the operator
*/
function getOperatorTotalEth(address operator) public view returns (uint256) {
(, , uint256 nonTerminalKeys) = ISDCollateral(staderConfig.getSDCollateral()).getOperatorInfo(operator);
uint256 nonClaimedEth = IOperatorRewardsCollector(staderConfig.getOperatorRewardsCollector()).getBalance(
operator
);
// The actual bonded ETH per non-terminal key is 4 ETH on the beacon chain.
// However, for a conservative estimate in our calculations, we use conservativeEthPerKey (2 ETH).
// This conservative approach accounts for potential slashing risks and withdrawal delays
// associated with ETH staking on the beacon chain.
return nonTerminalKeys * conservativeEthPerKey + nonClaimedEth;
}
/// @notice Returns the liquidation data for a given operator
/// If the operator is not liquidated, the function returns an empty OperatorLiquidation struct
function getOperatorLiquidation(address account) external view override returns (OperatorLiquidation memory) {
if (liquidationIndexByOperator[account] == 0) return OperatorLiquidation(0, 0, 0, false, false, address(0));
return liquidations[liquidationIndexByOperator[account] - 1];
}
/// @notice Returns the liquidation threshold percent
function getLiquidationThreshold() external view returns (uint256) {
return (riskConfig.liquidationThreshold);
}
/**
* @dev Assumes fee has already been accrued up to the current block
* @param sdAmount The amount of the SD token to delegate
*/
function _delegate(uint256 sdAmount) internal {
uint256 exchangeRate = _exchangeRateStored();
if (!IERC20(staderConfig.getStaderToken()).transferFrom(msg.sender, address(this), sdAmount)) {
revert SDTransferFailed();
}
uint256 cTokenShares = (sdAmount * DECIMAL) / exchangeRate;
delegatorCTokenBalance[msg.sender] += cTokenShares;
cTokenTotalSupply += cTokenShares;
emit Delegated(msg.sender, sdAmount, cTokenShares);
}
function _requestWithdraw(uint256 _sdAmountToWithdraw, uint256 cTokenToBurn) internal returns (uint256) {
if (requestIdsByDelegatorAddress[msg.sender].length + 1 > maxNonRedeemedDelegatorRequestCount) {
revert MaxLimitOnWithdrawRequestCountReached();
}
sdRequestedForWithdraw += _sdAmountToWithdraw;
delegatorWithdrawRequests[nextRequestId] = DelegatorWithdrawInfo(
msg.sender,
cTokenToBurn,
_sdAmountToWithdraw,
0,
block.number
);
requestIdsByDelegatorAddress[msg.sender].push(nextRequestId);
emit WithdrawRequestReceived(msg.sender, nextRequestId, _sdAmountToWithdraw);
nextRequestId++;
return nextRequestId - 1;
}
function _utilize(address utilizer, uint256 utilizeAmount) internal {
if (liquidationIndexByOperator[utilizer] != 0) revert AlreadyLiquidated();
UserData memory userData = getUserData(utilizer);
if (userData.healthFactor <= DECIMAL) {
revert UnHealthyPosition();
}
if (getPoolAvailableSDBalance() < utilizeAmount + sdRequestedForWithdraw + accumulatedProtocolFee) {
revert InsufficientPoolBalance();
}
uint256 accountUtilizedPrev = _utilizerBalanceStoredInternal(utilizer);
utilizerData[utilizer].principal = accountUtilizedPrev + utilizeAmount;
utilizerData[utilizer].utilizeIndex = utilizeIndex;
totalUtilizedSD += utilizeAmount;
ISDCollateral(staderConfig.getSDCollateral()).depositSDFromUtilityPool(utilizer, utilizeAmount);
emit SDUtilized(utilizer, utilizeAmount);
}
function _repay(address utilizer, uint256 repayAmount)
internal
returns (uint256 repayAmountFinal, uint256 feePaid)
{
/* We fetch the amount the utilizer owes, with accumulated fee */
uint256 accountUtilizedPrev = _utilizerBalanceStoredInternal(utilizer);
repayAmountFinal = (repayAmount == type(uint256).max || repayAmount > accountUtilizedPrev)
? accountUtilizedPrev
: repayAmount;
if (!IERC20(staderConfig.getStaderToken()).transferFrom(msg.sender, address(this), repayAmountFinal)) {
revert SDTransferFailed();
}
uint256 feeAccrued = accountUtilizedPrev -
ISDCollateral(staderConfig.getSDCollateral()).operatorUtilizedSDBalance(utilizer);
if (!staderConfig.onlyStaderContract(msg.sender, staderConfig.SD_COLLATERAL())) {
if (repayAmountFinal > feeAccrued) {
ISDCollateral(staderConfig.getSDCollateral()).reduceUtilizedSDPosition(
utilizer,
repayAmountFinal - feeAccrued
);
}
}
feePaid = Math.min(repayAmountFinal, feeAccrued);
utilizerData[utilizer].principal = accountUtilizedPrev - repayAmountFinal;
utilizerData[utilizer].utilizeIndex = utilizeIndex;
totalUtilizedSD = totalUtilizedSD > repayAmountFinal ? totalUtilizedSD - repayAmountFinal : 0;
emit Repaid(utilizer, repayAmountFinal);
}
/**
* @notice Return the utilized balance of account based on stored data
* @param account The address whose balance should be calculated
* @return (calculated balance)
*/
function _utilizerBalanceStoredInternal(address account) internal view returns (uint256) {
/* Get utilizeBalance and utilizeIndex */
UtilizerStruct storage utilizerSnapshot = utilizerData[account];
/* If utilizedBalance = 0 then utilizeIndex is likely also 0.
* Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
*/
if (utilizerSnapshot.principal == 0) {
return 0;
}
/* Calculate new utilized balance using the utilize index:
* currentUtilizedBalance = utilizer.principal * utilizeIndex / utilizer.utilizeIndex
*/
return (utilizerSnapshot.principal * utilizeIndex) / utilizerSnapshot.utilizeIndex;
}
/**
* @notice Calculates the exchange rate between SD token and corresponding cToken
* @dev This function does not accrue fee before calculating the exchange rate
* @return calculated exchange rate scaled by 1e18
*/
function _exchangeRateStored() internal view virtual returns (uint256) {
if (cTokenTotalSupply == 0) {
/*
* if cToken supply is zero:
* exchangeRate = initialExchangeRate
*/
return DECIMAL;
} else {
/*
* Otherwise:
* exchangeRate = (poolAvailable SD + totalUtilizedSD - totalProtocolFee) / totalSupply
*/
uint256 poolBalancePlusUtilizedSDMinusReserves = getPoolAvailableSDBalance() +
totalUtilizedSD -
accumulatedProtocolFee;
uint256 exchangeRate = (poolBalancePlusUtilizedSDMinusReserves * DECIMAL) / cTokenTotalSupply;
return exchangeRate;
}
}
/// delete entry from delegatorWithdrawRequests mapping and in requestIdsByDelegatorAddress mapping
function _deleteRequestId(uint256 _requestId) internal {
delete (delegatorWithdrawRequests[_requestId]);
uint256 userRequestCount = requestIdsByDelegatorAddress[msg.sender].length;
uint256[] storage requestIds = requestIdsByDelegatorAddress[msg.sender];
for (uint256 i; i < userRequestCount; ) {
if (_requestId == requestIds[i]) {
requestIds[i] = requestIds[userRequestCount - 1];
requestIds.pop();
return;
}
unchecked {
++i;
}
}
revert CannotFindRequestId();
}
/// @notice Updates the risk configuration
function _updateRiskConfig(
uint256 liquidationThreshold,
uint256 liquidationBonusPercent,
uint256 liquidationFeePercent,
uint256 ltv
) internal {
if (liquidationThreshold > 100 || liquidationThreshold == 0) revert InvalidInput();
if (liquidationBonusPercent > 100) revert InvalidInput();
if (liquidationFeePercent > 100) revert InvalidInput();
if (ltv > 100 || ltv == 0) revert InvalidInput();
riskConfig = RiskConfig({
liquidationThreshold: liquidationThreshold,
liquidationBonusPercent: liquidationBonusPercent,
liquidationFeePercent: liquidationFeePercent,
ltv: ltv
});
emit RiskConfigUpdated(liquidationThreshold, liquidationBonusPercent, liquidationFeePercent, ltv);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
import '../interfaces/IStaderConfig.sol';
import '../interfaces/INodeRegistry.sol';
import '../interfaces/IPoolUtils.sol';
import '../interfaces/IVaultProxy.sol';
library UtilLib {
error ZeroAddress();
error InvalidPubkeyLength();
error CallerNotManager();
error CallerNotOperator();
error CallerNotStaderContract();
error CallerNotWithdrawVault();
error TransferFailed();
uint64 private constant VALIDATOR_PUBKEY_LENGTH = 48;
/// @notice zero address check modifier
function checkNonZeroAddress(address _address) internal pure {
if (_address == address(0)) revert ZeroAddress();
}
//checks for Manager role in staderConfig
function onlyManagerRole(address _addr, IStaderConfig _staderConfig) internal view {
if (!_staderConfig.onlyManagerRole(_addr)) {
revert CallerNotManager();
}
}
function onlyOperatorRole(address _addr, IStaderConfig _staderConfig) internal view {
if (!_staderConfig.onlyOperatorRole(_addr)) {
revert CallerNotOperator();
}
}
//checks if caller is a stader contract address
function onlyStaderContract(
address _addr,
IStaderConfig _staderConfig,
bytes32 _contractName
) internal view {
if (!_staderConfig.onlyStaderContract(_addr, _contractName)) {
revert CallerNotStaderContract();
}
}
function getPubkeyForValidSender(
uint8 _poolId,
uint256 _validatorId,
address _addr,
IStaderConfig _staderConfig
) internal view returns (bytes memory) {
address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
(, bytes memory pubkey, , , address withdrawVaultAddress, , , ) = INodeRegistry(nodeRegistry).validatorRegistry(
_validatorId
);
if (_addr != withdrawVaultAddress) {
revert CallerNotWithdrawVault();
}
return pubkey;
}
function getOperatorForValidSender(
uint8 _poolId,
uint256 _validatorId,
address _addr,
IStaderConfig _staderConfig
) internal view returns (address) {
address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
(, , , , address withdrawVaultAddress, uint256 operatorId, , ) = INodeRegistry(nodeRegistry).validatorRegistry(
_validatorId
);
if (_addr != withdrawVaultAddress) {
revert CallerNotWithdrawVault();
}
(, , , , address operator) = INodeRegistry(nodeRegistry).operatorStructById(operatorId);
return operator;
}
function onlyValidatorWithdrawVault(
uint8 _poolId,
uint256 _validatorId,
address _addr,
IStaderConfig _staderConfig
) internal view {
address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
(, , , , address withdrawVaultAddress, , , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId);
if (_addr != withdrawVaultAddress) {
revert CallerNotWithdrawVault();
}
}
function getOperatorAddressByValidatorId(
uint8 _poolId,
uint256 _validatorId,
IStaderConfig _staderConfig
) internal view returns (address) {
address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
(, , , , , uint256 operatorId, , ) = INodeRegistry(nodeRegistry).validatorRegistry(_validatorId);
(, , , , address operatorAddress) = INodeRegistry(nodeRegistry).operatorStructById(operatorId);
return operatorAddress;
}
function getOperatorAddressByOperatorId(
uint8 _poolId,
uint256 _operatorId,
IStaderConfig _staderConfig
) internal view returns (address) {
address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(_poolId);
(, , , , address operatorAddress) = INodeRegistry(nodeRegistry).operatorStructById(_operatorId);
return operatorAddress;
}
function getOperatorRewardAddress(address _operator, IStaderConfig _staderConfig)
internal
view
returns (address payable)
{
uint8 poolId = IPoolUtils(_staderConfig.getPoolUtils()).getOperatorPoolId(_operator);
address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(poolId);
uint256 operatorId = INodeRegistry(nodeRegistry).operatorIDByAddress(_operator);
return INodeRegistry(nodeRegistry).getOperatorRewardAddress(operatorId);
}
/**
* @notice Computes the public key root.
* @param _pubkey The validator public key for which to compute the root.
* @return The root of the public key.
*/
function getPubkeyRoot(bytes calldata _pubkey) internal pure returns (bytes32) {
if (_pubkey.length != VALIDATOR_PUBKEY_LENGTH) {
revert InvalidPubkeyLength();
}
// Append 16 bytes of zero padding to the pubkey and compute its hash to get the pubkey root.
return sha256(abi.encodePacked(_pubkey, bytes16(0)));
}
function getValidatorSettleStatus(bytes calldata _pubkey, IStaderConfig _staderConfig)
internal
view
returns (bool)
{
uint8 poolId = IPoolUtils(_staderConfig.getPoolUtils()).getValidatorPoolId(_pubkey);
address nodeRegistry = IPoolUtils(_staderConfig.getPoolUtils()).getNodeRegistry(poolId);
uint256 validatorId = INodeRegistry(nodeRegistry).validatorIdByPubkey(_pubkey);
(, , , , address withdrawVaultAddress, , , ) = INodeRegistry(nodeRegistry).validatorRegistry(validatorId);
return IVaultProxy(withdrawVaultAddress).vaultSettleStatus();
}
function computeExchangeRate(
uint256 totalETHBalance,
uint256 totalETHXSupply,
IStaderConfig _staderConfig
) internal view returns (uint256) {
uint256 DECIMALS = _staderConfig.getDecimals();
uint256 newExchangeRate = (totalETHBalance == 0 || totalETHXSupply == 0)
? DECIMALS
: (totalETHBalance * DECIMALS) / totalETHXSupply;
return newExchangeRate;
}
function sendValue(address _receiver, uint256 _amount) internal {
(bool success, ) = payable(_receiver).call{value: _amount}('');
if (!success) {
revert TransferFailed();
}
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
interface IStaderConfig {
// Errors
error InvalidLimits();
error InvalidMinDepositValue();
error InvalidMaxDepositValue();
error InvalidMinWithdrawValue();
error InvalidMaxWithdrawValue();
error IndenticalValue();
// Events
event SetConstant(bytes32 key, uint256 amount);
event SetVariable(bytes32 key, uint256 amount);
event SetAccount(bytes32 key, address newAddress);
event SetContract(bytes32 key, address newAddress);
event SetToken(bytes32 key, address newAddress);
//Contracts
function POOL_UTILS() external view returns (bytes32);
function POOL_SELECTOR() external view returns (bytes32);
function SD_COLLATERAL() external view returns (bytes32);
function OPERATOR_REWARD_COLLECTOR() external view returns (bytes32);
function VAULT_FACTORY() external view returns (bytes32);
function STADER_ORACLE() external view returns (bytes32);
function AUCTION_CONTRACT() external view returns (bytes32);
function PENALTY_CONTRACT() external view returns (bytes32);
function PERMISSIONED_POOL() external view returns (bytes32);
function STAKE_POOL_MANAGER() external view returns (bytes32);
function ETH_DEPOSIT_CONTRACT() external view returns (bytes32);
function PERMISSIONLESS_POOL() external view returns (bytes32);
function USER_WITHDRAW_MANAGER() external view returns (bytes32);
function STADER_INSURANCE_FUND() external view returns (bytes32);
function PERMISSIONED_NODE_REGISTRY() external view returns (bytes32);
function PERMISSIONLESS_NODE_REGISTRY() external view returns (bytes32);
function PERMISSIONED_SOCIALIZING_POOL() external view returns (bytes32);
function PERMISSIONLESS_SOCIALIZING_POOL() external view returns (bytes32);
function NODE_EL_REWARD_VAULT_IMPLEMENTATION() external view returns (bytes32);
function VALIDATOR_WITHDRAWAL_VAULT_IMPLEMENTATION() external view returns (bytes32);
//SD Utility Pool
function SD_UTILITY_POOL() external view returns (bytes32);
function SD_INCENTIVE_CONTROLLER() external view returns (bytes32);
//POR Feed Proxy
function ETH_BALANCE_POR_FEED() external view returns (bytes32);
function ETHX_SUPPLY_POR_FEED() external view returns (bytes32);
//Roles
function MANAGER() external view returns (bytes32);
function OPERATOR() external view returns (bytes32);
// Constants
function getStakedEthPerNode() external view returns (uint256);
function getPreDepositSize() external view returns (uint256);
function getFullDepositSize() external view returns (uint256);
function getDecimals() external view returns (uint256);
function getTotalFee() external view returns (uint256);
function getOperatorMaxNameLength() external view returns (uint256);
// Variables
function getSocializingPoolCycleDuration() external view returns (uint256);
function getSocializingPoolOptInCoolingPeriod() external view returns (uint256);
function getRewardsThreshold() external view returns (uint256);
function getMinDepositAmount() external view returns (uint256);
function getMaxDepositAmount() external view returns (uint256);
function getMinWithdrawAmount() external view returns (uint256);
function getMaxWithdrawAmount() external view returns (uint256);
function getMinBlockDelayToFinalizeWithdrawRequest() external view returns (uint256);
function getWithdrawnKeyBatchSize() external view returns (uint256);
// Accounts
function getAdmin() external view returns (address);
function getStaderTreasury() external view returns (address);
// Contracts
function getPoolUtils() external view returns (address);
function getPoolSelector() external view returns (address);
function getSDCollateral() external view returns (address);
function getOperatorRewardsCollector() external view returns (address);
function getVaultFactory() external view returns (address);
function getStaderOracle() external view returns (address);
function getAuctionContract() external view returns (address);
function getPenaltyContract() external view returns (address);
function getPermissionedPool() external view returns (address);
function getStakePoolManager() external view returns (address);
function getETHDepositContract() external view returns (address);
function getPermissionlessPool() external view returns (address);
function getUserWithdrawManager() external view returns (address);
function getStaderInsuranceFund() external view returns (address);
function getPermissionedNodeRegistry() external view returns (address);
function getPermissionlessNodeRegistry() external view returns (address);
function getPermissionedSocializingPool() external view returns (address);
function getPermissionlessSocializingPool() external view returns (address);
function getNodeELRewardVaultImplementation() external view returns (address);
function getValidatorWithdrawalVaultImplementation() external view returns (address);
function getETHBalancePORFeedProxy() external view returns (address);
function getETHXSupplyPORFeedProxy() external view returns (address);
function getSDUtilityPool() external view returns (address);
function getSDIncentiveController() external view returns (address);
// Tokens
function getStaderToken() external view returns (address);
function getETHxToken() external view returns (address);
//checks roles and stader contracts
function onlyStaderContract(address _addr, bytes32 _contractName) external view returns (bool);
function onlyManagerRole(address account) external view returns (bool);
function onlyOperatorRole(address account) external view returns (bool);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
import './IStaderConfig.sol';
interface ISDIncentiveController {
//errors
error NoRewardsToClaim();
error InvalidEmissionRate();
error InvalidEndBlock();
error InvalidRewardAmount();
error ExistingRewardPeriod();
error SDTransferFailed();
// events
/// @dev Emitted when the Stader configuration contract is updated.
/// @param staderConfig The new Stader configuration contract.
event UpdatedStaderConfig(address staderConfig);
/// @dev Emitted when the emission rate of rewards is updated.
/// @param newEmissionRate The new emission rate that was set.
event EmissionRateUpdated(uint256 newEmissionRate);
/// @dev Emitted when a reward is claimed.
/// @param user The user who claimed the reward.
/// @param reward The amount of reward claimed.
event RewardClaimed(address indexed user, uint256 reward);
/// @dev Emitted when a reward is updated.
/// @param user The user whose reward was updated.
/// @param reward The new reward amount.
event RewardUpdated(address indexed user, uint256 reward);
/// @dev Emitted when the reward end block is updated.
/// @param newRewardEndBlock The new reward end block that was set.
event RewardEndBlockUpdated(uint256 newRewardEndBlock);
// functions
function start(uint256 rewardAmount, uint256 duration) external;
function claim(address account) external;
function updateRewardForAccount(address account) external;
function updateStaderConfig(address _staderConfig) external;
function rewardPerToken() external view returns (uint256);
function earned(address account) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
/**
* @dev Represents user's financial state in the system.
*/
struct UserData {
uint256 totalInterestSD; // Total accrued SD interest for the user.
uint256 totalCollateralInEth; // Total collateral in Eth for the user.
uint256 healthFactor; // Numerical health factor for liquidation risk.
uint256 lockedEth; // Amount of ETH locked for liquidation.
}
/**
* @dev Details of a liquidation event for an operator.
*/
struct OperatorLiquidation {
uint256 totalAmountInEth; // Total ETH involved in liquidation.
uint256 totalBonusInEth; // Bonus ETH in liquidation.
uint256 totalFeeInEth; // Fee ETH collected from liquidation.
bool isRepaid; // Indicates if liquidation is repaid.
bool isClaimed; // Indicates if liquidation is claimed.
address liquidator; // Address of the liquidator.
}
interface ISDUtilityPool {
error InvalidInput();
error NotClaimable();
error AlreadyClaimed();
error NotLiquidator();
error NotLiquidatable();
error SDTransferFailed();
error UnHealthyPosition();
error CannotFindRequestId();
error SDUtilizeLimitReached();
error InvalidWithdrawAmount();
error InvalidAmountOfWithdraw();
error InsufficientPoolBalance();
error CallerNotAuthorizedToRedeem();
error OperatorUtilizedSDBalanceNonZero();
error MaxLimitOnWithdrawRequestCountReached();
error RequestIdNotFinalized(uint256 requestId);
error AlreadyLiquidated();
event WithdrawnProtocolFee(uint256 amount);
event ProtocolFeeFactorUpdated(uint256 protocolFeeFactor);
event UpdatedStaderConfig(address indexed _staderConfig);
event SDUtilized(address utilizer, uint256 utilizeAmount);
event FinalizedWithdrawRequest(uint256 nextRequestIdToFinalize);
event RequestRedeemed(address caller, uint256 sdToTransfer);
event Repaid(address indexed utilizer, uint256 repayAmount);
event UpdatedMaxNonRedeemedDelegatorRequestCount(uint256 count);
event UpdatedFinalizationBatchLimit(uint256 finalizationBatchLimit);
event UtilizationRatePerBlockUpdated(uint256 utilizationRatePerBlock);
event ClearedUtilizerInterest(address indexed utilizer, uint256 sdInterest);
event UpdatedMaxETHWorthOfSDPerValidator(uint256 maxETHWorthOfSDPerValidator);
event Delegated(address indexed delegator, uint256 sdAmount, uint256 sdXToMint);
event Redeemed(address indexed delegator, uint256 sdAmount, uint256 sdXAmount);
event RepaidUtilizedSDBalance(address indexed utilizer, uint256 utilizedSDAmount);
event UpdatedMinBlockDelayToFinalizeRequest(uint256 minBlockDelayToFinalizeRequest);
event LiquidationCall(
address indexed account,
uint256 totalLiquidationAmountInEth,
uint256 liquidationBonusInEth,
uint256 liquidationFeeInEth,
address indexed liquidator
);
event CompleteLiquidation(uint256 indexed index);
event RiskConfigUpdated(
uint256 liquidationThreshold,
uint256 liquidationBonusPercent,
uint256 liquidationFeePercent,
uint256 ltv
);
event AccruedFees(uint256 feeAccumulated, uint256 totalProtocolFee, uint256 totalUtilizedSD);
event WithdrawRequestReceived(address caller, uint256 nextRequestId, uint256 sdAmountToWithdraw);
event UpdatedConservativeEthPerKey(uint256 conservativeEthPerKey);
struct UtilizerStruct {
uint256 principal;
uint256 utilizeIndex;
}
/// @notice structure representing a user request for withdrawal.
struct DelegatorWithdrawInfo {
address owner; // address that can claim on behalf of this request
uint256 amountOfCToken; //amount of CToken to withdraw
uint256 sdExpected; //sd requested at exchangeRate of withdraw
uint256 sdFinalized; // final SD for claiming according to finalization exchange rate
uint256 requestBlock; // block number of withdraw request
}
/**
* @dev Defines risk parameters for liquidations and loans.
*/
struct RiskConfig {
uint256 liquidationThreshold; // Threshold for liquidation (%).
uint256 liquidationBonusPercent; // Bonus for liquidators (%).
uint256 liquidationFeePercent; // Liquidation fee (%).
uint256 ltv; // Loan-to-Value ratio (%).
}
function delegate(uint256 sdAmount) external;
function requestWithdraw(uint256 cTokenAmount) external returns (uint256);
function requestWithdrawWithSDAmount(uint256 sdAmount) external returns (uint256);
function finalizeDelegatorWithdrawalRequest() external;
function claim(uint256 requestId) external;
function utilize(uint256 utilizeAmount) external;
function utilizeWhileAddingKeys(
address operator,
uint256 utilizeAmount,
uint256 nonTerminalKeyCount
) external;
function repayFullAmount() external returns (uint256, uint256);
function repay(uint256 repayAmount) external returns (uint256, uint256);
function repayOnBehalf(address utilizer, uint256 repayAmount) external returns (uint256, uint256);
function completeLiquidation(address account) external;
function withdrawProtocolFee(uint256 _amount) external;
function accrueFee() external;
function liquidationCall(address account) external;
function clearUtilizerInterest(address[] calldata _utilizer) external;
function repayUtilizedSDBalance(address _utilizer, uint256 amount) external;
function utilizerBalanceCurrent(address account) external returns (uint256);
function exchangeRateCurrent() external returns (uint256);
function maxApproveSD() external;
//Setters
function updateProtocolFee(uint256 _protocolFee) external;
function updateUtilizationRatePerBlock(uint256 _utilizationRatePerBlock) external;
function updateMaxETHWorthOfSDPerValidator(uint256 _maxETHWorthOfSDPerValidator) external;
function updateFinalizationBatchLimit(uint256 _finalizationBatchLimit) external;
function updateMinBlockDelayToFinalizeRequest(uint256 _minBlockDelayToFinalizeRequest) external;
function updateMaxNonRedeemedDelegatorRequestCount(uint256 _count) external;
function updateStaderConfig(address _staderConfig) external;
function updateConservativeEthPerKey(uint256 _newEthPerKey) external;
//Getters
function maxETHWorthOfSDPerValidator() external view returns (uint256);
function cTokenTotalSupply() external view returns (uint256);
function totalUtilizedSD() external view returns (uint256);
function delegatorCTokenBalance(address) external view returns (uint256);
function delegatorWithdrawRequestedCTokenCount(address) external view returns (uint256);
function liquidationIndexByOperator(address) external view returns (uint256);
function getPoolAvailableSDBalance() external view returns (uint256);
function sdRequestedForWithdraw() external view returns (uint256);
function accumulatedProtocolFee() external view returns (uint256);
function utilizerBalanceStored(address account) external view returns (uint256);
function getDelegationRatePerBlock() external view returns (uint256);
function utilizationRatePerBlock() external view returns (uint256);
function exchangeRateStored() external view returns (uint256);
function poolUtilization() external view returns (uint256);
function getUtilizerLatestBalance(address _utilizer) external view returns (uint256);
function getDelegatorLatestSDBalance(address _delegator) external view returns (uint256);
function getLatestExchangeRate() external view returns (uint256);
function utilizerData(address) external view returns (uint256 principal, uint256 utilizeIndex);
function getOperatorLiquidation(address) external view returns (OperatorLiquidation memory);
function delegatorWithdrawRequests(uint256)
external
view
returns (
address owner,
uint256 amountOfCToken,
uint256 sdExpected,
uint256 sdFinalized,
uint256 requestBlock
);
function requestIdsByDelegatorAddress(address, uint256) external view returns (uint256);
function getRequestIdsByDelegator(address _owner) external view returns (uint256[] memory);
function getLiquidationThreshold() external view returns (uint256);
function getUserData(address account) external view returns (UserData memory);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
import '../IStaderConfig.sol';
interface ISDCollateral {
struct PoolThresholdInfo {
uint256 minThreshold;
uint256 maxThreshold;
uint256 withdrawThreshold;
string units;
}
// errors
error InsufficientSDToWithdraw(uint256 operatorSDCollateral);
error InvalidPoolId();
error InvalidPoolLimit();
error SDTransferFailed();
error NoStateChange();
error NonTerminalKeysNotZero();
error InsufficientSelfBondToRepay();
// events
event SDRepaid(address operator, uint256 repayAmount);
event UpdatedStaderConfig(address indexed staderConfig);
event SDDeposited(address indexed operator, uint256 sdAmount);
event UtilizedSDDeposited(address indexed operator, uint256 sdAmount);
event SDWithdrawn(address indexed operator, uint256 sdAmount);
event ReducedUtilizedPosition(address indexed operator, uint256 sdAmount);
event UtilizedSDSlashed(address operator, uint256 sdSlashFromUtilized);
event SDSlashed(address indexed operator, address indexed auction, uint256 sdSlashed);
event UpdatedPoolThreshold(uint8 poolId, uint256 minThreshold, uint256 withdrawThreshold);
event UpdatedPoolIdForOperator(uint8 poolId, address operator);
// methods
function depositSDAsCollateral(uint256 _sdAmount) external;
function depositSDAsCollateralOnBehalf(address _operator, uint256 _sdAmount) external;
function depositSDFromUtilityPool(address _operator, uint256 _sdAmount) external;
function reduceUtilizedSDPosition(address operator, uint256 amount) external;
function withdraw(uint256 _requestedSD) external;
function withdrawOnBehalf(uint256 _requestedSD, address _operator) external;
function transferBackUtilizedSD(address _operator) external;
function slashValidatorSD(uint256 _validatorId, uint8 _poolId) external;
function maxApproveSD() external;
// setters
function updateStaderConfig(address _staderConfig) external;
function updatePoolThreshold(
uint8 _poolId,
uint256 _minThreshold,
uint256 _maxThreshold,
uint256 _withdrawThreshold,
string memory _units
) external;
// getters
function staderConfig() external view returns (IStaderConfig);
function operatorSDBalance(address) external view returns (uint256);
function operatorUtilizedSDBalance(address) external view returns (uint256);
function getOperatorWithdrawThreshold(address _operator) external view returns (uint256 operatorWithdrawThreshold);
function hasEnoughSDCollateral(
address _operator,
uint8 _poolId,
uint256 _numValidators
) external view returns (bool);
function getMinimumSDToBond(uint8 _poolId, uint256 _numValidator) external view returns (uint256 _minSDToBond);
function getRemainingSDToBond(
address _operator,
uint8 _poolId,
uint256 _numValidator
) external view returns (uint256);
function getRewardEligibleSD(address _operator) external view returns (uint256 _rewardEligibleSD);
function convertSDToETH(uint256 _sdAmount) external view returns (uint256);
function convertETHToSD(uint256 _ethAmount) external view returns (uint256);
function getOperatorInfo(address _operator)
external
view
returns (
uint8 _poolId,
uint256 _operatorId,
uint256 _validatorCount
);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
import './INodeRegistry.sol';
// Interface for the PoolUtils contract
interface IPoolUtils {
// Errors
error EmptyNameString();
error PoolIdNotPresent();
error MismatchingPoolId();
error PubkeyDoesNotExit();
error PubkeyAlreadyExist();
error NameCrossedMaxLength();
error InvalidLengthOfPubkey();
error OperatorIsNotOnboarded();
error InvalidLengthOfSignature();
error ExistingOrMismatchingPoolId();
// Events
event PoolAdded(uint8 indexed poolId, address poolAddress);
event PoolAddressUpdated(uint8 indexed poolId, address poolAddress);
event DeactivatedPool(uint8 indexed poolId, address poolAddress);
event UpdatedStaderConfig(address staderConfig);
event ExitValidator(bytes pubkey);
event ExitOperator(address indexed operator, uint256 totalAmount);
// returns the details of a specific pool
function poolAddressById(uint8) external view returns (address poolAddress);
function poolIdArray(uint256) external view returns (uint8);
function getPoolIdArray() external view returns (uint8[] memory);
// Pool functions
function addNewPool(uint8 _poolId, address _poolAddress) external;
function updatePoolAddress(uint8 _poolId, address _poolAddress) external;
function processValidatorExitList(bytes[] calldata _pubkeys) external;
function processOperatorExit(address _operator, uint256 totalAmount) external;
function getOperatorTotalNonTerminalKeys(
uint8 _poolId,
address _nodeOperator,
uint256 _startIndex,
uint256 _endIndex
) external view returns (uint256);
function getSocializingPoolAddress(uint8 _poolId) external view returns (address);
// Pool getters
function getProtocolFee(uint8 _poolId) external view returns (uint256); // returns the protocol fee (0-10000)
function getOperatorFee(uint8 _poolId) external view returns (uint256); // returns the operator fee (0-10000)
function getTotalActiveValidatorCount() external view returns (uint256); //returns total active validators across all pools
function getActiveValidatorCountByPool(uint8 _poolId) external view returns (uint256); // returns the total number of active validators in a specific pool
function getQueuedValidatorCountByPool(uint8 _poolId) external view returns (uint256); // returns the total number of queued validators in a specific pool
function getCollateralETH(uint8 _poolId) external view returns (uint256);
function getNodeRegistry(uint8 _poolId) external view returns (address);
// check for duplicate pubkey across all pools
function isExistingPubkey(bytes calldata _pubkey) external view returns (bool);
// check for duplicate operator across all pools
function isExistingOperator(address _operAddr) external view returns (bool);
function isExistingPoolId(uint8 _poolId) external view returns (bool);
function getOperatorPoolId(address _operAddr) external view returns (uint8);
function getValidatorPoolId(bytes calldata _pubkey) external view returns (uint8);
function onlyValidName(string calldata _name) external;
function onlyValidKeys(
bytes calldata _pubkey,
bytes calldata _preDepositSignature,
bytes calldata _depositSignature
) external;
function calculateRewardShare(uint8 _poolId, uint256 _totalRewards)
external
view
returns (
uint256 userShare,
uint256 operatorShare,
uint256 protocolShare
);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
interface IOperatorRewardsCollector {
//errors
error InsufficientBalance();
error WethTransferFailed();
// events
event UpdatedStaderConfig(address indexed staderConfig);
event Claimed(address indexed receiver, uint256 amount);
event DepositedFor(address indexed sender, address indexed receiver, uint256 amount);
event UpdatedWethAddress(address indexed weth);
// methods
function depositFor(address _receiver) external payable;
function claim() external;
function claimLiquidation(address operator) external;
function withdrawableInEth(address operator) external view returns (uint256);
function getBalance(address operator) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.1) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
StringsUpgradeable.toHexString(account),
" is missing role ",
StringsUpgradeable.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
import '../library/ValidatorStatus.sol';
struct Validator {
ValidatorStatus status; // status of validator
bytes pubkey; //pubkey of the validator
bytes preDepositSignature; //signature for 1 ETH deposit on beacon chain
bytes depositSignature; //signature for 31 ETH deposit on beacon chain
address withdrawVaultAddress; //withdrawal vault address of validator
uint256 operatorId; // stader network assigned Id
uint256 depositBlock; // block number of the 31ETH deposit
uint256 withdrawnBlock; //block number when oracle report validator as withdrawn
}
struct Operator {
bool active; // operator status
bool optedForSocializingPool; // operator opted for socializing pool
string operatorName; // name of the operator
address payable operatorRewardAddress; //Eth1 address of node for reward
address operatorAddress; //address of operator to interact with stader
}
// Interface for the NodeRegistry contract
interface INodeRegistry {
// Errors
error DuplicatePoolIDOrPoolNotAdded();
error OperatorAlreadyOnBoardedInProtocol();
error maxKeyLimitReached();
error OperatorNotOnBoarded();
error InvalidKeyCount();
error InvalidStartAndEndIndex();
error OperatorIsDeactivate();
error MisMatchingInputKeysSize();
error PageNumberIsZero();
error UNEXPECTED_STATUS();
error PubkeyAlreadyExist();
error NotEnoughSDCollateral();
error TooManyVerifiedKeysReported();
error TooManyWithdrawnKeysReported();
error CallerNotExistingRewardAddress();
error CallerNotNewRewardAddress();
// Events
event AddedValidatorKey(address indexed nodeOperator, bytes pubkey, uint256 validatorId);
event ValidatorMarkedAsFrontRunned(bytes pubkey, uint256 validatorId);
event ValidatorWithdrawn(bytes pubkey, uint256 validatorId);
event ValidatorStatusMarkedAsInvalidSignature(bytes pubkey, uint256 validatorId);
event UpdatedValidatorDepositBlock(uint256 validatorId, uint256 depositBlock);
event UpdatedMaxNonTerminalKeyPerOperator(uint64 maxNonTerminalKeyPerOperator);
event UpdatedInputKeyCountLimit(uint256 batchKeyDepositLimit);
event UpdatedStaderConfig(address staderConfig);
event RewardAddressProposed(address indexed nodeOperator, address indexed rewardAddress);
event OperatorRewardAddressUpdated(address indexed nodeOperator, address indexed rewardAddress);
event UpdatedOperatorName(address indexed nodeOperator, string operatorName);
event IncreasedTotalActiveValidatorCount(uint256 totalActiveValidatorCount);
event UpdatedVerifiedKeyBatchSize(uint256 verifiedKeysBatchSize);
event UpdatedWithdrawnKeyBatchSize(uint256 withdrawnKeysBatchSize);
event DecreasedTotalActiveValidatorCount(uint256 totalActiveValidatorCount);
function withdrawnValidators(bytes[] calldata _pubkeys) external;
function markValidatorReadyToDeposit(
bytes[] calldata _readyToDepositPubkey,
bytes[] calldata _frontRunPubkey,
bytes[] calldata _invalidSignaturePubkey
) external;
// return validator struct for a validator Id
function validatorRegistry(uint256)
external
view
returns (
ValidatorStatus status,
bytes calldata pubkey,
bytes calldata preDepositSignature,
bytes calldata depositSignature,
address withdrawVaultAddress,
uint256 operatorId,
uint256 depositTime,
uint256 withdrawnTime
);
// returns the operator struct given operator Id
function operatorStructById(uint256)
external
view
returns (
bool active,
bool optedForSocializingPool,
string calldata operatorName,
address payable operatorRewardAddress,
address operatorAddress
);
// Returns the last block the operator changed the opt-in status for socializing pool
function getSocializingPoolStateChangeBlock(uint256 _operatorId) external view returns (uint256);
function getAllActiveValidators(uint256 _pageNumber, uint256 _pageSize) external view returns (Validator[] memory);
function getValidatorsByOperator(
address _operator,
uint256 _pageNumber,
uint256 _pageSize
) external view returns (Validator[] memory);
/**
*
* @param _nodeOperator @notice operator total non withdrawn keys within a specified validator list
* @param _startIndex start index in validator queue to start with
* @param _endIndex up to end index of validator queue to to count
*/
function getOperatorTotalNonTerminalKeys(
address _nodeOperator,
uint256 _startIndex,
uint256 _endIndex
) external view returns (uint64);
// returns the total number of queued validators across all operators
function getTotalQueuedValidatorCount() external view returns (uint256);
// returns the total number of active validators across all operators
function getTotalActiveValidatorCount() external view returns (uint256);
function getCollateralETH() external view returns (uint256);
function getOperatorTotalKeys(uint256 _operatorId) external view returns (uint256 totalKeys);
function operatorIDByAddress(address) external view returns (uint256);
function getOperatorRewardAddress(uint256 _operatorId) external view returns (address payable);
function isExistingPubkey(bytes calldata _pubkey) external view returns (bool);
function isExistingOperator(address _operAddr) external view returns (bool);
function POOL_ID() external view returns (uint8);
function inputKeyCountLimit() external view returns (uint16);
function nextOperatorId() external view returns (uint256);
function nextValidatorId() external view returns (uint256);
function maxNonTerminalKeyPerOperator() external view returns (uint64);
function verifiedKeyBatchSize() external view returns (uint256);
function totalActiveValidatorCount() external view returns (uint256);
function validatorIdByPubkey(bytes calldata _pubkey) external view returns (uint256);
function validatorIdsByOperatorId(uint256, uint256) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
import './IStaderConfig.sol';
interface IVaultProxy {
error CallerNotOwner();
error AlreadyInitialized();
event UpdatedOwner(address owner);
event UpdatedStaderConfig(address staderConfig);
//Getters
function vaultSettleStatus() external view returns (bool);
function isValidatorWithdrawalVault() external view returns (bool);
function isInitialized() external view returns (bool);
function poolId() external view returns (uint8);
function id() external view returns (uint256);
function owner() external view returns (address);
function staderConfig() external view returns (IStaderConfig);
//Setters
function updateOwner() external;
function updateStaderConfig(address _staderConfig) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.1) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* 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.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Internal function that returns the initialized version. Returns `_initialized`
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Internal function that returns the initialized version. Returns `_initializing`
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.1) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;
enum ValidatorStatus {
INITIALIZED,
INVALID_SIGNATURE,
FRONT_RUN,
PRE_DEPOSIT,
DEPOSITED,
WITHDRAWN
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.1) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0-rc.1) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@chainlink/=node_modules/@chainlink/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@uniswap/=node_modules/@uniswap/",
"base64-sol/=node_modules/base64-sol/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/",
"hardhat/=node_modules/hardhat/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"AlreadyLiquidated","type":"error"},{"inputs":[],"name":"CallerNotAuthorizedToRedeem","type":"error"},{"inputs":[],"name":"CallerNotManager","type":"error"},{"inputs":[],"name":"CallerNotStaderContract","type":"error"},{"inputs":[],"name":"CannotFindRequestId","type":"error"},{"inputs":[],"name":"InsufficientPoolBalance","type":"error"},{"inputs":[],"name":"InvalidAmountOfWithdraw","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidWithdrawAmount","type":"error"},{"inputs":[],"name":"MaxLimitOnWithdrawRequestCountReached","type":"error"},{"inputs":[],"name":"NotClaimable","type":"error"},{"inputs":[],"name":"NotLiquidatable","type":"error"},{"inputs":[],"name":"NotLiquidator","type":"error"},{"inputs":[],"name":"OperatorUtilizedSDBalanceNonZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"RequestIdNotFinalized","type":"error"},{"inputs":[],"name":"SDTransferFailed","type":"error"},{"inputs":[],"name":"SDUtilizeLimitReached","type":"error"},{"inputs":[],"name":"UnHealthyPosition","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feeAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalProtocolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalUtilizedSD","type":"uint256"}],"name":"AccruedFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"utilizer","type":"address"},{"indexed":false,"internalType":"uint256","name":"sdInterest","type":"uint256"}],"name":"ClearedUtilizerInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"}],"name":"CompleteLiquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":false,"internalType":"uint256","name":"sdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sdXToMint","type":"uint256"}],"name":"Delegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nextRequestIdToFinalize","type":"uint256"}],"name":"FinalizedWithdrawRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalLiquidationAmountInEth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationBonusInEth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationFeeInEth","type":"uint256"},{"indexed":true,"internalType":"address","name":"liquidator","type":"address"}],"name":"LiquidationCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"protocolFeeFactor","type":"uint256"}],"name":"ProtocolFeeFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":false,"internalType":"uint256","name":"sdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sdXAmount","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"utilizer","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"Repaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"utilizer","type":"address"},{"indexed":false,"internalType":"uint256","name":"utilizedSDAmount","type":"uint256"}],"name":"RepaidUtilizedSDBalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"sdToTransfer","type":"uint256"}],"name":"RequestRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"liquidationThreshold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationBonusPercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationFeePercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ltv","type":"uint256"}],"name":"RiskConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"utilizer","type":"address"},{"indexed":false,"internalType":"uint256","name":"utilizeAmount","type":"uint256"}],"name":"SDUtilized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"conservativeEthPerKey","type":"uint256"}],"name":"UpdatedConservativeEthPerKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"finalizationBatchLimit","type":"uint256"}],"name":"UpdatedFinalizationBatchLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxETHWorthOfSDPerValidator","type":"uint256"}],"name":"UpdatedMaxETHWorthOfSDPerValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"}],"name":"UpdatedMaxNonRedeemedDelegatorRequestCount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minBlockDelayToFinalizeRequest","type":"uint256"}],"name":"UpdatedMinBlockDelayToFinalizeRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_staderConfig","type":"address"}],"name":"UpdatedStaderConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"utilizationRatePerBlock","type":"uint256"}],"name":"UtilizationRatePerBlockUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"nextRequestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sdAmountToWithdraw","type":"uint256"}],"name":"WithdrawRequestReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawnProtocolFee","type":"event"},{"inputs":[],"name":"DECIMAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PROTOCOL_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_UTILIZATION_RATE_PER_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_SD_DELEGATE_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_SD_WITHDRAW_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accumulatedProtocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cTokenTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_utilizer","type":"address[]"}],"name":"clearUtilizerInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"completeLiquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"conservativeEthPerKey","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sdAmount","type":"uint256"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegatorCTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegatorWithdrawRequestedCTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"delegatorWithdrawRequests","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"amountOfCToken","type":"uint256"},{"internalType":"uint256","name":"sdExpected","type":"uint256"},{"internalType":"uint256","name":"sdFinalized","type":"uint256"},{"internalType":"uint256","name":"requestBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalizationBatchLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalizeDelegatorWithdrawalRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDelegationRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegator","type":"address"}],"name":"getDelegatorLatestSDBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLiquidationThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getOperatorLiquidation","outputs":[{"components":[{"internalType":"uint256","name":"totalAmountInEth","type":"uint256"},{"internalType":"uint256","name":"totalBonusInEth","type":"uint256"},{"internalType":"uint256","name":"totalFeeInEth","type":"uint256"},{"internalType":"bool","name":"isRepaid","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"},{"internalType":"address","name":"liquidator","type":"address"}],"internalType":"struct OperatorLiquidation","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"getOperatorTotalEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolAvailableSDBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegator","type":"address"}],"name":"getRequestIdsByDelegator","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getUserData","outputs":[{"components":[{"internalType":"uint256","name":"totalInterestSD","type":"uint256"},{"internalType":"uint256","name":"totalCollateralInEth","type":"uint256"},{"internalType":"uint256","name":"healthFactor","type":"uint256"},{"internalType":"uint256","name":"lockedEth","type":"uint256"}],"internalType":"struct UserData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_utilizer","type":"address"}],"name":"getUtilizerLatestBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_staderConfig","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"liquidationCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"liquidationIndexByOperator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"liquidations","outputs":[{"internalType":"uint256","name":"totalAmountInEth","type":"uint256"},{"internalType":"uint256","name":"totalBonusInEth","type":"uint256"},{"internalType":"uint256","name":"totalFeeInEth","type":"uint256"},{"internalType":"bool","name":"isRepaid","type":"bool"},{"internalType":"bool","name":"isClaimed","type":"bool"},{"internalType":"address","name":"liquidator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxApproveSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxETHWorthOfSDPerValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxNonRedeemedDelegatorRequestCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minBlockDelayToFinalizeRequest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRequestIdToFinalize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolUtilization","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repay","outputs":[{"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"internalType":"uint256","name":"feePaid","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repayFullAmount","outputs":[{"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"internalType":"uint256","name":"feePaid","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"utilizer","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayOnBehalf","outputs":[{"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"internalType":"uint256","name":"feePaid","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_utilizer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repayUtilizedSDBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"requestIdsByDelegatorAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cTokenAmount","type":"uint256"}],"name":"requestWithdraw","outputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sdAmount","type":"uint256"}],"name":"requestWithdrawWithSDAmount","outputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"riskConfig","outputs":[{"internalType":"uint256","name":"liquidationThreshold","type":"uint256"},{"internalType":"uint256","name":"liquidationBonusPercent","type":"uint256"},{"internalType":"uint256","name":"liquidationFeePercent","type":"uint256"},{"internalType":"uint256","name":"ltv","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sdRequestedForWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sdReservedForClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"staderConfig","outputs":[{"internalType":"contract IStaderConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUtilizedSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newEthPerKey","type":"uint256"}],"name":"updateConservativeEthPerKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_finalizationBatchLimit","type":"uint256"}],"name":"updateFinalizationBatchLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxETHWorthOfSDPerValidator","type":"uint256"}],"name":"updateMaxETHWorthOfSDPerValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_count","type":"uint256"}],"name":"updateMaxNonRedeemedDelegatorRequestCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minBlockDelayToFinalizeRequest","type":"uint256"}],"name":"updateMinBlockDelayToFinalizeRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_protocolFee","type":"uint256"}],"name":"updateProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidationThreshold","type":"uint256"},{"internalType":"uint256","name":"liquidationBonusPercent","type":"uint256"},{"internalType":"uint256","name":"liquidationFeePercent","type":"uint256"},{"internalType":"uint256","name":"ltv","type":"uint256"}],"name":"updateRiskConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staderConfig","type":"address"}],"name":"updateStaderConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_utilizationRatePerBlock","type":"uint256"}],"name":"updateUtilizationRatePerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"utilizationRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"utilizeAmount","type":"uint256"}],"name":"utilize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"utilizeIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"utilizeAmount","type":"uint256"},{"internalType":"uint256","name":"nonTerminalKeyCount","type":"uint256"}],"name":"utilizeWhileAddingKeys","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"utilizerBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"utilizerBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"utilizerData","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"utilizeIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e4565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e2576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615cdc80620000f46000396000f3fe608060405234801561001057600080fd5b50600436106105965760003560e01c80636d00679c116102e2578063abf9db0211610191578063c51cd1cc116100ee578063da695857116100a2578063ec29c5511161007c578063ec29c55114610c07578063ee63e5f914610c1a578063ffc9896b14610c2d57600080fd5b8063da69585714610b73578063e41b55d914610b7b578063e65efbe414610bf457600080fd5b8063d2ac4a3d116100d3578063d2ac4a3d14610b3a578063d547741f14610b4d578063d844cb6c14610b6057600080fd5b8063c51cd1cc14610b14578063cb2d89dd14610b2757600080fd5b8063b8ca3b8311610145578063bc1428f61161012a578063bc1428f614610afa578063bd6d894d14610b03578063c083f3e614610b0b57600080fd5b8063b8ca3b8314610ae2578063bbb8436214610af157600080fd5b8063b0e21e8a11610176578063b0e21e8a14610ac3578063b26cc39414610acc578063b4c1273b14610ad457600080fd5b8063abf9db0214610a90578063aeea5af714610ab057600080fd5b8063962c70701161023f5780639f689e0b116101f3578063a217fddf116101d8578063a217fddf14610a32578063a544a62c14610a3a578063a66c84f414610a4357600080fd5b80639f689e0b14610a0c5780639fa6dd3514610a1f57600080fd5b80639a3263ee116102245780639a3263ee146109ca5780639e070088146109d25780639ee804cb146109f957600080fd5b8063962c7070146109a157806399775f40146109aa57600080fd5b80637844e3af116102965780638456cb591161027b5780638456cb59146109575780638763a3281461095f57806391d148541461096857600080fd5b80637844e3af1461090e5780637c90a6ca1461092157600080fd5b80636f2bd0b2116102c75780636f2bd0b2146108ea57806371898b4e146108f3578063745400c9146108fb57600080fd5b80636d00679c146108cf5780636e236aee146108d757600080fd5b806337a4adf7116104495780634e7878ee116103a657806362569a511161035a5780636a84a985116103345780636a84a985146108ae5780636ab55fd9146108b75780636c540baf146108c657600080fd5b806362569a5114610872578063634c48c714610885578063673ab3fa1461088e57600080fd5b8063531810bc1161038b578063531810bc146108485780635393618e146108545780635c975abb1461086757600080fd5b80634e7878ee1461081c5780634f8f7a371461082857600080fd5b80634256dd78116103fd578063490ffa35116103e2578063490ffa35146107d65780634a2965af146108015780634ae9b8bc1461081457600080fd5b80634256dd78146107b0578063485cc955146107c357600080fd5b80633e04cd351161042e5780633e04cd351461078d5780633f4ba83a14610795578063424cd8331461079d57600080fd5b806337a4adf71461077b5780633b92e3cf1461078457600080fd5b8063248a9ca3116104f757806334d093f6116104ab57806336978412116104905780633697841214610742578063371fd8e614610755578063379607f51461076857600080fd5b806334d093f61461072757806336568abe1461072f57600080fd5b80632807c313116104dc5780632807c313146107025780632b8869411461070b5780632f2ff15d1461071457600080fd5b8063248a9ca3146106cc578063267fca73146106ef57600080fd5b806320552a6e1161054e5780632229152811610533578063222915281461069d578063232d70c3146106b057806323c4ac1a146106b957600080fd5b806320552a6e1461066d5780632170c14c1461068a57600080fd5b806312372ffe1161057f57806312372ffe146105d8578063182df0f5146106445780631c557f051461065a57600080fd5b8063019f0aa91461059b57806301ffc9a7146105b0575b600080fd5b6105ae6105a936600461578c565b610c73565b005b6105c36105be3660046157b8565b610eed565b60405190151581526020015b60405180910390f35b6105eb6105e63660046157fa565b610f86565b6040516105cf9190600060c0820190508251825260208301516020830152604083015160408301526060830151151560608301526080830151151560808301526001600160a01b0360a08401511660a083015292915050565b61064c6110b2565b6040519081526020016105cf565b6105ae610668366004615817565b6110c1565b610675611143565b604080519283526020830191909152016105cf565b61064c6106983660046157fa565b611177565b61064c6106ab3660046157fa565b61139b565b61064c60e45481565b6105ae6106c7366004615830565b6113e7565b61064c6106da366004615817565b60009081526065602052604090206001015490565b6105ae6106fd366004615817565b611647565b61064c60d05481565b61064c60d55481565b6105ae610722366004615865565b61169a565b61064c6116c4565b6105ae61073d366004615865565b6117c5565b61064c6107503660046157fa565b611870565b610675610763366004615817565b61191c565b6105ae610776366004615817565b611939565b61064c60cf5481565b61064c60d35481565b6105ae611c97565b6105ae611e4e565b6105ae6107ab366004615817565b611e64565b6105ae6107be366004615817565b6120ea565b6105ae6107d1366004615895565b612180565b60d8546107e9906001600160a01b031681565b6040516001600160a01b0390911681526020016105cf565b6105ae61080f366004615817565b6123eb565b60d95461064c565b61064c6416262714cf81565b61064c6108363660046157fa565b60e06020526000908152604090205481565b61064c64e8d4a5100081565b6105ae610862366004615817565b61242b565b60975460ff166105c3565b6105ae6108803660046158c3565b612477565b61064c60cb5481565b61064c61089c3660046157fa565b60e36020526000908152604090205481565b61064c60d25481565b61064c670de0b6b3a764000081565b61064c60ca5481565b61064c612495565b61064c6108e53660046157fa565b612502565b61064c60d45481565b6105ae61250d565b61064c610909366004615817565b6127f4565b61064c61091c36600461578c565b612911565b60d95460da5460db5460dc546109379392919084565b6040805194855260208501939093529183015260608201526080016105cf565b6105ae612942565b61064c60cc5481565b6105c3610976366004615865565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b61064c60ce5481565b6109bd6109b83660046157fa565b612963565b6040516105cf91906158f5565b61064c6129cf565b6106756109e03660046157fa565b60de602052600090815260409020805460019091015482565b6105ae610a073660046157fa565b612a23565b610675610a1a36600461578c565b612a9a565b6105ae610a2d366004615817565b612ac2565b61064c600081565b61064c60cd5481565b610a56610a51366004615817565b612c07565b6040805196875260208701959095529385019290925215156060840152151560808301526001600160a01b031660a082015260c0016105cf565b61064c610a9e3660046157fa565b60df6020526000908152604090205481565b6105ae610abe366004615939565b612c5f565b61064c60c95481565b6105ae612e77565b61064c66038d7ea4c6800081565b61064c67016345785d8a000081565b61064c60d15481565b61064c60d65481565b61064c612f94565b61064c60d75481565b61064c610b22366004615817565b612fa6565b6105ae610b35366004615817565b6130bf565b6105ae610b483660046157fa565b613152565b6105ae610b5b366004615865565b613659565b6105ae610b6e3660046157fa565b61367e565b61064c613862565b610bc2610b89366004615817565b60e160205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0390931693919290919085565b604080516001600160a01b0390961686526020860194909452928401919091526060830152608082015260a0016105cf565b61064c610c023660046157fa565b61397a565b6105ae610c15366004615817565b61398d565b6105ae610c28366004615817565b613c02565b610c40610c3b3660046157fa565b613c42565b6040516105cf91908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b60d854604080517ff122961f0000000000000000000000000000000000000000000000000000000081529051610d069233926001600160a01b0390911691829163f122961f9160048083019260209291908290030181865afa158015610cdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0191906159ae565b613f75565b610d0e612e77565b60d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8591906159c7565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526001600160a01b0391909116906323b872dd906064016020604051808303816000875af1158015610df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1791906159e4565b610e4d576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e5883614035565b9050610e648282615a35565b6001600160a01b038416600090815260de6020526040902090815560cb5460019091015560cc548210610e98576000610ea6565b8160cc54610ea69190615a35565b60cc556040518281526001600160a01b038416907f37057a3afa8d7c32b75c4534845b8e937e76c0f9cf30fbe71122af20c33646dd906020015b60405180910390a2505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610f8057507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6040805160c08101825260008082526020808301829052828401829052606083018290526080830182905260a083018290526001600160a01b038516825260e390529182205490910361100a5750506040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6001600160a01b038216600090815260e3602052604090205460dd9061103290600190615a35565b8154811061104257611042615a48565b60009182526020918290206040805160c08101825260049093029091018054835260018101549383019390935260028301549082015260039091015460ff80821615156060840152610100820416151560808301526001600160a01b03620100009091041660a082015292915050565b60006110bc614072565b905090565b60006110cc816140ca565b81600003611106576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60e48290556040518281527f475227c841ac4234d6b624ffe157a80f62c0b4d66161f98684c2fc2ad79bdf52906020015b60405180910390a15050565b60008061114e6140d4565b611156612e77565b600061116133614035565b905061116d3382614141565b9094909350915050565b60008060d860009054906101000a90046001600160a01b03166001600160a01b031663aa9537956040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f191906159c7565b6040517f27d9ab5d0000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015291909116906327d9ab5d90602401606060405180830381865afa158015611252573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112769190615a77565b92505050600060d860009054906101000a90046001600160a01b03166001600160a01b031663278671bb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f391906159c7565b6040517ff8b2cb4f0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152919091169063f8b2cb4f90602401602060405180830381865afa158015611354573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137891906159ae565b90508060e454836113899190615ab4565b6113939190615ad3565b949350505050565b6000806113a66116c4565b6001600160a01b038416600090815260df6020526040902054909150670de0b6b3a7640000906113d69083615ab4565b6113e09190615ae6565b9392505050565b6113ef6140d4565b60d854604080517f152a91da00000000000000000000000000000000000000000000000000000000815290516114599233926001600160a01b0390911691829163152a91da9160048083019260209291908290030181865afa158015610cdd573d6000803e3d6000fd5b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa1580156114bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e091906159c7565b6040517fb11a3a9b0000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015291925060009183169063b11a3a9b90602401602060405180830381865afa158015611545573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156991906159ae565b90506000826001600160a01b031663e614e17c60d0546040518263ffffffff1660e01b815260040161159d91815260200190565b602060405180830381865afa1580156115ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115de91906159ae565b6115e89085615ab4565b9050806115f58684615ad3565b111561162d576040517fdb8f07da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611635612e77565b61163f8686614690565b505050505050565b60d85461165e9033906001600160a01b0316614925565b60d48190556040518181527f7ffbe87ac4b7820fd4ca4ac8c7c7820cc79c7cdd9631ac083c06bb833be63587906020015b60405180910390a150565b6000828152606560205260409020600101546116b5816140ca565b6116bf83836149de565b505050565b60ca54600090439082906116d89083615a35565b905060008160ce546116ea9190615ab4565b90506000670de0b6b3a764000060cc54836117059190615ab4565b61170f9190615ae6565b9050600060cc54826117219190615ad3565b9050600060cd54670de0b6b3a76400008460c95461173f9190615ab4565b6117499190615ae6565b6117539190615ad3565b905060cf5460000361177357670de0b6b3a7640000965050505050505090565b6000818361177f613862565b6117899190615ad3565b6117939190615a35565b9050600060cf54670de0b6b3a7640000836117ae9190615ab4565b6117b89190615ae6565b9998505050505050505050565b6001600160a01b0381163314611862576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61186c8282614a80565b5050565b60ca54600090439082906118849083615a35565b905060008160ce546118969190615ab4565b60cb549091506000906118ba6118ac8285615ab4565b670de0b6b3a7640000614b03565b6118c49190615ad3565b6001600160a01b038716600090815260de6020526040812080549293509190036118f5575060009695505050505050565b60018101548154611907908490615ab4565b6119119190615ae6565b979650505050505050565b6000806119276140d4565b61192f612e77565b61116d3384614141565b6119416140d4565b60d154811061197f576040517fc219f93500000000000000000000000000000000000000000000000000000000815260048101829052602401611859565b600081815260e16020908152604091829020825160a08101845281546001600160a01b0316808252600183015493820193909352600282015493810193909352600381015460608401526004015460808301523314611a0a576040517f7f1cdd1500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000816060015190508060d56000828254611a259190615a35565b90915550611a34905083614b3a565b60d860009054906101000a90046001600160a01b03166001600160a01b031663a9fe1b336040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aab91906159c7565b6040517f1e83409a0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b039190911690631e83409a90602401600060405180830381600087803b158015611b0757600080fd5b505af1158015611b1b573d6000803e3d6000fd5b5050505060d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9691906159c7565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390526001600160a01b03919091169063a9059cbb906044016020604051808303816000875af1158015611bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2291906159e4565b611c58576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051338152602081018390527ff7aca15eb385953329daa8e235ce29ead201e26c1e36e1083d929821401bb7d291015b60405180910390a1505050565b611c9f6140d4565b60d854611cb69033906001600160a01b0316614925565b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa158015611d19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3d91906159c7565b9050611d4881614c73565b60d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbf91906159c7565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301526000196024830152919091169063095ea7b3906044016020604051808303816000875af1158015611e2a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186c91906159e4565b6000611e59816140ca565b611e61614cb3565b50565b611e6c6140d4565b60d854611e839033906001600160a01b0316614925565b611e8b612e77565b60cd54811180611ea15750611e9e613862565b81115b15611ed8576040517fdb73cdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060cd6000828254611eea9190615a35565b909155505060d854604080517fe069f71400000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169163e069f714916004808201926020929091908290030181865afa158015611f52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7691906159c7565b6001600160a01b031663a9059cbb60d860009054906101000a90046001600160a01b03166001600160a01b03166372ce78b06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffb91906159c7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015612060573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208491906159e4565b6120ba576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518181527fa32a67c2a472d948ee4cdcce3fdf2df7a9a99b762c69858f0651b1b22067efdf9060200161168f565b60d8546121019033906001600160a01b0316614925565b67016345785d8a0000811115612143576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61214b612e77565b60c98190556040518181527fba813ee7ea736ec5148f515c7fe651c522fa84413c6c5ce693bd74abade775d39060200161168f565b600054610100900460ff16158080156121a05750600054600160ff909116105b806121ba5750303b1580156121ba575060005460ff166001145b612246576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611859565b6000805460ff19166001179055801561228657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61228f83614c73565b61229882614c73565b6122a0614d05565b6122a8614d9c565b60d880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038416179055670de0b6b3a764000060cb8190556408dc0fa1ec60ce55600060c955600160d281905560d155603260d48190554360ca5561c4e060d6556103e860d75560d091909155671bc16d674ec8000060e45561233c90604690601e90600590614e3b565b6123476000846149de565b612358670de0b6b3a7640000614fb0565b6040516001600160a01b038316907fdb2219043d7b197cb235f1af0cf6d782d77dee3de19e3f4fb6d39aae633b448590600090a280156116bf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c8a565b60006123f6816140ca565b60d68290556040518281527faa3bf534da453100a74c0c499340ebed87ce7f16483706a8b1e5ca11b998278990602001611137565b60d8546124429033906001600160a01b0316614925565b60d08190556040518181527f9491876f555a700a2938143a5a27937708ab194a6f8d94cd7eb8eefae92f34f59060200161168f565b6000612482816140ca565b61248e85858585614e3b565b5050505050565b60008060c954670de0b6b3a76400006124ae9190615a35565b90506000670de0b6b3a76400008260ce546124c99190615ab4565b6124d39190615ae6565b9050670de0b6b3a7640000816124e76129cf565b6124f19190615ab4565b6124fb9190615ae6565b9250505090565b6000610f8082614035565b6125156140d4565b61251d612e77565b6000612527614072565b9050600061254660d25460d45460d1546125419190615ad3565b615194565b60d15490915060005b8282101561279957600082815260e160209081526040808320815160a08101835281546001600160a01b0316815260018201549381018490526002820154928101839052600382015460608201526004909101546080820152929091906125cd83670de0b6b3a76400006125c38b86615ab4565b6125419190615ae6565b90506125d7613862565b60cd546125e48388615ad3565b6125ee9190615ad3565b118061260a57504360d65485608001516126089190615ad3565b115b156126185750505050612799565b60d860009054906101000a90046001600160a01b03166001600160a01b031663a9fe1b336040518163ffffffff1660e01b8152600401602060405180830381865afa15801561266b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061268f91906159c7565b84516040517ff0ea59150000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015291169063f0ea591590602401600060405180830381600087803b1580156126ed57600080fd5b505af1158015612701573d6000803e3d6000fd5b505050600087815260e16020526040812060030183905560d3805486935090919061272d908490615a35565b9091555061273d90508186615ad3565b84516001600160a01b0316600090815260e0602052604081208054929750849290919061276b908490615a35565b925050819055508160cf60008282546127849190615a35565b90915550506001909501945061254f92505050565b8160d1819055508060d560008282546127b29190615ad3565b909155505060d1546040519081527f12a00f5e4c3614409f2dd90dc5be91b9b64ef89bac58a5b034ec0094376dbd37906020015b60405180910390a150505050565b60006127fe6140d4565b33600090815260df6020526040902054821115612847576040517f09491c4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61284f612e77565b6000612859614072565b33600090815260df602052604081208054929350859290919061287d908490615a35565b909155505033600090815260e06020526040812080548592906128a1908490615ad3565b9091555060009050670de0b6b3a76400006128bc8584615ab4565b6128c69190615ae6565b905064e8d4a51000811015612907576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61139381856151aa565b60e2602052816000526040600020818154811061292d57600080fd5b90600052602060002001600091509150505481565b60d8546129599033906001600160a01b0316614925565b612961615329565b565b6001600160a01b038116600090815260e260209081526040918290208054835181840281018401909452808452606093928301828280156129c357602002820191906000526020600020905b8154815260200190600101908083116129af575b50505050509050919050565b600060cc546000036129e15750600090565b60cd5460cc546129ef613862565b6129f99190615ad3565b612a039190615a35565b670de0b6b3a764000060cc54612a199190615ab4565b6110bc9190615ae6565b6000612a2e816140ca565b612a3782614c73565b60d880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384169081179091556040517fdb2219043d7b197cb235f1af0cf6d782d77dee3de19e3f4fb6d39aae633b448590600090a25050565b600080612aa56140d4565b612aad612e77565b612ab78484614141565b909590945092505050565b612aca6140d4565b66038d7ea4c68000811015612b0b576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b13612e77565b60d860009054906101000a90046001600160a01b03166001600160a01b031663a9fe1b336040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8a91906159c7565b6040517ff0ea59150000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b03919091169063f0ea591590602401600060405180830381600087803b158015612be657600080fd5b505af1158015612bfa573d6000803e3d6000fd5b50505050611e6181614fb0565b60dd8181548110612c1757600080fd5b60009182526020909120600490910201805460018201546002830154600390930154919350919060ff808216916101008104909116906201000090046001600160a01b031686565b6000612c6a816140ca565b612c72612e77565b8160005b8181101561248e576000858583818110612c9257612c92615a48565b9050602002016020810190612ca791906157fa565b905060d860009054906101000a90046001600160a01b03166001600160a01b031663aa9537956040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2091906159c7565b6040517fb11a3a9b0000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152919091169063b11a3a9b90602401602060405180830381865afa158015612d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da591906159ae565b15612ddc576040517feb42183800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612de782614035565b6001600160a01b038316600090815260de6020526040812090815560cb5460019091015560cc549091508110612e1e576000612e2c565b8060cc54612e2c9190615a35565b60cc556040518181526001600160a01b038316907fe4e48d484ff3673a949d4949c3d1959419699d892dcdd4640d67f72b6d48cf249060200160405180910390a25050600101612c76565b612e7f6140d4565b60ca544390819003612e8e5750565b600060ca5482612e9e9190615a35565b905060008160ce54612eb09190615ab4565b90506000670de0b6b3a764000060cc5483612ecb9190615ab4565b612ed59190615ae6565b90508060cc6000828254612ee99190615ad3565b909155505060c954670de0b6b3a764000090612f06908390615ab4565b612f109190615ae6565b60cd6000828254612f219190615ad3565b909155505060cb54612f37906118ac9084615ab4565b60cb6000828254612f489190615ad3565b909155505060ca84905560cd5460cc546040805184815260208101939093528201527f7119249986febcaf2eaa8565a4a5f37df51951d3933512847e77ad489aff89a5906060016127e6565b6000612f9e612e77565b6110bc614072565b6000612fb06140d4565b64e8d4a51000821015612fef576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ff7612e77565b6000613001614072565b9050600061302061301a670de0b6b3a764000086615ab4565b83614b03565b33600090815260df602052604090205490915081111561306c576040517f09491c4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260df60205260408120805483929061308b908490615a35565b909155505033600090815260e06020526040812080548392906130af908490615ad3565b90915550611393905084826151aa565b60d8546130d69033906001600160a01b0316614925565b6416262714cf811115613115576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61311d612e77565b60ce8190556040518181527f3d9659ac5decde6b265b661cde27cd4a357992c35cfa014eb789ad7cbe89ff8b9060200161168f565b61315a6140d4565b6001600160a01b038116600090815260e36020526040902054156131aa576040517fc466f95700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6131b2612e77565b60006131bd82613c42565b9050670de0b6b3a764000081604001511115613205576040517fddeb79ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613213828260000151614141565b505060d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa158015613278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061329c91906159c7565b82516040517fdfdafccb0000000000000000000000000000000000000000000000000000000081526001600160a01b03929092169163dfdafccb916132e79160040190815260200190565b602060405180830381865afa158015613304573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332891906159ae565b90506000606460d9600101548361333f9190615ab4565b6133499190615ae6565b90506000606460d960020154846133609190615ab4565b61336a9190615ae6565b90506000816133798486615ad3565b6133839190615ad3565b6040805160c0810182528281526020808201878152828401878152600060608501818152608086018281523360a0880190815260dd805460018101825581865289517fac507b9f8bf86ad8bb770f71cd2b1992902ae0314d93fc0f2bb011d70e79622660049283029081019190915597517fac507b9f8bf86ad8bb770f71cd2b1992902ae0314d93fc0f2bb011d70e79622789015595517fac507b9f8bf86ad8bb770f71cd2b1992902ae0314d93fc0f2bb011d70e79622888015592517fac507b9f8bf86ad8bb770f71cd2b1992902ae0314d93fc0f2bb011d70e7962299096018054925191517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169690961761010091151591909102177fffffffffffffffffffff0000000000000000000000000000000000000000ffff16620100006001600160a01b039283160217909455548d8416825260e38552908690205560d85485517f6ccb9d70000000000000000000000000000000000000000000000000000000008152955196975093959390911693636ccb9d7093818301939290918290030181865afa158015613561573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358591906159c7565b6040517fbbad83150000000000000000000000000000000000000000000000000000000081526001600160a01b03898116600483015260248201859052919091169063bbad831590604401600060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505060408051858152602081018890529081018690523392506001600160a01b038a1691507fcc9de8be9ac1f02b70a8ca2612f451a769d6d160ad91de17dcc38e54c567a5329060600160405180910390a350505050505050565b600082815260656020526040902060010154613674816140ca565b6116bf8383614a80565b6136866140d4565b60d854604080517f79175a7400000000000000000000000000000000000000000000000000000000815290516136f09233926001600160a01b039091169182916379175a749160048083019260209291908290030181865afa158015610cdd573d6000803e3d6000fd5b6001600160a01b038116600090815260e360205260408120549003613741576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116600090815260e36020526040902054600160dd6137688284615a35565b8154811061377857613778615a48565b60009182526020808320600492909202909101600301805460ff1916931515939093179092556001600160a01b038416815260e3909152604090205460019060dd906137c5908390615a35565b815481106137d5576137d5615a48565b600091825260208083206003600490930201919091018054931515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909416939093179092556001600160a01b038416815260e390915260408082208290555182917f2f0c36e8e230af6ceee7ecc30319e10800731fef4913c80afcf23f84b148df5d91a25050565b60d55460d854604080517fe069f7140000000000000000000000000000000000000000000000000000000081529051600093926001600160a01b03169163e069f7149160048083019260209291908290030181865afa1580156138c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ed91906159c7565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561394c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061397091906159ae565b6110bc9190615a35565b6000613984612e77565b610f8082614035565b6139956140d4565b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa1580156139f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a1c91906159c7565b6040517f27d9ab5d0000000000000000000000000000000000000000000000000000000081523360048201529091506000906001600160a01b038316906327d9ab5d90602401606060405180830381865afa158015613a7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa39190615a77565b6040517fb11a3a9b000000000000000000000000000000000000000000000000000000008152336004820152909350600092506001600160a01b038516915063b11a3a9b90602401602060405180830381865afa158015613b08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b2c91906159ae565b90506000836001600160a01b031663e614e17c60d0546040518263ffffffff1660e01b8152600401613b6091815260200190565b602060405180830381865afa158015613b7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ba191906159ae565b613bab9084615ab4565b905080613bb88684615ad3565b1115613bf0576040517fdb8f07da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613bf8612e77565b61248e3386614690565b6000613c0d816140ca565b60d78290556040518281527f620864df809b46dfaffcfb35289f5efd1abd7c309562a0bdb89ee19903b2ed1090602001611137565b613c6d6040518060800160405280600081526020016000815260200160008152602001600081525090565b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa158015613cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cf491906159c7565b6040517fb11a3a9b0000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152919091169063b11a3a9b90602401602060405180830381865afa158015613d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d7991906159ae565b613d8284611870565b613d8c9190615a35565b90506000613d9984611177565b9050600060d860009054906101000a90046001600160a01b03166001600160a01b031663aa9537956040518163ffffffff1660e01b8152600401602060405180830381865afa158015613df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1491906159c7565b6001600160a01b031663e614e17c836040518263ffffffff1660e01b8152600401613e4191815260200190565b602060405180830381865afa158015613e5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8291906159ae565b905060008315613ec757613e97846064615ab4565b60d954670de0b6b3a764000090613eae9085615ab4565b613eb89190615ab4565b613ec29190615ae6565b613ecb565b6000195b9050604051806080016040528085815260200184815260200182815260200160e36000896001600160a01b03166001600160a01b0316815260200190815260200160002054600014613f66576001600160a01b038816600090815260e3602052604090205460dd90613f3f90600190615a35565b81548110613f4f57613f4f615a48565b906000526020600020906004020160000154613f69565b60005b90529695505050505050565b6040517fb31239220000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526024820183905283169063b312392290604401602060405180830381865afa158015613fdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fff91906159e4565b6116bf576040517f168dfea100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116600090815260de602052604081208054820361405e5750600092915050565b600181015460cb5482546113d69190615ab4565b600060cf5460000361408b5750670de0b6b3a764000090565b600060cd5460cc5461409b613862565b6140a59190615ad3565b6140af9190615a35565b9050600060cf54670de0b6b3a7640000836113d69190615ab4565b611e618133615366565b60975460ff1615612961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611859565b600080600061414f85614035565b905060001984148061416057508084115b61416a578361416c565b805b925060d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156141c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141e591906159c7565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018590526001600160a01b0391909116906323b872dd906064016020604051808303816000875af1158015614253573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061427791906159e4565b6142ad576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa158015614310573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061433491906159c7565b6040517fb11a3a9b0000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152919091169063b11a3a9b90602401602060405180830381865afa158015614395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143b991906159ae565b6143c39083615a35565b60d854604080517ff122961f00000000000000000000000000000000000000000000000000000000815290519293506001600160a01b039091169163b3123922913391849163f122961f9160048083019260209291908290030181865afa158015614432573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061445691906159ae565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156144b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144db91906159e4565b6145ee57808411156145ee5760d860009054906101000a90046001600160a01b03166001600160a01b031663aa9537956040518163ffffffff1660e01b8152600401602060405180830381865afa15801561453a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061455e91906159c7565b6001600160a01b031663956b95e7876145778488615a35565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156145d557600080fd5b505af11580156145e9573d6000803e3d6000fd5b505050505b6145f88482615194565b92506146048483615a35565b6001600160a01b038716600090815260de6020526040902090815560cb5460019091015560cc548410614638576000614646565b8360cc546146469190615a35565b60cc556040518481526001600160a01b038716907f0516911bcc3a0a7412a44601057c0a0a1ec628bde049a84284bc4288665344889060200160405180910390a250509250929050565b6001600160a01b038216600090815260e36020526040902054156146e0576040517fc466f95700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006146eb83613c42565b9050670de0b6b3a7640000816040015111614732576040517f53d1636700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cd5460d3546147429084615ad3565b61474c9190615ad3565b614754613862565b101561478c576040517fbc6072f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061479784614035565b90506147a38382615ad3565b6001600160a01b038516600090815260de6020526040812091825560cb5460019092019190915560cc80548592906147dc908490615ad3565b909155505060d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169163aa953795916004808201926020929091908290030181865afa158015614844573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061486891906159c7565b6040517fc85e8dde0000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260248201869052919091169063c85e8dde90604401600060405180830381600087803b1580156148cd57600080fd5b505af11580156148e1573d6000803e3d6000fd5b5050604080516001600160a01b0388168152602081018790527f29f5a3c94649e9fd569197488f431f12d8b1fe681596964128403511823a638693500190506127e6565b6040517f6240fb9c0000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152821690636240fb9c90602401602060405180830381865afa158015614984573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149a891906159e4565b61186c576040517fc4230ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1661186c5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055614a3c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff161561186c5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008215614b315781614b17600185615a35565b614b219190615ae6565b614b2c906001615ad3565b6113e0565b60009392505050565b600081815260e16020908152604080832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560018101849055600281018490556003810184905560040183905533835260e290915281208054915b82811015614c4057818181548110614bb457614bb4615a48565b90600052602060002001548403614c385781614bd1600185615a35565b81548110614be157614be1615a48565b9060005260206000200154828281548110614bfe57614bfe615a48565b906000526020600020018190555081805480614c1c57614c1c615b21565b6001900381819060005260206000200160009055905550505050565b600101614b9a565b506040517f74ec20b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116611e61576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614cbb615413565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600054610100900460ff16612961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611859565b600054610100900460ff16614e33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611859565b61296161547f565b6064841180614e48575083155b15614e7f576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064831115614eba576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064821115614ef5576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064811180614f02575080155b15614f39576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051608080820183528682526020808301879052828401869052606092830185905260d988905560da87905560db86905560dc85905583518881529081018790529283018590529082018390527f62dd46f943681bd727e339f4baaa19fb66ea209fbe7d9b4a75aa74c33acc18f391016127e6565b6000614fba614072565b905060d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa15801561500f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061503391906159c7565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018490526001600160a01b0391909116906323b872dd906064016020604051808303816000875af11580156150a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906150c591906159e4565b6150fb576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081615110670de0b6b3a764000085615ab4565b61511a9190615ae6565b33600090815260df602052604081208054929350839290919061513e908490615ad3565b925050819055508060cf60008282546151579190615ad3565b9091555050604080518481526020810183905233917f9a8f44850296624dadfd9c246d17e47171d35727a181bd090aa14bbbe00238bb9101610ee0565b60008183106151a357816113e0565b5090919050565b60d75433600090815260e260205260408120549091906151cb906001615ad3565b1115615203576040517f6b304ad800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260d360008282546152159190615ad3565b90915550506040805160a08101825233808252602080830186815283850188815260006060808701828152436080890190815260d28054855260e188528a852099518a547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178a5595516001808b0191909155945160028a0155905160038901555160049097019690965584815260e284528681208354815493840182559082529084902090910155548451928352908201529182018590527f0edfc24f4f80277416f78f699d4733f7bb58fd6fb8838e2b1033162cee5fd7aa910160405180910390a160d2805490600061531583615b50565b9190505550600160d2546113e09190615a35565b6153316140d4565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614ce83390565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1661186c5761539981615522565b6153a4836020615534565b6040516020016153b5929190615b8e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261185991600401615c0f565b60975460ff16612961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401611859565b600054610100900460ff16615516576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611859565b6097805460ff19169055565b6060610f806001600160a01b03831660145b60606000615543836002615ab4565b61554e906002615ad3565b67ffffffffffffffff81111561556657615566615c60565b6040519080825280601f01601f191660200182016040528015615590576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000816000815181106155c7576155c7615a48565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061562a5761562a615a48565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000615666846002615ab4565b615671906001615ad3565b90505b600181111561570e577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106156b2576156b2615a48565b1a60f81b8282815181106156c8576156c8615a48565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361570781615c8f565b9050615674565b5083156113e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611859565b6001600160a01b0381168114611e6157600080fd5b6000806040838503121561579f57600080fd5b82356157aa81615777565b946020939093013593505050565b6000602082840312156157ca57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146113e057600080fd5b60006020828403121561580c57600080fd5b81356113e081615777565b60006020828403121561582957600080fd5b5035919050565b60008060006060848603121561584557600080fd5b833561585081615777565b95602085013595506040909401359392505050565b6000806040838503121561587857600080fd5b82359150602083013561588a81615777565b809150509250929050565b600080604083850312156158a857600080fd5b82356158b381615777565b9150602083013561588a81615777565b600080600080608085870312156158d957600080fd5b5050823594602084013594506040840135936060013592509050565b6020808252825182820181905260009190848201906040850190845b8181101561592d57835183529284019291840191600101615911565b50909695505050505050565b6000806020838503121561594c57600080fd5b823567ffffffffffffffff8082111561596457600080fd5b818501915085601f83011261597857600080fd5b81358181111561598757600080fd5b8660208260051b850101111561599c57600080fd5b60209290920196919550909350505050565b6000602082840312156159c057600080fd5b5051919050565b6000602082840312156159d957600080fd5b81516113e081615777565b6000602082840312156159f657600080fd5b815180151581146113e057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610f8057610f80615a06565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080600060608486031215615a8c57600080fd5b835160ff81168114615a9d57600080fd5b602085015160409095015190969495509392505050565b6000816000190483118215151615615ace57615ace615a06565b500290565b80820180821115610f8057610f80615a06565b600082615b1c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60006000198203615b6357615b63615a06565b5060010190565b60005b83811015615b85578181015183820152602001615b6d565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615bc6816017850160208801615b6a565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615c03816028840160208801615b6a565b01602801949350505050565b6020815260008251806020840152615c2e816040850160208701615b6a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600081615c9e57615c9e615a06565b50600019019056fea2646970667358221220a0f6cdc836898eab69a9cd7f5c092511af32b731ba4f903c8bfeff3e04b8fa5264736f6c63430008100033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106105965760003560e01c80636d00679c116102e2578063abf9db0211610191578063c51cd1cc116100ee578063da695857116100a2578063ec29c5511161007c578063ec29c55114610c07578063ee63e5f914610c1a578063ffc9896b14610c2d57600080fd5b8063da69585714610b73578063e41b55d914610b7b578063e65efbe414610bf457600080fd5b8063d2ac4a3d116100d3578063d2ac4a3d14610b3a578063d547741f14610b4d578063d844cb6c14610b6057600080fd5b8063c51cd1cc14610b14578063cb2d89dd14610b2757600080fd5b8063b8ca3b8311610145578063bc1428f61161012a578063bc1428f614610afa578063bd6d894d14610b03578063c083f3e614610b0b57600080fd5b8063b8ca3b8314610ae2578063bbb8436214610af157600080fd5b8063b0e21e8a11610176578063b0e21e8a14610ac3578063b26cc39414610acc578063b4c1273b14610ad457600080fd5b8063abf9db0214610a90578063aeea5af714610ab057600080fd5b8063962c70701161023f5780639f689e0b116101f3578063a217fddf116101d8578063a217fddf14610a32578063a544a62c14610a3a578063a66c84f414610a4357600080fd5b80639f689e0b14610a0c5780639fa6dd3514610a1f57600080fd5b80639a3263ee116102245780639a3263ee146109ca5780639e070088146109d25780639ee804cb146109f957600080fd5b8063962c7070146109a157806399775f40146109aa57600080fd5b80637844e3af116102965780638456cb591161027b5780638456cb59146109575780638763a3281461095f57806391d148541461096857600080fd5b80637844e3af1461090e5780637c90a6ca1461092157600080fd5b80636f2bd0b2116102c75780636f2bd0b2146108ea57806371898b4e146108f3578063745400c9146108fb57600080fd5b80636d00679c146108cf5780636e236aee146108d757600080fd5b806337a4adf7116104495780634e7878ee116103a657806362569a511161035a5780636a84a985116103345780636a84a985146108ae5780636ab55fd9146108b75780636c540baf146108c657600080fd5b806362569a5114610872578063634c48c714610885578063673ab3fa1461088e57600080fd5b8063531810bc1161038b578063531810bc146108485780635393618e146108545780635c975abb1461086757600080fd5b80634e7878ee1461081c5780634f8f7a371461082857600080fd5b80634256dd78116103fd578063490ffa35116103e2578063490ffa35146107d65780634a2965af146108015780634ae9b8bc1461081457600080fd5b80634256dd78146107b0578063485cc955146107c357600080fd5b80633e04cd351161042e5780633e04cd351461078d5780633f4ba83a14610795578063424cd8331461079d57600080fd5b806337a4adf71461077b5780633b92e3cf1461078457600080fd5b8063248a9ca3116104f757806334d093f6116104ab57806336978412116104905780633697841214610742578063371fd8e614610755578063379607f51461076857600080fd5b806334d093f61461072757806336568abe1461072f57600080fd5b80632807c313116104dc5780632807c313146107025780632b8869411461070b5780632f2ff15d1461071457600080fd5b8063248a9ca3146106cc578063267fca73146106ef57600080fd5b806320552a6e1161054e5780632229152811610533578063222915281461069d578063232d70c3146106b057806323c4ac1a146106b957600080fd5b806320552a6e1461066d5780632170c14c1461068a57600080fd5b806312372ffe1161057f57806312372ffe146105d8578063182df0f5146106445780631c557f051461065a57600080fd5b8063019f0aa91461059b57806301ffc9a7146105b0575b600080fd5b6105ae6105a936600461578c565b610c73565b005b6105c36105be3660046157b8565b610eed565b60405190151581526020015b60405180910390f35b6105eb6105e63660046157fa565b610f86565b6040516105cf9190600060c0820190508251825260208301516020830152604083015160408301526060830151151560608301526080830151151560808301526001600160a01b0360a08401511660a083015292915050565b61064c6110b2565b6040519081526020016105cf565b6105ae610668366004615817565b6110c1565b610675611143565b604080519283526020830191909152016105cf565b61064c6106983660046157fa565b611177565b61064c6106ab3660046157fa565b61139b565b61064c60e45481565b6105ae6106c7366004615830565b6113e7565b61064c6106da366004615817565b60009081526065602052604090206001015490565b6105ae6106fd366004615817565b611647565b61064c60d05481565b61064c60d55481565b6105ae610722366004615865565b61169a565b61064c6116c4565b6105ae61073d366004615865565b6117c5565b61064c6107503660046157fa565b611870565b610675610763366004615817565b61191c565b6105ae610776366004615817565b611939565b61064c60cf5481565b61064c60d35481565b6105ae611c97565b6105ae611e4e565b6105ae6107ab366004615817565b611e64565b6105ae6107be366004615817565b6120ea565b6105ae6107d1366004615895565b612180565b60d8546107e9906001600160a01b031681565b6040516001600160a01b0390911681526020016105cf565b6105ae61080f366004615817565b6123eb565b60d95461064c565b61064c6416262714cf81565b61064c6108363660046157fa565b60e06020526000908152604090205481565b61064c64e8d4a5100081565b6105ae610862366004615817565b61242b565b60975460ff166105c3565b6105ae6108803660046158c3565b612477565b61064c60cb5481565b61064c61089c3660046157fa565b60e36020526000908152604090205481565b61064c60d25481565b61064c670de0b6b3a764000081565b61064c60ca5481565b61064c612495565b61064c6108e53660046157fa565b612502565b61064c60d45481565b6105ae61250d565b61064c610909366004615817565b6127f4565b61064c61091c36600461578c565b612911565b60d95460da5460db5460dc546109379392919084565b6040805194855260208501939093529183015260608201526080016105cf565b6105ae612942565b61064c60cc5481565b6105c3610976366004615865565b60009182526065602090815260408084206001600160a01b0393909316845291905290205460ff1690565b61064c60ce5481565b6109bd6109b83660046157fa565b612963565b6040516105cf91906158f5565b61064c6129cf565b6106756109e03660046157fa565b60de602052600090815260409020805460019091015482565b6105ae610a073660046157fa565b612a23565b610675610a1a36600461578c565b612a9a565b6105ae610a2d366004615817565b612ac2565b61064c600081565b61064c60cd5481565b610a56610a51366004615817565b612c07565b6040805196875260208701959095529385019290925215156060840152151560808301526001600160a01b031660a082015260c0016105cf565b61064c610a9e3660046157fa565b60df6020526000908152604090205481565b6105ae610abe366004615939565b612c5f565b61064c60c95481565b6105ae612e77565b61064c66038d7ea4c6800081565b61064c67016345785d8a000081565b61064c60d15481565b61064c60d65481565b61064c612f94565b61064c60d75481565b61064c610b22366004615817565b612fa6565b6105ae610b35366004615817565b6130bf565b6105ae610b483660046157fa565b613152565b6105ae610b5b366004615865565b613659565b6105ae610b6e3660046157fa565b61367e565b61064c613862565b610bc2610b89366004615817565b60e160205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0390931693919290919085565b604080516001600160a01b0390961686526020860194909452928401919091526060830152608082015260a0016105cf565b61064c610c023660046157fa565b61397a565b6105ae610c15366004615817565b61398d565b6105ae610c28366004615817565b613c02565b610c40610c3b3660046157fa565b613c42565b6040516105cf91908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b60d854604080517ff122961f0000000000000000000000000000000000000000000000000000000081529051610d069233926001600160a01b0390911691829163f122961f9160048083019260209291908290030181865afa158015610cdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0191906159ae565b613f75565b610d0e612e77565b60d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8591906159c7565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018390526001600160a01b0391909116906323b872dd906064016020604051808303816000875af1158015610df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1791906159e4565b610e4d576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e5883614035565b9050610e648282615a35565b6001600160a01b038416600090815260de6020526040902090815560cb5460019091015560cc548210610e98576000610ea6565b8160cc54610ea69190615a35565b60cc556040518281526001600160a01b038416907f37057a3afa8d7c32b75c4534845b8e937e76c0f9cf30fbe71122af20c33646dd906020015b60405180910390a2505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610f8057507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6040805160c08101825260008082526020808301829052828401829052606083018290526080830182905260a083018290526001600160a01b038516825260e390529182205490910361100a5750506040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b6001600160a01b038216600090815260e3602052604090205460dd9061103290600190615a35565b8154811061104257611042615a48565b60009182526020918290206040805160c08101825260049093029091018054835260018101549383019390935260028301549082015260039091015460ff80821615156060840152610100820416151560808301526001600160a01b03620100009091041660a082015292915050565b60006110bc614072565b905090565b60006110cc816140ca565b81600003611106576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60e48290556040518281527f475227c841ac4234d6b624ffe157a80f62c0b4d66161f98684c2fc2ad79bdf52906020015b60405180910390a15050565b60008061114e6140d4565b611156612e77565b600061116133614035565b905061116d3382614141565b9094909350915050565b60008060d860009054906101000a90046001600160a01b03166001600160a01b031663aa9537956040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f191906159c7565b6040517f27d9ab5d0000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015291909116906327d9ab5d90602401606060405180830381865afa158015611252573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112769190615a77565b92505050600060d860009054906101000a90046001600160a01b03166001600160a01b031663278671bb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f391906159c7565b6040517ff8b2cb4f0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152919091169063f8b2cb4f90602401602060405180830381865afa158015611354573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137891906159ae565b90508060e454836113899190615ab4565b6113939190615ad3565b949350505050565b6000806113a66116c4565b6001600160a01b038416600090815260df6020526040902054909150670de0b6b3a7640000906113d69083615ab4565b6113e09190615ae6565b9392505050565b6113ef6140d4565b60d854604080517f152a91da00000000000000000000000000000000000000000000000000000000815290516114599233926001600160a01b0390911691829163152a91da9160048083019260209291908290030181865afa158015610cdd573d6000803e3d6000fd5b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa1580156114bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e091906159c7565b6040517fb11a3a9b0000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015291925060009183169063b11a3a9b90602401602060405180830381865afa158015611545573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156991906159ae565b90506000826001600160a01b031663e614e17c60d0546040518263ffffffff1660e01b815260040161159d91815260200190565b602060405180830381865afa1580156115ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115de91906159ae565b6115e89085615ab4565b9050806115f58684615ad3565b111561162d576040517fdb8f07da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611635612e77565b61163f8686614690565b505050505050565b60d85461165e9033906001600160a01b0316614925565b60d48190556040518181527f7ffbe87ac4b7820fd4ca4ac8c7c7820cc79c7cdd9631ac083c06bb833be63587906020015b60405180910390a150565b6000828152606560205260409020600101546116b5816140ca565b6116bf83836149de565b505050565b60ca54600090439082906116d89083615a35565b905060008160ce546116ea9190615ab4565b90506000670de0b6b3a764000060cc54836117059190615ab4565b61170f9190615ae6565b9050600060cc54826117219190615ad3565b9050600060cd54670de0b6b3a76400008460c95461173f9190615ab4565b6117499190615ae6565b6117539190615ad3565b905060cf5460000361177357670de0b6b3a7640000965050505050505090565b6000818361177f613862565b6117899190615ad3565b6117939190615a35565b9050600060cf54670de0b6b3a7640000836117ae9190615ab4565b6117b89190615ae6565b9998505050505050505050565b6001600160a01b0381163314611862576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b61186c8282614a80565b5050565b60ca54600090439082906118849083615a35565b905060008160ce546118969190615ab4565b60cb549091506000906118ba6118ac8285615ab4565b670de0b6b3a7640000614b03565b6118c49190615ad3565b6001600160a01b038716600090815260de6020526040812080549293509190036118f5575060009695505050505050565b60018101548154611907908490615ab4565b6119119190615ae6565b979650505050505050565b6000806119276140d4565b61192f612e77565b61116d3384614141565b6119416140d4565b60d154811061197f576040517fc219f93500000000000000000000000000000000000000000000000000000000815260048101829052602401611859565b600081815260e16020908152604091829020825160a08101845281546001600160a01b0316808252600183015493820193909352600282015493810193909352600381015460608401526004015460808301523314611a0a576040517f7f1cdd1500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000816060015190508060d56000828254611a259190615a35565b90915550611a34905083614b3a565b60d860009054906101000a90046001600160a01b03166001600160a01b031663a9fe1b336040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aab91906159c7565b6040517f1e83409a0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b039190911690631e83409a90602401600060405180830381600087803b158015611b0757600080fd5b505af1158015611b1b573d6000803e3d6000fd5b5050505060d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9691906159c7565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390526001600160a01b03919091169063a9059cbb906044016020604051808303816000875af1158015611bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2291906159e4565b611c58576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051338152602081018390527ff7aca15eb385953329daa8e235ce29ead201e26c1e36e1083d929821401bb7d291015b60405180910390a1505050565b611c9f6140d4565b60d854611cb69033906001600160a01b0316614925565b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa158015611d19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3d91906159c7565b9050611d4881614c73565b60d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbf91906159c7565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301526000196024830152919091169063095ea7b3906044016020604051808303816000875af1158015611e2a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186c91906159e4565b6000611e59816140ca565b611e61614cb3565b50565b611e6c6140d4565b60d854611e839033906001600160a01b0316614925565b611e8b612e77565b60cd54811180611ea15750611e9e613862565b81115b15611ed8576040517fdb73cdf000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060cd6000828254611eea9190615a35565b909155505060d854604080517fe069f71400000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169163e069f714916004808201926020929091908290030181865afa158015611f52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7691906159c7565b6001600160a01b031663a9059cbb60d860009054906101000a90046001600160a01b03166001600160a01b03166372ce78b06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffb91906159c7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015612060573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208491906159e4565b6120ba576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518181527fa32a67c2a472d948ee4cdcce3fdf2df7a9a99b762c69858f0651b1b22067efdf9060200161168f565b60d8546121019033906001600160a01b0316614925565b67016345785d8a0000811115612143576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61214b612e77565b60c98190556040518181527fba813ee7ea736ec5148f515c7fe651c522fa84413c6c5ce693bd74abade775d39060200161168f565b600054610100900460ff16158080156121a05750600054600160ff909116105b806121ba5750303b1580156121ba575060005460ff166001145b612246576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611859565b6000805460ff19166001179055801561228657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61228f83614c73565b61229882614c73565b6122a0614d05565b6122a8614d9c565b60d880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038416179055670de0b6b3a764000060cb8190556408dc0fa1ec60ce55600060c955600160d281905560d155603260d48190554360ca5561c4e060d6556103e860d75560d091909155671bc16d674ec8000060e45561233c90604690601e90600590614e3b565b6123476000846149de565b612358670de0b6b3a7640000614fb0565b6040516001600160a01b038316907fdb2219043d7b197cb235f1af0cf6d782d77dee3de19e3f4fb6d39aae633b448590600090a280156116bf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611c8a565b60006123f6816140ca565b60d68290556040518281527faa3bf534da453100a74c0c499340ebed87ce7f16483706a8b1e5ca11b998278990602001611137565b60d8546124429033906001600160a01b0316614925565b60d08190556040518181527f9491876f555a700a2938143a5a27937708ab194a6f8d94cd7eb8eefae92f34f59060200161168f565b6000612482816140ca565b61248e85858585614e3b565b5050505050565b60008060c954670de0b6b3a76400006124ae9190615a35565b90506000670de0b6b3a76400008260ce546124c99190615ab4565b6124d39190615ae6565b9050670de0b6b3a7640000816124e76129cf565b6124f19190615ab4565b6124fb9190615ae6565b9250505090565b6000610f8082614035565b6125156140d4565b61251d612e77565b6000612527614072565b9050600061254660d25460d45460d1546125419190615ad3565b615194565b60d15490915060005b8282101561279957600082815260e160209081526040808320815160a08101835281546001600160a01b0316815260018201549381018490526002820154928101839052600382015460608201526004909101546080820152929091906125cd83670de0b6b3a76400006125c38b86615ab4565b6125419190615ae6565b90506125d7613862565b60cd546125e48388615ad3565b6125ee9190615ad3565b118061260a57504360d65485608001516126089190615ad3565b115b156126185750505050612799565b60d860009054906101000a90046001600160a01b03166001600160a01b031663a9fe1b336040518163ffffffff1660e01b8152600401602060405180830381865afa15801561266b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061268f91906159c7565b84516040517ff0ea59150000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015291169063f0ea591590602401600060405180830381600087803b1580156126ed57600080fd5b505af1158015612701573d6000803e3d6000fd5b505050600087815260e16020526040812060030183905560d3805486935090919061272d908490615a35565b9091555061273d90508186615ad3565b84516001600160a01b0316600090815260e0602052604081208054929750849290919061276b908490615a35565b925050819055508160cf60008282546127849190615a35565b90915550506001909501945061254f92505050565b8160d1819055508060d560008282546127b29190615ad3565b909155505060d1546040519081527f12a00f5e4c3614409f2dd90dc5be91b9b64ef89bac58a5b034ec0094376dbd37906020015b60405180910390a150505050565b60006127fe6140d4565b33600090815260df6020526040902054821115612847576040517f09491c4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61284f612e77565b6000612859614072565b33600090815260df602052604081208054929350859290919061287d908490615a35565b909155505033600090815260e06020526040812080548592906128a1908490615ad3565b9091555060009050670de0b6b3a76400006128bc8584615ab4565b6128c69190615ae6565b905064e8d4a51000811015612907576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61139381856151aa565b60e2602052816000526040600020818154811061292d57600080fd5b90600052602060002001600091509150505481565b60d8546129599033906001600160a01b0316614925565b612961615329565b565b6001600160a01b038116600090815260e260209081526040918290208054835181840281018401909452808452606093928301828280156129c357602002820191906000526020600020905b8154815260200190600101908083116129af575b50505050509050919050565b600060cc546000036129e15750600090565b60cd5460cc546129ef613862565b6129f99190615ad3565b612a039190615a35565b670de0b6b3a764000060cc54612a199190615ab4565b6110bc9190615ae6565b6000612a2e816140ca565b612a3782614c73565b60d880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384169081179091556040517fdb2219043d7b197cb235f1af0cf6d782d77dee3de19e3f4fb6d39aae633b448590600090a25050565b600080612aa56140d4565b612aad612e77565b612ab78484614141565b909590945092505050565b612aca6140d4565b66038d7ea4c68000811015612b0b576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b13612e77565b60d860009054906101000a90046001600160a01b03166001600160a01b031663a9fe1b336040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b8a91906159c7565b6040517ff0ea59150000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b03919091169063f0ea591590602401600060405180830381600087803b158015612be657600080fd5b505af1158015612bfa573d6000803e3d6000fd5b50505050611e6181614fb0565b60dd8181548110612c1757600080fd5b60009182526020909120600490910201805460018201546002830154600390930154919350919060ff808216916101008104909116906201000090046001600160a01b031686565b6000612c6a816140ca565b612c72612e77565b8160005b8181101561248e576000858583818110612c9257612c92615a48565b9050602002016020810190612ca791906157fa565b905060d860009054906101000a90046001600160a01b03166001600160a01b031663aa9537956040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2091906159c7565b6040517fb11a3a9b0000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152919091169063b11a3a9b90602401602060405180830381865afa158015612d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da591906159ae565b15612ddc576040517feb42183800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612de782614035565b6001600160a01b038316600090815260de6020526040812090815560cb5460019091015560cc549091508110612e1e576000612e2c565b8060cc54612e2c9190615a35565b60cc556040518181526001600160a01b038316907fe4e48d484ff3673a949d4949c3d1959419699d892dcdd4640d67f72b6d48cf249060200160405180910390a25050600101612c76565b612e7f6140d4565b60ca544390819003612e8e5750565b600060ca5482612e9e9190615a35565b905060008160ce54612eb09190615ab4565b90506000670de0b6b3a764000060cc5483612ecb9190615ab4565b612ed59190615ae6565b90508060cc6000828254612ee99190615ad3565b909155505060c954670de0b6b3a764000090612f06908390615ab4565b612f109190615ae6565b60cd6000828254612f219190615ad3565b909155505060cb54612f37906118ac9084615ab4565b60cb6000828254612f489190615ad3565b909155505060ca84905560cd5460cc546040805184815260208101939093528201527f7119249986febcaf2eaa8565a4a5f37df51951d3933512847e77ad489aff89a5906060016127e6565b6000612f9e612e77565b6110bc614072565b6000612fb06140d4565b64e8d4a51000821015612fef576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ff7612e77565b6000613001614072565b9050600061302061301a670de0b6b3a764000086615ab4565b83614b03565b33600090815260df602052604090205490915081111561306c576040517f09491c4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260df60205260408120805483929061308b908490615a35565b909155505033600090815260e06020526040812080548392906130af908490615ad3565b90915550611393905084826151aa565b60d8546130d69033906001600160a01b0316614925565b6416262714cf811115613115576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61311d612e77565b60ce8190556040518181527f3d9659ac5decde6b265b661cde27cd4a357992c35cfa014eb789ad7cbe89ff8b9060200161168f565b61315a6140d4565b6001600160a01b038116600090815260e36020526040902054156131aa576040517fc466f95700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6131b2612e77565b60006131bd82613c42565b9050670de0b6b3a764000081604001511115613205576040517fddeb79ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613213828260000151614141565b505060d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa158015613278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061329c91906159c7565b82516040517fdfdafccb0000000000000000000000000000000000000000000000000000000081526001600160a01b03929092169163dfdafccb916132e79160040190815260200190565b602060405180830381865afa158015613304573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332891906159ae565b90506000606460d9600101548361333f9190615ab4565b6133499190615ae6565b90506000606460d960020154846133609190615ab4565b61336a9190615ae6565b90506000816133798486615ad3565b6133839190615ad3565b6040805160c0810182528281526020808201878152828401878152600060608501818152608086018281523360a0880190815260dd805460018101825581865289517fac507b9f8bf86ad8bb770f71cd2b1992902ae0314d93fc0f2bb011d70e79622660049283029081019190915597517fac507b9f8bf86ad8bb770f71cd2b1992902ae0314d93fc0f2bb011d70e79622789015595517fac507b9f8bf86ad8bb770f71cd2b1992902ae0314d93fc0f2bb011d70e79622888015592517fac507b9f8bf86ad8bb770f71cd2b1992902ae0314d93fc0f2bb011d70e7962299096018054925191517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009093169615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169690961761010091151591909102177fffffffffffffffffffff0000000000000000000000000000000000000000ffff16620100006001600160a01b039283160217909455548d8416825260e38552908690205560d85485517f6ccb9d70000000000000000000000000000000000000000000000000000000008152955196975093959390911693636ccb9d7093818301939290918290030181865afa158015613561573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061358591906159c7565b6040517fbbad83150000000000000000000000000000000000000000000000000000000081526001600160a01b03898116600483015260248201859052919091169063bbad831590604401600060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505060408051858152602081018890529081018690523392506001600160a01b038a1691507fcc9de8be9ac1f02b70a8ca2612f451a769d6d160ad91de17dcc38e54c567a5329060600160405180910390a350505050505050565b600082815260656020526040902060010154613674816140ca565b6116bf8383614a80565b6136866140d4565b60d854604080517f79175a7400000000000000000000000000000000000000000000000000000000815290516136f09233926001600160a01b039091169182916379175a749160048083019260209291908290030181865afa158015610cdd573d6000803e3d6000fd5b6001600160a01b038116600090815260e360205260408120549003613741576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116600090815260e36020526040902054600160dd6137688284615a35565b8154811061377857613778615a48565b60009182526020808320600492909202909101600301805460ff1916931515939093179092556001600160a01b038416815260e3909152604090205460019060dd906137c5908390615a35565b815481106137d5576137d5615a48565b600091825260208083206003600490930201919091018054931515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909416939093179092556001600160a01b038416815260e390915260408082208290555182917f2f0c36e8e230af6ceee7ecc30319e10800731fef4913c80afcf23f84b148df5d91a25050565b60d55460d854604080517fe069f7140000000000000000000000000000000000000000000000000000000081529051600093926001600160a01b03169163e069f7149160048083019260209291908290030181865afa1580156138c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ed91906159c7565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561394c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061397091906159ae565b6110bc9190615a35565b6000613984612e77565b610f8082614035565b6139956140d4565b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa1580156139f8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a1c91906159c7565b6040517f27d9ab5d0000000000000000000000000000000000000000000000000000000081523360048201529091506000906001600160a01b038316906327d9ab5d90602401606060405180830381865afa158015613a7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa39190615a77565b6040517fb11a3a9b000000000000000000000000000000000000000000000000000000008152336004820152909350600092506001600160a01b038516915063b11a3a9b90602401602060405180830381865afa158015613b08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b2c91906159ae565b90506000836001600160a01b031663e614e17c60d0546040518263ffffffff1660e01b8152600401613b6091815260200190565b602060405180830381865afa158015613b7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ba191906159ae565b613bab9084615ab4565b905080613bb88684615ad3565b1115613bf0576040517fdb8f07da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613bf8612e77565b61248e3386614690565b6000613c0d816140ca565b60d78290556040518281527f620864df809b46dfaffcfb35289f5efd1abd7c309562a0bdb89ee19903b2ed1090602001611137565b613c6d6040518060800160405280600081526020016000815260200160008152602001600081525090565b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa158015613cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cf491906159c7565b6040517fb11a3a9b0000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152919091169063b11a3a9b90602401602060405180830381865afa158015613d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d7991906159ae565b613d8284611870565b613d8c9190615a35565b90506000613d9984611177565b9050600060d860009054906101000a90046001600160a01b03166001600160a01b031663aa9537956040518163ffffffff1660e01b8152600401602060405180830381865afa158015613df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e1491906159c7565b6001600160a01b031663e614e17c836040518263ffffffff1660e01b8152600401613e4191815260200190565b602060405180830381865afa158015613e5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8291906159ae565b905060008315613ec757613e97846064615ab4565b60d954670de0b6b3a764000090613eae9085615ab4565b613eb89190615ab4565b613ec29190615ae6565b613ecb565b6000195b9050604051806080016040528085815260200184815260200182815260200160e36000896001600160a01b03166001600160a01b0316815260200190815260200160002054600014613f66576001600160a01b038816600090815260e3602052604090205460dd90613f3f90600190615a35565b81548110613f4f57613f4f615a48565b906000526020600020906004020160000154613f69565b60005b90529695505050505050565b6040517fb31239220000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526024820183905283169063b312392290604401602060405180830381865afa158015613fdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fff91906159e4565b6116bf576040517f168dfea100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116600090815260de602052604081208054820361405e5750600092915050565b600181015460cb5482546113d69190615ab4565b600060cf5460000361408b5750670de0b6b3a764000090565b600060cd5460cc5461409b613862565b6140a59190615ad3565b6140af9190615a35565b9050600060cf54670de0b6b3a7640000836113d69190615ab4565b611e618133615366565b60975460ff1615612961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611859565b600080600061414f85614035565b905060001984148061416057508084115b61416a578361416c565b805b925060d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156141c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141e591906159c7565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018590526001600160a01b0391909116906323b872dd906064016020604051808303816000875af1158015614253573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061427791906159e4565b6142ad576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163aa9537959160048083019260209291908290030181865afa158015614310573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061433491906159c7565b6040517fb11a3a9b0000000000000000000000000000000000000000000000000000000081526001600160a01b038881166004830152919091169063b11a3a9b90602401602060405180830381865afa158015614395573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143b991906159ae565b6143c39083615a35565b60d854604080517ff122961f00000000000000000000000000000000000000000000000000000000815290519293506001600160a01b039091169163b3123922913391849163f122961f9160048083019260209291908290030181865afa158015614432573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061445691906159ae565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156144b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144db91906159e4565b6145ee57808411156145ee5760d860009054906101000a90046001600160a01b03166001600160a01b031663aa9537956040518163ffffffff1660e01b8152600401602060405180830381865afa15801561453a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061455e91906159c7565b6001600160a01b031663956b95e7876145778488615a35565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156145d557600080fd5b505af11580156145e9573d6000803e3d6000fd5b505050505b6145f88482615194565b92506146048483615a35565b6001600160a01b038716600090815260de6020526040902090815560cb5460019091015560cc548410614638576000614646565b8360cc546146469190615a35565b60cc556040518481526001600160a01b038716907f0516911bcc3a0a7412a44601057c0a0a1ec628bde049a84284bc4288665344889060200160405180910390a250509250929050565b6001600160a01b038216600090815260e36020526040902054156146e0576040517fc466f95700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006146eb83613c42565b9050670de0b6b3a7640000816040015111614732576040517f53d1636700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cd5460d3546147429084615ad3565b61474c9190615ad3565b614754613862565b101561478c576040517fbc6072f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061479784614035565b90506147a38382615ad3565b6001600160a01b038516600090815260de6020526040812091825560cb5460019092019190915560cc80548592906147dc908490615ad3565b909155505060d854604080517faa95379500000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169163aa953795916004808201926020929091908290030181865afa158015614844573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061486891906159c7565b6040517fc85e8dde0000000000000000000000000000000000000000000000000000000081526001600160a01b03868116600483015260248201869052919091169063c85e8dde90604401600060405180830381600087803b1580156148cd57600080fd5b505af11580156148e1573d6000803e3d6000fd5b5050604080516001600160a01b0388168152602081018790527f29f5a3c94649e9fd569197488f431f12d8b1fe681596964128403511823a638693500190506127e6565b6040517f6240fb9c0000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152821690636240fb9c90602401602060405180830381865afa158015614984573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149a891906159e4565b61186c576040517fc4230ae300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1661186c5760008281526065602090815260408083206001600160a01b03851684529091529020805460ff19166001179055614a3c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff161561186c5760008281526065602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008215614b315781614b17600185615a35565b614b219190615ae6565b614b2c906001615ad3565b6113e0565b60009392505050565b600081815260e16020908152604080832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560018101849055600281018490556003810184905560040183905533835260e290915281208054915b82811015614c4057818181548110614bb457614bb4615a48565b90600052602060002001548403614c385781614bd1600185615a35565b81548110614be157614be1615a48565b9060005260206000200154828281548110614bfe57614bfe615a48565b906000526020600020018190555081805480614c1c57614c1c615b21565b6001900381819060005260206000200160009055905550505050565b600101614b9a565b506040517f74ec20b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116611e61576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614cbb615413565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600054610100900460ff16612961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611859565b600054610100900460ff16614e33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611859565b61296161547f565b6064841180614e48575083155b15614e7f576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064831115614eba576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064821115614ef5576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064811180614f02575080155b15614f39576040517fb4fa3fb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051608080820183528682526020808301879052828401869052606092830185905260d988905560da87905560db86905560dc85905583518881529081018790529283018590529082018390527f62dd46f943681bd727e339f4baaa19fb66ea209fbe7d9b4a75aa74c33acc18f391016127e6565b6000614fba614072565b905060d860009054906101000a90046001600160a01b03166001600160a01b031663e069f7146040518163ffffffff1660e01b8152600401602060405180830381865afa15801561500f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061503391906159c7565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018490526001600160a01b0391909116906323b872dd906064016020604051808303816000875af11580156150a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906150c591906159e4565b6150fb576040517fd3544e3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081615110670de0b6b3a764000085615ab4565b61511a9190615ae6565b33600090815260df602052604081208054929350839290919061513e908490615ad3565b925050819055508060cf60008282546151579190615ad3565b9091555050604080518481526020810183905233917f9a8f44850296624dadfd9c246d17e47171d35727a181bd090aa14bbbe00238bb9101610ee0565b60008183106151a357816113e0565b5090919050565b60d75433600090815260e260205260408120549091906151cb906001615ad3565b1115615203576040517f6b304ad800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260d360008282546152159190615ad3565b90915550506040805160a08101825233808252602080830186815283850188815260006060808701828152436080890190815260d28054855260e188528a852099518a547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178a5595516001808b0191909155945160028a0155905160038901555160049097019690965584815260e284528681208354815493840182559082529084902090910155548451928352908201529182018590527f0edfc24f4f80277416f78f699d4733f7bb58fd6fb8838e2b1033162cee5fd7aa910160405180910390a160d2805490600061531583615b50565b9190505550600160d2546113e09190615a35565b6153316140d4565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614ce83390565b60008281526065602090815260408083206001600160a01b038516845290915290205460ff1661186c5761539981615522565b6153a4836020615534565b6040516020016153b5929190615b8e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261185991600401615c0f565b60975460ff16612961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401611859565b600054610100900460ff16615516576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401611859565b6097805460ff19169055565b6060610f806001600160a01b03831660145b60606000615543836002615ab4565b61554e906002615ad3565b67ffffffffffffffff81111561556657615566615c60565b6040519080825280601f01601f191660200182016040528015615590576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000816000815181106155c7576155c7615a48565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061562a5761562a615a48565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000615666846002615ab4565b615671906001615ad3565b90505b600181111561570e577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106156b2576156b2615a48565b1a60f81b8282815181106156c8576156c8615a48565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361570781615c8f565b9050615674565b5083156113e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401611859565b6001600160a01b0381168114611e6157600080fd5b6000806040838503121561579f57600080fd5b82356157aa81615777565b946020939093013593505050565b6000602082840312156157ca57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146113e057600080fd5b60006020828403121561580c57600080fd5b81356113e081615777565b60006020828403121561582957600080fd5b5035919050565b60008060006060848603121561584557600080fd5b833561585081615777565b95602085013595506040909401359392505050565b6000806040838503121561587857600080fd5b82359150602083013561588a81615777565b809150509250929050565b600080604083850312156158a857600080fd5b82356158b381615777565b9150602083013561588a81615777565b600080600080608085870312156158d957600080fd5b5050823594602084013594506040840135936060013592509050565b6020808252825182820181905260009190848201906040850190845b8181101561592d57835183529284019291840191600101615911565b50909695505050505050565b6000806020838503121561594c57600080fd5b823567ffffffffffffffff8082111561596457600080fd5b818501915085601f83011261597857600080fd5b81358181111561598757600080fd5b8660208260051b850101111561599c57600080fd5b60209290920196919550909350505050565b6000602082840312156159c057600080fd5b5051919050565b6000602082840312156159d957600080fd5b81516113e081615777565b6000602082840312156159f657600080fd5b815180151581146113e057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610f8057610f80615a06565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080600060608486031215615a8c57600080fd5b835160ff81168114615a9d57600080fd5b602085015160409095015190969495509392505050565b6000816000190483118215151615615ace57615ace615a06565b500290565b80820180821115610f8057610f80615a06565b600082615b1c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60006000198203615b6357615b63615a06565b5060010190565b60005b83811015615b85578181015183820152602001615b6d565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615bc6816017850160208801615b6a565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351615c03816028840160208801615b6a565b01602801949350505050565b6020815260008251806020840152615c2e816040850160208701615b6a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600081615c9e57615c9e615a06565b50600019019056fea2646970667358221220a0f6cdc836898eab69a9cd7f5c092511af32b731ba4f903c8bfeff3e04b8fa5264736f6c63430008100033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.