Source Code
Overview
MNT Balance
MNT Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PoolMaster
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 50 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {ERC20Upgradeable, IERC20MetadataUpgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol';
import {SafeERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol';
import {ReentrancyGuardUpgradeable} from '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import {SafeCastUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol';
import {IBondNFT, CallbackParams} from './interfaces/IBondNFT.sol';
import {IPoolFactory} from './interfaces/IPoolFactory.sol';
import {InitParams, PoolStatus} from './interfaces/IPoolMaster.sol';
import {UtilsGuard} from './utils/Utils.sol';
import {Decimal} from './libraries/Decimal.sol';
import {RewardAsset} from './libraries/RewardAsset.sol';
/**
* @title A smart contract storage the open pool;
* @notice Credit Vaults Pool is a very flexible lending product that has higher lender APR,
* potentially high flexibility for lenders, and can be customized and used by any borrower type;
*/
contract PoolMaster is Initializable, ERC20Upgradeable, ReentrancyGuardUpgradeable, UtilsGuard {
using SafeERC20Upgradeable for IERC20MetadataUpgradeable;
using Decimal for uint256;
using RewardAsset for RewardAsset.Data;
using SafeCastUpgradeable for uint256;
using SafeCastUpgradeable for int256;
/**
* All events:
* {Supplied} - returning info about supplied of liquidity;
* {WithdrawalRequested} - returning info about requested amount;
* {Redeemed} - returning info about redeemed liquidity;
* {DepositCapChanged} - returning info about the changed deposit capacity;
* {MinDepositChanged} - returning info about the changed minimum deposit;
* {NoticePeriodChanged} - returning info about the changed notice period;
* {RepaymentFrequencyChanged} - returning info about the changed repayment frequency;
* {BondRedeemed} - durning info about the redeemed bond NFT;
* {RepaymentRequested} - returning info about the requested repayment;
* {APRChanged} - returning info about the changed APR;
* {APRChangeRequested} - returning info about the requested APR change;
* {BorrowerChanged} - returning info about the changed borrower;
* {PoolProtocolFeeChanged} - returning info about the changed pool protocol fee;
* {RewardAssetInfoSet} - returning info about the set reward asset info;
* {FullRepayment} - returning info about the full repayment;
* {Repayment} - returning info about the repayment;
* {RewardWithdrawn} - returning info about the withdrawn reward;
* {Closed} - returning if the pool is closed;
* {Defaulted} - returning if the pool is defaulted;
*/
event Supplied(address indexed lender, uint256 amount, uint256 tokensAmount);
event WithdrawalRequested(
address indexed lender,
uint256 repaymentDate,
uint256 amount,
uint256 bondNFTIdCounter
);
event Redeemed(address indexed lender, uint256 amount, uint256 tokensAmount);
event DepositCapChanged(uint256 newDepositCap);
event MinDepositChanged(uint256 newMinDeposit);
event NoticePeriodChanged(uint256 newValue);
event RepaymentFrequencyChanged(uint256 newRepaymentFrequency);
event BondRedeemed(
address indexed lender,
uint256 indexed bondId,
uint256 amount,
uint256 receivedAmount
);
event RepaymentRequested(uint256 repaymentDate);
event APRChanged(uint256 newAPR);
event APRChangeRequested(uint256 newAPR, uint256 applyDate);
event BorrowerChanged(address newBorrower);
event RewardAssetInfoSet(address asset, uint256 rate);
event FullRepayment(uint256 amount, uint256 penaltyAmount, uint256 feesAmount);
event Repayment(uint256 amount, uint256 penaltyAmount, uint256 feesAmount);
event RewardWithdrawn(address asset, uint256 amount);
event Closed();
event Defaulted();
/**
* All Errors:
*/
error WrongNumber();
error OnlyFactory();
error OnlyBorrower();
error OnlyGovernor();
error PoolInactive();
error PoolHasLiquidity();
error InsufficientFunds();
error NoDebtFound();
error RepaymentMissing();
/**
* @notice Deposit Cap - amount beyond which Lenders can't execute deposit transaction
*/
uint256 public depositCap;
/**
* @notice repayments are being made (every X days)
*/
uint256 public repaymentFrequency;
/**
* @notice notice period for withdrawals
*/
uint256 public minimumNoticePeriod;
/**
* @notice minimum deposit amount
*/
uint256 public minDeposit;
/**
* @notice Lending APR
*/
uint256 public lendAPR;
uint256 public penaltyRate;
uint256 public gracePeriod;
uint256 public protocolFee;
uint256 public periodToStartAuction;
bool public isKycRequired;
address public borrower;
IERC20MetadataUpgradeable public asset;
IPoolFactory public poolFactory;
IBondNFT public bondNFT;
uint8 private _decimals;
uint256 private _bondNFTIdCounter;
uint256 private _fullRepaymentDate;
bool internal isAuctionStarted;
uint256 internal _currentRepaymentDate;
uint256 internal _lastRequestIndex;
uint public constant MINIMUM_LIQUIDITY = 10 ** 3;
struct RepaymentRoundInfo {
uint256 debtAmount;
uint256 bondTokenId;
uint256 paidAt;
uint256 exchangeRate;
}
/**
* @dev Record the debt info for a specific repayment period.
* @notice `Repayment` date -> `Repayment round` info;
*/
mapping(uint256 => RepaymentRoundInfo) public repaymentRoundInfo;
struct BorrowInfo {
uint256 borrows;
uint256 feesAmount;
uint256 penaltyAmount;
uint256 exchangeRate;
uint256 lastAccrual;
uint256 overdueEntrance;
PoolStatus status;
}
BorrowInfo internal _info;
RewardAsset.Data internal rewardAssetInfo;
mapping(uint256 => uint256) internal _aprChanges;
/// @notice Number of unpaid repayment rounds, used to block withdrawals if there are 2 active rounds
uint8 private _unpaidRounds;
/**
* @dev Modifier that allows only PoolsFactory to call the function;
*/
modifier onlyPoolFactory() {
if (msg.sender != address(poolFactory)) revert OnlyFactory();
_;
}
/**
* @dev Modifier that allows only `borrower`;
*/
modifier onlyBorrower() {
if (msg.sender != borrower) revert OnlyBorrower();
_;
}
/**
* @dev Modifier that pool was closed;
*/
modifier onlyActive() {
accrueInterest();
PoolStatus poolStatus = _status(_info);
if (poolStatus != PoolStatus.Active && poolStatus != PoolStatus.Overdue) revert PoolInactive();
_;
}
modifier onlyEligible(address _account) {
/// Exclude ongoing pool transfers;
if (_account != address(this) && _account != address(0)) {
checkKycStatus(_account);
}
_;
}
modifier onlyGovernor() {
if (msg.sender != poolFactory.owner()) revert OnlyGovernor();
_;
}
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @dev Initializing parameters of the term pool contract;
* @notice Initializing pool with input parameters,
* returning `true` if all `success`;
*/
function __init(
InitParams calldata params,
bool kycRequired
) public virtual initializer returns (bool) {
__ReentrancyGuard_init();
asset = IERC20MetadataUpgradeable(params.asset);
string memory currencySymbol = asset.symbol();
__ERC20_init(
params.name,
string(
bytes.concat(bytes('cp'), bytes(params.borrowerSymbol), bytes('-'), bytes(currencySymbol))
)
);
_decimals = asset.decimals();
/// Setting address of the `BondNFT`;
bondNFT = IBondNFT(params.bondNFT);
/// Setting address of the `PoolFactory.sol`;
poolFactory = IPoolFactory(msg.sender);
/// Initializing a new `nft contract` with parameters;
bool success = bondNFT.__init(address(this), '');
/// For some reason, the pool was not created;
if (success == false) return false;
/// Setting `protocol rates and fees`;
RewardAsset.RewardAssetData[] memory _rewardAssetInfo;
(penaltyRate, gracePeriod, protocolFee, periodToStartAuction, _rewardAssetInfo) = poolFactory
.getPoolConfigVars();
// Copy rewardAsset info from pool factory;
// Sets the index of each asset and saves asset info;
for (uint256 i; i < _rewardAssetInfo.length; i++) {
rewardAssetInfo.insert(_rewardAssetInfo[i].asset, _rewardAssetInfo[i].rate);
}
/// We initialize its data;
minDeposit = params.minDeposit;
depositCap = params.depositCap;
repaymentFrequency = params.repaymentFrequency;
minimumNoticePeriod = params.minimumNoticePeriod;
lendAPR = params.lendAPR;
borrower = params.borrower;
isKycRequired = kycRequired;
_info.lastAccrual = block.timestamp;
_info.exchangeRate = Decimal.MULTIPLIER;
return true;
}
/**
* @dev Supply of liquidity for open pool;
* @notice `Lender` provides the borrower pool with the required amount of `asset`;
* {tokensAmount} - amount after you deposit USDC;
*/
function supply(uint256 _amount) external nonReentrant onlyActive {
if (msg.sender == borrower || _fullRepaymentDate != 0) revert ActionNotAllowed();
// Check lender kyc status
checkKycStatus(msg.sender);
/// @dev If borrower is blacklisted, deposits are blocked
poolFactory.checkBorrowerStatus(borrower);
uint256 currentSize = poolSize();
bool depositCapEnabled = depositCap != 0;
if (_amount == type(uint256).max) {
_amount = asset.balanceOf(msg.sender);
if (depositCapEnabled) {
if (currentSize >= depositCap) revert WrongNumber();
uint256 allowedAmount = depositCap - currentSize;
_amount = _amount > allowedAmount ? allowedAmount : _amount;
}
}
if (
_amount == 0 ||
minDeposit > _amount ||
(depositCapEnabled && _amount + currentSize > depositCap)
) revert WrongNumber();
// swap the supplied amount
uint256 tokensAmount = _amount.divDecimal(_info.exchangeRate);
if (_currentRepaymentDate == 0) {
/// Set currentRepayment date on initial supply;
_currentRepaymentDate = block.timestamp + repaymentFrequency;
if (tokensAmount < MINIMUM_LIQUIDITY) revert WrongNumber();
tokensAmount -= MINIMUM_LIQUIDITY;
_mint(address(this), MINIMUM_LIQUIDITY);
}
_info.borrows += _amount;
_mint(msg.sender, tokensAmount);
asset.safeTransferFrom(msg.sender, borrower, _amount);
emit Supplied(msg.sender, _amount, tokensAmount);
}
/**
* @notice Used to request a withdrawal;
* @param _amount - number of asset user wants to withdraw;
* {calculatedAmount} - calculated amount of the `bondNFT`;
*/
function requestWithdrawal(uint256 _amount) external onlyActive {
if (_fullRepaymentDate != 0) revert ActionNotAllowed();
if (_amount == type(uint256).max) {
_amount = balanceOf(msg.sender);
}
if (_amount == 0 || _amount > balanceOf(msg.sender)) revert InsufficientFunds();
// get current repayment date
uint256 currentRepDate = currentRepaymentDate();
// Get the next repayment date allowed for withdrawal
uint256 repDate = getNextRepaymentDate();
// store current repayment date in case it was virtually calculated
if (repaymentRoundInfo[currentRepDate].debtAmount == 0 && currentRepDate != repDate) {
_currentRepaymentDate = repDate;
} else {
_currentRepaymentDate = currentRepDate;
}
RepaymentRoundInfo storage info = repaymentRoundInfo[repDate];
if (info.bondTokenId == 0) {
/// Increasing `_bondNFTIdCounter` only if the repayment round is different;
_bondNFTIdCounter += 1;
info.bondTokenId = _bondNFTIdCounter;
// Block withdrawals in case there are already 2 active repayment rounds
if (_unpaidRounds == 2) revert ActionNotAllowed();
++_unpaidRounds;
} else if (info.paidAt != 0 && _unpaidRounds == 0) {
// the current round was paid already, but still may store withdrawals
/// Increasing `_bondNFTIdCounter` so the new withdrawals can have different exchange rate;
_bondNFTIdCounter += 1;
info.bondTokenId = _bondNFTIdCounter;
/// @dev use-case when there are multiple payment for the same round
++_unpaidRounds;
}
/// Lock `_amount` tokens in the smart contract;
_transfer(msg.sender, address(this), _amount);
// start accruing round reward per share
RewardAsset.RewardAssetData[] memory _rewardAsset = getRewardAssetInfo();
_accrueRoundReward(repDate);
for (uint256 i; i < _rewardAsset.length; i++) {
address rewardAssetAddr = _rewardAsset[i].asset;
rewardAssetInfo.decreaseRewardCorrection(
rewardAssetAddr,
msg.sender,
_amount,
rewardAssetInfo.magnifiedRoundRewardPerShare[info.bondTokenId][rewardAssetAddr]
);
}
rewardAssetInfo.roundLastDistribution[info.bondTokenId] = block.timestamp;
info.debtAmount += _amount;
/// Store withdrawal info snapshot as token metadata;
/// Mint ERC1155 tokens to `lender`;
bondNFT.mint(
msg.sender,
_bondNFTIdCounter,
_amount,
'',
CallbackParams({
endDate: repDate,
penaltyRate: penaltyRate,
interestRate: lendAPR,
exchangeRate: 0
})
);
emit WithdrawalRequested(msg.sender, repDate, _amount, _bondNFTIdCounter);
}
/**
* @notice Used to request a repayment by the governor;
* @dev only called by governor;
* @param _repaymentDate The repayment date when borrower should repay;
*/
function requestFullRepayment(uint256 _repaymentDate) external onlyGovernor onlyActive {
if (_fullRepaymentDate != 0 || _currentRepaymentDate == 0) revert ActionNotAllowed();
/// Disallow repayment date in past;
uint256 currentRepDate = currentRepaymentDate();
if (block.timestamp > _repaymentDate) revert InvalidArgument();
/// Repayment date is either future date, or the current unpaid round date;
_currentRepaymentDate = currentRepDate;
_fullRepaymentDate = _repaymentDate;
emit RepaymentRequested(_repaymentDate);
}
/**
* @notice Used by borrower to repay full amount;
*/
function repayAll() external nonReentrant onlyBorrower onlyActive {
uint256 repayAmount;
uint256 penaltyAmount;
uint256 feesAmount;
uint256 nextRepDate;
// In case the full repayment was request, repay interest up to the current timestamp
if (_fullRepaymentDate != 0) {
// The existing accrual info should be used to repay full amount
repayAmount = _info.borrows;
penaltyAmount = _info.penaltyAmount;
feesAmount = _info.feesAmount;
_fullRepaymentDate = 0;
if (repaymentRoundInfo[_currentRepaymentDate].debtAmount > 0) {
// Accrue rewards interest for the current round
_accrueRoundReward(_currentRepaymentDate);
// Mark future repayments as paid in case the are any
repaymentRoundInfo[_currentRepaymentDate].debtAmount = 0;
repaymentRoundInfo[_currentRepaymentDate].paidAt = block.timestamp;
repaymentRoundInfo[_currentRepaymentDate].exchangeRate = _info.exchangeRate;
}
nextRepDate = _getNextUnpaidRound(true);
if (repaymentRoundInfo[nextRepDate].debtAmount > 0) {
// Mark future repayments as paid in case the are any
repaymentRoundInfo[nextRepDate].paidAt = block.timestamp;
repaymentRoundInfo[nextRepDate].exchangeRate = _info.exchangeRate;
}
} else {
uint256 currentRepDate = currentRepaymentDate();
RepaymentRoundInfo storage roundInfo = repaymentRoundInfo[currentRepDate];
BorrowInfo memory bInfo;
if (roundInfo.debtAmount != 0) {
// get precalculated amounts for the current repayment date
uint256 roundSupply = roundInfo.debtAmount;
(repayAmount, penaltyAmount, feesAmount) = _handleRoundRepay(currentRepDate);
// burn locked tokens obtained during the withdrawal requests in the current round
_burn(address(this), roundSupply);
if (block.timestamp > currentRepDate) {
// in case the timestamp is above repayment date apply pre-calculated interest for remaining liquidity up to nearest repayment date (in future)
bInfo = _accrueInterestVirtual(currentRepDate + repaymentFrequency);
repayAmount += bInfo.borrows;
feesAmount += bInfo.feesAmount;
penaltyAmount += bInfo.penaltyAmount;
/// Store the ex rate for redeeming conversion;
_info.exchangeRate = bInfo.exchangeRate;
// get new current repayment date after repaying the overdue one
nextRepDate = _getNextUnpaidRound(true);
if (repaymentRoundInfo[nextRepDate].debtAmount > 0) {
// Mark future repayments as paid in case the are any
repaymentRoundInfo[nextRepDate].exchangeRate = bInfo.exchangeRate;
repaymentRoundInfo[nextRepDate].paidAt = bInfo.lastAccrual;
}
} else {
// in case the timestamp is prior to the exchange rate, pre-calculate interest for the remaining liquidity up to the repayment date
bInfo = _accrueInterestVirtual(currentRepDate);
repayAmount += bInfo.borrows;
feesAmount += bInfo.feesAmount;
penaltyAmount += bInfo.penaltyAmount;
/// Store the round ex rate for redeeming conversion;
_info.exchangeRate = roundInfo.exchangeRate;
nextRepDate = _getNextUnpaidRound(true);
if (repaymentRoundInfo[nextRepDate].debtAmount > 0) {
// Mark future repayments as paid in case the are any
repaymentRoundInfo[nextRepDate].exchangeRate = roundInfo.exchangeRate;
repaymentRoundInfo[nextRepDate].paidAt = roundInfo.paidAt;
}
}
} else {
// in case there is no repayment rounds (no withdrawals requested), apply the pre-calculated interest up to repayment date as total interest
bInfo = _accrueInterestVirtual(currentRepDate);
repayAmount = bInfo.borrows;
feesAmount = bInfo.feesAmount;
penaltyAmount = bInfo.penaltyAmount;
/// Store the accrued ex rate for redeeming conversion;
_info.exchangeRate = bInfo.exchangeRate;
}
}
// Reset borrows info
_info.feesAmount = 0;
_info.borrows = 0;
_info.penaltyAmount = 0;
_info.overdueEntrance = 0;
// Decrease unpaid rounds;
_unpaidRounds = 0;
// Accrue rewards interest for the next round
_accrueRoundReward(nextRepDate);
/// Burn all locked tokens obtained during withdrawals requests;
_burn(address(this), balanceOf(address(this)));
_transferRepayment(repayAmount, penaltyAmount, feesAmount);
emit FullRepayment(repayAmount, penaltyAmount, feesAmount);
_closePool();
}
/**
* @notice used to repay current period debt
*/
function repay() external nonReentrant onlyBorrower onlyActive {
uint256 currentRepDate = currentRepaymentDate();
RepaymentRoundInfo storage roundInfo = repaymentRoundInfo[currentRepDate];
if (roundInfo.debtAmount == 0) revert NoDebtFound();
// get precalculated amounts for the current repayment date
uint256 roundAmount = roundInfo.debtAmount;
(uint256 amount, uint256 penaltyAmount, uint256 feesAmount) = _handleRoundRepay(currentRepDate);
// Decrease unpaid rounds;
_unpaidRounds -= 1;
// update storage variable // set next repayment date in case in the current one no more withdrawals allowed
if (minimumNoticePeriod == 0) {
_currentRepaymentDate = currentRepaymentDate();
} else {
_currentRepaymentDate = _getNextUnpaidRound(true);
}
// burn locked tokens obtained during the withdrawal requests
_burn(address(this), roundAmount);
_transferRepayment(amount, penaltyAmount, feesAmount);
emit Repayment(amount, penaltyAmount, feesAmount);
}
function _handleRoundRepay(
uint256 currentRepDate
) internal returns (uint256 amount, uint256 penaltyAmount, uint256 feesAmount) {
RepaymentRoundInfo storage roundInfo = repaymentRoundInfo[currentRepDate];
// calculate the repayment amounts for the current repayment date
(amount, penaltyAmount, feesAmount) = _dueOf(_info, roundInfo, block.timestamp, currentRepDate);
if (block.timestamp > currentRepDate) {
// in case the repayment is happen during overdue period, store payment date and exchange rate for redeeming swap
roundInfo.paidAt = block.timestamp;
roundInfo.exchangeRate = _info.exchangeRate;
// Substract the accrued fees, interest and penalty for lenders requested repayment
_info.feesAmount -= feesAmount;
_info.borrows -= amount;
_info.penaltyAmount -= penaltyAmount;
_info.overdueEntrance = 0;
} else {
roundInfo.paidAt = currentRepDate;
// apply the exchange rate for redeeming
roundInfo.exchangeRate = _accrueInterestVirtual(currentRepDate).exchangeRate;
// apply the exchange rate to the bond
bondNFT.setExchangeRate(roundInfo.bondTokenId, roundInfo.exchangeRate);
// calculate interest accrued for lenders that requested repayment up to current ts
uint256 _borrows = roundInfo.debtAmount.mulDecimal(_info.exchangeRate);
// extract penalty from _borrows
_borrows -= penaltyAmount;
// Substract the accrued fees and interest for lenders requested repayment
_info.feesAmount -= calcRateAmount(_borrows, _info.borrows, _info.feesAmount);
_info.borrows -= _borrows;
_info.penaltyAmount -= penaltyAmount;
}
// update rounds reward per share accumulated since first request
_accrueRoundReward(currentRepDate);
_accrueRoundReward(_getNextUnpaidRound(false));
/// @dev After repayment is made the remaining interest and fees are for the available liquidity
roundInfo.debtAmount = 0;
return (amount, penaltyAmount, feesAmount);
}
function _transferRepayment(uint256 amount, uint256 penaltyAmount, uint256 feesAmount) internal {
if (feesAmount > 0) {
// transfer the fees amount to the treasury
asset.safeTransferFrom(msg.sender, poolFactory.treasury(), feesAmount);
}
asset.safeTransferFrom(msg.sender, address(this), amount + penaltyAmount);
}
/**
* @notice Used to redeem liquidity from the pool
* @param _amount Amount to be redeemed
*/
function redeem(uint256 _amount) external nonReentrant {
accrueInterest();
uint256 tokensBalance = balanceOf(msg.sender);
// Allow redeeming only if the pool is closed
if (_info.status != PoolStatus.Closed) revert RepaymentMissing();
if (_amount == type(uint256).max) _amount = tokensBalance;
// Disallow redeeming if the amount exceeds balance
if (_amount == 0 || tokensBalance == 0 || _amount > tokensBalance) revert InsufficientFunds();
/// Exchange cpTokens for currency tokens
uint256 receivedAmount = _amount.mulDecimal(_info.exchangeRate);
/// Burn cpTokens;
_burn(msg.sender, _amount);
/// Transfer the currency tokens;
asset.safeTransfer(msg.sender, receivedAmount);
emit Redeemed(msg.sender, receivedAmount, _amount);
}
/**
* @dev Swap the bond NFT with the asset amount;
* @notice Redeeming `_amount` of the NFT to amount `asset`;
* {lenderBondAmount} - bond balance of the `lender`;
*/
function redeemBond(uint256 _id) external nonReentrant {
accrueInterest();
/// Get Bond balance of the `lender`;
uint256 lenderBondAmount = bondNFT.balanceOf(msg.sender, _id);
if (lenderBondAmount == 0) revert NonZeroValue();
// get bond token metadata
CallbackParams memory bondParams = bondNFT.tokenData(_id);
RepaymentRoundInfo storage roundInfo = repaymentRoundInfo[bondParams.endDate];
if (roundInfo.paidAt == 0 || roundInfo.paidAt > block.timestamp) revert RepaymentMissing();
// apply the bond rewards accrued during tokens lock, up to repayment date
RewardAsset.RewardAssetData[] memory _rewardAsset = getRewardAssetInfo();
for (uint256 i; i < _rewardAsset.length; i++) {
address rewardAssetAddr = _rewardAsset[i].asset;
rewardAssetInfo.increaseRewardCorrection(
rewardAssetAddr,
msg.sender,
lenderBondAmount,
rewardAssetInfo.magnifiedRoundRewardPerShare[_id][rewardAssetAddr]
);
}
/// burn bond tokens;
bondNFT.burn(msg.sender, _id, lenderBondAmount);
// Exchange bond tokens for currency tokens
uint256 receivedAmount = lenderBondAmount.mulDecimal(roundInfo.exchangeRate);
// If the bond has the exchange rate stored, use it for conversion
if (bondParams.exchangeRate != 0) {
receivedAmount = lenderBondAmount.mulDecimal(bondParams.exchangeRate);
}
asset.safeTransfer(msg.sender, receivedAmount);
emit BondRedeemed(msg.sender, _id, lenderBondAmount, receivedAmount);
}
/*
* @dev Close this pool;
* @notice `borrower` call this function for closing;
*/
function closePool() external onlyBorrower {
// Pool can be closed only if there is no liquidity provided
if (_currentRepaymentDate != 0) revert PoolHasLiquidity();
_closePool();
}
// this should close even if pool is in default state
function _closePool() internal {
if (_info.status == PoolStatus.Closed) revert PoolInactive();
_info.status = PoolStatus.Closed;
_currentRepaymentDate = 0;
emit Closed();
}
/**
* @notice Calculate total due amounts
* @return Returns the total due amounts;
*/
function totalDue() external view returns (uint256, uint256, uint256) {
if (_info.borrows == 0) return (0, 0, 0);
return _totalDue();
}
/**
* @notice Calculate due amounts
* @param repDate Repayment round timestamp
* @return Returns the due for the `round`;
*/
function dueOf(uint256 repDate) external view returns (uint256, uint256, uint256) {
RepaymentRoundInfo storage roundInfo = repaymentRoundInfo[repDate];
if (roundInfo.debtAmount == 0) return (0, 0, 0);
return _dueOf(_accrueInterestVirtual(block.timestamp), roundInfo, block.timestamp, repDate);
}
function _totalDue()
internal
view
returns (uint256 amount, uint256 penaltyAmount, uint256 feesAmount)
{
BorrowInfo memory bInfo = _accrueInterestVirtual(block.timestamp);
if (_fullRepaymentDate != 0 || bInfo.status == PoolStatus.Default) {
// If the full repayment was requested calculate due values based on round stored amount up to the current timestamp
return (bInfo.borrows, bInfo.penaltyAmount, bInfo.feesAmount);
}
uint256 currentRepDate = currentRepaymentDate();
RepaymentRoundInfo storage roundInfo = repaymentRoundInfo[currentRepDate];
if (roundInfo.debtAmount != 0) {
(amount, penaltyAmount, feesAmount) = _dueOf(
bInfo,
roundInfo,
block.timestamp,
currentRepDate
);
if (block.timestamp > currentRepDate) {
// Substract the accrued fees, interest and penalty for lenders requested repayment
bInfo.feesAmount -= feesAmount;
bInfo.borrows -= amount;
(uint256 _amount, , uint256 _fees) = _accrueToRepaymentDate(
bInfo,
currentRepDate + repaymentFrequency
);
amount += _amount;
feesAmount += _fees;
} else {
// calculate amount for remaining funds
uint256 _borrows = roundInfo.debtAmount.mulDecimal(bInfo.exchangeRate);
// extract penalty from _borrows
_borrows -= penaltyAmount;
bInfo.feesAmount -= calcRateAmount(_borrows, bInfo.borrows, bInfo.feesAmount);
bInfo.borrows -= _borrows;
/// @dev The virtual interest amount contains accrual for the remaining funds until current repayment date
(uint256 _amount, , uint256 _fees) = _accrueToRepaymentDate(bInfo, currentRepDate);
amount += _amount;
feesAmount += _fees;
}
return (amount, bInfo.penaltyAmount, feesAmount);
}
// if no withdrawals calculate due up to nearest repayment date (in future)
return _accrueToRepaymentDate(bInfo, currentRepDate);
}
function _accrueToRepaymentDate(
BorrowInfo memory bInfo,
uint256 repDate
) internal view returns (uint256, uint256, uint256) {
// get period
uint256 deltaPeriod = 0;
if (repDate > block.timestamp) {
deltaPeriod = repDate - block.timestamp;
}
// calculate due up to nearest repayment date (in future)
bInfo.feesAmount += bInfo.borrows.mulDecimal(calcDeltaRate(deltaPeriod, protocolFee));
bInfo.borrows += bInfo.borrows.mulDecimal(calcDeltaRate(deltaPeriod, lendAPR));
return (bInfo.borrows, bInfo.penaltyAmount, bInfo.feesAmount);
}
function _dueOf(
BorrowInfo memory bInfo,
RepaymentRoundInfo memory info,
uint256 timestamp,
uint256 repaymentDate
) internal view returns (uint256 amount, uint256 penaltyAmount, uint256 feesAmount) {
if (timestamp > repaymentDate) {
// calculate total interest that contains penalty interest + additional interest;
amount = info.debtAmount.mulDecimal(bInfo.exchangeRate);
// calculate amount penalty in case the timestamp is above repayment date
penaltyAmount =
amount -
calcRateAmount(amount, bInfo.borrows + bInfo.penaltyAmount, bInfo.borrows);
// substract the penalty interest from the calculated amount
amount -= penaltyAmount;
feesAmount = calcRateAmount(amount, bInfo.borrows, bInfo.feesAmount);
} else {
// calculate accrued fees for the specific amount up to current repayment date
(amount, penaltyAmount, feesAmount) = accrueAmounts(
bInfo.borrows,
bInfo.feesAmount,
bInfo.penaltyAmount,
info.debtAmount,
totalSupply(),
calcDeltaRate(repaymentDate - timestamp, lendAPR),
calcDeltaRate(repaymentDate - timestamp, protocolFee)
);
}
return (amount, penaltyAmount, feesAmount);
}
/**
* @notice Used to check if the account is passed KYC
* @param _account The wallet address of the account
*/
function checkKycStatus(address _account) public {
if (isKycRequired) {
poolFactory.checkKycStatus(_account);
}
}
/**
* @notice Function is called through Factory to withdraw reward for some user
* @param _asset The address of reward asset
* @param account Account to withdraw reward for
* @return withdrawable amount
*/
function withdrawReward(
address _asset,
address account
) external onlyPoolFactory onlyEligible(account) returns (uint256) {
accrueInterest();
_accrueReward();
(, uint256 _withdrawable) = accumulativeRewardOf(_asset, account);
if (_withdrawable > 0) {
rewardAssetInfo.updateRewardWithdrawals(_asset, account, _withdrawable);
emit RewardWithdrawn(_asset, _withdrawable);
}
return _withdrawable;
}
/**
* @notice Returns the accumulated reward of specific reward asset for the given account
* @dev Returns the accumulated reward in 18 decimal places
* @param _rewardAsset The address of reward asset
* @param account The address of the user
* @return accumulated accumulated rewards of the specific reward asset for the given account
* @return withdrawable withdrawble part of the reward for the given account
*/
function accumulativeRewardOf(
address _rewardAsset,
address account
) public view returns (uint256 accumulated, uint256 withdrawable) {
accumulated = _accumulativeRewardOf(_rewardAsset, account);
withdrawable = accumulated - rewardAssetInfo.rewardWithdrawals[_rewardAsset][account];
}
function _accumulativeRewardOf(
address _rewardAsset,
address account
) internal view returns (uint256) {
uint256 currentTime = _accrueInterestVirtual(block.timestamp).lastAccrual;
uint256 currentRewardPerShare = rewardAssetInfo.magnifiedRewardPerShare[_rewardAsset];
uint256 index = rewardAssetInfo.addressIndex[_rewardAsset];
uint256 rate = rewardAssetInfo.rewardAssetData[index].rate;
if (
totalSupply() != 0 &&
rewardAssetInfo.lastRewardDistribution != 0 &&
currentTime > rewardAssetInfo.lastRewardDistribution &&
rate != 0
) {
uint256 period = currentTime - rewardAssetInfo.lastRewardDistribution;
currentRewardPerShare += (REWARD_MAGNITUDE * period * rate) / totalSupply();
}
return
((balanceOf(account) * currentRewardPerShare).toInt256() +
rewardAssetInfo.magnifiedRewardCorrections[_rewardAsset][account]).toUint256() /
REWARD_MAGNITUDE;
}
/**
* @notice accrue reward
*/
function _accrueReward() internal {
// get reward assets array
uint256 currentTime = _info.lastAccrual;
if (
totalSupply() != 0 &&
rewardAssetInfo.lastRewardDistribution != 0 &&
currentTime > rewardAssetInfo.lastRewardDistribution
) {
RewardAsset.RewardAssetData[] memory _rewardAsset = getRewardAssetInfo();
for (uint256 i; i < _rewardAsset.length; i++) {
if (_rewardAsset[i].rate != 0) {
rewardAssetInfo.updateMagnifiedRewardPerShare(
_rewardAsset[i].asset,
currentTime - rewardAssetInfo.lastRewardDistribution,
_rewardAsset[i].rate,
REWARD_MAGNITUDE,
totalSupply()
);
}
}
}
rewardAssetInfo.lastRewardDistribution = currentTime;
}
/**
* @notice accrue round bond reward
* @dev A round can incorporate multiple bonds
*/
function _accrueRoundReward(uint256 roundDate) internal {
RepaymentRoundInfo storage roundInfo = repaymentRoundInfo[roundDate];
uint256 bondId = roundInfo.bondTokenId;
uint256 lastDistribution = rewardAssetInfo.roundLastDistribution[bondId];
if (totalSupply() != 0 && block.timestamp > lastDistribution && roundInfo.debtAmount > 0) {
RewardAsset.RewardAssetData[] memory _rewardAsset = getRewardAssetInfo();
// update round reward per share accumulated since first request
for (uint256 i; i < _rewardAsset.length; i++) {
rewardAssetInfo.updateMagnifiedRoundRewardPerShare(
_rewardAsset[i].asset,
bondId,
block.timestamp - lastDistribution,
_rewardAsset[i].rate,
REWARD_MAGNITUDE,
totalSupply()
);
}
rewardAssetInfo.roundLastDistribution[bondId] = block.timestamp;
}
}
/**
* @notice Used to change repayment frequency;
* @dev The minimal repayment frequency is one day.
* @param _newRepaymentFrequency The new repayment frequency to be set;
*/
function changeRepaymentFrequency(
uint256 _newRepaymentFrequency
) external onlyBorrower onlyActive {
if (_newRepaymentFrequency < 1 days || _unpaidRounds == 2) revert ActionNotAllowed();
// Unable to increase repayment frequency if pool is active;
if (_newRepaymentFrequency > repaymentFrequency && _currentRepaymentDate != 0)
revert PoolHasLiquidity();
repaymentFrequency = _newRepaymentFrequency;
emit RepaymentFrequencyChanged(_newRepaymentFrequency);
}
/**
* @notice Is used to either decrease or increase deposit capacity;
* @param _newDepositCap the deposit capacity to be set;
*/
function changeDepositCapacity(uint256 _newDepositCap) external onlyBorrower onlyActive {
depositCap = _newDepositCap;
emit DepositCapChanged(_newDepositCap);
}
/**
* @notice Is used to change minimum deposit amount;
* @param _newMinDeposit the min deposit about to be set;
*/
function changeMinDeposit(uint256 _newMinDeposit) external onlyBorrower onlyActive {
// Disallow values higher then current deposit cap in case there is
if (depositCap > 0 && _newMinDeposit > depositCap) revert MinDepositExceedCap();
minDeposit = _newMinDeposit;
emit MinDepositChanged(_newMinDeposit);
}
/**
* @notice Setting less period of the pool, the period can be 0;
* @dev Change `minimumNoticePeriod` in this pool;
*/
function changeNoticePeriod(uint256 _newNoticePeriod) external onlyBorrower onlyActive {
// After the pool is created the notice period cannot be increased
if (_newNoticePeriod > minimumNoticePeriod || _unpaidRounds == 2) revert ActionNotAllowed();
minimumNoticePeriod = _newNoticePeriod;
emit NoticePeriodChanged(_newNoticePeriod);
}
/**
* @notice Used to change pool protocol fee
* @dev Only called by governor
* @param _newProtocolFee New Protocol fee to be set
*/
function changePoolProtocolFee(uint256 _newProtocolFee) external onlyGovernor onlyActive {
if (_newProtocolFee == 0 || _newProtocolFee > 1e18) revert WrongNumber();
protocolFee = _newProtocolFee;
}
/**
* @notice used to set a period to start auction
* @param period the new start auction period
*/
function setPeriodToStartAuction(uint256 period) external onlyGovernor {
if (period == 0) revert WrongNumber();
periodToStartAuction = period;
}
/**
* @notice Used to change pool borrower address
* @dev Only called by pool factory
* @param _newBorrower The address of the new borrower
*/
function changeBorrower(address _newBorrower) external onlyPoolFactory {
borrower = _newBorrower;
emit BorrowerChanged(_newBorrower);
}
/**
* @notice Used to set the reward asset and rating
* @dev Only called by owner(governor)
* @param _asset The address of reward asset to be set
* @param _rate The reward rate per sec to be set;
*/
function setRewardAssetInfo(
address _asset,
uint256 _rate
) external onlyGovernor nonZeroAddress(_asset) {
accrueInterest();
_accrueReward();
_accrueRoundReward(currentRepaymentDate());
_accrueRoundReward(_getNextUnpaidRound(false));
bool success = rewardAssetInfo.insert(_asset, _rate);
if (!success) revert RequestFailed();
emit RewardAssetInfoSet(_asset, _rate);
}
/**
* @notice Change lending APR percentage
* @dev Function can change lending APR;
*/
function changeAPR(
uint256 _newAPR
) external onlyActive onlyBorrower nonSameValue(_newAPR, lendAPR) {
if (_newAPR == 0) revert WrongNumber();
// if current repayment date is zero or no supplies yet the decrease apr request is applied immediately
uint256 applyDate = currentRepaymentDate();
if (_newAPR > lendAPR || applyDate == 0) {
// in case an increase request is submitted, the change is applied immediately.
lendAPR = _newAPR;
// remove the old request
_aprChanges[_lastRequestIndex] = 0;
emit APRChanged(_newAPR);
} else {
if (minimumNoticePeriod == 0) applyDate += repaymentFrequency;
// APR decrease change is applied in the upcoming repayment after 2 notice periods
while (block.timestamp + 2 * minimumNoticePeriod > applyDate) {
applyDate += repaymentFrequency;
}
_aprChanges[applyDate] = _newAPR;
_lastRequestIndex = applyDate;
emit APRChangeRequested(_newAPR, applyDate);
}
}
/**
* @notice Used to set the pool status to `Default`;
* @dev Only called by the governor;
*/
function forceDefault() external onlyGovernor onlyActive {
_info.status = PoolStatus.Default;
emit Defaulted();
}
/**
* @notice Function is called by Auction contract when auction is started
*/
function processAuctionStart() external onlyPoolFactory {
accrueInterest();
isAuctionStarted = true;
}
/**
* @notice used to cancel unstarted auction
*/
function cancelAuction() external {
accrueInterest();
bool periodToStartPassed = block.timestamp >= _info.lastAccrual + periodToStartAuction;
if (_info.status == PoolStatus.Default && !isAuctionStarted && periodToStartPassed) {
_processAuctionResolution(0);
} else {
revert ActionNotAllowed();
}
}
/**
* @notice Function is called by Auction contract to process pool debt claim
* @param _payedAmount The total amount obtained after auction resolution
* @dev Closes pool after auction ends, regardless of auction result
*/
function processDebtClaim(uint256 _payedAmount) external onlyPoolFactory {
return _processAuctionResolution(_payedAmount);
}
/**
* @dev Return the `decimals` of this ERC20 standard;
*/
function decimals() public view override returns (uint8) {
return _decimals;
}
/**
* @dev Function to get current pool `status`;
* @return Pool `status` as state `enumerable`;
*/
function status() external view returns (PoolStatus) {
return _status(_accrueInterestVirtual(block.timestamp));
}
function cash() public view returns (uint256) {
return asset.balanceOf(address(this));
}
/**
* @notice Pool Size == Total Borrows == Borrower Balance;
* @return Returns total borrowed amount for all `lenders`;
*/
function poolSize() public view returns (uint256) {
BorrowInfo memory bInfo = _accrueInterestVirtual(block.timestamp);
return bInfo.borrows + bInfo.penaltyAmount;
}
/**
* @notice Returns the array of reward asset info;
*/
function getRewardAssetInfo() public view returns (RewardAsset.RewardAssetData[] memory) {
return rewardAssetInfo.getList();
}
/**
* @dev Used to calculate the exchange rate;
* @return Returns the current exchange rate;
*/
function exchangeRate() external view returns (uint256) {
return _accrueInterestVirtual(block.timestamp).exchangeRate;
}
/**
* @dev Used to calculate the current unpaid repayment date;
* @return newRepaymentDate Returns the current unpaid repayment date;
*/
function currentRepaymentDate() public view returns (uint256 newRepaymentDate) {
newRepaymentDate = _currentRepaymentDate;
if (newRepaymentDate == 0) return 0;
// in case the full repayment is requested return it
if (_fullRepaymentDate != 0 && (_fullRepaymentDate < newRepaymentDate || _unpaidRounds == 0))
return _fullRepaymentDate;
// in case the stored repayment date is unpaid return it
if (repaymentRoundInfo[newRepaymentDate].debtAmount > 0) {
return newRepaymentDate;
}
// get the new repayment date, by iterate over repayment frequency periods
while (block.timestamp > newRepaymentDate) {
newRepaymentDate += repaymentFrequency;
if (repaymentRoundInfo[newRepaymentDate].debtAmount > 0) break;
}
}
/**
* @dev Used to calculate the next repayment date used for request withdrawals;
* @return nextRepDate the next repayment date;
*/
function getNextRepaymentDate() public view returns (uint256 nextRepDate) {
nextRepDate = currentRepaymentDate();
if (nextRepDate == 0) return 0;
// In case the notice period is zero or less than the remaining time until repayment date, assign new repayment round date
if (minimumNoticePeriod == 0 || (block.timestamp + minimumNoticePeriod > nextRepDate)) {
while (block.timestamp + minimumNoticePeriod > nextRepDate) {
nextRepDate += repaymentFrequency;
}
}
}
// ------- Internal functions -------------- //
function _getNextUnpaidRound(bool checkCurrentRound) internal view returns (uint256 nextRepDate) {
nextRepDate = currentRepaymentDate();
if (checkCurrentRound && repaymentRoundInfo[nextRepDate].debtAmount > 0) {
return nextRepDate;
}
while (block.timestamp + minimumNoticePeriod > nextRepDate) {
nextRepDate += repaymentFrequency;
if (repaymentRoundInfo[nextRepDate].debtAmount > 0) break;
}
}
/**
* @dev Function to get current pool `status`;
* @notice Compare variables for set `status`;
* {debt} - amount of the debt;
* {overdue} - time of the overdue;
* @return Pool `status` as state `enumerable`;
* {PoolStatus.Overdue} - if there are overdue repayments;
* {PoolStatus.Default} - if the pool is in default state;
* {PoolStatus.Closed} - if the pool is closed;
*/
function _status(BorrowInfo memory info) internal view returns (PoolStatus) {
if (info.status == PoolStatus.Closed || info.status == PoolStatus.Default) {
return info.status;
}
uint256 currentRepDate = currentRepaymentDate();
if (
block.timestamp > currentRepDate &&
block.timestamp < currentRepDate + gracePeriod &&
(repaymentRoundInfo[currentRepDate].debtAmount > 0 || _fullRepaymentDate != 0)
) {
return PoolStatus.Overdue;
}
return info.status;
}
function accrueInterest() public {
// apply new APR in case it is requested
if (_aprChanges[_lastRequestIndex] != 0 && block.timestamp > _lastRequestIndex) {
// calculate exchange rate with the old apr until prev repayment date
_info = _accrueInterestVirtual(_lastRequestIndex);
uint256 newAPR = _aprChanges[_lastRequestIndex];
_aprChanges[_lastRequestIndex] = 0;
lendAPR = newAPR;
emit APRChanged(newAPR);
}
// accrue interest up to current timestamp
_info = _accrueInterestVirtual(block.timestamp);
}
function _accrueInterestVirtual(
uint256 timestamp
) internal view returns (BorrowInfo memory newInfo) {
/// @dev Read info from storage to memory
newInfo = _info;
/// @dev If last accrual was at current block or pool is closed or in default, return info as is
if (
timestamp < newInfo.lastAccrual ||
newInfo.status == PoolStatus.Default ||
newInfo.status == PoolStatus.Closed
) {
return newInfo;
}
newInfo.overdueEntrance = _overdueEntrance();
uint256 lastAccrual = timestamp;
// in case current timestamp is in overdue period, calculate the interest until the pool entered in overdue period
if (newInfo.overdueEntrance != 0 && newInfo.overdueEntrance < lastAccrual) {
newInfo = _accrueInterestVirtual(newInfo.overdueEntrance);
}
if (totalSupply() != 0) {
uint256 penaltyPeriod = 0;
// if the pool is in overdue period calculate penalty period
if (newInfo.overdueEntrance != 0 && newInfo.overdueEntrance < lastAccrual) {
penaltyPeriod = lastAccrual - newInfo.lastAccrual;
}
// check for default state
if (newInfo.overdueEntrance != 0 && timestamp > newInfo.overdueEntrance + gracePeriod) {
lastAccrual = newInfo.overdueEntrance + gracePeriod;
penaltyPeriod = lastAccrual - newInfo.lastAccrual;
newInfo.status = PoolStatus.Default;
}
uint256 timeDelta = lastAccrual - newInfo.lastAccrual;
// calculate interest and penalty for the time period
uint256 borrowsDelta = calcDeltaRate(timeDelta, lendAPR);
uint256 feesDelta = calcDeltaRate(timeDelta, protocolFee);
uint256 penaltyDelta = calcDeltaRate(penaltyPeriod, penaltyRate);
// calc borrows, penalty and fees for borrows amount (compounding)
newInfo.penaltyAmount += newInfo.borrows.mulDecimal(penaltyDelta);
newInfo.feesAmount += newInfo.borrows.mulDecimal(feesDelta);
newInfo.borrows += newInfo.borrows.mulDecimal(borrowsDelta);
// Calculate new exchange rate borrows + penalty + cash / totalSupply
newInfo.exchangeRate = (newInfo.borrows + newInfo.penaltyAmount).divDecimal(totalSupply());
}
newInfo.lastAccrual = lastAccrual;
}
function _overdueEntrance() internal view returns (uint256) {
// if the pool is already in overdue period return the entering date
if (_info.overdueEntrance != 0) {
return _info.overdueEntrance;
}
uint256 repDate = currentRepaymentDate();
// if the current timestamp pass the repayment date return the entering date
if (
block.timestamp > repDate &&
(repaymentRoundInfo[repDate].debtAmount > 0 || _fullRepaymentDate != 0)
) {
return repDate;
}
return 0;
}
function _processAuctionResolution(uint256 _payedAmount) internal {
/// @dev Calculate new exchange rate based on the amount obtained for the auction
_info.exchangeRate = _payedAmount.divDecimal(
(_info.borrows + _info.penaltyAmount).divDecimal(_info.exchangeRate)
);
_info.borrows = 0;
_info.penaltyAmount = 0;
_fullRepaymentDate = 0;
uint256 currentRepDate = currentRepaymentDate();
// Mark the current repayment date as paid (the period that causes default -> Auction)
if (repaymentRoundInfo[currentRepDate].debtAmount > 0) {
// Accrue rewards interest for the current round
_accrueRoundReward(currentRepDate);
repaymentRoundInfo[currentRepDate].debtAmount = 0;
repaymentRoundInfo[currentRepDate].paidAt = _info.lastAccrual;
repaymentRoundInfo[currentRepDate].exchangeRate = _info.exchangeRate;
}
uint256 nextRepDate = _getNextUnpaidRound(true);
// Mark the future repayment date as paid (in case exists)
if (repaymentRoundInfo[nextRepDate].debtAmount > 0) {
// Accrue rewards interest for the next round
_accrueRoundReward(nextRepDate);
repaymentRoundInfo[nextRepDate].paidAt = _info.lastAccrual;
repaymentRoundInfo[nextRepDate].exchangeRate = _info.exchangeRate;
}
// burn all locked tokens obtained during withdrawal requests
_burn(address(this), balanceOf(address(this)));
_closePool();
}
/*
* @dev {see ERC20 _beforeTokenTransfer}
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override onlyEligible(to) {
super._beforeTokenTransfer(from, to, amount);
}
/**
* @notice Override of mint function with rewards corrections
* @param account Account to mint for
* @param amount Amount to mint
*/
function _mint(address account, uint256 amount) internal override {
_accrueReward();
_accrueRoundReward(currentRepaymentDate());
_accrueRoundReward(_getNextUnpaidRound(false));
RewardAsset.RewardAssetData[] memory _rewardAsset = getRewardAssetInfo();
for (uint256 i; i < _rewardAsset.length; i++) {
rewardAssetInfo.decreaseRewardCorrection(_rewardAsset[i].asset, account, amount);
}
super._mint(account, amount);
}
/**
* @notice Override of burn function with rewards corrections
* @param account Account to burn from
* @param amount Amount to burn
*/
function _burn(address account, uint256 amount) internal override {
_accrueReward();
RewardAsset.RewardAssetData[] memory _rewardAsset = getRewardAssetInfo();
for (uint256 i; i < _rewardAsset.length; i++) {
rewardAssetInfo.increaseRewardCorrection(_rewardAsset[i].asset, account, amount);
}
super._burn(account, amount);
}
/**
* @notice Override of transfer function with rewards corrections
* @param from Account to transfer from
* @param to Account to transfer to
* @param amount Amount to transfer
*/
function _transfer(address from, address to, uint256 amount) internal override {
accrueInterest();
_accrueReward();
RewardAsset.RewardAssetData[] memory _rewardAsset = getRewardAssetInfo();
for (uint256 i; i < _rewardAsset.length; i++) {
address rewardAssetAddr = _rewardAsset[i].asset;
rewardAssetInfo.increaseRewardCorrection(rewardAssetAddr, from, amount);
rewardAssetInfo.decreaseRewardCorrection(rewardAssetAddr, to, amount);
}
super._transfer(from, to, amount);
}
/**
* @notice Override of bond transfer function with rewards corrections
* @param roundDate round date
* @param bondId bond id
* @param from Account to transfer from
* @param to Account to transfer to
* @param amount Amount to transfer
*/
function applyBondRewardCorections(
uint256 roundDate,
uint256 bondId,
address from,
address to,
uint256 amount
) external {
if (msg.sender != address(bondNFT)) revert ActionNotAllowed();
_accrueRoundReward(roundDate);
RewardAsset.RewardAssetData[] memory _rewardAsset = getRewardAssetInfo();
for (uint256 i; i < _rewardAsset.length; i++) {
address rewardAssetAddr = _rewardAsset[i].asset;
rewardAssetInfo.increaseRewardCorrection(
rewardAssetAddr,
from,
amount,
rewardAssetInfo.magnifiedRoundRewardPerShare[bondId][rewardAssetAddr]
);
rewardAssetInfo.decreaseRewardCorrection(
rewardAssetAddr,
to,
amount,
rewardAssetInfo.magnifiedRoundRewardPerShare[bondId][rewardAssetAddr]
);
}
}
/**
* @dev Return calculated rate for a specific time period
*/
function calcDeltaRate(uint256 timeDelta, uint256 rate) private pure returns (uint256) {
return (rate * timeDelta) / YEAR;
}
/**
* @dev Return rated fees amount for a specific value based on full amount and fees
*/
function calcRateAmount(
uint256 amount,
uint256 fullAmount,
uint256 feesAmount
) private pure returns (uint256) {
return (amount * feesAmount) / fullAmount;
}
/**
* @dev Return pre-calculated amounts for a specific period
*/
function accrueAmounts(
uint256 _borrows,
uint256 _feesAmount,
uint256 _penaltyAmount,
uint256 _amount,
uint256 _supply,
uint256 interestDelta,
uint256 feesDelta
) private pure returns (uint256, uint256, uint256) {
_feesAmount += _borrows.mulDecimal(feesDelta);
_borrows += _borrows.mulDecimal(interestDelta);
// New amount + penalty = tokensAmount * exchangeRate (borrows + penalty / totalSupply)
_amount = _amount.mulDecimal((_borrows + _penaltyAmount).divDecimal(_supply));
_penaltyAmount = _amount - calcRateAmount(_amount, _borrows + _penaltyAmount, _borrows);
// substract the penalty interest from the calculated amount
_amount -= _penaltyAmount;
return (_amount, _penaltyAmount, calcRateAmount(_amount, _borrows, _feesAmount));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!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 Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165Upgradeable.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155Upgradeable is IERC165Upgradeable {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20Upgradeable.sol";
import "./extensions/IERC20MetadataUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @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[45] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// 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 IERC20Upgradeable {
/**
* @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.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../extensions/IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20Upgradeable {
using AddressUpgradeable for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library 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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCastUpgradeable {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}//SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {IERC1155Upgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol';
struct CallbackParams {
uint256 endDate;
uint256 penaltyRate;
uint256 interestRate;
uint256 exchangeRate;
}
/**
* @title Interface for a `BondNFT.sol`;
*/
interface IBondNFT is IERC1155Upgradeable {
/// @notice Creating a new NFT contract and setting inside parameters;
function __init(address _poolMasterAddress, string memory _uri) external returns (bool);
/// @notice Minting tokens;
function mint(
address _account,
uint256 _id,
uint256 _amount,
bytes memory _data,
CallbackParams calldata _callBackParams
) external;
/// @notice Burning tokens;
function burn(address _account, uint256 _id, uint256 _amount) external;
/// @notice Return balance of `msg.sender`;
function balanceOf(address account, uint256 id) external view returns (uint256);
/// @notice Return id information params;
function tokenData(uint256 id) external view returns (CallbackParams memory);
function setExchangeRate(uint256 id, uint256 exchangeRate) external;
/// @notice Minting batch tokens;
function mintBatch(
address _to,
uint256[] memory _ids,
uint256[] memory _amounts,
bytes memory _data
) external;
/// @notice Burning batch tokens;
function burnBatch(address _account, uint256[] memory _ids, uint256[] memory _amounts) external;
}//SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {RewardAsset} from '../libraries/RewardAsset.sol';
/**
* @title Interface for a `PoolFactory.sol`;
*/
interface IPoolFactory {
function checkKycStatus(address _account) external;
function checkBorrowerStatus(address _borrower) external;
function owner() external view returns (address);
function getPoolConfigVars()
external
view
returns (uint256, uint256, uint256, uint256, RewardAsset.RewardAssetData[] memory);
function treasury() external view returns (address);
function auction() external view returns (address);
function isPool(address pool) external view returns (bool);
function processPoolAuctionStart(address pool) external;
function processPoolAuctionEnd(address pool, uint256 claimedAmount) external;
}
interface IPoolFactoryLite {
function whitelistLender(address _lender) external;
function whitelistBorrower(address _borrower) external;
function blacklistLender(address _lender) external;
function blacklistBorrower(address _borrower) external;
function whitelistedLenders(address _account) external view returns (bool);
function whitelistedBorrowers(address _account) external view returns (bool);
}//SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
struct InitParams {
uint256 depositCap;
uint256 repaymentFrequency;
uint256 minimumNoticePeriod;
uint256 minDeposit;
uint256 lendAPR;
address borrower;
address asset;
address bondNFT;
string name;
string borrowerSymbol;
}
///@dev Defining a Status Enumeration;
enum PoolStatus {
Active,
Overdue,
Default,
Closed
}
/**
* @title Interface for a `PoolMaster.sol`;
*/
interface IPoolMaster {
/// @notice creating a new pool and setting inside parameters;
function __init(InitParams calldata params, bool kycRequired) external returns (bool);
/// @notice returning the `deposit cap`;
function depositCap() external view returns (uint256);
/// @notice returning the `repayment frequency`;
function repaymentFrequency() external view returns (uint256);
/// @notice returning the `minimum notice period`;
function minimumNoticePeriod() external view returns (uint256);
/// @notice returning the `lend APR`;
function lendAPR() external view returns (uint256);
/// @notice returning the `asset`;
function asset() external view returns (address);
/// @notice returning the `symbol`;
function symbol() external view returns (string memory);
/// @notice returning the `borrower`;
function borrower() external view returns (address);
function checkKycStatus(address _account) external;
function status() external view returns (PoolStatus);
function decimals() external view returns (uint8);
function poolSize() external view returns (uint256);
function totalSupply() external view returns (uint256);
function withdrawReward(address _asset, address account) external returns (uint256);
function supply(uint256 _amount) external;
function repay() external;
function repayAll() external;
function redeem(uint256 _amount) external;
function redeemBond(uint256 bondId) external;
function processAuctionStart() external;
function processDebtClaim(uint256 _payedAmount) external;
function changeBorrower(address _borrower) external;
function cancelAuction() external;
function applyBondRewardCorections(
uint256 roundDate,
uint256 bondId,
address from,
address to,
uint256 amount
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
library Decimal {
/// @notice Number one as 18-digit decimal
uint256 internal constant MULTIPLIER = 1e18;
/**
* @notice Internal function for 10-digits decimal division
* @param number Integer number
* @param decimal Decimal number
* @return Returns multiplied numbers
*/
function mulDecimal(uint256 number, uint256 decimal) internal pure returns (uint256) {
return (number * decimal) / MULTIPLIER;
}
/**
* @notice Internal function for 10-digits decimal multiplication
* @param number Integer number
* @param decimal Decimal number
* @return Returns integer number divided by second
*/
function divDecimal(uint256 number, uint256 decimal) internal pure returns (uint256) {
return (number * MULTIPLIER) / decimal;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {SafeCastUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol';
library RewardAsset {
using SafeCastUpgradeable for uint256;
using SafeCastUpgradeable for int256;
struct RewardAssetData {
address asset; // the addess of the reward asset
uint256 rate; // the reward rate of the asset
}
struct Data {
mapping(address => bool) flags; // tracks whether the reward has already been added or not.
mapping(address => uint256) addressIndex; // saves the index of each reward asset
mapping(address => uint256) magnifiedRewardPerShare; // rewardAsset -> magnifiedRewardPerShare
mapping(uint256 => uint256) roundLastDistribution; //Timestamp when last round staking reward distribution occurred
mapping(address => mapping(address => int256)) magnifiedRewardCorrections; // rewardAsset -> account -> magnifiedReward correction
mapping(address => mapping(address => uint256)) rewardWithdrawals; // rewardAsset -> lender -> amount
mapping(uint256 => mapping(address => uint256)) magnifiedRoundRewardPerShare; // round bond ID -> rewardAsset -> magnifiedRewardPerShare
RewardAssetData[] rewardAssetData; // the array of the rewardAssetData
uint256 id; //a number that increments when a new reward asset is added
uint256 lastRewardDistribution; //Timestamp when last staking reward distribution occurred
}
/**
* @notice used to insert new reward asset with rate
* @param self see {Data}
* @param asset the address of the reward asset
* @param rate the reward rate of the asset
*/
function insert(Data storage self, address asset, uint256 rate) internal returns (bool) {
if (self.flags[asset]) {
uint256 index = self.addressIndex[asset];
if (self.rewardAssetData[index].rate == rate) {
return false;
}
self.rewardAssetData[index].rate = rate;
return true;
}
self.flags[asset] = true;
self.rewardAssetData.push(RewardAssetData(asset, rate));
self.addressIndex[asset] = self.id;
self.id++;
return true;
}
/**
* see {decreaseRewardCorrection}
*/
function decreaseRewardCorrection(
Data storage self,
address asset,
address account,
uint256 amount
) internal {
return
decreaseRewardCorrection(self, asset, account, amount, self.magnifiedRewardPerShare[asset]);
}
/**
* @notice decreases the reward of the specified asset for the given account
* @param self see {Data}
* @param asset the address of the reward asset
* @param account the address of the lender
* @param amount the number of reward per share
* @param share the number of shares held by the lender
*/
function decreaseRewardCorrection(
Data storage self,
address asset,
address account,
uint256 amount,
uint256 share
) internal {
self.magnifiedRewardCorrections[asset][account] -= (share * amount).toInt256();
}
/**
* see {increaseRewardCorrection}
*/
function increaseRewardCorrection(
Data storage self,
address asset,
address account,
uint256 amount
) internal {
return
increaseRewardCorrection(self, asset, account, amount, self.magnifiedRewardPerShare[asset]);
}
/**
* @notice increases the reward of the specified asset for the given account
* @param self see {Data}
* @param asset the address of the reward asset
* @param account the address of the lender
* @param amount the number of reward per share
* @param share the number of shares held by the lender
*/
function increaseRewardCorrection(
Data storage self,
address asset,
address account,
uint256 amount,
uint256 share
) internal {
self.magnifiedRewardCorrections[asset][account] += (share * amount).toInt256();
}
/**
* @notice used to calculate and save the reward per share
* @param self see {Data}
* @param asset the address of the asset
* @param period the duration of time between now and the last reward distribution date
* @param rate the number of the reward rate
* @param rewardMagnitude value by which all rewards are magnified for calculation
* @param totalSupply the total supply of pool tokens
*/
function updateMagnifiedRewardPerShare(
Data storage self,
address asset,
uint256 period,
uint256 rate,
uint256 rewardMagnitude,
uint256 totalSupply
) internal {
uint256 _rewardPerShare = ((rewardMagnitude * period * rate)) / totalSupply;
self.magnifiedRewardPerShare[asset] += _rewardPerShare;
}
/**
* @notice used to calculate and save the reward per share for the given round
* @param self see {Data}
* @param asset the address of the asset
* @param roundBondId the round bond Id
* @param period the duration of time between now and the last reward distribution date
* @param rate the number of the reward rate
* @param rewardMagnitude value by which all rewards are magnified for calculation
* @param totalSupply the total supply of pool tokens
*/
function updateMagnifiedRoundRewardPerShare(
Data storage self,
address asset,
uint256 roundBondId,
uint256 period,
uint256 rate,
uint256 rewardMagnitude,
uint256 totalSupply
) internal {
uint256 _rewardPerShare = ((rewardMagnitude * period * rate)) / totalSupply;
self.magnifiedRoundRewardPerShare[roundBondId][asset] += _rewardPerShare;
}
/**
* @notice used to update the reward withdrawn by the lender for the specified asset
* @param self see {Data}
* @param asset the address of the asset
* @param account the address of the lender
* @param amount the amount of reward withdrawn
*/
function updateRewardWithdrawals(
Data storage self,
address asset,
address account,
uint256 amount
) internal {
self.rewardWithdrawals[asset][account] += amount;
}
/**
* @notice used to retrieve the list of available reward assets
* @param self see {Data}
* @return returns the array of the reward assets
*/
function getList(Data storage self) internal view returns (RewardAssetData[] memory) {
return self.rewardAssetData;
}
}//SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
abstract contract UtilsGuard {
error NonZeroAddress();
error NonZeroValue();
error NotSameValue();
error NotSameAddress();
error RequestFailed();
error ActionNotAllowed();
error InvalidArgument();
error MinDepositExceedCap();
uint256 internal constant YEAR = 365 days;
/// @notice Value by which all rewards are magnified for calculation
uint256 internal constant REWARD_MAGNITUDE = 2 ** 128;
modifier nonZeroAddress(address _addr) {
if (_addr == address(0)) revert NonZeroAddress();
_;
}
modifier nonZeroValue(uint256 _val) {
if (_val == 0) revert NonZeroValue();
_;
}
modifier nonSameValue(uint256 _val1, uint256 _val2) {
if (_val1 == _val2) revert NotSameValue();
_;
}
modifier nonSameAddress(address _addr1, address _addr2) {
if (_addr1 == _addr2) revert NotSameAddress();
_;
}
function toWei(uint256 amount_, uint256 decimals) internal pure returns (uint256) {
return amount_ * 10 ** (18 - decimals);
}
function fromWei(uint256 amount_, uint256 decimals) internal pure returns (uint256) {
return amount_ / 10 ** (18 - decimals);
}
}{
"optimizer": {
"enabled": true,
"runs": 50
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ActionNotAllowed","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidArgument","type":"error"},{"inputs":[],"name":"MinDepositExceedCap","type":"error"},{"inputs":[],"name":"NoDebtFound","type":"error"},{"inputs":[],"name":"NonZeroAddress","type":"error"},{"inputs":[],"name":"NonZeroValue","type":"error"},{"inputs":[],"name":"NotSameAddress","type":"error"},{"inputs":[],"name":"NotSameValue","type":"error"},{"inputs":[],"name":"OnlyBorrower","type":"error"},{"inputs":[],"name":"OnlyFactory","type":"error"},{"inputs":[],"name":"OnlyGovernor","type":"error"},{"inputs":[],"name":"PoolHasLiquidity","type":"error"},{"inputs":[],"name":"PoolInactive","type":"error"},{"inputs":[],"name":"RepaymentMissing","type":"error"},{"inputs":[],"name":"RequestFailed","type":"error"},{"inputs":[],"name":"WrongNumber","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"applyDate","type":"uint256"}],"name":"APRChangeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAPR","type":"uint256"}],"name":"APRChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":true,"internalType":"uint256","name":"bondId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"receivedAmount","type":"uint256"}],"name":"BondRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newBorrower","type":"address"}],"name":"BorrowerChanged","type":"event"},{"anonymous":false,"inputs":[],"name":"Closed","type":"event"},{"anonymous":false,"inputs":[],"name":"Defaulted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDepositCap","type":"uint256"}],"name":"DepositCapChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penaltyAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feesAmount","type":"uint256"}],"name":"FullRepayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMinDeposit","type":"uint256"}],"name":"MinDepositChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"NoticePeriodChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensAmount","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penaltyAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feesAmount","type":"uint256"}],"name":"Repayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newRepaymentFrequency","type":"uint256"}],"name":"RepaymentFrequencyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"repaymentDate","type":"uint256"}],"name":"RepaymentRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"RewardAssetInfoSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensAmount","type":"uint256"}],"name":"Supplied","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"repaymentDate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bondNFTIdCounter","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"depositCap","type":"uint256"},{"internalType":"uint256","name":"repaymentFrequency","type":"uint256"},{"internalType":"uint256","name":"minimumNoticePeriod","type":"uint256"},{"internalType":"uint256","name":"minDeposit","type":"uint256"},{"internalType":"uint256","name":"lendAPR","type":"uint256"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"bondNFT","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"borrowerSymbol","type":"string"}],"internalType":"struct InitParams","name":"params","type":"tuple"},{"internalType":"bool","name":"kycRequired","type":"bool"}],"name":"__init","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardAsset","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"accumulativeRewardOf","outputs":[{"internalType":"uint256","name":"accumulated","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundDate","type":"uint256"},{"internalType":"uint256","name":"bondId","type":"uint256"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"applyBondRewardCorections","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract IERC20MetadataUpgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bondNFT","outputs":[{"internalType":"contract IBondNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrower","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newAPR","type":"uint256"}],"name":"changeAPR","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newBorrower","type":"address"}],"name":"changeBorrower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newDepositCap","type":"uint256"}],"name":"changeDepositCapacity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMinDeposit","type":"uint256"}],"name":"changeMinDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newNoticePeriod","type":"uint256"}],"name":"changeNoticePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newProtocolFee","type":"uint256"}],"name":"changePoolProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newRepaymentFrequency","type":"uint256"}],"name":"changeRepaymentFrequency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"checkKycStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentRepaymentDate","outputs":[{"internalType":"uint256","name":"newRepaymentDate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"repDate","type":"uint256"}],"name":"dueOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceDefault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getNextRepaymentDate","outputs":[{"internalType":"uint256","name":"nextRepDate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardAssetInfo","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"rate","type":"uint256"}],"internalType":"struct RewardAsset.RewardAssetData[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isKycRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lendAPR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumNoticePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"penaltyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodToStartAuction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolFactory","outputs":[{"internalType":"contract IPoolFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"processAuctionStart","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_payedAmount","type":"uint256"}],"name":"processDebtClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"redeemBond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repayAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repaymentFrequency","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"repaymentRoundInfo","outputs":[{"internalType":"uint256","name":"debtAmount","type":"uint256"},{"internalType":"uint256","name":"bondTokenId","type":"uint256"},{"internalType":"uint256","name":"paidAt","type":"uint256"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_repaymentDate","type":"uint256"}],"name":"requestFullRepayment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"requestWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"period","type":"uint256"}],"name":"setPeriodToStartAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_rate","type":"uint256"}],"name":"setRewardAssetInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"enum PoolStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"supply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDue","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"withdrawReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61600080620000f36000396000f3fe608060405234801561001057600080fd5b50600436106103355760003560e01c806371dbc900116101bf578063a9059cbb116100fa578063db006a751161009d578063db006a75146106f8578063dbd5edc71461070b578063dd62ed3e14610714578063df65513914610727578063e61dfbea1461073c578063eb81033f1461074f578063fa3ae6dc14610757578063fc9de5a81461075f57600080fd5b8063a9059cbb14610693578063ae573ffc146106a6578063b0e21e8a146106af578063b0f3af47146106b8578063b69b05c4146106cb578063ba9a7a56146106de578063cace1aa7146106e7578063d6b7494f146106ef57600080fd5b806393e88f3a1161016257806393e88f3a1461062257806395d89b4114610639578063961be391146106415780639944b5f6146106495780639ee679e81461065c578063a06db7dc1461066f578063a457c2d714610678578063a6afed951461068b57600080fd5b806371dbc9001461056357806379aa80e7146105765780637df1f1b91461057e5780638367d1ff1461059657806389ddd0ed146105a95780638d516e1c146105b25780638fa8b79014610607578063928cdffd1461060f57600080fd5b80633e4191dc1161028f5780634ec18db9116102325780634ec18db9146104eb578063536108c3146104f357806358413d70146105065780636107155214610519578063619cc4ac1461052257806365b810a51461053557806366805de51461054857806370a082311461055057600080fd5b80633e4191dc14610483578063402d888314610490578063414a62791461049857806341b3d185146104a15780634219dc40146104aa5780634b2a12da146104bd5780634c9e2f12146104d05780634e7c13fe146104e357600080fd5b8063042a20771461033a57806306fdde031461034f578063095ea7b31461036d57806310c802f11461039057806318160ddd146103a35780631a294fd8146103b5578063200d2ed2146103c857806323b872dd146103dd57806324c259f8146103f05780632f917dff14610403578063313ce56714610416578063354030231461043557806338d52e0f1461044857806339509351146104685780633ba0b9a91461047b575b600080fd5b61034d610348366004615696565b610787565b005b610357610a6f565b60405161036491906156d3565b60405180910390f35b61038061037b36600461571b565b610b01565b6040519015158152602001610364565b61038061039e366004615755565b610b1b565b6035545b604051908152602001610364565b61034d6103c3366004615696565b611053565b6103d061126b565b60405161036491906157c2565b6103806103eb3660046157ea565b611283565b61034d6103fe366004615696565b6112a9565b61034d610411366004615696565b611377565b60a354600160a01b900460ff1660405160ff9091168152602001610364565b61034d610443366004615696565b61149e565b60a15461045b906001600160a01b031681565b604051610364919061582b565b61038061047636600461571b565b611832565b6103a7611854565b60a0546103809060ff1681565b61034d611868565b6103a760995481565b6103a7609a5481565b60a25461045b906001600160a01b031681565b61034d6104cb366004615696565b611a69565b61034d6104de366004615696565b611bb9565b61034d611d53565b6103a7611eee565b6103a761050136600461583f565b611f13565b61034d610514366004615696565b611fe5565b6103a7609b5481565b61034d610530366004615696565b612168565b61034d610543366004615696565b6123b4565b61034d6123e8565b6103a761055e36600461586d565b612441565b61034d61057136600461586d565b61245c565b6103a76124e2565b60a05461045b9061010090046001600160a01b031681565b61034d6105a436600461586d565b612566565b6103a7609f5481565b6105e76105c0366004615696565b60a96020526000908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610364565b61034d6125cf565b61034d61061d36600461588a565b612648565b61062a61273d565b604051610364939291906158dc565b61035761276e565b6103a761277d565b61034d61065736600461571b565b6127ef565b61034d61066a366004615696565b612959565b6103a7609d5481565b61038061068636600461571b565b612d98565b61034d612e1e565b6103806106a136600461571b565b612f59565b6103a760985481565b6103a7609e5481565b60a35461045b906001600160a01b031681565b61034d6106d9366004615696565b612f67565b6103a76103e881565b6103a76130b9565b6103a7609c5481565b61034d610706366004615696565b61311d565b6103a760975481565b6103a761072236600461583f565b61322c565b61072f613257565b60405161036491906158f2565b61062a61074a366004615696565b613263565b61034d6132de565b61034d613320565b61077261076d36600461583f565b61370e565b60408051928352602083019190915201610364565b61078f613757565b610797612e1e565b60a354604051627eeac760e11b81526000916001600160a01b03169062fdd58e906107c8903390869060040161594a565b602060405180830381865afa1580156107e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108099190615963565b90508060000361082c5760405163e320176b60e01b815260040160405180910390fd5b60a35460405163b4b5b48f60e01b8152600481018490526000916001600160a01b03169063b4b5b48f90602401608060405180830381865afa158015610876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089a91906159ea565b8051600090815260a96020526040902060028101549192509015806108c25750428160020154115b156108e057604051633cc9de1f60e11b815260040160405180910390fd5b60006108ea613257565b905060005b815181101561096357600082828151811061090c5761090c615a4f565b60209081029190910181015151600089815260b7835260408082206001600160a01b038416835290935291909120549091506109509060b190839033908a906137b0565b508061095b81615a7b565b9150506108ef565b5060a354604051637a94c56560e11b815233600482015260248101879052604481018690526001600160a01b039091169063f5298aca90606401600060405180830381600087803b1580156109b757600080fd5b505af11580156109cb573d6000803e3d6000fd5b5050505060006109e883600301548661380790919063ffffffff16565b90508360600151600014610a09576060840151610a06908690613807565b90505b60a154610a20906001600160a01b03163383613826565b6040805186815260208101839052879133917f1ed7ee1a43efec4a4f81e0d29338046bc1b1f4f035f86d69176f2d3518baae8b910160405180910390a35050505050610a6c6001606555565b50565b606060368054610a7e90615a94565b80601f0160208091040260200160405190810160405280929190818152602001828054610aaa90615a94565b8015610af75780601f10610acc57610100808354040283529160200191610af7565b820191906000526020600020905b815481529060010190602001808311610ada57829003601f168201915b5050505050905090565b600033610b0f818585613888565b60019150505b92915050565b60008054610100900460ff1615808015610b3c5750600054600160ff909116105b80610b565750303b158015610b56575060005460ff166001145b610bbe5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610be1576000805461ff0019166101001790555b610be96139ac565b610bf960e0850160c0860161586d565b60a180546001600160a01b0319166001600160a01b03929092169182179055604080516395d89b4160e01b81529051600092916395d89b4191600480830192869291908290030181865afa158015610c55573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c7d9190810190615ace565b9050610d30610c90610100870187615b61565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526002815261063760f41b60208201529150610ced9050610120890189615b61565b604051806040016040528060018152602001602d60f81b81525086604051602001610d1c959493929190615bae565b6040516020818303038152906040526139db565b60a160009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da79190615bfd565b60a3805460ff92909216600160a01b0260ff60a01b19909216919091179055610dd7610100860160e0870161586d565b60a380546001600160a01b03929092166001600160a01b0319928316811790915560a2805490921633179091556040805163a811299960e01b81523060048201526024810191909152600060448201819052919063a8112999906064016020604051808303816000875af1158015610e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e779190615c20565b9050801515600003610e8e57600093505050611006565b60a25460408051632370903960e01b815290516060926001600160a01b03169163237090399160048083019260009291908290030181865afa158015610ed8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f009190810190615c3d565b609f91909155609e91909155609d91909155609c91909155905060005b8151811015610f8957610f76828281518110610f3b57610f3b615a4f565b602002602001015160000151838381518110610f5957610f59615a4f565b60200260200101516020015160b1613a109092919063ffffffff16565b5080610f8181615a7b565b915050610f1d565b506060870135609a558635609755602087013560985560408701356099556080870135609b55610fbf60c0880160a0890161586d565b60a080546001600160a81b0319166101006001600160a01b03939093169290920260ff19169190911787151517905550504260ae5550670de0b6b3a764000060ad55600191505b801561104c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5092915050565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ca9190615d3a565b6001600160a01b0316336001600160a01b0316146110fb5760405163070545c960e51b815260040160405180910390fd5b611103612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05460009261117a929160c083019060ff166003811115611161576111616157ac565b6003811115611172576111726157ac565b905250613b5c565b90506000816003811115611190576111906157ac565b141580156111b0575060018160038111156111ad576111ad6157ac565b14155b156111ce57604051630f509b1160e01b815260040160405180910390fd5b60a5541515806111de575060a754155b156111fc5760405163829e373360e01b815260040160405180910390fd5b60006112066124e2565b9050824211156112295760405163a9cb9e0d60e01b815260040160405180910390fd5b60a781905560a58390556040518381527fc01f2cfc592122ca3951f635d0ddd6a7a7cdc30ab7bfc0f25184e89f16af1c3c9060200160405180910390a1505050565b600061127e61127942613c05565b613b5c565b905090565b600033611291858285613e6f565b61129c858585613ee9565b60019150505b9392505050565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113209190615d3a565b6001600160a01b0316336001600160a01b0316146113515760405163070545c960e51b815260040160405180910390fd5b8060000361137257604051631aa3503f60e11b815260040160405180910390fd5b609f55565b60a05461010090046001600160a01b031633146113a757604051630ac9915d60e01b815260040160405180910390fd5b6113af612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05460009261140d929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611423576114236157ac565b1415801561144357506001816003811115611440576114406157ac565b14155b1561146157604051630f509b1160e01b815260040160405180910390fd5b60978290556040518281527f2bc390be6d76c38a7a1e46eb6629b370c4cd792e13afd099527cbce28c5ecf77906020015b60405180910390a15050565b6114a6613757565b6114ae612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05460009261150c929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611522576115226157ac565b141580156115425750600181600381111561153f5761153f6157ac565b14155b1561156057604051630f509b1160e01b815260040160405180910390fd5b60a05461010090046001600160a01b031633148061157f575060a55415155b1561159d5760405163829e373360e01b815260040160405180910390fd5b6115a633612566565b60a25460a054604051631fb014e160e01b81526001600160a01b0392831692631fb014e1926115e1926101009091049091169060040161582b565b600060405180830381600087803b1580156115fb57600080fd5b505af115801561160f573d6000803e3d6000fd5b50505050600061161d611eee565b6097549091501515600184016116ed5760a1546040516370a0823160e01b81526001600160a01b03909116906370a082319061165d90339060040161582b565b602060405180830381865afa15801561167a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169e9190615963565b935080156116ed5760975482106116c857604051631aa3503f60e11b815260040160405180910390fd5b6000826097546116d89190615d57565b90508085116116e757846116e9565b805b9450505b8315806116fb575083609a54115b80611718575080801561171857506097546117168386615d6a565b115b1561173657604051631aa3503f60e11b815260040160405180910390fd5b60ad54600090611747908690613f6c565b905060a7546000036117a0576098546117609042615d6a565b60a7556103e881101561178657604051631aa3503f60e11b815260040160405180910390fd5b6117926103e882615d57565b90506117a0306103e8613f81565b8460aa60000160008282546117b59190615d6a565b909155506117c590503382613f81565b60a05460a1546117e9916001600160a01b0391821691339161010090041688614001565b604080518681526020810183905233917f5c2c0d2616a06b35bb159b4d7e227972b59bb33f8d5229ca0e5e438259bfd5d3910160405180910390a250505050610a6c6001606555565b600033610b0f818585611845838361322c565b61184f9190615d6a565b613888565b600061185f42613c05565b60600151905090565b611870613757565b60a05461010090046001600160a01b031633146118a057604051630ac9915d60e01b815260040160405180910390fd5b6118a8612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092611906929160c083019060ff166003811115611161576111616157ac565b9050600081600381111561191c5761191c6157ac565b1415801561193c57506001816003811115611939576119396157ac565b14155b1561195a57604051630f509b1160e01b815260040160405180910390fd5b60006119646124e2565b600081815260a960205260408120805492935091900361199757604051633c74e66760e01b815260040160405180910390fd5b8054600080806119a686614039565b60bc805493965091945092506001916000906119c690849060ff16615d7d565b92506101000a81548160ff021916908360ff1602179055506099546000036119f8576119f06124e2565b60a755611a06565b611a026001614291565b60a7555b611a103085614300565b611a1b838383614368565b7f84150d563c486763473e5a92eeb9297b1ee15fd60a18bc0b93ffe30bda41b2d0838383604051611a4e939291906158dc565b60405180910390a150505050505050611a676001606555565b565b60a05461010090046001600160a01b03163314611a9957604051630ac9915d60e01b815260040160405180910390fd5b611aa1612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092611aff929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611b1557611b156157ac565b14158015611b3557506001816003811115611b3257611b326157ac565b14155b15611b5357604051630f509b1160e01b815260040160405180910390fd5b6000609754118015611b66575060975482115b15611b84576040516301f45a5b60e41b815260040160405180910390fd5b609a8290556040518281527fa000bf02376732aba3d876c4c1a507f71dc704bc53a9197154014ac0262fe8a690602001611492565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c309190615d3a565b6001600160a01b0316336001600160a01b031614611c615760405163070545c960e51b815260040160405180910390fd5b611c69612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092611cc7929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611cdd57611cdd6157ac565b14158015611cfd57506001816003811115611cfa57611cfa6157ac565b14155b15611d1b57604051630f509b1160e01b815260040160405180910390fd5b811580611d2f5750670de0b6b3a764000082115b15611d4d57604051631aa3503f60e11b815260040160405180910390fd5b50609e55565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dca9190615d3a565b6001600160a01b0316336001600160a01b031614611dfb5760405163070545c960e51b815260040160405180910390fd5b611e03612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092611e61929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611e7757611e776157ac565b14158015611e9757506001816003811115611e9457611e946157ac565b14155b15611eb557604051630f509b1160e01b815260040160405180910390fd5b60b0805460ff191660021790556040517f46b9cd4891c2c9c48ba40bb38b2058575e06ecdaab42ec43bcb2574c4be226be90600090a150565b600080611efa42613c05565b60408101518151919250611f0d91615d6a565b91505090565b60a2546000906001600160a01b03163314611f4157604051630636a15760e11b815260040160405180910390fd5b816001600160a01b0381163014801590611f6357506001600160a01b03811615155b15611f7157611f7181612566565b611f79612e1e565b611f81614420565b6000611f8d858561370e565b9150508015611fdd57611fa360b1868684614504565b7f1d3eee4ca001cff39eec6ec7615aacf2f2bd61791273830728ba00ccbd6e13378582604051611fd492919061594a565b60405180910390a15b949350505050565b60a05461010090046001600160a01b0316331461201557604051630ac9915d60e01b815260040160405180910390fd5b61201d612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05460009261207b929160c083019060ff166003811115611161576111616157ac565b90506000816003811115612091576120916157ac565b141580156120b1575060018160038111156120ae576120ae6157ac565b14155b156120cf57604051630f509b1160e01b815260040160405180910390fd5b620151808210806120e5575060bc5460ff166002145b156121035760405163829e373360e01b815260040160405180910390fd5b60985482118015612115575060a75415155b1561213357604051631df60e1360e31b815260040160405180910390fd5b60988290556040518281527fd210d635a13704244ee03b7760dabd85ee85bad16a85f30016dd9f1829889f5090602001611492565b612170612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b0546000926121ce929160c083019060ff166003811115611161576111616157ac565b905060008160038111156121e4576121e46157ac565b1415801561220457506001816003811115612201576122016157ac565b14155b1561222257604051630f509b1160e01b815260040160405180910390fd5b60a05461010090046001600160a01b0316331461225257604051630ac9915d60e01b815260040160405180910390fd5b81609b5480820361227657604051637a06de1f60e01b815260040160405180910390fd5b8360000361229757604051631aa3503f60e11b815260040160405180910390fd5b60006122a16124e2565b9050609b548511806122b1575080155b1561230e57609b85905560a854600090815260bb602052604080822091909155517fb0f8bd9fe66bce43fb8d6b03bdc7a4f02ccdfe8f6674cf8bd0beaaa7a2a75702906123019087815260200190565b60405180910390a16123ad565b609954600003612328576098546123259082615d6a565b90505b8060995460026123389190615d96565b6123429042615d6a565b111561235c576098546123559082615d6a565b9050612328565b600081815260bb602090815260409182902087905560a883905581518781529081018390527f5fd5094086b5c595b0724f9a2855ae82ee5aace5deb6628118d539afc9fb5d25910160405180910390a15b5050505050565b60a2546001600160a01b031633146123df57604051630636a15760e11b815260040160405180910390fd5b610a6c81614548565b60a05461010090046001600160a01b0316331461241857604051630ac9915d60e01b815260040160405180910390fd5b60a7541561243957604051631df60e1360e31b815260040160405180910390fd5b611a6761462b565b6001600160a01b031660009081526033602052604090205490565b60a2546001600160a01b0316331461248757604051630636a15760e11b815260040160405180910390fd5b60a08054610100600160a81b0319166101006001600160a01b038416021790556040517fa1cc029f3440726d0dd25b6385e24d209e5bf7817d6662d6e4bfdfbc621c1cf2906124d790839061582b565b60405180910390a150565b60a75460008190036124f45750600090565b60a5541580159061251357508060a5541080612513575060bc5460ff16155b1561251f575060a55490565b600081815260a96020526040902054156125365790565b804211156125635760985461254b9082615d6a565b600081815260a9602052604090205490915015612536575b90565b60a05460ff1615610a6c5760a254604051638367d1ff60e01b81526001600160a01b0390911690638367d1ff906125a190849060040161582b565b600060405180830381600087803b1580156125bb57600080fd5b505af11580156123ad573d6000803e3d6000fd5b6125d7612e1e565b609f5460ae546000916125e991615d6a565b4210159050600260b05460ff166003811115612607576126076157ac565b148015612617575060a65460ff16155b80156126205750805b1561262f57610a6c6000614548565b60405163829e373360e01b815260040160405180910390fd5b60a3546001600160a01b031633146126735760405163829e373360e01b815260040160405180910390fd5b61267c8561469f565b6000612686613257565b905060005b81518110156127345760008282815181106126a8576126a8615a4f565b60209081029190910181015151600089815260b7835260408082206001600160a01b038416835290935291909120549091506126ec9060b1908390899088906137b0565b600087815260b7602090815260408083206001600160a01b03851684529091529020546127219060b19083908890889061478a565b508061272c81615a7b565b91505061268b565b50505050505050565b600080600060aa6000015460000361275b5750600092839250829150565b6127636147d0565b925092509250909192565b606060378054610a7e90615a94565b60a1546040516370a0823160e01b81526000916001600160a01b0316906370a08231906127ae90309060040161582b565b602060405180830381865afa1580156127cb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127e9190615963565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612842573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128669190615d3a565b6001600160a01b0316336001600160a01b0316146128975760405163070545c960e51b815260040160405180910390fd5b816001600160a01b0381166128bf5760405163bf8d717560e01b815260040160405180910390fd5b6128c7612e1e565b6128cf614420565b6128df6128da6124e2565b61469f565b6128ec6128da6000614291565b60006128fa60b18585613a10565b90508061291a5760405163d1d8c29b60e01b815260040160405180910390fd5b7f6559a40d7d599532f862cac525e829c672483eeb4d978b4c2faf7bab0347a9ea848460405161294b92919061594a565b60405180910390a150505050565b612961612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b0546000926129bf929160c083019060ff166003811115611161576111616157ac565b905060008160038111156129d5576129d56157ac565b141580156129f5575060018160038111156129f2576129f26157ac565b14155b15612a1357604051630f509b1160e01b815260040160405180910390fd5b60a55415612a345760405163829e373360e01b815260040160405180910390fd5b6000198203612a4957612a4633612441565b91505b811580612a5d5750612a5a33612441565b82115b15612a7b5760405163356680b760e01b815260040160405180910390fd5b6000612a856124e2565b90506000612a916130b9565b600083815260a96020526040902054909150158015612ab05750808214155b15612abf5760a7819055612ac5565b60a78290555b600081815260a9602052604081206001810154909103612b5557600160a46000828254612af29190615d6a565b909155505060a454600182015560bc5460ff16600203612b255760405163829e373360e01b815260040160405180910390fd5b60bc8054600090612b389060ff16615dad565b91906101000a81548160ff021916908360ff160217905550612bbc565b600281015415801590612b6b575060bc5460ff16155b15612bbc57600160a46000828254612b839190615d6a565b909155505060a454600182015560bc8054600090612ba39060ff16615dad565b91906101000a81548160ff021916908360ff1602179055505b612bc7333087613ee9565b6000612bd1613257565b9050612bdc8361469f565b60005b8151811015612c58576000828281518110612bfc57612bfc615a4f565b602090810291909101810151516001860154600090815260b7835260408082206001600160a01b03841683529093529190912054909150612c459060b190839033908c9061478a565b5080612c5081615a7b565b915050612bdf565b506001820154600090815260b460205260408120429055825487918491612c80908490615d6a565b909155505060a35460a4805460408051608081018252878152609c5460208201908152609b548284019081526000606084018181529451632be6196560e21b81523360048201526024810196909652604486018e90526101006064870152610104860152915160848501525193830193909352915160c4820152905160e48201526001600160a01b039091169063af9865949061012401600060405180830381600087803b158015612d3157600080fd5b505af1158015612d45573d6000803e3d6000fd5b50505050336001600160a01b03167f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e848860a454604051612d88939291906158dc565b60405180910390a2505050505050565b60003381612da6828661322c565b905083811015612e065760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610bb5565b612e138286868403613888565b506001949350505050565b60a854600090815260bb602052604090205415801590612e3f575060a85442115b15612ef757612e4f60a854613c05565b805160aa908155602082015160ab55604082015160ac55606082015160ad55608082015160ae5560a082015160af5560c082015160b0805460ff19166001836003811115612e9f57612e9f6157ac565b02179055505060a854600090815260bb602090815260408083208054939055609b839055518281529192507fb0f8bd9fe66bce43fb8d6b03bdc7a4f02ccdfe8f6674cf8bd0beaaa7a2a75702910160405180910390a1505b612f0042613c05565b805160aa908155602082015160ab55604082015160ac55606082015160ad55608082015160ae5560a082015160af5560c082015160b0805460ff19166001836003811115612f5057612f506157ac565b02179055505050565b600033610b0f818585613ee9565b60a05461010090046001600160a01b03163314612f9757604051630ac9915d60e01b815260040160405180910390fd5b612f9f612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092612ffd929160c083019060ff166003811115611161576111616157ac565b90506000816003811115613013576130136157ac565b1415801561303357506001816003811115613030576130306157ac565b14155b1561305157604051630f509b1160e01b815260040160405180910390fd5b609954821180613066575060bc5460ff166002145b156130845760405163829e373360e01b815260040160405180910390fd5b60998290556040518281527f7a1e6d22e8e5c71b2b344863c99d8c804a7b916e9a2af7d804fa2ffdfef3f5db90602001611492565b60006130c36124e2565b9050806000036130d35750600090565b60995415806130ee575080609954426130ec9190615d6a565b115b15612563575b80609954426131039190615d6a565b1115612563576098546131169082615d6a565b90506130f4565b613125613757565b61312d612e1e565b600061313833612441565b9050600360b05460ff166003811115613153576131536157ac565b1461317157604051633cc9de1f60e11b815260040160405180910390fd5b600019820361317e578091505b811580613189575080155b8061319357508082115b156131b15760405163356680b760e01b815260040160405180910390fd5b60ad546000906131c2908490613807565b90506131ce3384614300565b60a1546131e5906001600160a01b03163383613826565b604080518281526020810185905233917ff3a670cd3af7d64b488926880889d08a8585a138ff455227af6737339a1ec262910160405180910390a25050610a6c6001606555565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b606061127e60b16149b0565b600081815260a960205260408120805482918291820361328e576000806000935093509350506132d7565b6132cf61329a42613c05565b604080516080810182528454815260018501546020820152600285015491810191909152600384015460608201524288614a29565b935093509350505b9193909250565b60a2546001600160a01b0316331461330957604051630636a15760e11b815260040160405180910390fd5b613311612e1e565b60a6805460ff19166001179055565b613328613757565b60a05461010090046001600160a01b0316331461335857604051630ac9915d60e01b815260040160405180910390fd5b613360612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b0546000926133be929160c083019060ff166003811115611161576111616157ac565b905060008160038111156133d4576133d46157ac565b141580156133f4575060018160038111156133f1576133f16157ac565b14155b1561341257604051630f509b1160e01b815260040160405180910390fd5b60008060008060a5546000146134cf5760aa5460ac5460ab54600060a581905560a754815260a9602052604090205492965090945092501561348b5761345960a75461469f565b60a78054600090815260a96020526040808220829055825482528082204260029091015560ad54925482529020600301555b6134956001614291565b600081815260a96020526040902054909150156134ca57600081815260a96020526040902042600282015560ad546003909101555b613678565b60006134d96124e2565b600081815260a9602052604090209091506134f2615649565b81541561364c57815461350484614039565b919950975095506135153082614300565b834211156135bd576135336098548561352e9190615d6a565b613c05565b80519092506135429089615d6a565b97508160200151866135549190615d6a565b95508160400151876135669190615d6a565b606083015160ad55965061357a6001614291565b600081815260a96020526040902054909550156135b8576060820151600086815260a960205260409020600381019190915560808301516002909101555b613646565b6135c684613c05565b80519092506135d59089615d6a565b97508160200151866135e79190615d6a565b95508160400151876135f99190615d6a565b600384015460ad55965061360d6001614291565b600081815260a960205260409020549095501561364657600380840154600087815260a960205260409020918201556002808501549101555b50613674565b61365583613c05565b805160208201516040830151606084015160ad55919950909750955090505b5050505b600060ab81905560aa81905560ac81905560af5560bc805460ff1916905561369f8161469f565b6136b1306136ac30612441565b614300565b6136bc848484614368565b7f64d4a547e018f465abf2f43db33fc010ad2a8b3378ca0462ed67ac8b096a8d6d8484846040516136ef939291906158dc565b60405180910390a16136ff61462b565b5050505050611a676001606555565b60008061371b8484614afa565b6001600160a01b03808616600090815260b6602090815260408083209388168352929052205490925061374e9083615d57565b90509250929050565b6002606554036137a95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb5565b6002606555565b6137c26137bd8383615d96565b614c4b565b6001600160a01b0380861660009081526004880160209081526040808320938816835292905290812080549091906137fb908490615dcc565b90915550505050505050565b6000670de0b6b3a764000061381c8385615d96565b6112a29190615df4565b61387c8363a9059cbb60e01b848460405160240161384592919061594a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614cb9565b505050565b6001606555565b6001600160a01b0383166138ea5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610bb5565b6001600160a01b03821661394b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610bb5565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600054610100900460ff166139d35760405162461bcd60e51b8152600401610bb590615e16565b611a67614d8e565b600054610100900460ff16613a025760405162461bcd60e51b8152600401610bb590615e16565b613a0c8282614db5565b5050565b6001600160a01b03821660009081526020849052604081205460ff1615613abb576001600160a01b038316600090815260018501602052604090205460078501805484919083908110613a6557613a65615a4f565b90600052602060002090600202016001015403613a865760009150506112a2565b82856007018281548110613a9c57613a9c615a4f565b90600052602060002090600202016001018190555060019150506112a2565b6001600160a01b038381166000818152602087815260408083208054600160ff1990911681179091558151808301835285815280840189815260078c01805480850182559087528587209251600290910290920180546001600160a01b0319169290981691909117875551958101959095556008890180549484529489019091528120829055909190613b4d83615a7b565b90915550600195945050505050565b600060038260c001516003811115613b7657613b766157ac565b1480613b97575060028260c001516003811115613b9557613b956157ac565b145b15613ba4575060c0015190565b6000613bae6124e2565b90508042118015613bca5750609d54613bc79082615d6a565b42105b8015613bee5750600081815260a96020526040902054151580613bee575060a55415155b15613bfc5750600192915050565b505060c0015190565b613c0d615649565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05490919060c083019060ff166003811115613c6657613c666157ac565b6003811115613c7757613c776157ac565b8152505090508060800151821080613ca4575060028160c001516003811115613ca257613ca26157ac565b145b80613cc4575060038160c001516003811115613cc257613cc26157ac565b145b15613cce57919050565b613cd6614df5565b60a08201819052829015801590613cf05750808260a00151105b15613d0557613d028260a00151613c05565b91505b60355415613e655760008260a00151600014158015613d275750818360a00151105b15613d3e576080830151613d3b9083615d57565b90505b60a083015115801590613d615750609d548360a00151613d5e9190615d6a565b84115b15613d9457609d548360a00151613d789190615d6a565b9150826080015182613d8a9190615d57565b600260c085015290505b6000836080015183613da69190615d57565b90506000613db682609b54614e4c565b90506000613dc683609e54614e4c565b90506000613dd685609c54614e4c565b8751909150613de59082613807565b87604001818151613df69190615d6a565b9052508651613e059083613807565b87602001818151613e169190615d6a565b9052508651613e259084613807565b87518890613e34908390615d6a565b905250613e5a613e4360355490565b60408901518951613e549190615d6a565b90613f6c565b606088015250505050505b6080820152919050565b6000613e7b848461322c565b90506000198114613ee35781811015613ed65760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610bb5565b613ee38484848403613888565b50505050565b613ef1612e1e565b613ef9614420565b6000613f03613257565b905060005b8151811015613f60576000828281518110613f2557613f25615a4f565b6020908102919091010151519050613f4060b1828887614e5d565b613f4d60b1828787614e91565b5080613f5881615a7b565b915050613f08565b50613ee3848484614ec5565b60008161381c670de0b6b3a764000085615d96565b613f89614420565b613f946128da6124e2565b613fa16128da6000614291565b6000613fab613257565b905060005b8151811015613ff657613fe4828281518110613fce57613fce615a4f565b60209081029190910101515160b1908686614e91565b80613fee81615a7b565b915050613fb0565b5061387c8383615069565b6040516001600160a01b0380851660248301528316604482015260648101829052613ee39085906323b872dd60e01b90608401613845565b600081815260a960209081526040808320815160e08101835260aa8054825260ab549482019490945260ac549281019290925260ad54606083015260ae54608083015260af5460a083015260b054849384936140f49290919060c083019060ff1660038111156140ab576140ab6157ac565b60038111156140bc576140bc6157ac565b905250604080516080810182528454815260018501546020820152600285015491810191909152600384015460608201524288614a29565b91955093509150428510156141695742600282015560ad54600382015560ab8054839190600090614126908490615d57565b909155505060aa8054859190600090614140908490615d57565b909155505060ac805484919060009061415a908490615d57565b9091555050600060af55614270565b6002810185905561417985613c05565b606001516003820181905560a3546001830154604051637aaf678360e11b8152600481019190915260248101929092526001600160a01b03169063f55ecf0690604401600060405180830381600087803b1580156141d657600080fd5b505af11580156141ea573d6000803e3d6000fd5b505060ad54835460009350614200925090613807565b905061420c8482615d57565b90506142238160aa6000015460aa60010154615124565b60ab8054600090614235908490615d57565b909155505060aa805482919060009061424f908490615d57565b909155505060ac8054859190600090614269908490615d57565b9091555050505b6142798561469f565b6142866128da6000614291565b600090559193909250565b600061429b6124e2565b90508180156142b75750600081815260a9602052604090205415155b156142c157919050565b80609954426142d09190615d6a565b11156142fb576098546142e39082615d6a565b600081815260a96020526040902054909150156142c1575b919050565b614308614420565b6000614312613257565b905060005b815181101561435d5761434b82828151811061433557614335615a4f565b60209081029190910101515160b1908686614e5d565b8061435581615a7b565b915050614317565b5061387c838361513b565b80156143fd576143fd3360a260009054906101000a90046001600160a01b03166001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143e99190615d3a565b60a1546001600160a01b0316919084614001565b61387c333061440c8587615d6a565b60a1546001600160a01b0316929190614001565b60ae5460355415801590614435575060ba5415155b8015614442575060ba5481115b156144ff576000614451613257565b905060005b81518110156144fc5781818151811061447157614471615a4f565b6020026020010151602001516000146144ea576144ea82828151811061449957614499615a4f565b60209081029190910101515160ba546144b29086615d57565b8484815181106144c4576144c4615a4f565b602002602001015160200151600160801b6144de60355490565b60b19493929190615269565b806144f481615a7b565b915050614456565b50505b60ba55565b6001600160a01b03808416600090815260058601602090815260408083209386168352929052908120805483929061453d908490615d6a565b909155505050505050565b60ad5460ac5460aa5461456c92614565929091613e549190615d6a565b8290613f6c565b60ad55600060aa81905560ac81905560a58190556145886124e2565b600081815260a96020526040902054909150156145cb576145a88161469f565b600081815260a96020526040812090815560ae54600282015560ad546003909101555b60006145d76001614291565b600081815260a960205260409020549091501561461a576145f78161469f565b60ae54600082815260a960205260409020600281019190915560ad546003909101555b614627306136ac30612441565b61387c5b600360b05460ff166003811115614644576146446157ac565b0361466257604051630f509b1160e01b815260040160405180910390fd5b60b0805460ff19166003179055600060a78190556040517f1cdde67b72a90f19919ac732a437ac2f7a10fc128d28c2a6e525d89ce5cd9d3a9190a1565b600081815260a960209081526040808320600181015480855260b4909352922054603554158015906146d057508042115b80156146dc5750825415155b15613ee35760006146eb613257565b905060005b81518110156147725761476082828151811061470e5761470e615a4f565b6020026020010151600001518585426147279190615d57565b85858151811061473957614739615a4f565b602002602001015160200151600160801b61475360355490565b60b19594939291906152c8565b8061476a81615a7b565b9150506146f0565b505050600090815260b4602052604090204290555050565b6147976137bd8383615d96565b6001600160a01b0380861660009081526004880160209081526040808320938816835292905290812080549091906137fb908490615e61565b6000806000806147df42613c05565b905060a5546000141580614808575060028160c001516003811115614806576148066157ac565b145b156148255780516040820151602090920151909591945092509050565b600061482f6124e2565b600081815260a9602052604090208054919250901561499857604080516080810182528254815260018301546020820152600283015491810191909152600382015460608201526148839084904285614a29565b91975095509350428210156148fe5783836020018181516148a49190615d57565b9052508251869084906148b8908390615d57565b90525060985460009081906148d89086906148d39087615d6a565b615332565b925050915081886148e99190615d6a565b97506148f58187615d6a565b9550505061498b565b606083015181546000916149129190613807565b905061491e8682615d57565b90506149338185600001518660200151615124565b846020018181516149449190615d57565b905250835181908590614958908390615d57565b9052506000806149688686615332565b925050915081896149799190615d6a565b98506149858188615d6a565b96505050505b5050604001519293909150565b6149a28383615332565b955095509550505050909192565b606081600701805480602002602001604051908101604052809291908181526020016000905b82821015614a1e576000848152602090819020604080518082019091526002850290910180546001600160a01b031682526001908101548284015290835290920191016149d6565b505050509050919050565b600080600083851115614a995760608701518651614a4691613807565b9250614a678388604001518960000151614a609190615d6a565b8951615124565b614a719084615d57565b9150614a7d8284615d57565b9250614a928388600001518960200151615124565b9050614af0565b614ae88760000151886020015189604001518960000151614ab960355490565b614ace614ac68c8c615d57565b609b54614e4c565b614ae3614adb8d8d615d57565b609e54614e4c565b6153b4565b919450925090505b9450945094915050565b600080614b0642613c05565b608001516001600160a01b038516600090815260b3602090815260408083205460b290925282205460b8805494955091939092919083908110614b4b57614b4b615a4f565b9060005260206000209060020201600101549050614b6860355490565b15801590614b77575060ba5415155b8015614b84575060ba5484115b8015614b8f57508015155b15614be05760ba54600090614ba49086615d57565b9050614baf60355490565b82614bbe83600160801b615d96565b614bc89190615d96565b614bd29190615df4565b614bdc9085615d6a565b9350505b6001600160a01b03808816600090815260b560209081526040808320938a1683529290522054600160801b90614c3690614c2786614c1d8b612441565b6137bd9190615d96565b614c319190615dcc565b61544a565b614c409190615df4565b979650505050505050565b60006001600160ff1b03821115614cb55760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608401610bb5565b5090565b6000614d0e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661549c9092919063ffffffff16565b9050805160001480614d2f575080806020019051810190614d2f9190615c20565b61387c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610bb5565b600054610100900460ff166138815760405162461bcd60e51b8152600401610bb590615e16565b600054610100900460ff16614ddc5760405162461bcd60e51b8152600401610bb590615e16565b6036614de88382615ecf565b50603761387c8282615ecf565b60af5460009015614e07575060af5490565b6000614e116124e2565b90508042118015614e3a5750600081815260a96020526040902054151580614e3a575060a55415155b15614e4457919050565b600091505090565b60006301e1338061381c8484615d96565b613ee384848484886002016000896001600160a01b03166001600160a01b03168152602001908152602001600020546137b0565b613ee384848484886002016000896001600160a01b03166001600160a01b031681526020019081526020016000205461478a565b6001600160a01b038316614f295760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610bb5565b6001600160a01b038216614f8b5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610bb5565b614f968383836154ab565b6001600160a01b0383166000908152603360205260409020548181101561500e5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610bb5565b6001600160a01b038085166000818152603360205260408082208686039055928616808252908390208054860190559151600080516020615fab8339815191529061505c9086815260200190565b60405180910390a3613ee3565b6001600160a01b0382166150bf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610bb5565b6150cb600083836154ab565b80603560008282546150dd9190615d6a565b90915550506001600160a01b038216600081815260336020908152604080832080548601905551848152600080516020615fab833981519152910160405180910390a35050565b6000826151318386615d96565b611fdd9190615df4565b6001600160a01b03821661519b5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610bb5565b6151a7826000836154ab565b6001600160a01b0382166000908152603360205260409020548181101561521b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610bb5565b6001600160a01b0383166000818152603360209081526040808320868603905560358054879003905551858152919291600080516020615fab833981519152910160405180910390a3505050565b600081846152778786615d96565b6152819190615d96565b61528b9190615df4565b6001600160a01b03871660009081526002890160205260408120805492935083929091906152ba908490615d6a565b909155505050505050505050565b600081846152d68786615d96565b6152e09190615d96565b6152ea9190615df4565b600087815260068a01602090815260408083206001600160a01b038c168452909152812080549293508392909190615323908490615d6a565b90915550505050505050505050565b60008080804285111561534c576153494286615d57565b90505b61536361535b82609e54614e4c565b875190613807565b866020018181516153749190615d6a565b905250609b546153899061535b908390614e4c565b86518790615398908390615d6a565b9052505084516040860151602090960151909690945092505050565b600080806153c28a85613807565b6153cc908a615d6a565b98506153d88a86613807565b6153e2908b615d6a565b99506153fc6153f587613e548b8e615d6a565b8890613807565b96506154128761540c8a8d615d6a565b8c615124565b61541c9088615d57565b97506154288888615d57565b96508688615437898d8d615124565b9250925092509750975097945050505050565b600080821215614cb55760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401610bb5565b6060611fdd84846000856154e0565b816001600160a01b03811630148015906154cd57506001600160a01b03811615155b156154db576154db81612566565b613ee3565b6060824710156155415760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610bb5565b600080866001600160a01b0316858760405161555d9190615f8e565b60006040518083038185875af1925050503d806000811461559a576040519150601f19603f3d011682016040523d82523d6000602084013e61559f565b606091505b5091509150614c40878383876060831561561a578251600003615613576001600160a01b0385163b6156135760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610bb5565b5081611fdd565b611fdd838381511561562f5781518083602001fd5b8060405162461bcd60e51b8152600401610bb591906156d3565b6040518060e0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160006003811115615691576156916157ac565b905290565b6000602082840312156156a857600080fd5b5035919050565b60005b838110156156ca5781810151838201526020016156b2565b50506000910152565b60208152600082518060208401526156f28160408501602087016156af565b601f01601f19169190910160400192915050565b6001600160a01b0381168114610a6c57600080fd5b6000806040838503121561572e57600080fd5b823561573981615706565b946020939093013593505050565b8015158114610a6c57600080fd5b6000806040838503121561576857600080fd5b82356001600160401b0381111561577e57600080fd5b8301610140818603121561579157600080fd5b915060208301356157a181615747565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b60208101600483106157e457634e487b7160e01b600052602160045260246000fd5b91905290565b6000806000606084860312156157ff57600080fd5b833561580a81615706565b9250602084013561581a81615706565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b6000806040838503121561585257600080fd5b823561585d81615706565b915060208301356157a181615706565b60006020828403121561587f57600080fd5b81356112a281615706565b600080600080600060a086880312156158a257600080fd5b853594506020860135935060408601356158bb81615706565b925060608601356158cb81615706565b949793965091946080013592915050565b9283526020830191909152604082015260600190565b602080825282518282018190526000919060409081850190868401855b8281101561593d57815180516001600160a01b0316855286015186850152928401929085019060010161590f565b5091979650505050505050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561597557600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156159b4576159b461597c565b60405290565b604051601f8201601f191681016001600160401b03811182821017156159e2576159e261597c565b604052919050565b6000608082840312156159fc57600080fd5b604051608081018181106001600160401b0382111715615a1e57615a1e61597c565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201615a8d57615a8d615a65565b5060010190565b600181811c90821680615aa857607f821691505b602082108103615ac857634e487b7160e01b600052602260045260246000fd5b50919050565b600060208284031215615ae057600080fd5b81516001600160401b0380821115615af757600080fd5b818401915084601f830112615b0b57600080fd5b815181811115615b1d57615b1d61597c565b615b30601f8201601f19166020016159ba565b9150808252856020828501011115615b4757600080fd5b615b588160208401602086016156af565b50949350505050565b6000808335601e19843603018112615b7857600080fd5b8301803591506001600160401b03821115615b9257600080fd5b602001915036819003821315615ba757600080fd5b9250929050565b60008651615bc0818460208b016156af565b82018587823760009086019081528451615bde8183602089016156af565b8451910190615bf18183602088016156af565b01979650505050505050565b600060208284031215615c0f57600080fd5b815160ff811681146112a257600080fd5b600060208284031215615c3257600080fd5b81516112a281615747565b600080600080600060a08688031215615c5557600080fd5b85519450602080870151945060408088015194506060880151935060808801516001600160401b0380821115615c8a57600080fd5b818a0191508a601f830112615c9e57600080fd5b815181811115615cb057615cb061597c565b615cbe858260051b016159ba565b818152858101925060069190911b83018501908c821115615cde57600080fd5b928501925b81841015615d275784848e031215615cfb5760008081fd5b615d03615992565b8451615d0e81615706565b8152848701518782015283529284019291850191615ce3565b8096505050505050509295509295909350565b600060208284031215615d4c57600080fd5b81516112a281615706565b81810381811115610b1557610b15615a65565b80820180821115610b1557610b15615a65565b60ff8281168282160390811115610b1557610b15615a65565b8082028115828204841417610b1557610b15615a65565b600060ff821660ff8103615dc357615dc3615a65565b60010192915050565b8082018281126000831280158216821582161715615dec57615dec615a65565b505092915050565b600082615e1157634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b818103600083128015838313168383128216171561104c5761104c615a65565b601f82111561387c57600081815260208120601f850160051c81016020861015615ea85750805b601f850160051c820191505b81811015615ec757828155600101615eb4565b505050505050565b81516001600160401b03811115615ee857615ee861597c565b615efc81615ef68454615a94565b84615e81565b602080601f831160018114615f315760008415615f195750858301515b600019600386901b1c1916600185901b178555615ec7565b600085815260208120601f198616915b82811015615f6057888601518255948401946001909101908401615f41565b5085821015615f7e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251615fa08184602087016156af565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212201c91eee26fee4166eea850276109efaaadf58ef9bbf3c48d065fc9590e011ca864736f6c63430008130033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103355760003560e01c806371dbc900116101bf578063a9059cbb116100fa578063db006a751161009d578063db006a75146106f8578063dbd5edc71461070b578063dd62ed3e14610714578063df65513914610727578063e61dfbea1461073c578063eb81033f1461074f578063fa3ae6dc14610757578063fc9de5a81461075f57600080fd5b8063a9059cbb14610693578063ae573ffc146106a6578063b0e21e8a146106af578063b0f3af47146106b8578063b69b05c4146106cb578063ba9a7a56146106de578063cace1aa7146106e7578063d6b7494f146106ef57600080fd5b806393e88f3a1161016257806393e88f3a1461062257806395d89b4114610639578063961be391146106415780639944b5f6146106495780639ee679e81461065c578063a06db7dc1461066f578063a457c2d714610678578063a6afed951461068b57600080fd5b806371dbc9001461056357806379aa80e7146105765780637df1f1b91461057e5780638367d1ff1461059657806389ddd0ed146105a95780638d516e1c146105b25780638fa8b79014610607578063928cdffd1461060f57600080fd5b80633e4191dc1161028f5780634ec18db9116102325780634ec18db9146104eb578063536108c3146104f357806358413d70146105065780636107155214610519578063619cc4ac1461052257806365b810a51461053557806366805de51461054857806370a082311461055057600080fd5b80633e4191dc14610483578063402d888314610490578063414a62791461049857806341b3d185146104a15780634219dc40146104aa5780634b2a12da146104bd5780634c9e2f12146104d05780634e7c13fe146104e357600080fd5b8063042a20771461033a57806306fdde031461034f578063095ea7b31461036d57806310c802f11461039057806318160ddd146103a35780631a294fd8146103b5578063200d2ed2146103c857806323b872dd146103dd57806324c259f8146103f05780632f917dff14610403578063313ce56714610416578063354030231461043557806338d52e0f1461044857806339509351146104685780633ba0b9a91461047b575b600080fd5b61034d610348366004615696565b610787565b005b610357610a6f565b60405161036491906156d3565b60405180910390f35b61038061037b36600461571b565b610b01565b6040519015158152602001610364565b61038061039e366004615755565b610b1b565b6035545b604051908152602001610364565b61034d6103c3366004615696565b611053565b6103d061126b565b60405161036491906157c2565b6103806103eb3660046157ea565b611283565b61034d6103fe366004615696565b6112a9565b61034d610411366004615696565b611377565b60a354600160a01b900460ff1660405160ff9091168152602001610364565b61034d610443366004615696565b61149e565b60a15461045b906001600160a01b031681565b604051610364919061582b565b61038061047636600461571b565b611832565b6103a7611854565b60a0546103809060ff1681565b61034d611868565b6103a760995481565b6103a7609a5481565b60a25461045b906001600160a01b031681565b61034d6104cb366004615696565b611a69565b61034d6104de366004615696565b611bb9565b61034d611d53565b6103a7611eee565b6103a761050136600461583f565b611f13565b61034d610514366004615696565b611fe5565b6103a7609b5481565b61034d610530366004615696565b612168565b61034d610543366004615696565b6123b4565b61034d6123e8565b6103a761055e36600461586d565b612441565b61034d61057136600461586d565b61245c565b6103a76124e2565b60a05461045b9061010090046001600160a01b031681565b61034d6105a436600461586d565b612566565b6103a7609f5481565b6105e76105c0366004615696565b60a96020526000908152604090208054600182015460028301546003909301549192909184565b604080519485526020850193909352918301526060820152608001610364565b61034d6125cf565b61034d61061d36600461588a565b612648565b61062a61273d565b604051610364939291906158dc565b61035761276e565b6103a761277d565b61034d61065736600461571b565b6127ef565b61034d61066a366004615696565b612959565b6103a7609d5481565b61038061068636600461571b565b612d98565b61034d612e1e565b6103806106a136600461571b565b612f59565b6103a760985481565b6103a7609e5481565b60a35461045b906001600160a01b031681565b61034d6106d9366004615696565b612f67565b6103a76103e881565b6103a76130b9565b6103a7609c5481565b61034d610706366004615696565b61311d565b6103a760975481565b6103a761072236600461583f565b61322c565b61072f613257565b60405161036491906158f2565b61062a61074a366004615696565b613263565b61034d6132de565b61034d613320565b61077261076d36600461583f565b61370e565b60408051928352602083019190915201610364565b61078f613757565b610797612e1e565b60a354604051627eeac760e11b81526000916001600160a01b03169062fdd58e906107c8903390869060040161594a565b602060405180830381865afa1580156107e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108099190615963565b90508060000361082c5760405163e320176b60e01b815260040160405180910390fd5b60a35460405163b4b5b48f60e01b8152600481018490526000916001600160a01b03169063b4b5b48f90602401608060405180830381865afa158015610876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089a91906159ea565b8051600090815260a96020526040902060028101549192509015806108c25750428160020154115b156108e057604051633cc9de1f60e11b815260040160405180910390fd5b60006108ea613257565b905060005b815181101561096357600082828151811061090c5761090c615a4f565b60209081029190910181015151600089815260b7835260408082206001600160a01b038416835290935291909120549091506109509060b190839033908a906137b0565b508061095b81615a7b565b9150506108ef565b5060a354604051637a94c56560e11b815233600482015260248101879052604481018690526001600160a01b039091169063f5298aca90606401600060405180830381600087803b1580156109b757600080fd5b505af11580156109cb573d6000803e3d6000fd5b5050505060006109e883600301548661380790919063ffffffff16565b90508360600151600014610a09576060840151610a06908690613807565b90505b60a154610a20906001600160a01b03163383613826565b6040805186815260208101839052879133917f1ed7ee1a43efec4a4f81e0d29338046bc1b1f4f035f86d69176f2d3518baae8b910160405180910390a35050505050610a6c6001606555565b50565b606060368054610a7e90615a94565b80601f0160208091040260200160405190810160405280929190818152602001828054610aaa90615a94565b8015610af75780601f10610acc57610100808354040283529160200191610af7565b820191906000526020600020905b815481529060010190602001808311610ada57829003601f168201915b5050505050905090565b600033610b0f818585613888565b60019150505b92915050565b60008054610100900460ff1615808015610b3c5750600054600160ff909116105b80610b565750303b158015610b56575060005460ff166001145b610bbe5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610be1576000805461ff0019166101001790555b610be96139ac565b610bf960e0850160c0860161586d565b60a180546001600160a01b0319166001600160a01b03929092169182179055604080516395d89b4160e01b81529051600092916395d89b4191600480830192869291908290030181865afa158015610c55573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c7d9190810190615ace565b9050610d30610c90610100870187615b61565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080518082019091526002815261063760f41b60208201529150610ced9050610120890189615b61565b604051806040016040528060018152602001602d60f81b81525086604051602001610d1c959493929190615bae565b6040516020818303038152906040526139db565b60a160009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da79190615bfd565b60a3805460ff92909216600160a01b0260ff60a01b19909216919091179055610dd7610100860160e0870161586d565b60a380546001600160a01b03929092166001600160a01b0319928316811790915560a2805490921633179091556040805163a811299960e01b81523060048201526024810191909152600060448201819052919063a8112999906064016020604051808303816000875af1158015610e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e779190615c20565b9050801515600003610e8e57600093505050611006565b60a25460408051632370903960e01b815290516060926001600160a01b03169163237090399160048083019260009291908290030181865afa158015610ed8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f009190810190615c3d565b609f91909155609e91909155609d91909155609c91909155905060005b8151811015610f8957610f76828281518110610f3b57610f3b615a4f565b602002602001015160000151838381518110610f5957610f59615a4f565b60200260200101516020015160b1613a109092919063ffffffff16565b5080610f8181615a7b565b915050610f1d565b506060870135609a558635609755602087013560985560408701356099556080870135609b55610fbf60c0880160a0890161586d565b60a080546001600160a81b0319166101006001600160a01b03939093169290920260ff19169190911787151517905550504260ae5550670de0b6b3a764000060ad55600191505b801561104c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5092915050565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ca9190615d3a565b6001600160a01b0316336001600160a01b0316146110fb5760405163070545c960e51b815260040160405180910390fd5b611103612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05460009261117a929160c083019060ff166003811115611161576111616157ac565b6003811115611172576111726157ac565b905250613b5c565b90506000816003811115611190576111906157ac565b141580156111b0575060018160038111156111ad576111ad6157ac565b14155b156111ce57604051630f509b1160e01b815260040160405180910390fd5b60a5541515806111de575060a754155b156111fc5760405163829e373360e01b815260040160405180910390fd5b60006112066124e2565b9050824211156112295760405163a9cb9e0d60e01b815260040160405180910390fd5b60a781905560a58390556040518381527fc01f2cfc592122ca3951f635d0ddd6a7a7cdc30ab7bfc0f25184e89f16af1c3c9060200160405180910390a1505050565b600061127e61127942613c05565b613b5c565b905090565b600033611291858285613e6f565b61129c858585613ee9565b60019150505b9392505050565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113209190615d3a565b6001600160a01b0316336001600160a01b0316146113515760405163070545c960e51b815260040160405180910390fd5b8060000361137257604051631aa3503f60e11b815260040160405180910390fd5b609f55565b60a05461010090046001600160a01b031633146113a757604051630ac9915d60e01b815260040160405180910390fd5b6113af612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05460009261140d929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611423576114236157ac565b1415801561144357506001816003811115611440576114406157ac565b14155b1561146157604051630f509b1160e01b815260040160405180910390fd5b60978290556040518281527f2bc390be6d76c38a7a1e46eb6629b370c4cd792e13afd099527cbce28c5ecf77906020015b60405180910390a15050565b6114a6613757565b6114ae612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05460009261150c929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611522576115226157ac565b141580156115425750600181600381111561153f5761153f6157ac565b14155b1561156057604051630f509b1160e01b815260040160405180910390fd5b60a05461010090046001600160a01b031633148061157f575060a55415155b1561159d5760405163829e373360e01b815260040160405180910390fd5b6115a633612566565b60a25460a054604051631fb014e160e01b81526001600160a01b0392831692631fb014e1926115e1926101009091049091169060040161582b565b600060405180830381600087803b1580156115fb57600080fd5b505af115801561160f573d6000803e3d6000fd5b50505050600061161d611eee565b6097549091501515600184016116ed5760a1546040516370a0823160e01b81526001600160a01b03909116906370a082319061165d90339060040161582b565b602060405180830381865afa15801561167a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169e9190615963565b935080156116ed5760975482106116c857604051631aa3503f60e11b815260040160405180910390fd5b6000826097546116d89190615d57565b90508085116116e757846116e9565b805b9450505b8315806116fb575083609a54115b80611718575080801561171857506097546117168386615d6a565b115b1561173657604051631aa3503f60e11b815260040160405180910390fd5b60ad54600090611747908690613f6c565b905060a7546000036117a0576098546117609042615d6a565b60a7556103e881101561178657604051631aa3503f60e11b815260040160405180910390fd5b6117926103e882615d57565b90506117a0306103e8613f81565b8460aa60000160008282546117b59190615d6a565b909155506117c590503382613f81565b60a05460a1546117e9916001600160a01b0391821691339161010090041688614001565b604080518681526020810183905233917f5c2c0d2616a06b35bb159b4d7e227972b59bb33f8d5229ca0e5e438259bfd5d3910160405180910390a250505050610a6c6001606555565b600033610b0f818585611845838361322c565b61184f9190615d6a565b613888565b600061185f42613c05565b60600151905090565b611870613757565b60a05461010090046001600160a01b031633146118a057604051630ac9915d60e01b815260040160405180910390fd5b6118a8612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092611906929160c083019060ff166003811115611161576111616157ac565b9050600081600381111561191c5761191c6157ac565b1415801561193c57506001816003811115611939576119396157ac565b14155b1561195a57604051630f509b1160e01b815260040160405180910390fd5b60006119646124e2565b600081815260a960205260408120805492935091900361199757604051633c74e66760e01b815260040160405180910390fd5b8054600080806119a686614039565b60bc805493965091945092506001916000906119c690849060ff16615d7d565b92506101000a81548160ff021916908360ff1602179055506099546000036119f8576119f06124e2565b60a755611a06565b611a026001614291565b60a7555b611a103085614300565b611a1b838383614368565b7f84150d563c486763473e5a92eeb9297b1ee15fd60a18bc0b93ffe30bda41b2d0838383604051611a4e939291906158dc565b60405180910390a150505050505050611a676001606555565b565b60a05461010090046001600160a01b03163314611a9957604051630ac9915d60e01b815260040160405180910390fd5b611aa1612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092611aff929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611b1557611b156157ac565b14158015611b3557506001816003811115611b3257611b326157ac565b14155b15611b5357604051630f509b1160e01b815260040160405180910390fd5b6000609754118015611b66575060975482115b15611b84576040516301f45a5b60e41b815260040160405180910390fd5b609a8290556040518281527fa000bf02376732aba3d876c4c1a507f71dc704bc53a9197154014ac0262fe8a690602001611492565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c309190615d3a565b6001600160a01b0316336001600160a01b031614611c615760405163070545c960e51b815260040160405180910390fd5b611c69612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092611cc7929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611cdd57611cdd6157ac565b14158015611cfd57506001816003811115611cfa57611cfa6157ac565b14155b15611d1b57604051630f509b1160e01b815260040160405180910390fd5b811580611d2f5750670de0b6b3a764000082115b15611d4d57604051631aa3503f60e11b815260040160405180910390fd5b50609e55565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dca9190615d3a565b6001600160a01b0316336001600160a01b031614611dfb5760405163070545c960e51b815260040160405180910390fd5b611e03612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092611e61929160c083019060ff166003811115611161576111616157ac565b90506000816003811115611e7757611e776157ac565b14158015611e9757506001816003811115611e9457611e946157ac565b14155b15611eb557604051630f509b1160e01b815260040160405180910390fd5b60b0805460ff191660021790556040517f46b9cd4891c2c9c48ba40bb38b2058575e06ecdaab42ec43bcb2574c4be226be90600090a150565b600080611efa42613c05565b60408101518151919250611f0d91615d6a565b91505090565b60a2546000906001600160a01b03163314611f4157604051630636a15760e11b815260040160405180910390fd5b816001600160a01b0381163014801590611f6357506001600160a01b03811615155b15611f7157611f7181612566565b611f79612e1e565b611f81614420565b6000611f8d858561370e565b9150508015611fdd57611fa360b1868684614504565b7f1d3eee4ca001cff39eec6ec7615aacf2f2bd61791273830728ba00ccbd6e13378582604051611fd492919061594a565b60405180910390a15b949350505050565b60a05461010090046001600160a01b0316331461201557604051630ac9915d60e01b815260040160405180910390fd5b61201d612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05460009261207b929160c083019060ff166003811115611161576111616157ac565b90506000816003811115612091576120916157ac565b141580156120b1575060018160038111156120ae576120ae6157ac565b14155b156120cf57604051630f509b1160e01b815260040160405180910390fd5b620151808210806120e5575060bc5460ff166002145b156121035760405163829e373360e01b815260040160405180910390fd5b60985482118015612115575060a75415155b1561213357604051631df60e1360e31b815260040160405180910390fd5b60988290556040518281527fd210d635a13704244ee03b7760dabd85ee85bad16a85f30016dd9f1829889f5090602001611492565b612170612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b0546000926121ce929160c083019060ff166003811115611161576111616157ac565b905060008160038111156121e4576121e46157ac565b1415801561220457506001816003811115612201576122016157ac565b14155b1561222257604051630f509b1160e01b815260040160405180910390fd5b60a05461010090046001600160a01b0316331461225257604051630ac9915d60e01b815260040160405180910390fd5b81609b5480820361227657604051637a06de1f60e01b815260040160405180910390fd5b8360000361229757604051631aa3503f60e11b815260040160405180910390fd5b60006122a16124e2565b9050609b548511806122b1575080155b1561230e57609b85905560a854600090815260bb602052604080822091909155517fb0f8bd9fe66bce43fb8d6b03bdc7a4f02ccdfe8f6674cf8bd0beaaa7a2a75702906123019087815260200190565b60405180910390a16123ad565b609954600003612328576098546123259082615d6a565b90505b8060995460026123389190615d96565b6123429042615d6a565b111561235c576098546123559082615d6a565b9050612328565b600081815260bb602090815260409182902087905560a883905581518781529081018390527f5fd5094086b5c595b0724f9a2855ae82ee5aace5deb6628118d539afc9fb5d25910160405180910390a15b5050505050565b60a2546001600160a01b031633146123df57604051630636a15760e11b815260040160405180910390fd5b610a6c81614548565b60a05461010090046001600160a01b0316331461241857604051630ac9915d60e01b815260040160405180910390fd5b60a7541561243957604051631df60e1360e31b815260040160405180910390fd5b611a6761462b565b6001600160a01b031660009081526033602052604090205490565b60a2546001600160a01b0316331461248757604051630636a15760e11b815260040160405180910390fd5b60a08054610100600160a81b0319166101006001600160a01b038416021790556040517fa1cc029f3440726d0dd25b6385e24d209e5bf7817d6662d6e4bfdfbc621c1cf2906124d790839061582b565b60405180910390a150565b60a75460008190036124f45750600090565b60a5541580159061251357508060a5541080612513575060bc5460ff16155b1561251f575060a55490565b600081815260a96020526040902054156125365790565b804211156125635760985461254b9082615d6a565b600081815260a9602052604090205490915015612536575b90565b60a05460ff1615610a6c5760a254604051638367d1ff60e01b81526001600160a01b0390911690638367d1ff906125a190849060040161582b565b600060405180830381600087803b1580156125bb57600080fd5b505af11580156123ad573d6000803e3d6000fd5b6125d7612e1e565b609f5460ae546000916125e991615d6a565b4210159050600260b05460ff166003811115612607576126076157ac565b148015612617575060a65460ff16155b80156126205750805b1561262f57610a6c6000614548565b60405163829e373360e01b815260040160405180910390fd5b60a3546001600160a01b031633146126735760405163829e373360e01b815260040160405180910390fd5b61267c8561469f565b6000612686613257565b905060005b81518110156127345760008282815181106126a8576126a8615a4f565b60209081029190910181015151600089815260b7835260408082206001600160a01b038416835290935291909120549091506126ec9060b1908390899088906137b0565b600087815260b7602090815260408083206001600160a01b03851684529091529020546127219060b19083908890889061478a565b508061272c81615a7b565b91505061268b565b50505050505050565b600080600060aa6000015460000361275b5750600092839250829150565b6127636147d0565b925092509250909192565b606060378054610a7e90615a94565b60a1546040516370a0823160e01b81526000916001600160a01b0316906370a08231906127ae90309060040161582b565b602060405180830381865afa1580156127cb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127e9190615963565b60a260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612842573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128669190615d3a565b6001600160a01b0316336001600160a01b0316146128975760405163070545c960e51b815260040160405180910390fd5b816001600160a01b0381166128bf5760405163bf8d717560e01b815260040160405180910390fd5b6128c7612e1e565b6128cf614420565b6128df6128da6124e2565b61469f565b6128ec6128da6000614291565b60006128fa60b18585613a10565b90508061291a5760405163d1d8c29b60e01b815260040160405180910390fd5b7f6559a40d7d599532f862cac525e829c672483eeb4d978b4c2faf7bab0347a9ea848460405161294b92919061594a565b60405180910390a150505050565b612961612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b0546000926129bf929160c083019060ff166003811115611161576111616157ac565b905060008160038111156129d5576129d56157ac565b141580156129f5575060018160038111156129f2576129f26157ac565b14155b15612a1357604051630f509b1160e01b815260040160405180910390fd5b60a55415612a345760405163829e373360e01b815260040160405180910390fd5b6000198203612a4957612a4633612441565b91505b811580612a5d5750612a5a33612441565b82115b15612a7b5760405163356680b760e01b815260040160405180910390fd5b6000612a856124e2565b90506000612a916130b9565b600083815260a96020526040902054909150158015612ab05750808214155b15612abf5760a7819055612ac5565b60a78290555b600081815260a9602052604081206001810154909103612b5557600160a46000828254612af29190615d6a565b909155505060a454600182015560bc5460ff16600203612b255760405163829e373360e01b815260040160405180910390fd5b60bc8054600090612b389060ff16615dad565b91906101000a81548160ff021916908360ff160217905550612bbc565b600281015415801590612b6b575060bc5460ff16155b15612bbc57600160a46000828254612b839190615d6a565b909155505060a454600182015560bc8054600090612ba39060ff16615dad565b91906101000a81548160ff021916908360ff1602179055505b612bc7333087613ee9565b6000612bd1613257565b9050612bdc8361469f565b60005b8151811015612c58576000828281518110612bfc57612bfc615a4f565b602090810291909101810151516001860154600090815260b7835260408082206001600160a01b03841683529093529190912054909150612c459060b190839033908c9061478a565b5080612c5081615a7b565b915050612bdf565b506001820154600090815260b460205260408120429055825487918491612c80908490615d6a565b909155505060a35460a4805460408051608081018252878152609c5460208201908152609b548284019081526000606084018181529451632be6196560e21b81523360048201526024810196909652604486018e90526101006064870152610104860152915160848501525193830193909352915160c4820152905160e48201526001600160a01b039091169063af9865949061012401600060405180830381600087803b158015612d3157600080fd5b505af1158015612d45573d6000803e3d6000fd5b50505050336001600160a01b03167f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e848860a454604051612d88939291906158dc565b60405180910390a2505050505050565b60003381612da6828661322c565b905083811015612e065760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610bb5565b612e138286868403613888565b506001949350505050565b60a854600090815260bb602052604090205415801590612e3f575060a85442115b15612ef757612e4f60a854613c05565b805160aa908155602082015160ab55604082015160ac55606082015160ad55608082015160ae5560a082015160af5560c082015160b0805460ff19166001836003811115612e9f57612e9f6157ac565b02179055505060a854600090815260bb602090815260408083208054939055609b839055518281529192507fb0f8bd9fe66bce43fb8d6b03bdc7a4f02ccdfe8f6674cf8bd0beaaa7a2a75702910160405180910390a1505b612f0042613c05565b805160aa908155602082015160ab55604082015160ac55606082015160ad55608082015160ae5560a082015160af5560c082015160b0805460ff19166001836003811115612f5057612f506157ac565b02179055505050565b600033610b0f818585613ee9565b60a05461010090046001600160a01b03163314612f9757604051630ac9915d60e01b815260040160405180910390fd5b612f9f612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b054600092612ffd929160c083019060ff166003811115611161576111616157ac565b90506000816003811115613013576130136157ac565b1415801561303357506001816003811115613030576130306157ac565b14155b1561305157604051630f509b1160e01b815260040160405180910390fd5b609954821180613066575060bc5460ff166002145b156130845760405163829e373360e01b815260040160405180910390fd5b60998290556040518281527f7a1e6d22e8e5c71b2b344863c99d8c804a7b916e9a2af7d804fa2ffdfef3f5db90602001611492565b60006130c36124e2565b9050806000036130d35750600090565b60995415806130ee575080609954426130ec9190615d6a565b115b15612563575b80609954426131039190615d6a565b1115612563576098546131169082615d6a565b90506130f4565b613125613757565b61312d612e1e565b600061313833612441565b9050600360b05460ff166003811115613153576131536157ac565b1461317157604051633cc9de1f60e11b815260040160405180910390fd5b600019820361317e578091505b811580613189575080155b8061319357508082115b156131b15760405163356680b760e01b815260040160405180910390fd5b60ad546000906131c2908490613807565b90506131ce3384614300565b60a1546131e5906001600160a01b03163383613826565b604080518281526020810185905233917ff3a670cd3af7d64b488926880889d08a8585a138ff455227af6737339a1ec262910160405180910390a25050610a6c6001606555565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b606061127e60b16149b0565b600081815260a960205260408120805482918291820361328e576000806000935093509350506132d7565b6132cf61329a42613c05565b604080516080810182528454815260018501546020820152600285015491810191909152600384015460608201524288614a29565b935093509350505b9193909250565b60a2546001600160a01b0316331461330957604051630636a15760e11b815260040160405180910390fd5b613311612e1e565b60a6805460ff19166001179055565b613328613757565b60a05461010090046001600160a01b0316331461335857604051630ac9915d60e01b815260040160405180910390fd5b613360612e1e565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b0546000926133be929160c083019060ff166003811115611161576111616157ac565b905060008160038111156133d4576133d46157ac565b141580156133f4575060018160038111156133f1576133f16157ac565b14155b1561341257604051630f509b1160e01b815260040160405180910390fd5b60008060008060a5546000146134cf5760aa5460ac5460ab54600060a581905560a754815260a9602052604090205492965090945092501561348b5761345960a75461469f565b60a78054600090815260a96020526040808220829055825482528082204260029091015560ad54925482529020600301555b6134956001614291565b600081815260a96020526040902054909150156134ca57600081815260a96020526040902042600282015560ad546003909101555b613678565b60006134d96124e2565b600081815260a9602052604090209091506134f2615649565b81541561364c57815461350484614039565b919950975095506135153082614300565b834211156135bd576135336098548561352e9190615d6a565b613c05565b80519092506135429089615d6a565b97508160200151866135549190615d6a565b95508160400151876135669190615d6a565b606083015160ad55965061357a6001614291565b600081815260a96020526040902054909550156135b8576060820151600086815260a960205260409020600381019190915560808301516002909101555b613646565b6135c684613c05565b80519092506135d59089615d6a565b97508160200151866135e79190615d6a565b95508160400151876135f99190615d6a565b600384015460ad55965061360d6001614291565b600081815260a960205260409020549095501561364657600380840154600087815260a960205260409020918201556002808501549101555b50613674565b61365583613c05565b805160208201516040830151606084015160ad55919950909750955090505b5050505b600060ab81905560aa81905560ac81905560af5560bc805460ff1916905561369f8161469f565b6136b1306136ac30612441565b614300565b6136bc848484614368565b7f64d4a547e018f465abf2f43db33fc010ad2a8b3378ca0462ed67ac8b096a8d6d8484846040516136ef939291906158dc565b60405180910390a16136ff61462b565b5050505050611a676001606555565b60008061371b8484614afa565b6001600160a01b03808616600090815260b6602090815260408083209388168352929052205490925061374e9083615d57565b90509250929050565b6002606554036137a95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610bb5565b6002606555565b6137c26137bd8383615d96565b614c4b565b6001600160a01b0380861660009081526004880160209081526040808320938816835292905290812080549091906137fb908490615dcc565b90915550505050505050565b6000670de0b6b3a764000061381c8385615d96565b6112a29190615df4565b61387c8363a9059cbb60e01b848460405160240161384592919061594a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614cb9565b505050565b6001606555565b6001600160a01b0383166138ea5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610bb5565b6001600160a01b03821661394b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610bb5565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600054610100900460ff166139d35760405162461bcd60e51b8152600401610bb590615e16565b611a67614d8e565b600054610100900460ff16613a025760405162461bcd60e51b8152600401610bb590615e16565b613a0c8282614db5565b5050565b6001600160a01b03821660009081526020849052604081205460ff1615613abb576001600160a01b038316600090815260018501602052604090205460078501805484919083908110613a6557613a65615a4f565b90600052602060002090600202016001015403613a865760009150506112a2565b82856007018281548110613a9c57613a9c615a4f565b90600052602060002090600202016001018190555060019150506112a2565b6001600160a01b038381166000818152602087815260408083208054600160ff1990911681179091558151808301835285815280840189815260078c01805480850182559087528587209251600290910290920180546001600160a01b0319169290981691909117875551958101959095556008890180549484529489019091528120829055909190613b4d83615a7b565b90915550600195945050505050565b600060038260c001516003811115613b7657613b766157ac565b1480613b97575060028260c001516003811115613b9557613b956157ac565b145b15613ba4575060c0015190565b6000613bae6124e2565b90508042118015613bca5750609d54613bc79082615d6a565b42105b8015613bee5750600081815260a96020526040902054151580613bee575060a55415155b15613bfc5750600192915050565b505060c0015190565b613c0d615649565b6040805160e08101825260aa8054825260ab54602083015260ac549282019290925260ad54606082015260ae54608082015260af5460a082015260b05490919060c083019060ff166003811115613c6657613c666157ac565b6003811115613c7757613c776157ac565b8152505090508060800151821080613ca4575060028160c001516003811115613ca257613ca26157ac565b145b80613cc4575060038160c001516003811115613cc257613cc26157ac565b145b15613cce57919050565b613cd6614df5565b60a08201819052829015801590613cf05750808260a00151105b15613d0557613d028260a00151613c05565b91505b60355415613e655760008260a00151600014158015613d275750818360a00151105b15613d3e576080830151613d3b9083615d57565b90505b60a083015115801590613d615750609d548360a00151613d5e9190615d6a565b84115b15613d9457609d548360a00151613d789190615d6a565b9150826080015182613d8a9190615d57565b600260c085015290505b6000836080015183613da69190615d57565b90506000613db682609b54614e4c565b90506000613dc683609e54614e4c565b90506000613dd685609c54614e4c565b8751909150613de59082613807565b87604001818151613df69190615d6a565b9052508651613e059083613807565b87602001818151613e169190615d6a565b9052508651613e259084613807565b87518890613e34908390615d6a565b905250613e5a613e4360355490565b60408901518951613e549190615d6a565b90613f6c565b606088015250505050505b6080820152919050565b6000613e7b848461322c565b90506000198114613ee35781811015613ed65760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610bb5565b613ee38484848403613888565b50505050565b613ef1612e1e565b613ef9614420565b6000613f03613257565b905060005b8151811015613f60576000828281518110613f2557613f25615a4f565b6020908102919091010151519050613f4060b1828887614e5d565b613f4d60b1828787614e91565b5080613f5881615a7b565b915050613f08565b50613ee3848484614ec5565b60008161381c670de0b6b3a764000085615d96565b613f89614420565b613f946128da6124e2565b613fa16128da6000614291565b6000613fab613257565b905060005b8151811015613ff657613fe4828281518110613fce57613fce615a4f565b60209081029190910101515160b1908686614e91565b80613fee81615a7b565b915050613fb0565b5061387c8383615069565b6040516001600160a01b0380851660248301528316604482015260648101829052613ee39085906323b872dd60e01b90608401613845565b600081815260a960209081526040808320815160e08101835260aa8054825260ab549482019490945260ac549281019290925260ad54606083015260ae54608083015260af5460a083015260b054849384936140f49290919060c083019060ff1660038111156140ab576140ab6157ac565b60038111156140bc576140bc6157ac565b905250604080516080810182528454815260018501546020820152600285015491810191909152600384015460608201524288614a29565b91955093509150428510156141695742600282015560ad54600382015560ab8054839190600090614126908490615d57565b909155505060aa8054859190600090614140908490615d57565b909155505060ac805484919060009061415a908490615d57565b9091555050600060af55614270565b6002810185905561417985613c05565b606001516003820181905560a3546001830154604051637aaf678360e11b8152600481019190915260248101929092526001600160a01b03169063f55ecf0690604401600060405180830381600087803b1580156141d657600080fd5b505af11580156141ea573d6000803e3d6000fd5b505060ad54835460009350614200925090613807565b905061420c8482615d57565b90506142238160aa6000015460aa60010154615124565b60ab8054600090614235908490615d57565b909155505060aa805482919060009061424f908490615d57565b909155505060ac8054859190600090614269908490615d57565b9091555050505b6142798561469f565b6142866128da6000614291565b600090559193909250565b600061429b6124e2565b90508180156142b75750600081815260a9602052604090205415155b156142c157919050565b80609954426142d09190615d6a565b11156142fb576098546142e39082615d6a565b600081815260a96020526040902054909150156142c1575b919050565b614308614420565b6000614312613257565b905060005b815181101561435d5761434b82828151811061433557614335615a4f565b60209081029190910101515160b1908686614e5d565b8061435581615a7b565b915050614317565b5061387c838361513b565b80156143fd576143fd3360a260009054906101000a90046001600160a01b03166001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143e99190615d3a565b60a1546001600160a01b0316919084614001565b61387c333061440c8587615d6a565b60a1546001600160a01b0316929190614001565b60ae5460355415801590614435575060ba5415155b8015614442575060ba5481115b156144ff576000614451613257565b905060005b81518110156144fc5781818151811061447157614471615a4f565b6020026020010151602001516000146144ea576144ea82828151811061449957614499615a4f565b60209081029190910101515160ba546144b29086615d57565b8484815181106144c4576144c4615a4f565b602002602001015160200151600160801b6144de60355490565b60b19493929190615269565b806144f481615a7b565b915050614456565b50505b60ba55565b6001600160a01b03808416600090815260058601602090815260408083209386168352929052908120805483929061453d908490615d6a565b909155505050505050565b60ad5460ac5460aa5461456c92614565929091613e549190615d6a565b8290613f6c565b60ad55600060aa81905560ac81905560a58190556145886124e2565b600081815260a96020526040902054909150156145cb576145a88161469f565b600081815260a96020526040812090815560ae54600282015560ad546003909101555b60006145d76001614291565b600081815260a960205260409020549091501561461a576145f78161469f565b60ae54600082815260a960205260409020600281019190915560ad546003909101555b614627306136ac30612441565b61387c5b600360b05460ff166003811115614644576146446157ac565b0361466257604051630f509b1160e01b815260040160405180910390fd5b60b0805460ff19166003179055600060a78190556040517f1cdde67b72a90f19919ac732a437ac2f7a10fc128d28c2a6e525d89ce5cd9d3a9190a1565b600081815260a960209081526040808320600181015480855260b4909352922054603554158015906146d057508042115b80156146dc5750825415155b15613ee35760006146eb613257565b905060005b81518110156147725761476082828151811061470e5761470e615a4f565b6020026020010151600001518585426147279190615d57565b85858151811061473957614739615a4f565b602002602001015160200151600160801b61475360355490565b60b19594939291906152c8565b8061476a81615a7b565b9150506146f0565b505050600090815260b4602052604090204290555050565b6147976137bd8383615d96565b6001600160a01b0380861660009081526004880160209081526040808320938816835292905290812080549091906137fb908490615e61565b6000806000806147df42613c05565b905060a5546000141580614808575060028160c001516003811115614806576148066157ac565b145b156148255780516040820151602090920151909591945092509050565b600061482f6124e2565b600081815260a9602052604090208054919250901561499857604080516080810182528254815260018301546020820152600283015491810191909152600382015460608201526148839084904285614a29565b91975095509350428210156148fe5783836020018181516148a49190615d57565b9052508251869084906148b8908390615d57565b90525060985460009081906148d89086906148d39087615d6a565b615332565b925050915081886148e99190615d6a565b97506148f58187615d6a565b9550505061498b565b606083015181546000916149129190613807565b905061491e8682615d57565b90506149338185600001518660200151615124565b846020018181516149449190615d57565b905250835181908590614958908390615d57565b9052506000806149688686615332565b925050915081896149799190615d6a565b98506149858188615d6a565b96505050505b5050604001519293909150565b6149a28383615332565b955095509550505050909192565b606081600701805480602002602001604051908101604052809291908181526020016000905b82821015614a1e576000848152602090819020604080518082019091526002850290910180546001600160a01b031682526001908101548284015290835290920191016149d6565b505050509050919050565b600080600083851115614a995760608701518651614a4691613807565b9250614a678388604001518960000151614a609190615d6a565b8951615124565b614a719084615d57565b9150614a7d8284615d57565b9250614a928388600001518960200151615124565b9050614af0565b614ae88760000151886020015189604001518960000151614ab960355490565b614ace614ac68c8c615d57565b609b54614e4c565b614ae3614adb8d8d615d57565b609e54614e4c565b6153b4565b919450925090505b9450945094915050565b600080614b0642613c05565b608001516001600160a01b038516600090815260b3602090815260408083205460b290925282205460b8805494955091939092919083908110614b4b57614b4b615a4f565b9060005260206000209060020201600101549050614b6860355490565b15801590614b77575060ba5415155b8015614b84575060ba5484115b8015614b8f57508015155b15614be05760ba54600090614ba49086615d57565b9050614baf60355490565b82614bbe83600160801b615d96565b614bc89190615d96565b614bd29190615df4565b614bdc9085615d6a565b9350505b6001600160a01b03808816600090815260b560209081526040808320938a1683529290522054600160801b90614c3690614c2786614c1d8b612441565b6137bd9190615d96565b614c319190615dcc565b61544a565b614c409190615df4565b979650505050505050565b60006001600160ff1b03821115614cb55760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608401610bb5565b5090565b6000614d0e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661549c9092919063ffffffff16565b9050805160001480614d2f575080806020019051810190614d2f9190615c20565b61387c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610bb5565b600054610100900460ff166138815760405162461bcd60e51b8152600401610bb590615e16565b600054610100900460ff16614ddc5760405162461bcd60e51b8152600401610bb590615e16565b6036614de88382615ecf565b50603761387c8282615ecf565b60af5460009015614e07575060af5490565b6000614e116124e2565b90508042118015614e3a5750600081815260a96020526040902054151580614e3a575060a55415155b15614e4457919050565b600091505090565b60006301e1338061381c8484615d96565b613ee384848484886002016000896001600160a01b03166001600160a01b03168152602001908152602001600020546137b0565b613ee384848484886002016000896001600160a01b03166001600160a01b031681526020019081526020016000205461478a565b6001600160a01b038316614f295760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610bb5565b6001600160a01b038216614f8b5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610bb5565b614f968383836154ab565b6001600160a01b0383166000908152603360205260409020548181101561500e5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610bb5565b6001600160a01b038085166000818152603360205260408082208686039055928616808252908390208054860190559151600080516020615fab8339815191529061505c9086815260200190565b60405180910390a3613ee3565b6001600160a01b0382166150bf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610bb5565b6150cb600083836154ab565b80603560008282546150dd9190615d6a565b90915550506001600160a01b038216600081815260336020908152604080832080548601905551848152600080516020615fab833981519152910160405180910390a35050565b6000826151318386615d96565b611fdd9190615df4565b6001600160a01b03821661519b5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610bb5565b6151a7826000836154ab565b6001600160a01b0382166000908152603360205260409020548181101561521b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610bb5565b6001600160a01b0383166000818152603360209081526040808320868603905560358054879003905551858152919291600080516020615fab833981519152910160405180910390a3505050565b600081846152778786615d96565b6152819190615d96565b61528b9190615df4565b6001600160a01b03871660009081526002890160205260408120805492935083929091906152ba908490615d6a565b909155505050505050505050565b600081846152d68786615d96565b6152e09190615d96565b6152ea9190615df4565b600087815260068a01602090815260408083206001600160a01b038c168452909152812080549293508392909190615323908490615d6a565b90915550505050505050505050565b60008080804285111561534c576153494286615d57565b90505b61536361535b82609e54614e4c565b875190613807565b866020018181516153749190615d6a565b905250609b546153899061535b908390614e4c565b86518790615398908390615d6a565b9052505084516040860151602090960151909690945092505050565b600080806153c28a85613807565b6153cc908a615d6a565b98506153d88a86613807565b6153e2908b615d6a565b99506153fc6153f587613e548b8e615d6a565b8890613807565b96506154128761540c8a8d615d6a565b8c615124565b61541c9088615d57565b97506154288888615d57565b96508688615437898d8d615124565b9250925092509750975097945050505050565b600080821215614cb55760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401610bb5565b6060611fdd84846000856154e0565b816001600160a01b03811630148015906154cd57506001600160a01b03811615155b156154db576154db81612566565b613ee3565b6060824710156155415760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610bb5565b600080866001600160a01b0316858760405161555d9190615f8e565b60006040518083038185875af1925050503d806000811461559a576040519150601f19603f3d011682016040523d82523d6000602084013e61559f565b606091505b5091509150614c40878383876060831561561a578251600003615613576001600160a01b0385163b6156135760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610bb5565b5081611fdd565b611fdd838381511561562f5781518083602001fd5b8060405162461bcd60e51b8152600401610bb591906156d3565b6040518060e0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160006003811115615691576156916157ac565b905290565b6000602082840312156156a857600080fd5b5035919050565b60005b838110156156ca5781810151838201526020016156b2565b50506000910152565b60208152600082518060208401526156f28160408501602087016156af565b601f01601f19169190910160400192915050565b6001600160a01b0381168114610a6c57600080fd5b6000806040838503121561572e57600080fd5b823561573981615706565b946020939093013593505050565b8015158114610a6c57600080fd5b6000806040838503121561576857600080fd5b82356001600160401b0381111561577e57600080fd5b8301610140818603121561579157600080fd5b915060208301356157a181615747565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b60208101600483106157e457634e487b7160e01b600052602160045260246000fd5b91905290565b6000806000606084860312156157ff57600080fd5b833561580a81615706565b9250602084013561581a81615706565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b6000806040838503121561585257600080fd5b823561585d81615706565b915060208301356157a181615706565b60006020828403121561587f57600080fd5b81356112a281615706565b600080600080600060a086880312156158a257600080fd5b853594506020860135935060408601356158bb81615706565b925060608601356158cb81615706565b949793965091946080013592915050565b9283526020830191909152604082015260600190565b602080825282518282018190526000919060409081850190868401855b8281101561593d57815180516001600160a01b0316855286015186850152928401929085019060010161590f565b5091979650505050505050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561597557600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156159b4576159b461597c565b60405290565b604051601f8201601f191681016001600160401b03811182821017156159e2576159e261597c565b604052919050565b6000608082840312156159fc57600080fd5b604051608081018181106001600160401b0382111715615a1e57615a1e61597c565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201615a8d57615a8d615a65565b5060010190565b600181811c90821680615aa857607f821691505b602082108103615ac857634e487b7160e01b600052602260045260246000fd5b50919050565b600060208284031215615ae057600080fd5b81516001600160401b0380821115615af757600080fd5b818401915084601f830112615b0b57600080fd5b815181811115615b1d57615b1d61597c565b615b30601f8201601f19166020016159ba565b9150808252856020828501011115615b4757600080fd5b615b588160208401602086016156af565b50949350505050565b6000808335601e19843603018112615b7857600080fd5b8301803591506001600160401b03821115615b9257600080fd5b602001915036819003821315615ba757600080fd5b9250929050565b60008651615bc0818460208b016156af565b82018587823760009086019081528451615bde8183602089016156af565b8451910190615bf18183602088016156af565b01979650505050505050565b600060208284031215615c0f57600080fd5b815160ff811681146112a257600080fd5b600060208284031215615c3257600080fd5b81516112a281615747565b600080600080600060a08688031215615c5557600080fd5b85519450602080870151945060408088015194506060880151935060808801516001600160401b0380821115615c8a57600080fd5b818a0191508a601f830112615c9e57600080fd5b815181811115615cb057615cb061597c565b615cbe858260051b016159ba565b818152858101925060069190911b83018501908c821115615cde57600080fd5b928501925b81841015615d275784848e031215615cfb5760008081fd5b615d03615992565b8451615d0e81615706565b8152848701518782015283529284019291850191615ce3565b8096505050505050509295509295909350565b600060208284031215615d4c57600080fd5b81516112a281615706565b81810381811115610b1557610b15615a65565b80820180821115610b1557610b15615a65565b60ff8281168282160390811115610b1557610b15615a65565b8082028115828204841417610b1557610b15615a65565b600060ff821660ff8103615dc357615dc3615a65565b60010192915050565b8082018281126000831280158216821582161715615dec57615dec615a65565b505092915050565b600082615e1157634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b818103600083128015838313168383128216171561104c5761104c615a65565b601f82111561387c57600081815260208120601f850160051c81016020861015615ea85750805b601f850160051c820191505b81811015615ec757828155600101615eb4565b505050505050565b81516001600160401b03811115615ee857615ee861597c565b615efc81615ef68454615a94565b84615e81565b602080601f831160018114615f315760008415615f195750858301515b600019600386901b1c1916600185901b178555615ec7565b600085815260208120601f198616915b82811015615f6057888601518255948401946001909101908401615f41565b5085821015615f7e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251615fa08184602087016156af565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212201c91eee26fee4166eea850276109efaaadf58ef9bbf3c48d065fc9590e011ca864736f6c63430008130033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MNT
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.