Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RolloverVault
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 750 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import { IERC20Upgradeable, IPerpetualTranche, IBondController, ITranche, IFeePolicy } from "./_interfaces/IPerpetualTranche.sol";
import { IVault } from "./_interfaces/IVault.sol";
import { IRolloverVault } from "./_interfaces/IRolloverVault.sol";
import { IERC20Burnable } from "./_interfaces/IERC20Burnable.sol";
import { TokenAmount, RolloverData, SubscriptionParams } from "./_interfaces/CommonTypes.sol";
import { UnauthorizedCall, UnauthorizedTransferOut, UnexpectedDecimals, UnexpectedAsset, OutOfBounds, UnacceptableSwap, InsufficientDeployment, DeployedCountOverLimit, InsufficientLiquidity } from "./_interfaces/ProtocolErrors.sol";
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import { ERC20BurnableUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import { EnumerableSetUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import { BondTranches, BondTranchesHelpers } from "./_utils/BondTranchesHelpers.sol";
import { TrancheHelpers } from "./_utils/TrancheHelpers.sol";
import { BondHelpers } from "./_utils/BondHelpers.sol";
import { PerpHelpers } from "./_utils/PerpHelpers.sol";
/*
* @title RolloverVault
*
* @notice A vault which generates yield (from fees) by performing rollovers on PerpetualTranche (or perp).
* The vault takes in AMPL or any other rebasing collateral as the "underlying" asset.
*
* Vault strategy:
* 1) deploy: The vault deposits the underlying asset into perp's current deposit bond
* to get tranche tokens in return, it then swaps these fresh tranche tokens for
* older tranche tokens (ones mature or approaching maturity) from perp.
* 2) recover: The vault redeems the tranches it holds for the underlying asset.
* NOTE: It performs both mature and immature redemption. Read more: https://bit.ly/3tuN6OC
*
* With v2.0, vault provides perp<>underlying swap liquidity and charges a fee.
* The swap fees are an additional source of yield for vault note holders.
*
* @dev When new tranches are added into the system, always double check if they are not malicious
* by only accepting one whitelisted by perp (ones part of perp's deposit bond or ones part of the perp reserve).
*
* We use `_syncAsset` and `_syncDeployedAsset` to keep track of tokens entering and leaving the system.
* When ever a tranche token enters or leaves the system, we immediately invoke `_syncDeployedAsset` to update book-keeping.
* We call `_syncAsset` at the very end of every external function which changes the vault's underlying or perp balance.
*
*/
contract RolloverVault is
ERC20BurnableUpgradeable,
OwnableUpgradeable,
PausableUpgradeable,
ReentrancyGuardUpgradeable,
IRolloverVault
{
// data handling
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using BondHelpers for IBondController;
using TrancheHelpers for ITranche;
using BondTranchesHelpers for BondTranches;
// ERC20 operations
using SafeERC20Upgradeable for IERC20Upgradeable;
// math
using MathUpgradeable for uint256;
//-------------------------------------------------------------------------
// Events
/// @notice Emits the vault asset's token balance that's recorded after a change.
/// @param token Address of token.
/// @param balance The recorded ERC-20 balance of the token.
event AssetSynced(IERC20Upgradeable token, uint256 balance);
//-------------------------------------------------------------------------
// Constants
/// @dev Internal percentages are fixed point numbers with {PERC_DECIMALS} places.
uint8 public constant PERC_DECIMALS = 8;
uint256 public constant ONE = (10 ** PERC_DECIMALS); // 1.0 or 100%
/// @dev Initial exchange rate between the underlying asset and notes.
uint256 private constant INITIAL_RATE = 10 ** 6;
/// @dev The maximum number of deployed assets that can be held in this vault at any given time.
uint8 public constant MAX_DEPLOYED_COUNT = 47;
// Replicating value used here:
// https://github.com/buttonwood-protocol/tranche/blob/main/contracts/BondController.sol
uint256 private constant TRANCHE_RATIO_GRANULARITY = 1000;
/// @dev Immature redemption may result in some dust tranches when balances are not perfectly divisible by the tranche ratio.
/// Based on current the implementation of `computeRedeemableTrancheAmounts`,
/// the dust balances which remain after immature redemption will be *at most* {TRANCHE_RATIO_GRANULARITY} or 1000.
/// We exclude the vault's dust tranche balances from TVL computation, note redemption and
/// during recovery (through recurrent immature redemption).
uint256 public constant TRANCHE_DUST_AMT = 10000000;
//--------------------------------------------------------------------------
// ASSETS
//
// The vault's assets are represented by a master list of ERC-20 tokens
// => { [underlying] U _deployed }
//
//
/// @notice The ERC20 token that can be deposited into this vault.
IERC20Upgradeable public underlying;
/// @dev The set of the intermediate ERC-20 tokens when the underlying asset has been put to use.
/// In the case of this vault, they represent the tranche tokens held before maturity.
EnumerableSetUpgradeable.AddressSet private _deployed;
//-------------------------------------------------------------------------
// Storage
/// @notice Minimum amount of underlying assets that must be deployed, for a deploy operation to succeed.
/// @dev The deployment transaction reverts, if the vaults does not have sufficient underlying tokens
/// to cover the minimum deployment amount.
uint256 public minDeploymentAmt;
/// @notice The perpetual token on which rollovers are performed.
IPerpetualTranche public perp;
//--------------------------------------------------------------------------
// v2.0.0 STORAGE ADDITION
/// @notice External contract that orchestrates fees across the spot protocol.
IFeePolicy public feePolicy;
/// @notice Reference to the address that has the ability to pause/unpause operations.
/// @dev The keeper is meant for time-sensitive operations, and may be different from the owner address.
/// @return The address of the keeper.
address public keeper;
//--------------------------------------------------------------------------
// The reserved liquidity is the subset of the vault's underlying tokens that it
// does not deploy for rolling over (or used for swaps) and simply holds.
// The existence of sufficient reserved liquidity ensures that
// a) The vault's TVL never goes too low and guards against the "share" manipulation attack.
// b) Not all of the vault's liquidity is locked up in tranches.
/// @notice The absolute amount of underlying tokens, reserved.
/// @custom:oz-upgrades-renamed-from minUnderlyingBal
uint256 public reservedUnderlyingBal;
/// @notice The percentage of the vault's "neutrally" subscribed TVL, reserved.
/// @dev A neutral subscription state implies the vault's TVL is exactly enough to
/// rollover over the entire supply of perp tokens.
/// NOTE: A neutral subscription ratio of 1.0 is distinct from a deviation ratio (dr) of 1.0.
/// For more details, refer to the fee policy documentation.
/// @custom:oz-upgrades-renamed-from minUnderlyingPerc
uint256 public reservedSubscriptionPerc;
//--------------------------------------------------------------------------
// Modifiers
/// @dev Throws if called by any account other than the keeper.
modifier onlyKeeper() {
if (msg.sender != keeper) {
revert UnauthorizedCall();
}
_;
}
//--------------------------------------------------------------------------
// Construction & Initialization
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/// @notice Contract state initialization.
/// @param name ERC-20 Name of the vault token.
/// @param symbol ERC-20 Symbol of the vault token.
/// @param perp_ ERC-20 address of the perpetual tranche rolled over.
/// @param feePolicy_ Address of the fee policy contract.
function init(
string memory name,
string memory symbol,
IPerpetualTranche perp_,
IFeePolicy feePolicy_
) external initializer {
// initialize dependencies
__ERC20_init(name, symbol);
__ERC20Burnable_init();
__Ownable_init();
__Pausable_init();
__ReentrancyGuard_init();
// setup underlying collateral
underlying = perp_.underlying();
// set reference to perp
perp = perp_;
// set the reference to the fee policy
updateFeePolicy(feePolicy_);
// set keeper reference
updateKeeper(owner());
// setting initial parameter values
minDeploymentAmt = 0;
reservedUnderlyingBal = 0;
reservedSubscriptionPerc = 0;
// sync underlying
_syncAsset(underlying);
}
//--------------------------------------------------------------------------
// Owner only methods
/// @notice Update the reference to the fee policy contract.
/// @param feePolicy_ New strategy address.
function updateFeePolicy(IFeePolicy feePolicy_) public onlyOwner {
if (feePolicy_.decimals() != PERC_DECIMALS) {
revert UnexpectedDecimals();
}
feePolicy = feePolicy_;
}
/// @notice Transfers a non-vault token out of the contract, which may have been added accidentally.
/// @param token The token address.
/// @param to The destination address.
/// @param amount The amount of tokens to be transferred.
function transferERC20(IERC20Upgradeable token, address to, uint256 amount) external onlyOwner nonReentrant {
if (isVaultAsset(token)) {
revert UnauthorizedTransferOut();
}
token.safeTransfer(to, amount);
}
/// @notice Updates the reference to the keeper.
/// @param keeper_ The address of the new keeper.
function updateKeeper(address keeper_) public onlyOwner {
keeper = keeper_;
}
//--------------------------------------------------------------------------
// Keeper only methods
/// @notice Pauses deposits, withdrawals and vault operations.
/// @dev NOTE: ERC-20 functions, like transfers will always remain operational.
function pause() external onlyKeeper {
_pause();
}
/// @notice Unpauses deposits, withdrawals and vault operations.
/// @dev NOTE: ERC-20 functions, like transfers will always remain operational.
function unpause() external onlyKeeper {
_unpause();
}
/// @notice Updates the minimum deployment amount requirement.
/// @param minDeploymentAmt_ The new minimum deployment amount, denominated in underlying tokens.
function updateMinDeploymentAmt(uint256 minDeploymentAmt_) external onlyKeeper {
minDeploymentAmt = minDeploymentAmt_;
}
/// @notice Updates absolute reserved underlying balance.
/// @param reservedUnderlyingBal_ The new reserved underlying balance.
function updateReservedUnderlyingBal(uint256 reservedUnderlyingBal_) external onlyKeeper {
reservedUnderlyingBal = reservedUnderlyingBal_;
}
/// @notice Updates the reserved subscription percentage.
/// @param reservedSubscriptionPerc_ The new reserved subscription percentage.
function updateReservedSubscriptionPerc(uint256 reservedSubscriptionPerc_) external onlyKeeper {
reservedSubscriptionPerc = reservedSubscriptionPerc_;
}
//--------------------------------------------------------------------------
// External & Public write methods
/// @inheritdoc IVault
/// @dev Simply batches the `recover` and `deploy` functions. Reverts if there are no funds to deploy.
function recoverAndRedeploy() external override {
recover();
deploy();
}
/// @inheritdoc IVault
/// @dev Its safer to call `recover` before `deploy` so the full available balance can be deployed.
/// The vault holds the reserved balance of underlying tokens and deploys the rest.
/// Reverts if no funds are rolled over or enforced deployment threshold is not reached.
function deploy() public override nonReentrant whenNotPaused {
IERC20Upgradeable underlying_ = underlying;
IPerpetualTranche perp_ = perp;
// We calculate the usable underlying balance.
uint256 underlyingBal = underlying_.balanceOf(address(this));
uint256 reservedBal = _totalReservedBalance(perp_.getTVL(), perp_.getDepositTrancheRatio());
uint256 usableBal = (underlyingBal > reservedBal) ? underlyingBal - reservedBal : 0;
// We ensure that at-least `minDeploymentAmt` amount of underlying tokens are deployed
// (i.e used productively for rollovers).
if (usableBal <= minDeploymentAmt) {
revert InsufficientDeployment();
}
// We tranche all the underlying held by the vault to create seniors and juniors
_tranche(perp_.getDepositBond(), underlying_, usableBal);
// Newly minted seniors are rolled into perp
if (!_rollover(perp_, underlying_)) {
revert InsufficientDeployment();
}
// sync underlying
_syncAsset(underlying);
}
/// @inheritdoc IVault
function recover() public override nonReentrant whenNotPaused {
// Redeem deployed tranches
uint8 deployedCount_ = uint8(_deployed.length());
if (deployedCount_ <= 0) {
return;
}
// execute redemption on each deployed asset
for (uint8 i = 0; i < deployedCount_; ++i) {
ITranche tranche = ITranche(_deployed.at(i));
uint256 trancheBalance = tranche.balanceOf(address(this));
// if the vault has no tranche balance,
// we continue to the next one.
if (trancheBalance <= 0) {
continue;
}
// get the parent bond
IBondController bond = IBondController(tranche.bond());
BondTranches memory bt = bond.getTranches();
// if bond has matured, redeem the tranche token
if (bond.secondsToMaturity() <= 0) {
// execute redemption
_execMatureTrancheRedemption(bond, tranche, trancheBalance);
}
// if not redeem using proportional balances
// redeems this tranche and it's siblings if the vault holds balances.
// NOTE: For gas optimization, we perform this operation only once
// i.e) when we encounter the most-senior tranche.
// We also skip if the tranche balance is too low as immature redemption will be a no-op.
else if (tranche == bt.tranches[0] && trancheBalance > TRANCHE_DUST_AMT) {
// execute redemption
_execImmatureTrancheRedemption(bond, bt);
}
}
// sync deployed tranches
// NOTE: We traverse the deployed set in the reverse order
// as deletions involve swapping the deleted element to the
// end of the set and removing the last element.
for (uint8 i = deployedCount_; i > 0; i--) {
_syncDeployedAsset(IERC20Upgradeable(_deployed.at(i - 1)));
}
// sync underlying
_syncAsset(underlying);
}
/// @inheritdoc IVault
function recover(IERC20Upgradeable token) public override nonReentrant whenNotPaused {
if (_deployed.contains(address(token))) {
_redeemTranche(ITranche(address(token)));
_syncAsset(underlying);
return;
}
IPerpetualTranche perp_ = perp;
if (address(token) == address(perp_)) {
// In case the vault holds perp tokens after swaps or if transferred in erroneously,
// anyone can execute this function to recover perps into tranches.
// This is not part of the regular recovery flow.
_meldPerps(perp_);
_syncAsset(perp_);
_syncAsset(underlying);
return;
}
revert UnexpectedAsset();
}
/// @inheritdoc IVault
function deposit(uint256 underlyingAmtIn) external override nonReentrant whenNotPaused returns (uint256) {
// Calculates the fee adjusted amount of notes minted when depositing `underlyingAmtIn` of underlying tokens.
// NOTE: This operation should precede any token transfers.
uint256 notes = computeMintAmt(underlyingAmtIn);
if (underlyingAmtIn <= 0 || notes <= 0) {
return 0;
}
// transfer user assets in
underlying.safeTransferFrom(msg.sender, address(this), underlyingAmtIn);
// mint notes
_mint(msg.sender, notes);
// sync underlying
_syncAsset(underlying);
return notes;
}
/// @inheritdoc IVault
function redeem(uint256 notes) public override nonReentrant whenNotPaused returns (TokenAmount[] memory) {
if (notes <= 0) {
return new TokenAmount[](0);
}
// Calculates the fee adjusted share of vault tokens to be redeemed
// NOTE: This operation should precede any token transfers.
TokenAmount[] memory redemptions = computeRedemptionAmts(notes);
// burn notes
_burn(msg.sender, notes);
// transfer assets out
uint8 redemptionsCount = uint8(redemptions.length);
for (uint8 i = 0; i < redemptionsCount; ++i) {
if (redemptions[i].amount == 0) {
continue;
}
// Transfer token share out
redemptions[i].token.safeTransfer(msg.sender, redemptions[i].amount);
// sync balances, wkt i=0 is the underlying and remaining are tranches
if (i == 0) {
_syncAsset(redemptions[i].token);
} else {
_syncDeployedAsset(redemptions[i].token);
}
}
return redemptions;
}
/// @inheritdoc IVault
function recoverAndRedeem(uint256 notes) external override returns (TokenAmount[] memory) {
recover();
return redeem(notes);
}
/// @inheritdoc IRolloverVault
/// @dev Callers should call `recover` before executing `swapUnderlyingForPerps` to maximize vault liquidity.
function swapUnderlyingForPerps(uint256 underlyingAmtIn) external nonReentrant whenNotPaused returns (uint256) {
// Calculates the fee adjusted perp amount to transfer to the user.
// NOTE: This operation should precede any token transfers.
IPerpetualTranche perp_ = perp;
IERC20Upgradeable underlying_ = underlying;
uint256 underlyingBalPre = underlying_.balanceOf(address(this));
(uint256 perpAmtOut, uint256 perpFeeAmtToBurn, SubscriptionParams memory s) = computeUnderlyingToPerpSwapAmt(
underlyingAmtIn
);
// Revert if insufficient tokens are swapped in or out
if (perpAmtOut <= 0 || underlyingAmtIn <= 0) {
revert UnacceptableSwap();
}
// transfer underlying in
underlying_.safeTransferFrom(msg.sender, address(this), underlyingAmtIn);
// tranche and mint perps as needed
_trancheAndMintPerps(perp_, underlying_, s.perpTVL, s.seniorTR, perpAmtOut + perpFeeAmtToBurn);
// Pay perp's fee share by burning some of the minted perps
if (perpFeeAmtToBurn > 0) {
IERC20Burnable(address(perp_)).burn(perpFeeAmtToBurn);
}
// transfer remaining perps out to the user
IERC20Upgradeable(address(perp_)).safeTransfer(msg.sender, perpAmtOut);
// NOTE: In case this operation mints slightly more perps than that are required for the swap,
// The vault continues to hold the perp dust until the subsequent `swapPerpsForUnderlying` or manual `recover(perp)`.
// We ensure that the vault's underlying token liquidity
// remains above the reserved level after swap.
uint256 underlyingBalPost = underlying_.balanceOf(address(this));
if (
(underlyingBalPost < underlyingBalPre) &&
(underlyingBalPost <= _totalReservedBalance((s.perpTVL + underlyingAmtIn), s.seniorTR))
) {
revert InsufficientLiquidity();
}
// sync underlying
_syncAsset(underlying_);
return perpAmtOut;
}
/// @inheritdoc IRolloverVault
function swapPerpsForUnderlying(uint256 perpAmtIn) external nonReentrant whenNotPaused returns (uint256) {
// Calculates the fee adjusted underlying amount to transfer to the user.
IPerpetualTranche perp_ = perp;
IERC20Upgradeable underlying_ = underlying;
uint256 underlyingBalPre = underlying_.balanceOf(address(this));
(uint256 underlyingAmtOut, uint256 perpFeeAmtToBurn, ) = computePerpToUnderlyingSwapAmt(perpAmtIn);
// Revert if insufficient tokens are swapped in or out
if (underlyingAmtOut <= 0 || perpAmtIn <= 0) {
revert UnacceptableSwap();
}
// transfer perps in
IERC20Upgradeable(perp_).safeTransferFrom(msg.sender, address(this), perpAmtIn);
// Pay perp's fee share by burning some of the transferred perps
if (perpFeeAmtToBurn > 0) {
IERC20Burnable(address(perp_)).burn(perpFeeAmtToBurn);
}
// Meld incoming perps
_meldPerps(perp_);
// transfer underlying out
underlying_.safeTransfer(msg.sender, underlyingAmtOut);
// Revert if swap reduces vault's available liquidity.
uint256 underlyingBalPost = underlying_.balanceOf(address(this));
if (underlyingBalPost < underlyingBalPre) {
revert InsufficientLiquidity();
}
// sync underlying
_syncAsset(underlying_);
return underlyingAmtOut;
}
//--------------------------------------------------------------------------
// External & Public compute methods
/// @inheritdoc IRolloverVault
function deviationRatio() external override nonReentrant returns (uint256) {
return feePolicy.computeDeviationRatio(_querySubscriptionState(perp));
}
/// @inheritdoc IRolloverVault
function computeUnderlyingToPerpSwapAmt(
uint256 underlyingAmtIn
) public returns (uint256, uint256, SubscriptionParams memory) {
IPerpetualTranche perp_ = perp;
// Compute equal value perps to swap out to the user
SubscriptionParams memory s = _querySubscriptionState(perp_);
uint256 perpAmtOut = underlyingAmtIn.mulDiv(perp_.totalSupply(), s.perpTVL);
//-----------------------------------------------------------------------------
// When user swaps underlying for vault's perps -> perps are minted by the vault
// We thus compute fees based on the post-mint subscription state.
uint256 perpFeePerc = feePolicy.computePerpMintFeePerc();
uint256 vaultFeePerc = feePolicy.computeUnderlyingToPerpVaultSwapFeePerc(
feePolicy.computeDeviationRatio(s),
feePolicy.computeDeviationRatio(
SubscriptionParams({ perpTVL: s.perpTVL + underlyingAmtIn, vaultTVL: s.vaultTVL, seniorTR: s.seniorTR })
)
);
//-----------------------------------------------------------------------------
// Calculate perp fee share to be paid by the vault
uint256 perpFeeAmtToBurn = perpAmtOut.mulDiv(perpFeePerc, ONE, MathUpgradeable.Rounding.Up);
// We deduct fees by transferring out fewer perp tokens
perpAmtOut = perpAmtOut.mulDiv(ONE - (perpFeePerc + vaultFeePerc), ONE);
return (perpAmtOut, perpFeeAmtToBurn, s);
}
/// @inheritdoc IRolloverVault
function computePerpToUnderlyingSwapAmt(
uint256 perpAmtIn
) public returns (uint256, uint256, SubscriptionParams memory) {
IPerpetualTranche perp_ = perp;
// Compute equal value underlying tokens to swap out
SubscriptionParams memory s = _querySubscriptionState(perp_);
uint256 underlyingAmtOut = perpAmtIn.mulDiv(s.perpTVL, perp_.totalSupply());
//-----------------------------------------------------------------------------
// When user swaps perps for vault's underlying -> perps are redeemed by the vault
// We thus compute fees based on the post-burn subscription state.
uint256 perpFeePerc = feePolicy.computePerpBurnFeePerc();
uint256 vaultFeePerc = feePolicy.computePerpToUnderlyingVaultSwapFeePerc(
feePolicy.computeDeviationRatio(s),
feePolicy.computeDeviationRatio(
SubscriptionParams({
perpTVL: s.perpTVL - underlyingAmtOut,
vaultTVL: s.vaultTVL,
seniorTR: s.seniorTR
})
)
);
//-----------------------------------------------------------------------------
// Calculate perp fee share to be paid by the vault
uint256 perpFeeAmtToBurn = perpAmtIn.mulDiv(perpFeePerc, ONE, MathUpgradeable.Rounding.Up);
// We deduct fees by transferring out fewer underlying tokens
underlyingAmtOut = underlyingAmtOut.mulDiv(ONE - (perpFeePerc + vaultFeePerc), ONE);
return (underlyingAmtOut, perpFeeAmtToBurn, s);
}
//--------------------------------------------------------------------------
// External & Public read methods
/// @inheritdoc IVault
function computeMintAmt(uint256 underlyingAmtIn) public view returns (uint256) {
//-----------------------------------------------------------------------------
uint256 feePerc = feePolicy.computeVaultMintFeePerc();
//-----------------------------------------------------------------------------
// Compute mint amt
uint256 noteSupply = totalSupply();
uint256 notes = (noteSupply > 0)
? noteSupply.mulDiv(underlyingAmtIn, getTVL())
: (underlyingAmtIn * INITIAL_RATE);
// The mint fees are settled by simply minting fewer vault notes.
notes = notes.mulDiv(ONE - feePerc, ONE);
return notes;
}
/// @inheritdoc IVault
function computeRedemptionAmts(uint256 noteAmtBurnt) public view returns (TokenAmount[] memory) {
uint256 noteSupply = totalSupply();
//-----------------------------------------------------------------------------
uint256 feePerc = feePolicy.computeVaultBurnFeePerc();
//-----------------------------------------------------------------------------
uint8 assetCount_ = 1 + uint8(_deployed.length());
// aggregating vault assets to be redeemed
TokenAmount[] memory redemptions = new TokenAmount[](assetCount_);
// underlying share to be redeemed
IERC20Upgradeable underlying_ = underlying;
redemptions[0] = TokenAmount({
token: underlying_,
amount: underlying_.balanceOf(address(this)).mulDiv(noteAmtBurnt, noteSupply)
});
redemptions[0].amount = redemptions[0].amount.mulDiv(ONE - feePerc, ONE);
for (uint8 i = 1; i < assetCount_; ++i) {
// tranche token share to be redeemed
IERC20Upgradeable token = IERC20Upgradeable(_deployed.at(i - 1));
redemptions[i] = TokenAmount({
token: token,
amount: token.balanceOf(address(this)).mulDiv(noteAmtBurnt, noteSupply)
});
// deduct redemption fee
redemptions[i].amount = redemptions[i].amount.mulDiv(ONE - feePerc, ONE);
// in case the redemption amount is just dust, we skip
if (redemptions[i].amount < TRANCHE_DUST_AMT) {
redemptions[i].amount = 0;
}
}
return redemptions;
}
/// @inheritdoc IVault
/// @dev The total value is denominated in the underlying asset.
function getTVL() public view override returns (uint256) {
// The underlying balance
uint256 totalValue = underlying.balanceOf(address(this));
// The deployed asset value denominated in the underlying
uint8 deployedCount_ = uint8(_deployed.length());
for (uint8 i = 0; i < deployedCount_; ++i) {
ITranche tranche = ITranche(_deployed.at(i));
uint256 balance = tranche.balanceOf(address(this));
if (balance > TRANCHE_DUST_AMT) {
totalValue += _computeVaultTrancheValue(tranche, underlying, balance);
}
}
return totalValue;
}
/// @inheritdoc IVault
/// @dev The asset value is denominated in the underlying asset.
function getVaultAssetValue(IERC20Upgradeable token) external view override returns (uint256) {
uint256 balance = token.balanceOf(address(this));
// Underlying asset
if (token == underlying) {
return balance;
}
// Deployed asset
else if (_deployed.contains(address(token))) {
ITranche tranche = ITranche(address(token));
return (balance > TRANCHE_DUST_AMT) ? _computeVaultTrancheValue(tranche, underlying, balance) : 0;
}
// Not a vault asset, so returning zero
return 0;
}
/// @inheritdoc IVault
function assetCount() external view override returns (uint256) {
return _deployed.length() + 1;
}
/// @inheritdoc IVault
function assetAt(uint256 i) external view override returns (IERC20Upgradeable) {
if (i == 0) {
return underlying;
} else if (i <= _deployed.length()) {
return IERC20Upgradeable(_deployed.at(i - 1));
}
revert OutOfBounds();
}
/// @inheritdoc IVault
function vaultAssetBalance(IERC20Upgradeable token) external view override returns (uint256) {
return isVaultAsset(token) ? token.balanceOf(address(this)) : 0;
}
/// @inheritdoc IVault
function isVaultAsset(IERC20Upgradeable token) public view override returns (bool) {
return token == underlying || _deployed.contains(address(token));
}
//--------------------------------------------------------------------------
// Private write methods
/// @dev Redeems tranche tokens held by the vault, for underlying.
/// In the case of immature redemption, this method will recover other sibling tranches as well.
/// Performs some book-keeping to keep track of the vault's assets.
function _redeemTranche(ITranche tranche) private {
uint256 trancheBalance = tranche.balanceOf(address(this));
// if the vault has no tranche balance,
// we update our internal book-keeping and return.
if (trancheBalance <= 0) {
_syncDeployedAsset(tranche);
return;
}
// get the parent bond
IBondController bond = IBondController(tranche.bond());
// if bond has matured, redeem the tranche token
if (bond.secondsToMaturity() <= 0) {
// execute redemption
_execMatureTrancheRedemption(bond, tranche, trancheBalance);
// sync deployed asset
_syncDeployedAsset(tranche);
}
// if not redeem using proportional balances
// redeems this tranche and it's siblings if the vault holds balances.
// We skip if the tranche balance is too low as immature redemption will be a no-op.
else if (trancheBalance > TRANCHE_DUST_AMT) {
// execute redemption
BondTranches memory bt = bond.getTranches();
_execImmatureTrancheRedemption(bond, bt);
// sync deployed asset, i.e) current tranche and its sibling.
_syncDeployedAsset(bt.tranches[0]);
_syncDeployedAsset(bt.tranches[1]);
} else {
_syncDeployedAsset(tranche);
}
}
/// @dev Redeems perp tokens held by the vault for tranches and
/// melds them with existing tranches to redeem more underlying tokens.
/// Performs some book-keeping to keep track of the vault's assets.
function _meldPerps(IPerpetualTranche perp_) private {
uint256 perpBalance = perp_.balanceOf(address(this));
if (perpBalance <= 0) {
return;
}
TokenAmount[] memory tranchesRedeemed = perp_.redeem(perpBalance);
// sync and meld perp's tranches
uint8 tranchesRedeemedCount = uint8(tranchesRedeemed.length);
for (uint8 i = 1; i < tranchesRedeemedCount; ++i) {
ITranche tranche = ITranche(address(tranchesRedeemed[i].token));
// if possible, meld redeemed tranche with
// existing tranches to redeem underlying.
_redeemTranche(tranche);
}
}
/// @dev Tranches the vault's underlying to mint perps..
/// Performs some book-keeping to keep track of the vault's assets.
function _trancheAndMintPerps(
IPerpetualTranche perp_,
IERC20Upgradeable underlying_,
uint256 perpTVL,
uint256 seniorTR,
uint256 perpAmtToMint
) private {
// Tranche as needed
IBondController depositBond = perp_.getDepositBond();
ITranche trancheIntoPerp = perp_.getDepositTranche();
(uint256 underylingAmtToTranche, uint256 seniorAmtToDeposit) = PerpHelpers.estimateUnderlyingAmtToTranche(
PerpHelpers.MintEstimationParams({
perpTVL: perpTVL,
perpSupply: perp_.totalSupply(),
depositBondCollateralBalance: underlying_.balanceOf(address(depositBond)),
depositBondTotalDebt: depositBond.totalDebt(),
depositTrancheSupply: trancheIntoPerp.totalSupply(),
depositTrancheTR: seniorTR
}),
perpAmtToMint
);
_tranche(depositBond, underlying_, underylingAmtToTranche);
// Mint perps
_checkAndApproveMax(trancheIntoPerp, address(perp_), seniorAmtToDeposit);
perp_.deposit(trancheIntoPerp, seniorAmtToDeposit);
// sync holdings
_syncDeployedAsset(trancheIntoPerp);
}
/// @dev Given a bond and its tranche data, deposits the provided amount into the bond
/// and receives tranche tokens in return.
/// Performs some book-keeping to keep track of the vault's assets.
function _tranche(IBondController bond, IERC20Upgradeable underlying_, uint256 underlyingAmt) private {
// Get bond tranches
BondTranches memory bt = bond.getTranches();
// amount is tranched
_checkAndApproveMax(underlying_, address(bond), underlyingAmt);
bond.deposit(underlyingAmt);
// sync holdings
_syncDeployedAsset(bt.tranches[0]);
_syncDeployedAsset(bt.tranches[1]);
}
/// @dev Rolls over freshly tranched tokens from the given bond for older tranches (close to maturity) from perp.
/// Redeems intermediate tranches for underlying if possible.
/// Performs some book-keeping to keep track of the vault's assets.
/// @return Flag indicating if any tokens were rolled over.
function _rollover(IPerpetualTranche perp_, IERC20Upgradeable underlying_) private returns (bool) {
// NOTE: The first element of the list is the mature tranche,
// there after the list is NOT ordered by maturity.
IERC20Upgradeable[] memory rolloverTokens = perp_.getReserveTokensUpForRollover();
// Batch rollover
bool rollover = false;
// We query perp's current deposit tranche
ITranche trancheIntoPerp = perp_.getDepositTranche();
// Compute available tranche in to rollover
uint256 trancheInAmtAvailable = trancheIntoPerp.balanceOf(address(this));
// Approve once for all rollovers
_checkAndApproveMax(trancheIntoPerp, address(perp_), trancheInAmtAvailable);
// We pair the senior tranche token held by the vault (from the deposit bond)
// with each of the perp's tokens available for rollovers and execute a rollover.
// We continue to rollover till either the vault's senior tranche balance is exhausted or
// there are no more tokens in perp available to be rolled-over.
uint8 rolloverTokensCount = uint8(rolloverTokens.length);
for (uint8 i = 0; (i < rolloverTokensCount && trancheInAmtAvailable > 0); ++i) {
// tokenOutOfPerp is the reserve token coming out of perp into the vault
IERC20Upgradeable tokenOutOfPerp = rolloverTokens[i];
// Perform rollover
RolloverData memory r = perp_.rollover(trancheIntoPerp, tokenOutOfPerp, trancheInAmtAvailable);
// no rollover occurred, skip updating balances
if (r.tokenOutAmt <= 0) {
continue;
}
// skip insertion into the deployed list the case of the mature tranche, ie underlying
if (rolloverTokens[i] != underlying_) {
// Clean up after rollover, merge seniors from perp
// with vault held juniors to recover more underlying.
_redeemTranche(ITranche(address(tokenOutOfPerp)));
}
// Calculate trancheIn available amount
trancheInAmtAvailable -= r.trancheInAmt;
// keep track if "at least" one rolled over operation occurred
rollover = true;
}
// Final cleanup, if there remain excess seniors we recover back to underlying.
_redeemTranche(trancheIntoPerp);
return (rollover);
}
/// @dev Low level method that redeems the given mature tranche for the underlying asset.
/// It interacts with the button-wood bond contract.
/// This function should NOT be called directly, use `recover()` or `_redeemTranche(tranche)`
/// which wrap this function with the internal book-keeping necessary,
/// to keep track of the vault's assets.
function _execMatureTrancheRedemption(IBondController bond, ITranche tranche, uint256 amount) private {
if (!bond.isMature()) {
bond.mature();
}
bond.redeemMature(address(tranche), amount);
}
/// @dev Low level method that redeems the given tranche for the underlying asset, before maturity.
/// If the vault holds sibling tranches with proportional balances, those will also get redeemed.
/// It interacts with the button-wood bond contract.
/// This function should NOT be called directly, use `recover()` or `recover(tranche)`
/// which wrap this function with the internal book-keeping necessary,
/// to keep track of the vault's assets.
function _execImmatureTrancheRedemption(IBondController bond, BondTranches memory bt) private {
uint256[] memory trancheAmts = bt.computeRedeemableTrancheAmounts(address(this));
// NOTE: It is guaranteed that if one tranche amount is zero, all amounts are zeros.
if (trancheAmts[0] > 0) {
bond.redeem(trancheAmts);
}
}
/// @dev Syncs balance and updates the deployed list based on the vault's token balance.
function _syncDeployedAsset(IERC20Upgradeable token) private {
uint256 balance = token.balanceOf(address(this));
emit AssetSynced(token, balance);
bool inVault = _deployed.contains(address(token));
if (balance > 0 && !inVault) {
// Inserts new token into the deployed assets list.
_deployed.add(address(token));
if (_deployed.length() > MAX_DEPLOYED_COUNT) {
revert DeployedCountOverLimit();
}
} else if (balance <= 0 && inVault) {
// Removes token into the deployed assets list.
_deployed.remove(address(token));
}
}
/// @dev Logs the token balance held by the vault.
function _syncAsset(IERC20Upgradeable token) private {
emit AssetSynced(token, token.balanceOf(address(this)));
}
/// @dev Checks if the spender has sufficient allowance. If not, approves the maximum possible amount.
function _checkAndApproveMax(IERC20Upgradeable token, address spender, uint256 amount) private {
uint256 allowance = token.allowance(address(this), spender);
if (allowance < amount) {
token.safeApprove(spender, type(uint256).max);
}
}
/// @dev Queries the current subscription state of the perp and vault systems.
function _querySubscriptionState(IPerpetualTranche perp_) private returns (SubscriptionParams memory) {
return
SubscriptionParams({
perpTVL: perp_.getTVL(),
vaultTVL: getTVL(),
seniorTR: perp_.getDepositTrancheRatio()
});
}
//--------------------------------------------------------------------------
// Private methods
/// @dev Computes the value of the given amount of tranche tokens, based on it's current CDR.
/// Value is denominated in the underlying collateral.
function _computeVaultTrancheValue(
ITranche tranche,
IERC20Upgradeable collateralToken,
uint256 trancheAmt
) private view returns (uint256) {
(uint256 trancheClaim, uint256 trancheSupply) = tranche.getTrancheCollateralization(collateralToken);
return trancheClaim.mulDiv(trancheAmt, trancheSupply, MathUpgradeable.Rounding.Up);
}
/// @dev Computes the balance of underlying tokens to NOT be used for any operation.
function _totalReservedBalance(uint256 perpTVL, uint256 seniorTR) private view returns (uint256) {
return
MathUpgradeable.max(
reservedUnderlyingBal,
perpTVL.mulDiv(TRANCHE_RATIO_GRANULARITY - seniorTR, seniorTR).mulDiv(reservedSubscriptionPerc, ONE)
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @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) (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.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.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/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 (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)
pragma solidity ^0.8.0;
import "../ERC20Upgradeable.sol";
import "../../../utils/ContextUpgradeable.sol";
import {Initializable} from "../../../proxy/utils/Initializable.sol";
/**
* @dev Extension of {ERC20} that allows token holders to destroy both their own
* tokens and those that they have an allowance for, in a way that can be
* recognized off-chain (via event analysis).
*/
abstract contract ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable {
function __ERC20Burnable_init() internal onlyInitializing {
}
function __ERC20Burnable_init_unchained() internal onlyInitializing {
}
/**
* @dev Destroys `amount` tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
/**
* @dev Destroys `amount` tokens from `account`, deducting from the caller's
* allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `amount`.
*/
function burnFrom(address account, uint256 amount) public virtual {
_spendAllowance(account, _msgSender(), amount);
_burn(account, amount);
}
/**
* @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 (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 (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.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
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSetUpgradeable {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import { ITranche } from "./ITranche.sol";
interface IBondController {
function collateralToken() external view returns (address);
function maturityDate() external view returns (uint256);
function creationDate() external view returns (uint256);
function totalDebt() external view returns (uint256);
function feeBps() external view returns (uint256);
function isMature() external view returns (bool);
function tranches(uint256 i) external view returns (ITranche token, uint256 ratio);
function trancheCount() external view returns (uint256 count);
function trancheTokenAddresses(ITranche token) external view returns (bool);
function deposit(uint256 amount) external;
function redeem(uint256[] memory amounts) external;
function mature() external;
function redeemMature(address tranche, uint256 amount) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
interface ITranche is IERC20Upgradeable {
function bond() external view returns (address);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
struct TokenAmount {
/// @notice The asset token redeemed.
IERC20Upgradeable token;
/// @notice The amount redeemed.
uint256 amount;
}
/// @notice The system subscription parameters.
struct SubscriptionParams {
/// @notice The current TVL of perp denominated in the underlying.
uint256 perpTVL;
/// @notice The current TVL of the vault denominated in the underlying.
uint256 vaultTVL;
/// @notice The tranche ratio of seniors accepted by perp.
uint256 seniorTR;
}
struct RolloverData {
/// @notice The amount of tokens rolled out.
uint256 tokenOutAmt;
/// @notice The amount of trancheIn tokens rolled in.
uint256 trancheInAmt;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import { IBondController } from "./buttonwood/IBondController.sol";
interface IBondIssuer {
/// @notice Event emitted when a new bond is issued by the issuer.
/// @param bond The newly issued bond.
event BondIssued(IBondController bond);
/// @notice Event emitted when a bond has matured.
/// @param bond The matured bond.
event BondMature(IBondController bond);
/// @notice The address of the underlying collateral token to be used for issued bonds.
/// @return Address of the collateral token.
function collateral() external view returns (address);
/// @notice Invokes `mature` on issued active bonds.
function matureActive() external;
/// @notice Issues a new bond if sufficient time has elapsed since the last issue.
function issue() external;
/// @notice Checks if a given bond has been issued by the issuer.
/// @param bond Address of the bond to check.
/// @return if the bond has been issued by the issuer.
function isInstance(IBondController bond) external view returns (bool);
/// @notice Fetches the most recently issued bond.
/// @return Address of the most recent bond.
function getLatestBond() external returns (IBondController);
/// @notice Returns the total number of bonds issued by this issuer.
/// @return Number of bonds.
function issuedCount() external view returns (uint256);
/// @notice The bond address from the issued list by index.
/// @param index The index of the bond in the issued list.
/// @return Address of the bond.
function issuedBondAt(uint256 index) external view returns (IBondController);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IERC20Burnable {
function burn(uint256 value) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import { SubscriptionParams } from "./CommonTypes.sol";
interface IFeePolicy {
/// @return The percentage of the mint perp tokens to be charged as fees,
/// as a fixed-point number with {DECIMALS} decimal places.
function computePerpMintFeePerc() external view returns (uint256);
/// @return The percentage of the burnt perp tokens to be charged as fees,
/// as a fixed-point number with {DECIMALS} decimal places.
function computePerpBurnFeePerc() external view returns (uint256);
/// @param dr The current system deviation ratio.
/// @return The applied exchange rate adjustment between tranches into perp and
/// tokens out of perp during a rollover,
/// as a fixed-point number with {DECIMALS} decimal places.
/// @dev - A fee of 0%, implies the rollover exchange rate is unaltered.
/// example) 100 tranchesIn for 100 tranchesOut
/// - A fee of 1%, implies the exchange rate is adjusted in favor of tranchesIn.
/// example) 100 tranchesIn for 99 tranchesOut; i.e) perp enrichment
/// - A fee of -1%, implies the exchange rate is adjusted in favor of tranchesOut.
/// example) 99 tranchesIn for 100 tranchesOut
function computePerpRolloverFeePerc(uint256 dr) external view returns (int256);
/// @return The percentage of the mint vault note amount to be charged as fees,
/// as a fixed-point number with {DECIMALS} decimal places.
function computeVaultMintFeePerc() external view returns (uint256);
/// @return The percentage of the burnt vault note amount to be charged as fees,
/// as a fixed-point number with {DECIMALS} decimal places.
function computeVaultBurnFeePerc() external view returns (uint256);
/// @param dr The current system deviation ratio.
/// @param dr_ The deviation ratio of the system after the operation is complete.
/// @return The percentage of perp tokens out to be charged as swap fees by the vault,
/// as a fixed-point numbers with {DECIMALS} decimal places.
function computeUnderlyingToPerpVaultSwapFeePerc(uint256 dr, uint256 dr_) external view returns (uint256);
/// @param dr The current system deviation ratio.
/// @param dr_ The deviation ratio of the system after the operation is complete.
/// @return The percentage of underlying tokens out to be charged as swap fees by the vault,
/// as a fixed-point numbers with {DECIMALS} decimal places.
function computePerpToUnderlyingVaultSwapFeePerc(uint256 dr, uint256 dr_) external view returns (uint256);
/// @return Number of decimals representing a multiplier of 1.0. So, 100% = 1*10**decimals.
function decimals() external view returns (uint8);
/// @param s The subscription parameters of both the perp and vault systems.
/// @return The deviation ratio given the system subscription parameters.
function computeDeviationRatio(SubscriptionParams memory s) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { IBondIssuer } from "./IBondIssuer.sol";
import { IFeePolicy } from "./IFeePolicy.sol";
import { IBondController } from "./buttonwood/IBondController.sol";
import { ITranche } from "./buttonwood/ITranche.sol";
import { IRolloverVault } from "./IRolloverVault.sol";
import { TokenAmount, RolloverData } from "./CommonTypes.sol";
interface IPerpetualTranche is IERC20Upgradeable {
//--------------------------------------------------------------------------
// Events
/// @notice Event emitted the reserve's current token balance is recorded after change.
/// @param token Address of token.
/// @param balance The recorded ERC-20 balance of the token held by the reserve.
event ReserveSynced(IERC20Upgradeable token, uint256 balance);
/// @notice Event emitted when the active deposit bond is updated.
/// @param bond Address of the new deposit bond.
event UpdatedDepositBond(IBondController bond);
//--------------------------------------------------------------------------
// Methods
/// @notice Deposits tranche tokens into the system and mint perp tokens.
/// @param trancheIn The address of the tranche token to be deposited.
/// @param trancheInAmt The amount of tranche tokens deposited.
/// @return The amount of perp tokens minted.
function deposit(ITranche trancheIn, uint256 trancheInAmt) external returns (uint256);
/// @notice Burn perp tokens and redeem the share of reserve assets.
/// @param perpAmtBurnt The amount of perp tokens burnt from the caller.
/// @return tokensOut The list of reserve tokens and amounts redeemed.
function redeem(uint256 perpAmtBurnt) external returns (TokenAmount[] memory tokensOut);
/// @notice Rotates newer tranches in for reserve tokens.
/// @param trancheIn The tranche token deposited.
/// @param tokenOut The reserve token to be redeemed.
/// @param trancheInAmt The amount of trancheIn tokens deposited.
/// @return r The rollover amounts in various denominations.
function rollover(
ITranche trancheIn,
IERC20Upgradeable tokenOut,
uint256 trancheInAmt
) external returns (RolloverData memory r);
/// @notice External contract that stores a predefined bond config and frequency,
/// and issues new bonds when poked.
/// @return The address of the bond issuer.
function bondIssuer() external view returns (IBondIssuer);
/// @notice Reference to the address that has the ability to pause/unpause operations.
/// @return The address of the keeper.
function keeper() external view returns (address);
/// @notice The address of the underlying rebasing ERC-20 collateral token backing the tranches.
/// @return Address of the underlying collateral token.
function underlying() external view returns (IERC20Upgradeable);
/// @return Address of perp's rollover vault.
function vault() external view returns (IRolloverVault);
/// @notice The parent bond whose tranches are currently accepted to mint perp tokens.
/// @return Address of the deposit bond.
function getDepositBond() external returns (IBondController);
/// @notice The tranche token contract currently accepted to mint perp tokens.
/// @return Address of the deposit tranche ERC-20 token.
function getDepositTranche() external returns (ITranche);
/// @return The tranche ratio of the current deposit tranche.
function getDepositTrancheRatio() external returns (uint256);
/// @notice The policy contract with the fee computation logic for the perp and vault systems.
/// @return Address of the policy contract.
function feePolicy() external view returns (IFeePolicy);
/// @notice Total count of tokens held in the reserve.
/// @return The reserve token count.
function getReserveCount() external returns (uint256);
/// @notice The token address from the reserve list by index.
/// @param index The index of a token.
/// @return The reserve token address.
function getReserveAt(uint256 index) external returns (IERC20Upgradeable);
/// @notice Checks if the given token is part of the reserve.
/// @param token The address of a token to check.
/// @return If the token is part of the reserve.
function inReserve(IERC20Upgradeable token) external returns (bool);
/// @notice Fetches the reserve's token balance.
/// @param token The address of the tranche token held by the reserve.
/// @return The ERC-20 balance of the reserve token.
function getReserveTokenBalance(IERC20Upgradeable token) external returns (uint256);
/// @notice Calculates the reserve's token value,
/// in a standard denomination as defined by the implementation.
/// @param token The address of the tranche token held by the reserve.
/// @return The value of the reserve token balance held by the reserve, in a standard denomination.
function getReserveTokenValue(IERC20Upgradeable token) external returns (uint256);
/// @notice Computes the total value of assets currently held in the reserve.
/// @return The total value of the perp system, in a standard denomination.
function getTVL() external returns (uint256);
/// @notice Fetches the list of reserve tokens which are up for rollover.
/// @return The list of reserve tokens up for rollover.
function getReserveTokensUpForRollover() external returns (IERC20Upgradeable[] memory);
/// @notice Computes the amount of perp tokens minted when `trancheInAmt` `trancheIn` tokens
/// are deposited into the system.
/// @param trancheIn The tranche token deposited.
/// @param trancheInAmt The amount of tranche tokens deposited.
/// @return The amount of perp tokens to be minted.
function computeMintAmt(ITranche trancheIn, uint256 trancheInAmt) external returns (uint256);
/// @notice Computes the amount reserve tokens redeemed when burning given number of perp tokens.
/// @param perpAmtBurnt The amount of perp tokens to be burnt.
/// @return tokensOut The list of reserve tokens and amounts redeemed.
function computeRedemptionAmts(uint256 perpAmtBurnt) external returns (TokenAmount[] memory tokensOut);
/// @notice Computes the amount reserve tokens that are rolled out for the given number
/// of `trancheIn` tokens rolled in.
/// @param trancheIn The tranche token rolled in.
/// @param tokenOut The reserve token to be rolled out.
/// @param trancheInAmtAvailable The amount of trancheIn tokens rolled in.
/// @return r The rollover amounts in various denominations.
function computeRolloverAmt(
ITranche trancheIn,
IERC20Upgradeable tokenOut,
uint256 trancheInAmtAvailable
) external returns (RolloverData memory r);
/// @notice Updates time dependent storage state.
function updateState() external;
/// @return The system's current deviation ratio.
function deviationRatio() external returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import { IVault } from "./IVault.sol";
import { SubscriptionParams } from "./CommonTypes.sol";
interface IRolloverVault is IVault {
/// @notice Allows users to swap their underlying tokens for perps held by the vault.
/// @param underlyingAmtIn The amount of underlying tokens swapped in.
/// @return The amount of perp tokens swapped out.
function swapUnderlyingForPerps(uint256 underlyingAmtIn) external returns (uint256);
/// @notice Allows users to swap their perp tokens for underlying tokens held by the vault.
/// @param perpAmtIn The amount of perp tokens swapped in.
/// @return The amount of underlying tokens swapped out.
function swapPerpsForUnderlying(uint256 perpAmtIn) external returns (uint256);
/// @notice Computes the amount of perp tokens that are returned when user swaps a given number of underlying tokens.
/// @param underlyingAmtIn The number of underlying tokens the user swaps in.
/// @return perpAmtOut The number of perp tokens returned to the user.
/// @return perpFeeAmtToBurn The amount of perp tokens to be paid to the perp contract as mint fees.
/// @return s The pre-swap perp and vault subscription state.
function computeUnderlyingToPerpSwapAmt(
uint256 underlyingAmtIn
) external returns (uint256, uint256, SubscriptionParams memory);
/// @notice Computes the amount of underlying tokens that are returned when user swaps a given number of perp tokens.
/// @param perpAmtIn The number of perp tokens the user swaps in.
/// @return underlyingAmtOut The number of underlying tokens returned to the user.
/// @return perpFeeAmtToBurn The amount of perp tokens to be paid to the perp contract as burn fees.
/// @return s The pre-swap perp and vault subscription state.
function computePerpToUnderlyingSwapAmt(
uint256 perpAmtIn
) external returns (uint256, uint256, SubscriptionParams memory);
/// @return The system's current deviation ratio.
function deviationRatio() external returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { TokenAmount } from "./CommonTypes.sol";
/*
* @title IVault
*
* @notice The standard interface for a generic vault as described by the "Vault Framework".
* http://thinking.farm/essays/2022-10-05-mechanical-finance/
*
* Users deposit a "underlying" asset and mint "notes" (or vault shares).
* The vault "deploys" underlying asset in a rules-based fashion (through a hard-coded strategy).
* It "recovers" deployed assets once the investment matures.
*
* The vault operates through two external poke functions which off-chain keepers can execute.
* 1) `deploy`: When executed, the vault "puts to work" the underlying assets it holds. The vault
* usually returns other ERC-20 tokens which act as receipts of the deployment.
* 2) `recover`: When executed, the vault turns in the receipts and retrieves the underlying asset and
* usually collects some yield for this work.
*
* The rules of the deployment and recovery are specific to the vault strategy.
*
* At any time the vault will hold multiple ERC20 tokens, together referred to as the vault's "assets".
* They can be a combination of the underlying asset and the deployed assets (receipts).
*
* On redemption users burn their "notes" to receive a proportional slice of all the vault's assets.
*
*/
interface IVault is IERC20Upgradeable {
/// @notice Recovers deployed funds and redeploys them.
function recoverAndRedeploy() external;
/// @notice Deploys deposited funds.
function deploy() external;
/// @notice Recovers deployed funds.
function recover() external;
/// @notice Recovers a given deployed asset.
/// @param token The ERC-20 token address of the deployed asset.
function recover(IERC20Upgradeable token) external;
/// @notice Deposits the underlying asset from {msg.sender} into the vault and mints notes.
/// @param amount The amount tokens to be deposited into the vault.
/// @return The amount of notes.
function deposit(uint256 amount) external returns (uint256);
/// @notice Burns notes and sends a proportional share of vault's assets back to {msg.sender}.
/// @param notes The amount of notes to be burnt.
/// @return The list of asset tokens and amounts redeemed.
function redeem(uint256 notes) external returns (TokenAmount[] memory);
/// @notice Batches the recover and redeem functions.
/// @param notes The amount of notes to be burnt.
/// @return The list of asset tokens and amounts redeemed.
function recoverAndRedeem(uint256 notes) external returns (TokenAmount[] memory);
/// @return The total value of assets currently held by the vault, denominated in a standard unit of account.
function getTVL() external view returns (uint256);
/// @param token The address of the asset ERC-20 token held by the vault.
/// @return The vault's asset token value, denominated in a standard unit of account.
function getVaultAssetValue(IERC20Upgradeable token) external view returns (uint256);
/// @notice The ERC20 token that can be deposited into this vault.
function underlying() external view returns (IERC20Upgradeable);
/// @return Total count of ERC-20 tokens held by the vault.
function assetCount() external view returns (uint256);
/// @param i The index of a token.
/// @return The vault's asset token address by index.
function assetAt(uint256 i) external view returns (IERC20Upgradeable);
/// @param token The address of the asset ERC-20 token held by the vault.
/// @return The vault's asset token balance.
function vaultAssetBalance(IERC20Upgradeable token) external view returns (uint256);
/// @param token The address of a token to check.
/// @return If the given token is held by the vault.
function isVaultAsset(IERC20Upgradeable token) external view returns (bool);
/// @notice Computes the amount of notes minted when given amount of underlying asset tokens
/// are deposited into the system.
/// @param amount The amount tokens to be deposited into the vault.
/// @return The amount of notes to be minted.
function computeMintAmt(uint256 amount) external returns (uint256);
/// @notice Computes the amount of asset tokens redeemed when burning given number of vault notes.
/// @param notes The amount of notes to be burnt.
/// @return The list of asset tokens and amounts redeemed.
function computeRedemptionAmts(uint256 notes) external returns (TokenAmount[] memory);
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.20; //------------------------------------------------------------------------- // Generic /// @notice Expected contract call to be triggered by authorized caller. error UnauthorizedCall(); /// @notice Expected transfer out asset to not be a reserve asset. error UnauthorizedTransferOut(); /// @notice Expected contract reference to not be `address(0)`. error UnacceptableReference(); /// @notice Expected interface contract to return a fixed point with a different number of decimals. error UnexpectedDecimals(); /// @notice Expected asset to be a valid reserve/vault asset. error UnexpectedAsset(); /// @notice Expected to mint a non-zero amount of notes. error UnacceptableDeposit(); /// @notice Expected to redeem a non-zero amount of notes. error UnacceptableRedemption(); /// @notice Updated parameters violate defined constraints. error UnacceptableParams(); /// @notice Storage array access out of bounds. error OutOfBounds(); /// @notice Expected the number of reserve assets to be under the limit. error ReserveCountOverLimit(); //------------------------------------------------------------------------- // Perp /// @notice Expected rollover to be acceptable. error UnacceptableRollover(); /// @notice Expected supply to be lower than the defined max supply. error ExceededMaxSupply(); /// @notice Expected the total mint amount per tranche to be lower than the limit. error ExceededMaxMintPerTranche(); //------------------------------------------------------------------------- // Vault /// @notice Expected more underlying token liquidity to perform operation. error InsufficientLiquidity(); /// @notice Expected to swap non-zero assets. error UnacceptableSwap(); /// @notice Expected more assets to be deployed. error InsufficientDeployment(); /// @notice Expected the number of vault assets deployed to be under the limit. error DeployedCountOverLimit(); /// @notice Expected parent bond to have only 2 children tranches. error UnacceptableTrancheLength(); //------------------------------------------------------------------------- // Fee Policy /// @notice Expected perc value to be at most (1 * 10**DECIMALS), i.e) 1.0 or 100%. error InvalidPerc(); /// @notice Expected target subscription ratio to be within defined bounds. error InvalidTargetSRBounds(); /// @notice Expected deviation ratio bounds to be valid. error InvalidDRBounds(); /// @notice Expected sigmoid asymptotes to be within defined bounds. error InvalidSigmoidAsymptotes();
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { IBondController } from "../_interfaces/buttonwood/IBondController.sol";
import { ITranche } from "../_interfaces/buttonwood/ITranche.sol";
import { TokenAmount } from "../_interfaces/CommonTypes.sol";
import { UnacceptableDeposit, UnacceptableTrancheLength } from "../_interfaces/ProtocolErrors.sol";
import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";
import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import { BondTranches } from "./BondTranchesHelpers.sol";
/**
* @title BondHelpers
*
* @notice Library with helper functions for ButtonWood's Bond contract.
*
*/
library BondHelpers {
using SafeCastUpgradeable for uint256;
using MathUpgradeable for uint256;
// Replicating value used here:
// https://github.com/buttonwood-protocol/tranche/blob/main/contracts/BondController.sol
uint256 private constant TRANCHE_RATIO_GRANULARITY = 1000;
/// @notice Given a bond, calculates the time remaining to maturity.
/// @param b The address of the bond contract.
/// @return The number of seconds before the bond reaches maturity.
function secondsToMaturity(IBondController b) internal view returns (uint256) {
uint256 maturityDate = b.maturityDate();
return maturityDate > block.timestamp ? maturityDate - block.timestamp : 0;
}
/// @notice Given a bond, retrieves all of the bond's tranches.
/// @param b The address of the bond contract.
/// @return bt The bond's tranche data.
function getTranches(IBondController b) internal view returns (BondTranches memory bt) {
if (b.trancheCount() != 2) {
revert UnacceptableTrancheLength();
}
(bt.tranches[0], bt.trancheRatios[0]) = b.tranches(0);
(bt.tranches[1], bt.trancheRatios[1]) = b.tranches(1);
}
/// @notice Given a bond, returns the tranche at the specified index.
/// @param b The address of the bond contract.
/// @param i Index of the tranche.
/// @return t The tranche address.
function trancheAt(IBondController b, uint8 i) internal view returns (ITranche t) {
(t, ) = b.tranches(i);
}
/// @notice Given a bond, returns the address of the most senior tranche.
/// @param b The address of the bond contract.
/// @return t The senior tranche address.
function getSeniorTranche(IBondController b) internal view returns (ITranche t) {
(t, ) = b.tranches(0);
}
/// @notice Given a bond, returns the tranche ratio of the most senior tranche.
/// @param b The address of the bond contract.
/// @return r The tranche ratio of the senior most tranche.
function getSeniorTrancheRatio(IBondController b) internal view returns (uint256 r) {
(, r) = b.tranches(0);
}
/// @notice Helper function to estimate the amount of tranches minted when a given amount of collateral
/// is deposited into the bond.
/// @dev This function is used off-chain services (using callStatic) to preview tranches minted.
/// This function assumes that the no fees are withheld for tranching.
/// @param b The address of the bond contract.
/// @return The tranche data, an array of tranche amounts.
function previewDeposit(IBondController b, uint256 collateralAmount) internal view returns (TokenAmount[] memory) {
if (b.isMature()) {
revert UnacceptableDeposit();
}
BondTranches memory bt = getTranches(b);
TokenAmount[] memory tranchesOut = new TokenAmount[](2);
uint256 totalDebt = b.totalDebt();
uint256 collateralBalance = IERC20Upgradeable(b.collateralToken()).balanceOf(address(b));
uint256 seniorAmt = collateralAmount.mulDiv(bt.trancheRatios[0], TRANCHE_RATIO_GRANULARITY);
if (collateralBalance > 0) {
seniorAmt = seniorAmt.mulDiv(totalDebt, collateralBalance);
}
tranchesOut[0] = TokenAmount({ token: bt.tranches[0], amount: seniorAmt });
uint256 juniorAmt = collateralAmount.mulDiv(bt.trancheRatios[1], TRANCHE_RATIO_GRANULARITY);
if (collateralBalance > 0) {
juniorAmt = juniorAmt.mulDiv(totalDebt, collateralBalance);
}
tranchesOut[1] = TokenAmount({ token: bt.tranches[1], amount: juniorAmt });
return tranchesOut;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import { ITranche } from "../_interfaces/buttonwood/ITranche.sol";
import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
// @dev We assume that all bonds in the system just have 2 tranches, i.e) one senior and one junior.
struct BondTranches {
ITranche[2] tranches;
uint256[2] trancheRatios;
}
/**
* @title BondTranchesHelpers
*
* @notice Library with helper functions for the bond's retrieved tranche data.
*
*/
library BondTranchesHelpers {
using MathUpgradeable for uint256;
/// @notice For a given bond's tranche data and user address, computes the maximum number of each of the bond's tranches
/// the user is able to redeem before the bond's maturity. These tranche amounts necessarily match the bond's tranche ratios.
/// @param bt The bond's tranche data.
/// @param u The address to check balance for.
/// @return An array of tranche token balances.
function computeRedeemableTrancheAmounts(
BondTranches memory bt,
address u
) internal view returns (uint256[] memory) {
uint256[] memory trancheBalsAvailable = new uint256[](2);
trancheBalsAvailable[0] = bt.tranches[0].balanceOf(u);
trancheBalsAvailable[1] = bt.tranches[1].balanceOf(u);
return computeRedeemableTrancheAmounts(bt, trancheBalsAvailable);
}
/// @notice For a given bond's tranche data and tranche balances available, computes the maximum number of each of the bond's tranches
/// the user is able to redeem before the bond's maturity.
/// The returned tranche amounts necessarily match the bond's tranche ratios.
/// @param bt The bond's tranche data.
/// @param trancheBalsAvailable The tranche balance of each bond tranche available to be used for redemption.
/// @return An array of tranche token balances.
function computeRedeemableTrancheAmounts(
BondTranches memory bt,
uint256[] memory trancheBalsAvailable
) internal pure returns (uint256[] memory) {
uint256[] memory trancheAmtsReq = new uint256[](2);
// We compute the amount of seniors required using all the juniors
trancheAmtsReq[1] = trancheBalsAvailable[1] - (trancheBalsAvailable[1] % bt.trancheRatios[1]);
trancheAmtsReq[0] = (trancheAmtsReq[1] * bt.trancheRatios[0]) / bt.trancheRatios[1];
// If enough seniors aren't available, we compute the amount of juniors required using all the seniors
if (trancheAmtsReq[0] > trancheBalsAvailable[0]) {
trancheAmtsReq[0] = trancheBalsAvailable[0] - (trancheBalsAvailable[0] % bt.trancheRatios[0]);
trancheAmtsReq[1] = (trancheAmtsReq[0] * bt.trancheRatios[1]) / bt.trancheRatios[0];
}
return trancheAmtsReq;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import { IBondController } from "../_interfaces/buttonwood/IBondController.sol";
import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import { BondHelpers } from "./BondHelpers.sol";
/**
* @title PerpHelpers
*
* @notice Library with helper functions for the Perpetual tranche contract.
*
*/
library PerpHelpers {
using MathUpgradeable for uint256;
using BondHelpers for IBondController;
// Replicating value used here:
// https://github.com/buttonwood-protocol/tranche/blob/main/contracts/BondController.sol
uint256 private constant TRANCHE_RATIO_GRANULARITY = 1000;
/// @dev Input data required to estimate the amount of underlying required to mint perps.
struct MintEstimationParams {
/// @notice perpTVL The current TVL of perp.
uint256 perpTVL;
/// @notice perpSupply The total supply of perp tokens.
uint256 perpSupply;
/// @notice depositBondCollateralBalance The total collateral balance of perp's deposit bond.
uint256 depositBondCollateralBalance;
/// @notice depositBondTotalDebt The total debt of perp's deposit bond.
uint256 depositBondTotalDebt;
/// @notice depositTrancheSupply The total supply of perp's deposit tranche.
uint256 depositTrancheSupply;
/// @notice depositTrancheTR The tranche ratio of perp's deposit tranche.
uint256 depositTrancheTR;
}
/// @notice This function estimates the amount of underlying tokens that need to be tranched
/// in order to mint the given amount of perp tokens.
/// @dev If this function errs, it is guaranteed to err by overestimating, i.e) when you tranche the estimated amount
/// of underlying tokens, then and use the senior tranches to mint perps,
/// you might end up minting slightly more than `perpAmtToMint`.
/// @param p The estimation input parameters.
/// @param perpAmtToMint The required number of perp tokens to mint.
/// @return underylingAmtToTranche The number of underlying tokens to tranche.
/// @return seniorAmtToDeposit The number of minted seniors to then deposit into perp.
function estimateUnderlyingAmtToTranche(
MintEstimationParams memory p,
uint256 perpAmtToMint
) internal pure returns (uint256, uint256) {
// We assume that:
// - Perp's deposit tranche is the most senior tranche in the deposit bond.
// - The deposit bond is NOT mature.
// - No fees are withheld while tranching
// Math explanation:
//
// Given [Y] underlying tokens,
// We can create S seniors,
// S = Y * seniorRatio / bondCDR
// = Y * (depositTrancheTR/TRANCHE_RATIO_GRANULARITY) / (depositBondCollateralBalance/depositBondTotalDebt)
// = (Y * depositTrancheTR * depositBondTotalDebt) / (TRANCHE_RATIO_GRANULARITY * depositBondCollateralBalance)
//
// Given [S] senior tranche tokens,
// We can mint X perps,
// X = S * price(senior) / price(perp)
// X = S * (seniorClaim / seniorSupply) / (perpTVL / perpSupply)
// X = (S * seniorClaim * perpSupply) / (seniorSupply * perpTVL)
//
// Thus given X (perpAmtToMint), we calculate S (seniorAmtToDeposit) and Y (underlyingAmtToTranche)
//
// S = (X * perpTVL * seniorSupply) / (perpSupply * seniorClaim)
// = X * (perpTVL / perpSupply) * (seniorSupply / seniorClaim)
//
// Y = (S * depositBondCollateralBalance * TRANCHE_RATIO_GRANULARITY) / (depositBondTotalDebt * depositTrancheTR)
// = S * (depositBondCollateralBalance / depositBondTotalDebt) * (TRANCHE_RATIO_GRANULARITY / depositTrancheTR)
//
uint256 seniorAmtToDeposit = (p.perpSupply > 0)
? perpAmtToMint.mulDiv(p.perpTVL, p.perpSupply, MathUpgradeable.Rounding.Up)
: perpAmtToMint;
uint256 depositTrancheClaim = MathUpgradeable.min(p.depositTrancheSupply, p.depositBondCollateralBalance);
seniorAmtToDeposit = (p.depositTrancheSupply > 0)
? seniorAmtToDeposit.mulDiv(p.depositTrancheSupply, depositTrancheClaim, MathUpgradeable.Rounding.Up)
: seniorAmtToDeposit;
uint256 underlyingAmtToTranche = (p.depositBondTotalDebt > 0)
? seniorAmtToDeposit.mulDiv(
p.depositBondCollateralBalance,
p.depositBondTotalDebt,
MathUpgradeable.Rounding.Up
)
: seniorAmtToDeposit;
underlyingAmtToTranche = underlyingAmtToTranche.mulDiv(
TRANCHE_RATIO_GRANULARITY,
p.depositTrancheTR,
MathUpgradeable.Rounding.Up
);
return (underlyingAmtToTranche, seniorAmtToDeposit);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { IBondController } from "../_interfaces/buttonwood/IBondController.sol";
import { ITranche } from "../_interfaces/buttonwood/ITranche.sol";
import { UnacceptableTrancheLength } from "../_interfaces/ProtocolErrors.sol";
import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import { BondHelpers } from "./BondHelpers.sol";
/**
* @title TrancheHelpers
*
* @notice Library with helper functions for tranche tokens.
*
*/
library TrancheHelpers {
using BondHelpers for IBondController;
/// @notice Given a tranche, calculates the claimable collateral balance backing the tranche supply.
/// @param tranche Address of the tranche token.
/// @param collateralToken Address of the tranche's underlying collateral token.
/// @return The collateral balance and the tranche token supply.
function getTrancheCollateralization(
ITranche tranche,
IERC20Upgradeable collateralToken
) internal view returns (uint256, uint256) {
IBondController bond = IBondController(tranche.bond());
uint256 trancheSupply = tranche.totalSupply();
uint256 trancheClaim = 0;
// When the tranche's parent bond is mature
if (bond.isMature()) {
trancheClaim = collateralToken.balanceOf(address(tranche));
return (trancheClaim, trancheSupply);
}
// NOTE: This implementation assumes the bond has only two tranches.
if (bond.trancheCount() != 2) {
revert UnacceptableTrancheLength();
}
uint256 bondCollateralBalance = collateralToken.balanceOf(address(bond));
// For junior tranche
if (bond.trancheAt(1) == tranche) {
uint256 seniorSupply = bond.totalDebt() - trancheSupply;
uint256 seniorClaim = MathUpgradeable.min(seniorSupply, bondCollateralBalance);
trancheClaim = bondCollateralBalance - seniorClaim;
}
// For senior tranche
else {
// require(bond.trancheAt(0) == tranche);
trancheClaim = MathUpgradeable.min(trancheSupply, bondCollateralBalance);
}
return (trancheClaim, trancheSupply);
}
}{
"optimizer": {
"enabled": true,
"runs": 750
},
"evmVersion": "paris",
"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":"DeployedCountOverLimit","type":"error"},{"inputs":[],"name":"InsufficientDeployment","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"OutOfBounds","type":"error"},{"inputs":[],"name":"UnacceptableSwap","type":"error"},{"inputs":[],"name":"UnacceptableTrancheLength","type":"error"},{"inputs":[],"name":"UnauthorizedCall","type":"error"},{"inputs":[],"name":"UnauthorizedTransferOut","type":"error"},{"inputs":[],"name":"UnexpectedAsset","type":"error"},{"inputs":[],"name":"UnexpectedDecimals","type":"error"},{"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":false,"internalType":"contract IERC20Upgradeable","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"AssetSynced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"MAX_DEPLOYED_COUNT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERC_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANCHE_DUST_AMT","outputs":[{"internalType":"uint256","name":"","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":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"name":"assetAt","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlyingAmtIn","type":"uint256"}],"name":"computeMintAmt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpAmtIn","type":"uint256"}],"name":"computePerpToUnderlyingSwapAmt","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"components":[{"internalType":"uint256","name":"perpTVL","type":"uint256"},{"internalType":"uint256","name":"vaultTVL","type":"uint256"},{"internalType":"uint256","name":"seniorTR","type":"uint256"}],"internalType":"struct SubscriptionParams","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"noteAmtBurnt","type":"uint256"}],"name":"computeRedemptionAmts","outputs":[{"components":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlyingAmtIn","type":"uint256"}],"name":"computeUnderlyingToPerpSwapAmt","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"components":[{"internalType":"uint256","name":"perpTVL","type":"uint256"},{"internalType":"uint256","name":"vaultTVL","type":"uint256"},{"internalType":"uint256","name":"seniorTR","type":"uint256"}],"internalType":"struct SubscriptionParams","name":"","type":"tuple"}],"stateMutability":"nonpayable","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":"deploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlyingAmtIn","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deviationRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feePolicy","outputs":[{"internalType":"contract IFeePolicy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTVL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"}],"name":"getVaultAssetValue","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":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"contract IPerpetualTranche","name":"perp_","type":"address"},{"internalType":"contract IFeePolicy","name":"feePolicy_","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"}],"name":"isVaultAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDeploymentAmt","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":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"perp","outputs":[{"internalType":"contract IPerpetualTranche","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"}],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"notes","type":"uint256"}],"name":"recoverAndRedeem","outputs":[{"components":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverAndRedeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"notes","type":"uint256"}],"name":"redeem","outputs":[{"components":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reservedSubscriptionPerc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reservedUnderlyingBal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpAmtIn","type":"uint256"}],"name":"swapPerpsForUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlyingAmtIn","type":"uint256"}],"name":"swapUnderlyingForPerps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"contract IERC20Upgradeable","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferERC20","outputs":[],"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":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFeePolicy","name":"feePolicy_","type":"address"}],"name":"updateFeePolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"keeper_","type":"address"}],"name":"updateKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minDeploymentAmt_","type":"uint256"}],"name":"updateMinDeploymentAmt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reservedSubscriptionPerc_","type":"uint256"}],"name":"updateReservedSubscriptionPerc","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reservedUnderlyingBal_","type":"uint256"}],"name":"updateReservedUnderlyingBal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"}],"name":"vaultAssetBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615dd780620000f36000396000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c806379cc6790116101de578063b6b55f251161010f578063d5620d60116100ad578063e36894f91161007c578063e36894f914610757578063eafe7a741461076a578063ef98f88414610772578063f2fde38b1461078557600080fd5b8063d5620d60146106d8578063db006a75146106f8578063dd62ed3e1461070b578063e1a2209f1461074457600080fd5b8063c2ee3a08116100e9578063c2ee3a08146106ab578063cc03c2e3146106b3578063ce746024146106bd578063d1c8ac7e146106c557600080fd5b8063b6b55f2514610671578063bf5d221414610684578063bfa4c00c1461069757600080fd5b80639788b3021161017c578063a457c2d711610156578063a457c2d714610624578063a9059cbb14610637578063aa9239f51461064a578063aced16611461065d57600080fd5b80639788b302146105f657806397b3fcaa146106095780639db5dbe41461061157600080fd5b80638da5cb5b116101b85780638da5cb5b146105c057806393334d2e146105d157806395d89b41146105db57806397790217146105e357600080fd5b806379cc67901461059157806382589038146105a45780638456cb59146105b857600080fd5b80633f4ba83a116102b85780636f307dc311610256578063726176871161023057806372617687146105665780637375c5d61461056e57806375d5179f14610581578063775c300c1461058957600080fd5b80636f307dc31461050957806370a0823114610535578063715018a61461055e57600080fd5b80635c975abb116102925780635c975abb146104b657806362b232a4146104c157806369f6f92c146104d45780636df71ab3146104e757600080fd5b80633f4ba83a1461049157806342966c68146104995780634594cb32146104ac57600080fd5b80632ad537e311610325578063372feac8116102ff578063372feac814610459578063395093511461046c578063396978251461047f5780633f45e08f1461048757600080fd5b80632ad537e314610429578063313ce5671461043c5780633434dc4e1461045157600080fd5b80630e07f854116103615780630e07f854146103de57806318160ddd146103f15780631cd66a951461040357806323b872dd1461041657600080fd5b806306fdde0314610388578063095ea7b3146103a65780630cd865ec146103c9575b600080fd5b610390610798565b60405161039d9190615435565b60405180910390f35b6103b96103b436600461547d565b61082a565b604051901515815260200161039d565b6103dc6103d73660046154a9565b610844565b005b6103dc6103ec3660046155a6565b6108f6565b6035545b60405190815260200161039d565b6103f561041136600461562f565b610b1a565b6103b9610424366004615648565b610d25565b6103f56104373660046154a9565b610d4b565b60125b60405160ff909116815260200161039d565b6103f5610e25565b6103f561046736600461562f565b610ebf565b6103b961047a36600461547d565b610fb1565b61043f602f81565b6103f56101305481565b6103dc610ff0565b6103dc6104a736600461562f565b611026565b6103f56101355481565b60c95460ff166103b9565b6103b96104cf3660046154a9565b611030565b6103dc6104e23660046154a9565b611057565b6104fa6104f536600461562f565b61110a565b60405161039d93929190615689565b61012d5461051d906001600160a01b031681565b6040516001600160a01b03909116815260200161039d565b6103f56105433660046154a9565b6001600160a01b031660009081526033602052604090205490565b6103dc611438565b6103dc61144a565b6103f561057c3660046154a9565b61145a565b61043f600881565b6103dc6114d8565b6103dc61059f36600461547d565b611731565b6101325461051d906001600160a01b031681565b6103dc61174a565b6097546001600160a01b031661051d565b6103f56101345481565b61039061177e565b6103dc6105f13660046154a9565b61178d565b6103dc61060436600461562f565b6117b8565b6103f56117ea565b6103dc61061f366004615648565b61194b565b6103b961063236600461547d565b6119a5565b6103b961064536600461547d565b611a42565b61051d61065836600461562f565b611a50565b6101335461051d906001600160a01b031681565b6103f561067f36600461562f565b611aad565b6103dc61069236600461562f565b611b2b565b6101315461051d906001600160a01b031681565b6103f5611b5d565b6103f56298968081565b6103dc611b6c565b6103dc6106d336600461562f565b611d88565b6106eb6106e636600461562f565b611dba565b60405161039d91906156b8565b6106eb61070636600461562f565b611dc9565b6103f5610719366004615710565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b6104fa61075236600461562f565b611f58565b6103f561076536600461562f565b612230565b6103f5612476565b6106eb61078036600461562f565b612493565b6103dc6107933660046154a9565b61281f565b6060603680546107a790615749565b80601f01602080910402602001604051908101604052809291908181526020018280546107d390615749565b80156108205780601f106107f557610100808354040283529160200191610820565b820191906000526020600020905b81548152906001019060200180831161080357829003601f168201915b5050505050905090565b600033610838818585612895565b60019150505b92915050565b61084c6129b9565b610854612a12565b61086061012e82612a65565b156108895761086e81612a87565b61012d54610884906001600160a01b0316612be9565b6108e9565b610131546001600160a01b039081169082168190036108d0576108ab81612c9a565b6108b481612be9565b61012d546108ca906001600160a01b0316612be9565b506108e9565b604051632c88119960e11b815260040160405180910390fd5b6108f3600160fb55565b50565b600054610100900460ff16158080156109165750600054600160ff909116105b806109305750303b158015610930575060005460ff166001145b6109a75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b6000805460ff1916600117905580156109ca576000805461ff0019166101001790555b6109d48585612de1565b6109dc612e44565b6109e4612e9d565b6109ec612efe565b6109f4612f5f565b826001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a569190615783565b61012d80546001600160a01b03199081166001600160a01b03938416179091556101318054909116918516919091179055610a9082611057565b610aa56105f16097546001600160a01b031690565b60006101308190556101348190556101355561012d54610acd906001600160a01b0316612be9565b8015610b13576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6000610b246129b9565b610b2c612a12565b6101315461012d546040516370a0823160e01b81523060048201526001600160a01b03928316929091169060009082906370a0823190602401602060405180830381865afa158015610b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba691906157a0565b9050600080610bb487611f58565b509092509050811580610bc5575086155b15610be35760405163173825e960e21b815260040160405180910390fd5b610bf86001600160a01b03861633308a612fc0565b8015610c5957604051630852cd8d60e31b8152600481018290526001600160a01b038616906342966c6890602401600060405180830381600087803b158015610c4057600080fd5b505af1158015610c54573d6000803e3d6000fd5b505050505b610c6285612c9a565b610c766001600160a01b0385163384613040565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce191906157a0565b905083811015610d045760405163bb55fd2760e01b815260040160405180910390fd5b610d0d85612be9565b50909450505050505b610d20600160fb55565b919050565b600033610d33858285613070565b610d3e8585856130fc565b60019150505b9392505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a0823190602401602060405180830381865afa158015610d94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db891906157a0565b61012d549091506001600160a01b0390811690841603610dd85792915050565b610de461012e84612a65565b15610e1c5782629896808211610dfb576000610e14565b61012d54610e149082906001600160a01b0316846132a7565b949350505050565b50600092915050565b6000610e2f6129b9565b61013254610131546001600160a01b03918216916301356c8c91610e5391166132da565b6040518263ffffffff1660e01b8152600401610e6f91906157b9565b602060405180830381865afa158015610e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb091906157a0565b9050610ebc600160fb55565b90565b60008061013260009054906101000a90046001600160a01b03166001600160a01b03166346ebcf236040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3a91906157a0565b90506000610f4760355490565b90506000808211610f6457610f5f620f4240866157f0565b610f78565b610f7885610f706117ea565b8491906133eb565b9050610fa883610f8a6008600a6158eb565b610f9491906158fa565b610fa06008600a6158eb565b8391906133eb565b95945050505050565b3360008181526034602090815260408083206001600160a01b03871684529091528120549091906108389082908690610feb90879061590d565b612895565b610133546001600160a01b0316331461101c57604051637bf6a16f60e01b815260040160405180910390fd5b6110246134dd565b565b6108f3338261352f565b61012d546000906001600160a01b038381169116148061083e575061083e61012e83612a65565b61105f613663565b600860ff16816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c69190615920565b60ff16146110e75760405163c51d798560e01b815260040160405180910390fd5b61013280546001600160a01b0319166001600160a01b0392909216919091179055565b60008061113160405180606001604052806000815260200160008152602001600081525090565b610131546001600160a01b03166000611149826132da565b905060006111bc836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561118e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b291906157a0565b83518991906133eb565b9050600061013260009054906101000a90046001600160a01b03166001600160a01b0316630a98b70d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611214573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123891906157a0565b61013254604051624d5b2360e21b81529192506000916001600160a01b0390911690636978ed069082906301356c8c906112769089906004016157b9565b602060405180830381865afa158015611293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b791906157a0565b61013260009054906101000a90046001600160a01b03166001600160a01b03166301356c8c60405180606001604052808f8b600001516112f7919061590d565b81526020018a6020015181526020018a604001518152506040518263ffffffff1660e01b815260040161132a91906157b9565b602060405180830381865afa158015611347573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136b91906157a0565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401602060405180830381865afa1580156113ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d091906157a0565b905060006113ee836113e46008600a6158eb565b86919060016136bd565b90506114276113fd838561590d565b6114096008600a6158eb565b61141391906158fa565b61141f6008600a6158eb565b8691906133eb565b9a9099509397509295505050505050565b611440613663565b611024600061370e565b611452611b6c565b6110246114d8565b600061146582611030565b61147057600061083e565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156114b4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083e91906157a0565b6114e06129b9565b6114e8612a12565b61012d54610131546040516370a0823160e01b81523060048201526001600160a01b03928316929091169060009083906370a0823190602401602060405180830381865afa15801561153e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156291906157a0565b90506000611636836001600160a01b03166397b3fcaa6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156115a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115cd91906157a0565b846001600160a01b0316638b5393826040518163ffffffff1660e01b81526004016020604051808303816000875af115801561160d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163191906157a0565b613760565b90506000818311611648576000611652565b61165282846158fa565b90506101305481116116775760405163167bb86960e11b815260040160405180910390fd5b6116e5846001600160a01b0316638fb69c4b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156116ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116de9190615783565b868361379a565b6116ef8486613823565b61170c5760405163167bb86960e11b815260040160405180910390fd5b61012d54611722906001600160a01b0316612be9565b5050505050611024600160fb55565b61173c823383613070565b611746828261352f565b5050565b610133546001600160a01b0316331461177657604051637bf6a16f60e01b815260040160405180910390fd5b611024613abf565b6060603780546107a790615749565b611795613663565b61013380546001600160a01b0319166001600160a01b0392909216919091179055565b610133546001600160a01b031633146117e457604051637bf6a16f60e01b815260040160405180910390fd5b61013455565b61012d546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185c91906157a0565b9050600061186b61012e613afc565b905060005b8160ff168160ff16101561194357600061188f61012e60ff8416613b06565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156118d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fd91906157a0565b9050629896808111156119305761012d546119239083906001600160a01b0316836132a7565b61192d908661590d565b94505b50508061193c90615943565b9050611870565b509092915050565b611953613663565b61195b6129b9565b61196483611030565b15611982576040516328071e2f60e11b815260040160405180910390fd5b6119966001600160a01b0384168383613040565b6119a0600160fb55565b505050565b3360008181526034602090815260408083206001600160a01b038716845290915281205490919083811015611a2a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161099e565b611a378286868403612895565b506001949350505050565b6000336108388185856130fc565b600081600003611a6c57505061012d546001600160a01b031690565b611a7761012e613afc565b8211611a945761083e611a8b6001846158fa565b61012e90613b06565b604051632d0483c560e21b815260040160405180910390fd5b6000611ab76129b9565b611abf612a12565b6000611aca83610ebf565b9050821580611ad7575080155b15611ae6576000915050610d16565b61012d54611aff906001600160a01b0316333086612fc0565b611b093382613b12565b61012d54611b1f906001600160a01b0316612be9565b9050610d20600160fb55565b610133546001600160a01b03163314611b5757604051637bf6a16f60e01b815260040160405180910390fd5b61013055565b611b696008600a6158eb565b81565b611b746129b9565b611b7c612a12565b6000611b8961012e613afc565b905060008160ff1611611b9c5750611d7e565b60005b8160ff168160ff161015611d25576000611bbe61012e60ff8416613b06565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2c91906157a0565b905060008111611c3d575050611d15565b6000826001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ca19190615783565b90506000611cb7826001600160a01b0316613bd3565b90506000611ccd836001600160a01b0316613d66565b11611ce257611cdd828585613de5565b611d10565b8051516001600160a01b038581169116148015611d0157506298968083115b15611d1057611d108282613f07565b505050505b611d1e81615943565b9050611b9f565b50805b60ff811615611d6557611d53611d4e611d42600184615978565b61012e9060ff16613b06565b613f64565b80611d5d81615991565b915050611d28565b5061012d54611d7c906001600160a01b0316612be9565b505b611024600160fb55565b610133546001600160a01b03163314611db457604051637bf6a16f60e01b815260040160405180910390fd5b61013555565b6060611dc4611b6c565b61083e825b6060611dd36129b9565b611ddb612a12565b60008211611e28576040805160008082526020820190925290611e20565b6040805180820190915260008082526020820152815260200190600190039081611df95790505b509050610d16565b6000611e3383612493565b9050611e3f338461352f565b805160005b8160ff168160ff161015611f4b57828160ff1681518110611e6757611e67615962565b60200260200101516020015160000315611f3b57611ed933848360ff1681518110611e9457611e94615962565b602002602001015160200151858460ff1681518110611eb557611eb5615962565b6020026020010151600001516001600160a01b03166130409092919063ffffffff16565b8060ff16600003611f1257611f0d838260ff1681518110611efc57611efc615962565b602002602001015160000151612be9565b611f3b565b611f3b838260ff1681518110611f2a57611f2a615962565b602002602001015160000151613f64565b611f4481615943565b9050611e44565b5050600160fb5592915050565b600080611f7f60405180606001604052806000815260200160008152602001600081525090565b610131546001600160a01b03166000611f97826132da565b9050600061200d8260000151846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fe1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200591906157a0565b8991906133eb565b9050600061013260009054906101000a90046001600160a01b03166001600160a01b031663ca9cbcbe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612065573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208991906157a0565b61013254604051624d5b2360e21b81529192506000916001600160a01b039091169063bf39d3db9082906301356c8c906120c79089906004016157b9565b602060405180830381865afa1580156120e4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210891906157a0565b61013254604080516060810190915288516001600160a01b03909216916301356c8c91908190612139908b906158fa565b81526020018a6020015181526020018a604001518152506040518263ffffffff1660e01b815260040161216c91906157b9565b602060405180830381865afa158015612189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ad91906157a0565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401602060405180830381865afa1580156121ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221291906157a0565b905060006113ee836122266008600a6158eb565b8c919060016136bd565b600061223a6129b9565b612242612a12565b6101315461012d546040516370a0823160e01b81523060048201526001600160a01b03928316929091169060009082906370a0823190602401602060405180830381865afa158015612298573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122bc91906157a0565b905060008060006122cc8861110a565b919450925090508215806122de575087155b156122fc5760405163173825e960e21b815260040160405180910390fd5b6123116001600160a01b03861633308b612fc0565b612331868683600001518460400151868861232c919061590d565b61408c565b811561239257604051630852cd8d60e31b8152600481018390526001600160a01b038716906342966c6890602401600060405180830381600087803b15801561237957600080fd5b505af115801561238d573d6000803e3d6000fd5b505050505b6123a66001600160a01b0387163385613040565b6040516370a0823160e01b81523060048201526000906001600160a01b038716906370a0823190602401602060405180830381865afa1580156123ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241191906157a0565b9050848110801561243c575081516124389061242e908b9061590d565b8360400151613760565b8111155b1561245a5760405163bb55fd2760e01b815260040160405180910390fd5b61246386612be9565b509195505050505050610d20600160fb55565b600061248361012e613afc565b61248e90600161590d565b905090565b606060006124a060355490565b9050600061013260009054906101000a90046001600160a01b03166001600160a01b031663916b7ed76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061251c91906157a0565b9050600061252b61012e613afc565b6125369060016159ae565b905060008160ff1667ffffffffffffffff811115612556576125566154c6565b60405190808252806020026020018201604052801561259b57816020015b60408051808201909152600080825260208201528152602001906001900390816125745790505b5061012d546040805180820182526001600160a01b0390921680835290516370a0823160e01b815230600482015292935091602082019061262e908a90899086906370a08231906024015b602060405180830381865afa158015612603573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262791906157a0565b91906133eb565b8152508260008151811061264457612644615962565b60209081029190910101526126a38461265f6008600a6158eb565b61266991906158fa565b6126756008600a6158eb565b8460008151811061268857612688615962565b6020026020010151602001516133eb9092919063ffffffff16565b826000815181106126b6576126b6615962565b602090810291909101810151015260015b8360ff168160ff1610156128135760006126e5611d42600184615978565b6040805180820182526001600160a01b03831680825291516370a0823160e01b815230600482015292935091602083019161272c918d918c916370a08231906024016125e6565b815250848360ff168151811061274457612744615962565b602090810291909101015261278a8661275f6008600a6158eb565b61276991906158fa565b6127756008600a6158eb565b868560ff168151811061268857612688615962565b848360ff168151811061279f5761279f615962565b6020026020010151602001818152505062989680848360ff16815181106127c8576127c8615962565b6020026020010151602001511015612802576000848360ff16815181106127f1576127f1615962565b602002602001015160200181815250505b5061280c81615943565b90506126c7565b50909695505050505050565b612827613663565b6001600160a01b03811661288c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161099e565b6108f38161370e565b6001600160a01b0383166128f75760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161099e565b6001600160a01b0382166129585760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161099e565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600260fb5403612a0b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161099e565b600260fb55565b60c95460ff16156110245760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161099e565b6001600160a01b03811660009081526001830160205260408120541515610d44565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612ace573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af291906157a0565b905060008111612b055761174682613f64565b6000826001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b699190615783565b90506000612b7f826001600160a01b0316613d66565b11612b9857612b8f818484613de5565b6119a083613f64565b62989680821115612b8f576000612bb7826001600160a01b0316613bd3565b9050612bc38282613f07565b8051612bd69060005b6020020151613f64565b8051612be3906001612bcc565b50505050565b6040516370a0823160e01b81523060048201527f3498084e435368f22f5e58d4957c351579c10be5ab20874cc78c9d0e28fa04099082906001600160a01b038216906370a0823190602401602060405180830381865afa158015612c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7591906157a0565b604080516001600160a01b03909316835260208301919091520160405180910390a150565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612ce1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0591906157a0565b905060008111612d13575050565b60405163db006a7560e01b8152600481018290526000906001600160a01b0384169063db006a75906024016000604051808303816000875af1158015612d5d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d8591908101906159eb565b805190915060015b8160ff168160ff161015610b13576000838260ff1681518110612db257612db2615962565b6020026020010151600001519050612dc981612a87565b50612dd381615943565b9050612d8d565b600160fb55565b600054610100900460ff16612e3a5760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b61174682826143c5565b600054610100900460ff166110245760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b600054610100900460ff16612ef65760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b611024614437565b600054610100900460ff16612f575760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b611024614499565b600054610100900460ff16612fb85760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b6110246144fe565b6040516001600160a01b0380851660248301528316604482015260648101829052612be39085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152614557565b6040516001600160a01b0383166024820152604481018290526119a090849063a9059cbb60e01b90606401612ff4565b6001600160a01b038381166000908152603460209081526040808320938616835292905220546000198114612be357818110156130ef5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161099e565b612be38484848403612895565b6001600160a01b0383166131605760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161099e565b6001600160a01b0382166131c25760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161099e565b6001600160a01b0383166000908152603360205260409020548181101561323a5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161099e565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061329a9086815260200190565b60405180910390a3612be3565b600080806132be6001600160a01b0387168661463f565b90925090506132d082858360016136bd565b9695505050505050565b6132fe60405180606001604052806000815260200160008152602001600081525090565b6040518060600160405280836001600160a01b03166397b3fcaa6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015613349573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336d91906157a0565b815260200161337a6117ea565b8152602001836001600160a01b0316638b5393826040518163ffffffff1660e01b81526004016020604051808303816000875af11580156133bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e391906157a0565b905292915050565b60008080600019858709858702925082811083820303915050806000036134255783828161341b5761341b615aa4565b0492505050610d44565b8084116134745760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640161099e565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6134e56149b4565b60c9805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03821661358f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161099e565b6001600160a01b038216600090815260336020526040902054818110156136035760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161099e565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6097546001600160a01b031633146110245760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161099e565b6000806136cb8686866133eb565b905060018360028111156136e1576136e1615aba565b1480156136fe5750600084806136f9576136f9615aa4565b868809115b15610fa8576132d060018261590d565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000610d4461013454613795610135546008600a61377e91906158eb565b61262761378d886103e86158fa565b8990896133eb565b614a06565b60006137ae846001600160a01b0316613bd3565b90506137bb838584614a1c565b60405163b6b55f2560e01b8152600481018390526001600160a01b0385169063b6b55f2590602401600060405180830381600087803b1580156137fd57600080fd5b505af1158015613811573d6000803e3d6000fd5b50508251612bd6925090506000612bcc565b600080836001600160a01b031663364d22fc6040518163ffffffff1660e01b81526004016000604051808303816000875af1158015613866573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261388e9190810190615ad0565b9050600080856001600160a01b031663332d83d56040518163ffffffff1660e01b81526004016020604051808303816000875af11580156138d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138f79190615783565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015613941573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396591906157a0565b9050613972828883614a1c565b835160005b8160ff168160ff1610801561398c5750600083115b15613aa9576000868260ff16815181106139a8576139a8615962565b6020908102919091010151604051632bf8f1a560e01b81526001600160a01b0387811660048301528083166024830152604482018790529192506000918c1690632bf8f1a59060640160408051808303816000875af1158015613a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a339190615b5f565b8051909150613a43575050613a99565b896001600160a01b0316888460ff1681518110613a6257613a62615962565b60200260200101516001600160a01b031614613a8157613a8182612a87565b6020810151613a9090866158fa565b94506001965050505b613aa281615943565b9050613977565b50613ab383612a87565b50919695505050505050565b613ac7612a12565b60c9805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135123390565b600061083e825490565b6000610d448383614ab0565b6001600160a01b038216613b685760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161099e565b8060356000828254613b7a919061590d565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b613bdb6153ce565b816001600160a01b03166359eb82246040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3d91906157a0565b600214613c5d5760405163673f20ed60e11b815260040160405180910390fd5b6040516313612cb160e11b8152600060048201526001600160a01b038316906326c25962906024016040805180830381865afa158015613ca1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc59190615b91565b82516020840151600060200201919091526001600160a01b0391821690526040516313612cb160e11b815260016004820152908316906326c25962906024016040805180830381865afa158015613d20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d449190615b91565b82516020808501518101929092526001600160a01b0392909216910152919050565b600080826001600160a01b031663d59624b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613da7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dcb91906157a0565b9050428111613ddb576000610d44565b610d4442826158fa565b826001600160a01b031663ae4e7fdf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e479190615bbf565b613e9f57826001600160a01b03166387b652076040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613e8657600080fd5b505af1158015613e9a573d6000803e3d6000fd5b505050505b604051630cf4838d60e21b81526001600160a01b038381166004830152602482018390528416906333d20e34906044015b600060405180830381600087803b158015613eea57600080fd5b505af1158015613efe573d6000803e3d6000fd5b50505050505050565b6000613f138230614ada565b9050600081600081518110613f2a57613f2a615962565b602002602001015111156119a057604051637cd7d93560e11b81526001600160a01b0384169063f9afb26a90613ed0908490600401615be1565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015613fab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fcf91906157a0565b604080516001600160a01b0385168152602081018390529192507f3498084e435368f22f5e58d4957c351579c10be5ab20874cc78c9d0e28fa0409910160405180910390a1600061402261012e84612a65565b9050600082118015614032575080155b156140705761404361012e84614c28565b50602f61405161012e613afc565b11156119a057604051633d816dad60e01b815260040160405180910390fd5b8115801561407b5750805b156119a057612be361012e84614c3d565b6000856001600160a01b0316638fb69c4b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156140ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f29190615783565b90506000866001600160a01b031663332d83d56040518163ffffffff1660e01b81526004016020604051808303816000875af1158015614136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061415a9190615783565b90506000806143236040518060c001604052808981526020018b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156141b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141d591906157a0565b81526040516370a0823160e01b81526001600160a01b0388811660048301526020909201918c16906370a0823190602401602060405180830381865afa158015614223573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424791906157a0565b8152602001866001600160a01b031663fc7b9c186040518163ffffffff1660e01b8152600401602060405180830381865afa15801561428a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ae91906157a0565b8152602001856001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156142f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061431591906157a0565b815260200188905286614c52565b9150915061433284898461379a565b61433d838a83614a1c565b6040516311f9fbc960e21b81526001600160a01b038481166004830152602482018390528a16906347e7ef24906044016020604051808303816000875af115801561438c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143b091906157a0565b506143ba83613f64565b505050505050505050565b600054610100900460ff1661441e5760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b603661442a8382615c67565b5060376119a08282615c67565b600054610100900460ff166144905760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b6110243361370e565b600054610100900460ff166144f25760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b60c9805460ff19169055565b600054610100900460ff16612dda5760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b60006145ac826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614d0b9092919063ffffffff16565b90508051600014806145cd5750808060200190518101906145cd9190615bbf565b6119a05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161099e565b6000806000846001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614682573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146a69190615783565b90506000856001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156146e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061470c91906157a0565b90506000826001600160a01b031663ae4e7fdf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561474e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147729190615bbf565b156147ee576040516370a0823160e01b81526001600160a01b0388811660048301528716906370a0823190602401602060405180830381865afa1580156147bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147e191906157a0565b94509092506149ad915050565b826001600160a01b03166359eb82246040518163ffffffff1660e01b8152600401602060405180830381865afa15801561482c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061485091906157a0565b6002146148705760405163673f20ed60e11b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b038481166004830152600091908816906370a0823190602401602060405180830381865afa1580156148ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148de91906157a0565b90506001600160a01b03808916906148f99086166001614d1a565b6001600160a01b03160361499957600083856001600160a01b031663fc7b9c186040518163ffffffff1660e01b8152600401602060405180830381865afa158015614948573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496c91906157a0565b61497691906158fa565b905060006149848284614d8f565b905061499081846158fa565b935050506149a6565b6149a38382614d8f565b91505b5093509150505b9250929050565b60c95460ff166110245760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161099e565b6000818311614a155781610d44565b5090919050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015614a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a9091906157a0565b905081811015612be357612be36001600160a01b03851684600019614d9e565b6000826000018281548110614ac757614ac7615962565b9060005260206000200154905092915050565b60408051600280825260608083018452926000929190602083019080368337019050508451516040516370a0823160e01b81526001600160a01b0386811660048301529293509116906370a0823190602401602060405180830381865afa158015614b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b6d91906157a0565b81600081518110614b8057614b80615962565b60209081029190910101528351600160200201516040516370a0823160e01b81526001600160a01b038581166004830152909116906370a0823190602401602060405180830381865afa158015614bdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bff91906157a0565b81600181518110614c1257614c12615962565b602002602001018181525050610e148482614eba565b6000610d44836001600160a01b038416615113565b6000610d44836001600160a01b038416615162565b600080600080856020015111614c685783614c7c565b84516020860151614c7c91869160016136bd565b90506000614c9286608001518760400151614d8f565b90506000866080015111614ca65781614cb9565b6080860151614cb99083908360016136bd565b9150600080876060015111614cce5782614ce5565b60408701516060880151614ce591859160016136bd565b60a0880151909150614cfe9082906103e89060016136bd565b9792965091945050505050565b6060610e148484600085615255565b6040516313612cb160e11b815260ff821660048201526000906001600160a01b038416906326c25962906024016040805180830381865afa158015614d63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d879190615b91565b509392505050565b6000818310614a155781610d44565b801580614e185750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614df2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e1691906157a0565b155b614e8a5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606482015260840161099e565b6040516001600160a01b0383166024820152604481018290526119a090849063095ea7b360e01b90606401612ff4565b604080516002808252606080830184529260009291906020830190803683370190505060208501519091506001602002015183600181518110614eff57614eff615962565b6020026020010151614f119190615d27565b83600181518110614f2457614f24615962565b6020026020010151614f3691906158fa565b81600181518110614f4957614f49615962565b6020026020010181815250508360200151600160028110614f6c57614f6c615962565b60200201518460200151600060028110614f8857614f88615962565b602002015182600181518110614fa057614fa0615962565b6020026020010151614fb291906157f0565b614fbc9190615d3b565b81600081518110614fcf57614fcf615962565b60200260200101818152505082600081518110614fee57614fee615962565b60200260200101518160008151811061500957615009615962565b60200260200101511115610d44576020840151518351849060009061503057615030615962565b60200260200101516150429190615d27565b8360008151811061505557615055615962565b602002602001015161506791906158fa565b8160008151811061507a5761507a615962565b602002602001018181525050836020015160006002811061509d5761509d615962565b602002015184602001516001600281106150b9576150b9615962565b6020020151826000815181106150d1576150d1615962565b60200260200101516150e391906157f0565b6150ed9190615d3b565b8160018151811061510057615100615962565b6020026020010181815250509392505050565b600081815260018301602052604081205461515a5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561083e565b50600061083e565b6000818152600183016020526040812054801561524b5760006151866001836158fa565b855490915060009061519a906001906158fa565b90508181146151ff5760008660000182815481106151ba576151ba615962565b90600052602060002001549050808760000184815481106151dd576151dd615962565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061521057615210615d4f565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061083e565b600091505061083e565b6060824710156152b65760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161099e565b600080866001600160a01b031685876040516152d29190615d65565b60006040518083038185875af1925050503d806000811461530f576040519150601f19603f3d011682016040523d82523d6000602084013e615314565b606091505b509150915061532587838387615330565b979650505050505050565b6060831561539f578251600003615398576001600160a01b0385163b6153985760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161099e565b5081610e14565b610e1483838151156153b45781518083602001fd5b8060405162461bcd60e51b815260040161099e9190615435565b60405180604001604052806153e16153f3565b81526020016153ee6153f3565b905290565b60405180604001604052806002906020820280368337509192915050565b60005b8381101561542c578181015183820152602001615414565b50506000910152565b6020815260008251806020840152615454816040850160208701615411565b601f01601f19169190910160400192915050565b6001600160a01b03811681146108f357600080fd5b6000806040838503121561549057600080fd5b823561549b81615468565b946020939093013593505050565b6000602082840312156154bb57600080fd5b8135610d4481615468565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156154ff576154ff6154c6565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561552e5761552e6154c6565b604052919050565b600082601f83011261554757600080fd5b813567ffffffffffffffff811115615561576155616154c6565b615574601f8201601f1916602001615505565b81815284602083860101111561558957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156155bc57600080fd5b843567ffffffffffffffff808211156155d457600080fd5b6155e088838901615536565b955060208701359150808211156155f657600080fd5b5061560387828801615536565b935050604085013561561481615468565b9150606085013561562481615468565b939692955090935050565b60006020828403121561564157600080fd5b5035919050565b60008060006060848603121561565d57600080fd5b833561566881615468565b9250602084013561567881615468565b929592945050506040919091013590565b8381526020810183905260a08101610e1460408301848051825260208082015190830152604090810151910152565b602080825282518282018190526000919060409081850190868401855b8281101561570357815180516001600160a01b031685528601518685015292840192908501906001016156d5565b5091979650505050505050565b6000806040838503121561572357600080fd5b823561572e81615468565b9150602083013561573e81615468565b809150509250929050565b600181811c9082168061575d57607f821691505b60208210810361577d57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561579557600080fd5b8151610d4481615468565b6000602082840312156157b257600080fd5b5051919050565b8151815260208083015190820152604080830151908201526060810161083e565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761083e5761083e6157da565b600181815b80851115615842578160001904821115615828576158286157da565b8085161561583557918102915b93841c939080029061580c565b509250929050565b6000826158595750600161083e565b816158665750600061083e565b816001811461587c5760028114615886576158a2565b600191505061083e565b60ff841115615897576158976157da565b50506001821b61083e565b5060208310610133831016604e8410600b84101617156158c5575081810a61083e565b6158cf8383615807565b80600019048211156158e3576158e36157da565b029392505050565b6000610d4460ff84168361584a565b8181038181111561083e5761083e6157da565b8082018082111561083e5761083e6157da565b60006020828403121561593257600080fd5b815160ff81168114610d4457600080fd5b600060ff821660ff8103615959576159596157da565b60010192915050565b634e487b7160e01b600052603260045260246000fd5b60ff828116828216039081111561083e5761083e6157da565b600060ff8216806159a4576159a46157da565b6000190192915050565b60ff818116838216019081111561083e5761083e6157da565b600067ffffffffffffffff8211156159e1576159e16154c6565b5060051b60200190565b600060208083850312156159fe57600080fd5b825167ffffffffffffffff811115615a1557600080fd5b8301601f81018513615a2657600080fd5b8051615a39615a34826159c7565b615505565b81815260069190911b82018301908381019087831115615a5857600080fd5b928401925b828410156153255760408489031215615a765760008081fd5b615a7e6154dc565b8451615a8981615468565b81528486015186820152825260409093019290840190615a5d565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60006020808385031215615ae357600080fd5b825167ffffffffffffffff811115615afa57600080fd5b8301601f81018513615b0b57600080fd5b8051615b19615a34826159c7565b81815260059190911b82018301908381019087831115615b3857600080fd5b928401925b82841015615325578351615b5081615468565b82529284019290840190615b3d565b600060408284031215615b7157600080fd5b615b796154dc565b82518152602083015160208201528091505092915050565b60008060408385031215615ba457600080fd5b8251615baf81615468565b6020939093015192949293505050565b600060208284031215615bd157600080fd5b81518015158114610d4457600080fd5b6020808252825182820181905260009190848201906040850190845b8181101561281357835183529284019291840191600101615bfd565b601f8211156119a057600081815260208120601f850160051c81016020861015615c405750805b601f850160051c820191505b81811015615c5f57828155600101615c4c565b505050505050565b815167ffffffffffffffff811115615c8157615c816154c6565b615c9581615c8f8454615749565b84615c19565b602080601f831160018114615cca5760008415615cb25750858301515b600019600386901b1c1916600185901b178555615c5f565b600085815260208120601f198616915b82811015615cf957888601518255948401946001909101908401615cda565b5085821015615d175787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600082615d3657615d36615aa4565b500690565b600082615d4a57615d4a615aa4565b500490565b634e487b7160e01b600052603160045260246000fd5b60008251615d77818460208701615411565b919091019291505056fe496e697469616c697a61626c653a20636f6e7472616374206973206e6f742069a264697066735822122098818f5eb684f75b9516379b647beb45238544924052b77985ea7fc1fc56373764736f6c63430008140033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103835760003560e01c806379cc6790116101de578063b6b55f251161010f578063d5620d60116100ad578063e36894f91161007c578063e36894f914610757578063eafe7a741461076a578063ef98f88414610772578063f2fde38b1461078557600080fd5b8063d5620d60146106d8578063db006a75146106f8578063dd62ed3e1461070b578063e1a2209f1461074457600080fd5b8063c2ee3a08116100e9578063c2ee3a08146106ab578063cc03c2e3146106b3578063ce746024146106bd578063d1c8ac7e146106c557600080fd5b8063b6b55f2514610671578063bf5d221414610684578063bfa4c00c1461069757600080fd5b80639788b3021161017c578063a457c2d711610156578063a457c2d714610624578063a9059cbb14610637578063aa9239f51461064a578063aced16611461065d57600080fd5b80639788b302146105f657806397b3fcaa146106095780639db5dbe41461061157600080fd5b80638da5cb5b116101b85780638da5cb5b146105c057806393334d2e146105d157806395d89b41146105db57806397790217146105e357600080fd5b806379cc67901461059157806382589038146105a45780638456cb59146105b857600080fd5b80633f4ba83a116102b85780636f307dc311610256578063726176871161023057806372617687146105665780637375c5d61461056e57806375d5179f14610581578063775c300c1461058957600080fd5b80636f307dc31461050957806370a0823114610535578063715018a61461055e57600080fd5b80635c975abb116102925780635c975abb146104b657806362b232a4146104c157806369f6f92c146104d45780636df71ab3146104e757600080fd5b80633f4ba83a1461049157806342966c68146104995780634594cb32146104ac57600080fd5b80632ad537e311610325578063372feac8116102ff578063372feac814610459578063395093511461046c578063396978251461047f5780633f45e08f1461048757600080fd5b80632ad537e314610429578063313ce5671461043c5780633434dc4e1461045157600080fd5b80630e07f854116103615780630e07f854146103de57806318160ddd146103f15780631cd66a951461040357806323b872dd1461041657600080fd5b806306fdde0314610388578063095ea7b3146103a65780630cd865ec146103c9575b600080fd5b610390610798565b60405161039d9190615435565b60405180910390f35b6103b96103b436600461547d565b61082a565b604051901515815260200161039d565b6103dc6103d73660046154a9565b610844565b005b6103dc6103ec3660046155a6565b6108f6565b6035545b60405190815260200161039d565b6103f561041136600461562f565b610b1a565b6103b9610424366004615648565b610d25565b6103f56104373660046154a9565b610d4b565b60125b60405160ff909116815260200161039d565b6103f5610e25565b6103f561046736600461562f565b610ebf565b6103b961047a36600461547d565b610fb1565b61043f602f81565b6103f56101305481565b6103dc610ff0565b6103dc6104a736600461562f565b611026565b6103f56101355481565b60c95460ff166103b9565b6103b96104cf3660046154a9565b611030565b6103dc6104e23660046154a9565b611057565b6104fa6104f536600461562f565b61110a565b60405161039d93929190615689565b61012d5461051d906001600160a01b031681565b6040516001600160a01b03909116815260200161039d565b6103f56105433660046154a9565b6001600160a01b031660009081526033602052604090205490565b6103dc611438565b6103dc61144a565b6103f561057c3660046154a9565b61145a565b61043f600881565b6103dc6114d8565b6103dc61059f36600461547d565b611731565b6101325461051d906001600160a01b031681565b6103dc61174a565b6097546001600160a01b031661051d565b6103f56101345481565b61039061177e565b6103dc6105f13660046154a9565b61178d565b6103dc61060436600461562f565b6117b8565b6103f56117ea565b6103dc61061f366004615648565b61194b565b6103b961063236600461547d565b6119a5565b6103b961064536600461547d565b611a42565b61051d61065836600461562f565b611a50565b6101335461051d906001600160a01b031681565b6103f561067f36600461562f565b611aad565b6103dc61069236600461562f565b611b2b565b6101315461051d906001600160a01b031681565b6103f5611b5d565b6103f56298968081565b6103dc611b6c565b6103dc6106d336600461562f565b611d88565b6106eb6106e636600461562f565b611dba565b60405161039d91906156b8565b6106eb61070636600461562f565b611dc9565b6103f5610719366004615710565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b6104fa61075236600461562f565b611f58565b6103f561076536600461562f565b612230565b6103f5612476565b6106eb61078036600461562f565b612493565b6103dc6107933660046154a9565b61281f565b6060603680546107a790615749565b80601f01602080910402602001604051908101604052809291908181526020018280546107d390615749565b80156108205780601f106107f557610100808354040283529160200191610820565b820191906000526020600020905b81548152906001019060200180831161080357829003601f168201915b5050505050905090565b600033610838818585612895565b60019150505b92915050565b61084c6129b9565b610854612a12565b61086061012e82612a65565b156108895761086e81612a87565b61012d54610884906001600160a01b0316612be9565b6108e9565b610131546001600160a01b039081169082168190036108d0576108ab81612c9a565b6108b481612be9565b61012d546108ca906001600160a01b0316612be9565b506108e9565b604051632c88119960e11b815260040160405180910390fd5b6108f3600160fb55565b50565b600054610100900460ff16158080156109165750600054600160ff909116105b806109305750303b158015610930575060005460ff166001145b6109a75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b6000805460ff1916600117905580156109ca576000805461ff0019166101001790555b6109d48585612de1565b6109dc612e44565b6109e4612e9d565b6109ec612efe565b6109f4612f5f565b826001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a569190615783565b61012d80546001600160a01b03199081166001600160a01b03938416179091556101318054909116918516919091179055610a9082611057565b610aa56105f16097546001600160a01b031690565b60006101308190556101348190556101355561012d54610acd906001600160a01b0316612be9565b8015610b13576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b6000610b246129b9565b610b2c612a12565b6101315461012d546040516370a0823160e01b81523060048201526001600160a01b03928316929091169060009082906370a0823190602401602060405180830381865afa158015610b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba691906157a0565b9050600080610bb487611f58565b509092509050811580610bc5575086155b15610be35760405163173825e960e21b815260040160405180910390fd5b610bf86001600160a01b03861633308a612fc0565b8015610c5957604051630852cd8d60e31b8152600481018290526001600160a01b038616906342966c6890602401600060405180830381600087803b158015610c4057600080fd5b505af1158015610c54573d6000803e3d6000fd5b505050505b610c6285612c9a565b610c766001600160a01b0385163384613040565b6040516370a0823160e01b81523060048201526000906001600160a01b038616906370a0823190602401602060405180830381865afa158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce191906157a0565b905083811015610d045760405163bb55fd2760e01b815260040160405180910390fd5b610d0d85612be9565b50909450505050505b610d20600160fb55565b919050565b600033610d33858285613070565b610d3e8585856130fc565b60019150505b9392505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a0823190602401602060405180830381865afa158015610d94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db891906157a0565b61012d549091506001600160a01b0390811690841603610dd85792915050565b610de461012e84612a65565b15610e1c5782629896808211610dfb576000610e14565b61012d54610e149082906001600160a01b0316846132a7565b949350505050565b50600092915050565b6000610e2f6129b9565b61013254610131546001600160a01b03918216916301356c8c91610e5391166132da565b6040518263ffffffff1660e01b8152600401610e6f91906157b9565b602060405180830381865afa158015610e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb091906157a0565b9050610ebc600160fb55565b90565b60008061013260009054906101000a90046001600160a01b03166001600160a01b03166346ebcf236040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3a91906157a0565b90506000610f4760355490565b90506000808211610f6457610f5f620f4240866157f0565b610f78565b610f7885610f706117ea565b8491906133eb565b9050610fa883610f8a6008600a6158eb565b610f9491906158fa565b610fa06008600a6158eb565b8391906133eb565b95945050505050565b3360008181526034602090815260408083206001600160a01b03871684529091528120549091906108389082908690610feb90879061590d565b612895565b610133546001600160a01b0316331461101c57604051637bf6a16f60e01b815260040160405180910390fd5b6110246134dd565b565b6108f3338261352f565b61012d546000906001600160a01b038381169116148061083e575061083e61012e83612a65565b61105f613663565b600860ff16816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c69190615920565b60ff16146110e75760405163c51d798560e01b815260040160405180910390fd5b61013280546001600160a01b0319166001600160a01b0392909216919091179055565b60008061113160405180606001604052806000815260200160008152602001600081525090565b610131546001600160a01b03166000611149826132da565b905060006111bc836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561118e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b291906157a0565b83518991906133eb565b9050600061013260009054906101000a90046001600160a01b03166001600160a01b0316630a98b70d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611214573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123891906157a0565b61013254604051624d5b2360e21b81529192506000916001600160a01b0390911690636978ed069082906301356c8c906112769089906004016157b9565b602060405180830381865afa158015611293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b791906157a0565b61013260009054906101000a90046001600160a01b03166001600160a01b03166301356c8c60405180606001604052808f8b600001516112f7919061590d565b81526020018a6020015181526020018a604001518152506040518263ffffffff1660e01b815260040161132a91906157b9565b602060405180830381865afa158015611347573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136b91906157a0565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401602060405180830381865afa1580156113ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d091906157a0565b905060006113ee836113e46008600a6158eb565b86919060016136bd565b90506114276113fd838561590d565b6114096008600a6158eb565b61141391906158fa565b61141f6008600a6158eb565b8691906133eb565b9a9099509397509295505050505050565b611440613663565b611024600061370e565b611452611b6c565b6110246114d8565b600061146582611030565b61147057600061083e565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156114b4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083e91906157a0565b6114e06129b9565b6114e8612a12565b61012d54610131546040516370a0823160e01b81523060048201526001600160a01b03928316929091169060009083906370a0823190602401602060405180830381865afa15801561153e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156291906157a0565b90506000611636836001600160a01b03166397b3fcaa6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156115a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115cd91906157a0565b846001600160a01b0316638b5393826040518163ffffffff1660e01b81526004016020604051808303816000875af115801561160d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163191906157a0565b613760565b90506000818311611648576000611652565b61165282846158fa565b90506101305481116116775760405163167bb86960e11b815260040160405180910390fd5b6116e5846001600160a01b0316638fb69c4b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156116ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116de9190615783565b868361379a565b6116ef8486613823565b61170c5760405163167bb86960e11b815260040160405180910390fd5b61012d54611722906001600160a01b0316612be9565b5050505050611024600160fb55565b61173c823383613070565b611746828261352f565b5050565b610133546001600160a01b0316331461177657604051637bf6a16f60e01b815260040160405180910390fd5b611024613abf565b6060603780546107a790615749565b611795613663565b61013380546001600160a01b0319166001600160a01b0392909216919091179055565b610133546001600160a01b031633146117e457604051637bf6a16f60e01b815260040160405180910390fd5b61013455565b61012d546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185c91906157a0565b9050600061186b61012e613afc565b905060005b8160ff168160ff16101561194357600061188f61012e60ff8416613b06565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156118d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fd91906157a0565b9050629896808111156119305761012d546119239083906001600160a01b0316836132a7565b61192d908661590d565b94505b50508061193c90615943565b9050611870565b509092915050565b611953613663565b61195b6129b9565b61196483611030565b15611982576040516328071e2f60e11b815260040160405180910390fd5b6119966001600160a01b0384168383613040565b6119a0600160fb55565b505050565b3360008181526034602090815260408083206001600160a01b038716845290915281205490919083811015611a2a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161099e565b611a378286868403612895565b506001949350505050565b6000336108388185856130fc565b600081600003611a6c57505061012d546001600160a01b031690565b611a7761012e613afc565b8211611a945761083e611a8b6001846158fa565b61012e90613b06565b604051632d0483c560e21b815260040160405180910390fd5b6000611ab76129b9565b611abf612a12565b6000611aca83610ebf565b9050821580611ad7575080155b15611ae6576000915050610d16565b61012d54611aff906001600160a01b0316333086612fc0565b611b093382613b12565b61012d54611b1f906001600160a01b0316612be9565b9050610d20600160fb55565b610133546001600160a01b03163314611b5757604051637bf6a16f60e01b815260040160405180910390fd5b61013055565b611b696008600a6158eb565b81565b611b746129b9565b611b7c612a12565b6000611b8961012e613afc565b905060008160ff1611611b9c5750611d7e565b60005b8160ff168160ff161015611d25576000611bbe61012e60ff8416613b06565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2c91906157a0565b905060008111611c3d575050611d15565b6000826001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ca19190615783565b90506000611cb7826001600160a01b0316613bd3565b90506000611ccd836001600160a01b0316613d66565b11611ce257611cdd828585613de5565b611d10565b8051516001600160a01b038581169116148015611d0157506298968083115b15611d1057611d108282613f07565b505050505b611d1e81615943565b9050611b9f565b50805b60ff811615611d6557611d53611d4e611d42600184615978565b61012e9060ff16613b06565b613f64565b80611d5d81615991565b915050611d28565b5061012d54611d7c906001600160a01b0316612be9565b505b611024600160fb55565b610133546001600160a01b03163314611db457604051637bf6a16f60e01b815260040160405180910390fd5b61013555565b6060611dc4611b6c565b61083e825b6060611dd36129b9565b611ddb612a12565b60008211611e28576040805160008082526020820190925290611e20565b6040805180820190915260008082526020820152815260200190600190039081611df95790505b509050610d16565b6000611e3383612493565b9050611e3f338461352f565b805160005b8160ff168160ff161015611f4b57828160ff1681518110611e6757611e67615962565b60200260200101516020015160000315611f3b57611ed933848360ff1681518110611e9457611e94615962565b602002602001015160200151858460ff1681518110611eb557611eb5615962565b6020026020010151600001516001600160a01b03166130409092919063ffffffff16565b8060ff16600003611f1257611f0d838260ff1681518110611efc57611efc615962565b602002602001015160000151612be9565b611f3b565b611f3b838260ff1681518110611f2a57611f2a615962565b602002602001015160000151613f64565b611f4481615943565b9050611e44565b5050600160fb5592915050565b600080611f7f60405180606001604052806000815260200160008152602001600081525090565b610131546001600160a01b03166000611f97826132da565b9050600061200d8260000151846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fe1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200591906157a0565b8991906133eb565b9050600061013260009054906101000a90046001600160a01b03166001600160a01b031663ca9cbcbe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612065573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208991906157a0565b61013254604051624d5b2360e21b81529192506000916001600160a01b039091169063bf39d3db9082906301356c8c906120c79089906004016157b9565b602060405180830381865afa1580156120e4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210891906157a0565b61013254604080516060810190915288516001600160a01b03909216916301356c8c91908190612139908b906158fa565b81526020018a6020015181526020018a604001518152506040518263ffffffff1660e01b815260040161216c91906157b9565b602060405180830381865afa158015612189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ad91906157a0565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401602060405180830381865afa1580156121ee573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221291906157a0565b905060006113ee836122266008600a6158eb565b8c919060016136bd565b600061223a6129b9565b612242612a12565b6101315461012d546040516370a0823160e01b81523060048201526001600160a01b03928316929091169060009082906370a0823190602401602060405180830381865afa158015612298573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122bc91906157a0565b905060008060006122cc8861110a565b919450925090508215806122de575087155b156122fc5760405163173825e960e21b815260040160405180910390fd5b6123116001600160a01b03861633308b612fc0565b612331868683600001518460400151868861232c919061590d565b61408c565b811561239257604051630852cd8d60e31b8152600481018390526001600160a01b038716906342966c6890602401600060405180830381600087803b15801561237957600080fd5b505af115801561238d573d6000803e3d6000fd5b505050505b6123a66001600160a01b0387163385613040565b6040516370a0823160e01b81523060048201526000906001600160a01b038716906370a0823190602401602060405180830381865afa1580156123ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241191906157a0565b9050848110801561243c575081516124389061242e908b9061590d565b8360400151613760565b8111155b1561245a5760405163bb55fd2760e01b815260040160405180910390fd5b61246386612be9565b509195505050505050610d20600160fb55565b600061248361012e613afc565b61248e90600161590d565b905090565b606060006124a060355490565b9050600061013260009054906101000a90046001600160a01b03166001600160a01b031663916b7ed76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061251c91906157a0565b9050600061252b61012e613afc565b6125369060016159ae565b905060008160ff1667ffffffffffffffff811115612556576125566154c6565b60405190808252806020026020018201604052801561259b57816020015b60408051808201909152600080825260208201528152602001906001900390816125745790505b5061012d546040805180820182526001600160a01b0390921680835290516370a0823160e01b815230600482015292935091602082019061262e908a90899086906370a08231906024015b602060405180830381865afa158015612603573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262791906157a0565b91906133eb565b8152508260008151811061264457612644615962565b60209081029190910101526126a38461265f6008600a6158eb565b61266991906158fa565b6126756008600a6158eb565b8460008151811061268857612688615962565b6020026020010151602001516133eb9092919063ffffffff16565b826000815181106126b6576126b6615962565b602090810291909101810151015260015b8360ff168160ff1610156128135760006126e5611d42600184615978565b6040805180820182526001600160a01b03831680825291516370a0823160e01b815230600482015292935091602083019161272c918d918c916370a08231906024016125e6565b815250848360ff168151811061274457612744615962565b602090810291909101015261278a8661275f6008600a6158eb565b61276991906158fa565b6127756008600a6158eb565b868560ff168151811061268857612688615962565b848360ff168151811061279f5761279f615962565b6020026020010151602001818152505062989680848360ff16815181106127c8576127c8615962565b6020026020010151602001511015612802576000848360ff16815181106127f1576127f1615962565b602002602001015160200181815250505b5061280c81615943565b90506126c7565b50909695505050505050565b612827613663565b6001600160a01b03811661288c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161099e565b6108f38161370e565b6001600160a01b0383166128f75760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161099e565b6001600160a01b0382166129585760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161099e565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600260fb5403612a0b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161099e565b600260fb55565b60c95460ff16156110245760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161099e565b6001600160a01b03811660009081526001830160205260408120541515610d44565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612ace573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af291906157a0565b905060008111612b055761174682613f64565b6000826001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b699190615783565b90506000612b7f826001600160a01b0316613d66565b11612b9857612b8f818484613de5565b6119a083613f64565b62989680821115612b8f576000612bb7826001600160a01b0316613bd3565b9050612bc38282613f07565b8051612bd69060005b6020020151613f64565b8051612be3906001612bcc565b50505050565b6040516370a0823160e01b81523060048201527f3498084e435368f22f5e58d4957c351579c10be5ab20874cc78c9d0e28fa04099082906001600160a01b038216906370a0823190602401602060405180830381865afa158015612c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7591906157a0565b604080516001600160a01b03909316835260208301919091520160405180910390a150565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612ce1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0591906157a0565b905060008111612d13575050565b60405163db006a7560e01b8152600481018290526000906001600160a01b0384169063db006a75906024016000604051808303816000875af1158015612d5d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d8591908101906159eb565b805190915060015b8160ff168160ff161015610b13576000838260ff1681518110612db257612db2615962565b6020026020010151600001519050612dc981612a87565b50612dd381615943565b9050612d8d565b600160fb55565b600054610100900460ff16612e3a5760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b61174682826143c5565b600054610100900460ff166110245760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b600054610100900460ff16612ef65760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b611024614437565b600054610100900460ff16612f575760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b611024614499565b600054610100900460ff16612fb85760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b6110246144fe565b6040516001600160a01b0380851660248301528316604482015260648101829052612be39085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152614557565b6040516001600160a01b0383166024820152604481018290526119a090849063a9059cbb60e01b90606401612ff4565b6001600160a01b038381166000908152603460209081526040808320938616835292905220546000198114612be357818110156130ef5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161099e565b612be38484848403612895565b6001600160a01b0383166131605760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161099e565b6001600160a01b0382166131c25760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161099e565b6001600160a01b0383166000908152603360205260409020548181101561323a5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161099e565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061329a9086815260200190565b60405180910390a3612be3565b600080806132be6001600160a01b0387168661463f565b90925090506132d082858360016136bd565b9695505050505050565b6132fe60405180606001604052806000815260200160008152602001600081525090565b6040518060600160405280836001600160a01b03166397b3fcaa6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015613349573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061336d91906157a0565b815260200161337a6117ea565b8152602001836001600160a01b0316638b5393826040518163ffffffff1660e01b81526004016020604051808303816000875af11580156133bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e391906157a0565b905292915050565b60008080600019858709858702925082811083820303915050806000036134255783828161341b5761341b615aa4565b0492505050610d44565b8084116134745760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f770000000000000000000000604482015260640161099e565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6134e56149b4565b60c9805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03821661358f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161099e565b6001600160a01b038216600090815260336020526040902054818110156136035760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161099e565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6097546001600160a01b031633146110245760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161099e565b6000806136cb8686866133eb565b905060018360028111156136e1576136e1615aba565b1480156136fe5750600084806136f9576136f9615aa4565b868809115b15610fa8576132d060018261590d565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000610d4461013454613795610135546008600a61377e91906158eb565b61262761378d886103e86158fa565b8990896133eb565b614a06565b60006137ae846001600160a01b0316613bd3565b90506137bb838584614a1c565b60405163b6b55f2560e01b8152600481018390526001600160a01b0385169063b6b55f2590602401600060405180830381600087803b1580156137fd57600080fd5b505af1158015613811573d6000803e3d6000fd5b50508251612bd6925090506000612bcc565b600080836001600160a01b031663364d22fc6040518163ffffffff1660e01b81526004016000604051808303816000875af1158015613866573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261388e9190810190615ad0565b9050600080856001600160a01b031663332d83d56040518163ffffffff1660e01b81526004016020604051808303816000875af11580156138d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138f79190615783565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015613941573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396591906157a0565b9050613972828883614a1c565b835160005b8160ff168160ff1610801561398c5750600083115b15613aa9576000868260ff16815181106139a8576139a8615962565b6020908102919091010151604051632bf8f1a560e01b81526001600160a01b0387811660048301528083166024830152604482018790529192506000918c1690632bf8f1a59060640160408051808303816000875af1158015613a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a339190615b5f565b8051909150613a43575050613a99565b896001600160a01b0316888460ff1681518110613a6257613a62615962565b60200260200101516001600160a01b031614613a8157613a8182612a87565b6020810151613a9090866158fa565b94506001965050505b613aa281615943565b9050613977565b50613ab383612a87565b50919695505050505050565b613ac7612a12565b60c9805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135123390565b600061083e825490565b6000610d448383614ab0565b6001600160a01b038216613b685760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161099e565b8060356000828254613b7a919061590d565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b613bdb6153ce565b816001600160a01b03166359eb82246040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3d91906157a0565b600214613c5d5760405163673f20ed60e11b815260040160405180910390fd5b6040516313612cb160e11b8152600060048201526001600160a01b038316906326c25962906024016040805180830381865afa158015613ca1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc59190615b91565b82516020840151600060200201919091526001600160a01b0391821690526040516313612cb160e11b815260016004820152908316906326c25962906024016040805180830381865afa158015613d20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d449190615b91565b82516020808501518101929092526001600160a01b0392909216910152919050565b600080826001600160a01b031663d59624b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613da7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dcb91906157a0565b9050428111613ddb576000610d44565b610d4442826158fa565b826001600160a01b031663ae4e7fdf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e479190615bbf565b613e9f57826001600160a01b03166387b652076040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613e8657600080fd5b505af1158015613e9a573d6000803e3d6000fd5b505050505b604051630cf4838d60e21b81526001600160a01b038381166004830152602482018390528416906333d20e34906044015b600060405180830381600087803b158015613eea57600080fd5b505af1158015613efe573d6000803e3d6000fd5b50505050505050565b6000613f138230614ada565b9050600081600081518110613f2a57613f2a615962565b602002602001015111156119a057604051637cd7d93560e11b81526001600160a01b0384169063f9afb26a90613ed0908490600401615be1565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015613fab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fcf91906157a0565b604080516001600160a01b0385168152602081018390529192507f3498084e435368f22f5e58d4957c351579c10be5ab20874cc78c9d0e28fa0409910160405180910390a1600061402261012e84612a65565b9050600082118015614032575080155b156140705761404361012e84614c28565b50602f61405161012e613afc565b11156119a057604051633d816dad60e01b815260040160405180910390fd5b8115801561407b5750805b156119a057612be361012e84614c3d565b6000856001600160a01b0316638fb69c4b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156140ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f29190615783565b90506000866001600160a01b031663332d83d56040518163ffffffff1660e01b81526004016020604051808303816000875af1158015614136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061415a9190615783565b90506000806143236040518060c001604052808981526020018b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156141b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141d591906157a0565b81526040516370a0823160e01b81526001600160a01b0388811660048301526020909201918c16906370a0823190602401602060405180830381865afa158015614223573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061424791906157a0565b8152602001866001600160a01b031663fc7b9c186040518163ffffffff1660e01b8152600401602060405180830381865afa15801561428a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ae91906157a0565b8152602001856001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156142f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061431591906157a0565b815260200188905286614c52565b9150915061433284898461379a565b61433d838a83614a1c565b6040516311f9fbc960e21b81526001600160a01b038481166004830152602482018390528a16906347e7ef24906044016020604051808303816000875af115801561438c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143b091906157a0565b506143ba83613f64565b505050505050505050565b600054610100900460ff1661441e5760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b603661442a8382615c67565b5060376119a08282615c67565b600054610100900460ff166144905760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b6110243361370e565b600054610100900460ff166144f25760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b60c9805460ff19169055565b600054610100900460ff16612dda5760405162461bcd60e51b815260206004820152602b6024820152600080516020615d8283398151915260448201526a6e697469616c697a696e6760a81b606482015260840161099e565b60006145ac826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614d0b9092919063ffffffff16565b90508051600014806145cd5750808060200190518101906145cd9190615bbf565b6119a05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161099e565b6000806000846001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614682573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146a69190615783565b90506000856001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156146e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061470c91906157a0565b90506000826001600160a01b031663ae4e7fdf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561474e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147729190615bbf565b156147ee576040516370a0823160e01b81526001600160a01b0388811660048301528716906370a0823190602401602060405180830381865afa1580156147bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147e191906157a0565b94509092506149ad915050565b826001600160a01b03166359eb82246040518163ffffffff1660e01b8152600401602060405180830381865afa15801561482c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061485091906157a0565b6002146148705760405163673f20ed60e11b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b038481166004830152600091908816906370a0823190602401602060405180830381865afa1580156148ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148de91906157a0565b90506001600160a01b03808916906148f99086166001614d1a565b6001600160a01b03160361499957600083856001600160a01b031663fc7b9c186040518163ffffffff1660e01b8152600401602060405180830381865afa158015614948573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496c91906157a0565b61497691906158fa565b905060006149848284614d8f565b905061499081846158fa565b935050506149a6565b6149a38382614d8f565b91505b5093509150505b9250929050565b60c95460ff166110245760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161099e565b6000818311614a155781610d44565b5090919050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015614a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a9091906157a0565b905081811015612be357612be36001600160a01b03851684600019614d9e565b6000826000018281548110614ac757614ac7615962565b9060005260206000200154905092915050565b60408051600280825260608083018452926000929190602083019080368337019050508451516040516370a0823160e01b81526001600160a01b0386811660048301529293509116906370a0823190602401602060405180830381865afa158015614b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614b6d91906157a0565b81600081518110614b8057614b80615962565b60209081029190910101528351600160200201516040516370a0823160e01b81526001600160a01b038581166004830152909116906370a0823190602401602060405180830381865afa158015614bdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bff91906157a0565b81600181518110614c1257614c12615962565b602002602001018181525050610e148482614eba565b6000610d44836001600160a01b038416615113565b6000610d44836001600160a01b038416615162565b600080600080856020015111614c685783614c7c565b84516020860151614c7c91869160016136bd565b90506000614c9286608001518760400151614d8f565b90506000866080015111614ca65781614cb9565b6080860151614cb99083908360016136bd565b9150600080876060015111614cce5782614ce5565b60408701516060880151614ce591859160016136bd565b60a0880151909150614cfe9082906103e89060016136bd565b9792965091945050505050565b6060610e148484600085615255565b6040516313612cb160e11b815260ff821660048201526000906001600160a01b038416906326c25962906024016040805180830381865afa158015614d63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d879190615b91565b509392505050565b6000818310614a155781610d44565b801580614e185750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614df2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e1691906157a0565b155b614e8a5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606482015260840161099e565b6040516001600160a01b0383166024820152604481018290526119a090849063095ea7b360e01b90606401612ff4565b604080516002808252606080830184529260009291906020830190803683370190505060208501519091506001602002015183600181518110614eff57614eff615962565b6020026020010151614f119190615d27565b83600181518110614f2457614f24615962565b6020026020010151614f3691906158fa565b81600181518110614f4957614f49615962565b6020026020010181815250508360200151600160028110614f6c57614f6c615962565b60200201518460200151600060028110614f8857614f88615962565b602002015182600181518110614fa057614fa0615962565b6020026020010151614fb291906157f0565b614fbc9190615d3b565b81600081518110614fcf57614fcf615962565b60200260200101818152505082600081518110614fee57614fee615962565b60200260200101518160008151811061500957615009615962565b60200260200101511115610d44576020840151518351849060009061503057615030615962565b60200260200101516150429190615d27565b8360008151811061505557615055615962565b602002602001015161506791906158fa565b8160008151811061507a5761507a615962565b602002602001018181525050836020015160006002811061509d5761509d615962565b602002015184602001516001600281106150b9576150b9615962565b6020020151826000815181106150d1576150d1615962565b60200260200101516150e391906157f0565b6150ed9190615d3b565b8160018151811061510057615100615962565b6020026020010181815250509392505050565b600081815260018301602052604081205461515a5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561083e565b50600061083e565b6000818152600183016020526040812054801561524b5760006151866001836158fa565b855490915060009061519a906001906158fa565b90508181146151ff5760008660000182815481106151ba576151ba615962565b90600052602060002001549050808760000184815481106151dd576151dd615962565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061521057615210615d4f565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061083e565b600091505061083e565b6060824710156152b65760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161099e565b600080866001600160a01b031685876040516152d29190615d65565b60006040518083038185875af1925050503d806000811461530f576040519150601f19603f3d011682016040523d82523d6000602084013e615314565b606091505b509150915061532587838387615330565b979650505050505050565b6060831561539f578251600003615398576001600160a01b0385163b6153985760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161099e565b5081610e14565b610e1483838151156153b45781518083602001fd5b8060405162461bcd60e51b815260040161099e9190615435565b60405180604001604052806153e16153f3565b81526020016153ee6153f3565b905290565b60405180604001604052806002906020820280368337509192915050565b60005b8381101561542c578181015183820152602001615414565b50506000910152565b6020815260008251806020840152615454816040850160208701615411565b601f01601f19169190910160400192915050565b6001600160a01b03811681146108f357600080fd5b6000806040838503121561549057600080fd5b823561549b81615468565b946020939093013593505050565b6000602082840312156154bb57600080fd5b8135610d4481615468565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156154ff576154ff6154c6565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561552e5761552e6154c6565b604052919050565b600082601f83011261554757600080fd5b813567ffffffffffffffff811115615561576155616154c6565b615574601f8201601f1916602001615505565b81815284602083860101111561558957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156155bc57600080fd5b843567ffffffffffffffff808211156155d457600080fd5b6155e088838901615536565b955060208701359150808211156155f657600080fd5b5061560387828801615536565b935050604085013561561481615468565b9150606085013561562481615468565b939692955090935050565b60006020828403121561564157600080fd5b5035919050565b60008060006060848603121561565d57600080fd5b833561566881615468565b9250602084013561567881615468565b929592945050506040919091013590565b8381526020810183905260a08101610e1460408301848051825260208082015190830152604090810151910152565b602080825282518282018190526000919060409081850190868401855b8281101561570357815180516001600160a01b031685528601518685015292840192908501906001016156d5565b5091979650505050505050565b6000806040838503121561572357600080fd5b823561572e81615468565b9150602083013561573e81615468565b809150509250929050565b600181811c9082168061575d57607f821691505b60208210810361577d57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561579557600080fd5b8151610d4481615468565b6000602082840312156157b257600080fd5b5051919050565b8151815260208083015190820152604080830151908201526060810161083e565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761083e5761083e6157da565b600181815b80851115615842578160001904821115615828576158286157da565b8085161561583557918102915b93841c939080029061580c565b509250929050565b6000826158595750600161083e565b816158665750600061083e565b816001811461587c5760028114615886576158a2565b600191505061083e565b60ff841115615897576158976157da565b50506001821b61083e565b5060208310610133831016604e8410600b84101617156158c5575081810a61083e565b6158cf8383615807565b80600019048211156158e3576158e36157da565b029392505050565b6000610d4460ff84168361584a565b8181038181111561083e5761083e6157da565b8082018082111561083e5761083e6157da565b60006020828403121561593257600080fd5b815160ff81168114610d4457600080fd5b600060ff821660ff8103615959576159596157da565b60010192915050565b634e487b7160e01b600052603260045260246000fd5b60ff828116828216039081111561083e5761083e6157da565b600060ff8216806159a4576159a46157da565b6000190192915050565b60ff818116838216019081111561083e5761083e6157da565b600067ffffffffffffffff8211156159e1576159e16154c6565b5060051b60200190565b600060208083850312156159fe57600080fd5b825167ffffffffffffffff811115615a1557600080fd5b8301601f81018513615a2657600080fd5b8051615a39615a34826159c7565b615505565b81815260069190911b82018301908381019087831115615a5857600080fd5b928401925b828410156153255760408489031215615a765760008081fd5b615a7e6154dc565b8451615a8981615468565b81528486015186820152825260409093019290840190615a5d565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b60006020808385031215615ae357600080fd5b825167ffffffffffffffff811115615afa57600080fd5b8301601f81018513615b0b57600080fd5b8051615b19615a34826159c7565b81815260059190911b82018301908381019087831115615b3857600080fd5b928401925b82841015615325578351615b5081615468565b82529284019290840190615b3d565b600060408284031215615b7157600080fd5b615b796154dc565b82518152602083015160208201528091505092915050565b60008060408385031215615ba457600080fd5b8251615baf81615468565b6020939093015192949293505050565b600060208284031215615bd157600080fd5b81518015158114610d4457600080fd5b6020808252825182820181905260009190848201906040850190845b8181101561281357835183529284019291840191600101615bfd565b601f8211156119a057600081815260208120601f850160051c81016020861015615c405750805b601f850160051c820191505b81811015615c5f57828155600101615c4c565b505050505050565b815167ffffffffffffffff811115615c8157615c816154c6565b615c9581615c8f8454615749565b84615c19565b602080601f831160018114615cca5760008415615cb25750858301515b600019600386901b1c1916600185901b178555615c5f565b600085815260208120601f198616915b82811015615cf957888601518255948401946001909101908401615cda565b5085821015615d175787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600082615d3657615d36615aa4565b500690565b600082615d4a57615d4a615aa4565b500490565b634e487b7160e01b600052603160045260246000fd5b60008251615d77818460208701615411565b919091019291505056fe496e697469616c697a61626c653a20636f6e7472616374206973206e6f742069a264697066735822122098818f5eb684f75b9516379b647beb45238544924052b77985ea7fc1fc56373764736f6c63430008140033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 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.