Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PerpetualTranche
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 { IERC20MetadataUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import { IERC20Upgradeable, IPerpetualTranche, IBondIssuer, IFeePolicy, IBondController, ITranche } from "./_interfaces/IPerpetualTranche.sol";
import { IRolloverVault } from "./_interfaces/IRolloverVault.sol";
import { TokenAmount, RolloverData, SubscriptionParams } from "./_interfaces/CommonTypes.sol";
import { UnauthorizedCall, UnauthorizedTransferOut, UnexpectedDecimals, UnexpectedAsset, UnacceptableParams, UnacceptableRollover, ExceededMaxSupply, ExceededMaxMintPerTranche, ReserveCountOverLimit } 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 { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";
import { SignedMathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SignedMathUpgradeable.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 { BondHelpers } from "./_utils/BondHelpers.sol";
/**
* @title PerpetualTranche
*
* @notice An opinionated implementation of a perpetual note ERC-20 token contract, backed by buttonwood tranches.
*
* Perpetual note tokens (or perps for short) are backed by senior tranche tokens (aka seniors) held in this contract's reserve.
* Users can mint perps by depositing seniors into the reserve.
* They can redeem tokens from the reserve by burning their perps.
*
* The whitelisted bond issuer issues new deposit bonds periodically based on a predefined frequency.
* Users can ONLY mint perps for seniors belonging to the active "deposit" bond.
* Users can burn perps, and redeem a proportional share of tokens held in the reserve.
*
* Once seniors held in the reserve mature, the underlying collateral is extracted
* into the reserve. At any time, the reserve holds at most 2 classes of tokens
* i.e) the seniors and the underlying collateral.
*
* Incentivized parties can "rollover" tranches approaching maturity or the underlying collateral,
* for newer seniors (which expire further out in the future) that belong to the updated "depositBond".
*
*
* @dev The time dependent system state is updated "lazily" without a need for an explicit poke
* from the outside world. Every external function that deals with the reserve
* invokes the `afterStateUpdate` modifier at the entry-point.
* This brings the system storage state up to date.
*
* CRITICAL: On the 3 main system operations: deposit, redeem and rollover;
* We first compute fees before executing any transfers in or out of the system.
* The ordering of operations is very important as the fee computation logic,
* requires the system TVL as an input and which should be recorded prior to any value
* entering or leaving the system.
*
* With the new demand based fee policy implementation,
* both perp and the rollover have a mutual dependency on each other.
* None of the perp operations will work unless it's pointed to a valid vault.
*
* When computing the value of assets in the system, the code always over-values by
* rounding up. When computing the value of incoming assets, the code rounds down.
*
*/
contract PerpetualTranche is
ERC20BurnableUpgradeable,
OwnableUpgradeable,
PausableUpgradeable,
ReentrancyGuardUpgradeable,
IPerpetualTranche
{
//-------------------------------------------------------------------------
// Libraries
// data handling
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using BondHelpers for IBondController;
// ERC20 operations
using SafeERC20Upgradeable for IERC20Upgradeable;
// Math
using MathUpgradeable for uint256;
using SignedMathUpgradeable for int256;
using SafeCastUpgradeable for int256;
//-------------------------------------------------------------------------
// Perp Math Basics:
//
// System holds tokens in the reserve {t1, t2 ... tn}
// with balances {b1, b2 ... bn}.
//
// System reserve value:
// RV => b1 . price(t1) + b2 . price(t2) + .... + bn . price(tn)
// => Σ bi . price(ti)
//
// When `ai` tokens of type `ti` are deposited into the system:
// Mint: mintAmt (perps) => (ai * price(ti) / RV) * supply(perps)
//
// This ensures that if 10% of the collateral value is deposited,
// the minter receives 10% of the perp token supply.
// This removes any race conditions for minters based on reserve state.
//
// When `p` perp tokens are redeemed:
// Redeem: ForEach ti => (p / supply(perps)) * bi
//
// When `ai` tokens of type `ti` are rolled in for tokens of type `tj`
// => ai * price(ti) = aj * price(tj)
// Rollover: aj => ai * price(ti) / (price(tj))
//
//
//-------------------------------------------------------------------------
// Constants & Immutables
// Number of decimals for a multiplier of 1.0x (i.e. 100%)
uint8 public constant FEE_POLICY_DECIMALS = 8;
uint256 public constant FEE_ONE = (10 ** FEE_POLICY_DECIMALS);
/// @dev The maximum number of reserve assets that can be held by perp.
uint8 public constant MAX_RESERVE_COUNT = 11;
//-------------------------------------------------------------------------
// Storage
/// @dev The perp token balances are represented as a fixed point unsigned integer with these many decimals.
uint8 private _decimals;
//--------------------------------------------------------------------------
// CONFIG
/// @inheritdoc IPerpetualTranche
address public override keeper;
/// @notice External contract that orchestrates fees across the spot protocol.
/// @custom:oz-upgrades-renamed-from feeStrategy
IFeePolicy public override feePolicy;
/// @notice DEPRECATED.
/// @dev This used to point to the external strategy that computes a given reserve token's price.
/// @custom:oz-upgrades-renamed-from pricingStrategy
// solhint-disable-next-line var-name-mixedcase
address private _pricingStrategy_DEPRECATED;
/// @notice DEPRECATED.
/// @dev This used to point to the external strategy that computes a given reserve token's discount factor.
/// Now, we assume perp accepts only the "senior" most tranche from a bond. Seniors have a discount of 1.0,
/// every other tranche has a discount of 0.
/// @custom:oz-upgrades-renamed-from discountStrategy
// solhint-disable-next-line var-name-mixedcase
address private _discountStrategy_DEPRECATED;
/// @inheritdoc IPerpetualTranche
/// @dev Only tranches of bonds issued by this whitelisted issuer are accepted into the reserve.
IBondIssuer public override bondIssuer;
/// @notice The active deposit bond of whose tranches are currently being accepted to mint perps.
IBondController private _depositBond;
/// @notice The minimum maturity time in seconds for a tranche below which
/// it can be rolled over.
uint256 public minTrancheMaturitySec;
/// @notice The maximum maturity time in seconds for a tranche above which
/// it can NOT get added into the reserve.
uint256 public maxTrancheMaturitySec;
/// @notice DEPRECATED.
/// @dev This used to control the percentage of the reserve value to be held as the underlying collateral.
/// With V2 perp cannot control this anymore, the rollover mechanics are dictated
/// by the amount of capital in the vault system.
/// @custom:oz-upgrades-renamed-from matureValueTargetPerc
// solhint-disable-next-line var-name-mixedcase
uint256 private _matureValueTargetPerc_DEPRECATED;
/// @notice The maximum supply of perps that can exist at any given time.
uint256 public maxSupply;
/// @notice The max number of perps that can be minted using the senior tranche in the minting bond.
uint256 public maxMintAmtPerTranche;
/// @notice The total number of perps that have been minted using a given tranche.
mapping(ITranche => uint256) public mintedSupplyPerTranche;
/// @notice DEPRECATED.
/// @dev This used to store the discount factor applied on each reserve token.
/// Now, we assume all tokens in perp have a discount factor of 1.
/// @custom:oz-upgrades-renamed-from appliedDiscounts
// solhint-disable-next-line var-name-mixedcase
mapping(IERC20Upgradeable => uint256) private _appliedDiscounts_DEPRECATED;
//--------------------------------------------------------------------------
// RESERVE
/// @notice Set of all tokens in the reserve which back the perps.
EnumerableSetUpgradeable.AddressSet private _reserves;
/// @notice DEPRECATED.
/// @dev The used to store the amount of all the mature tranches extracted and held as the collateral token,
/// i.e) the reserve's "virtual" mature tranche balance. The system no longer tracks this.
// solhint-disable-next-line var-name-mixedcase
uint256 private _matureTrancheBalance_DEPRECATED;
//--------------------------------------------------------------------------
// v2.0.0 STORAGE ADDITION
/// @notice Address of the authorized rollover vault.
/// @dev If this address is set, only the rollover vault can perform rollovers.
/// If not rollovers are publicly accessible.
IRolloverVault public override vault;
//--------------------------------------------------------------------------
// Modifiers
/// @dev Updates time-dependent reserve state.
modifier afterStateUpdate() {
updateState();
_;
}
/// @dev Throws if called by any account other than the keeper.
modifier onlyKeeper() {
if (keeper != msg.sender) {
revert UnauthorizedCall();
}
_;
}
/// @dev Throws if called not called by vault.
modifier onlyVault() {
if (address(vault) != msg.sender) {
revert UnauthorizedCall();
}
_;
}
//--------------------------------------------------------------------------
// Construction & Initialization
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/// @notice Contract state initialization.
/// @param name ERC-20 Name of the Perp token.
/// @param symbol ERC-20 Symbol of the Perp token.
/// @param collateral_ Address of the underlying collateral token.
/// @param bondIssuer_ Address of the bond issuer contract.
/// @param feePolicy_ Address of the fee policy contract.
function init(
string memory name,
string memory symbol,
IERC20Upgradeable collateral_,
IBondIssuer bondIssuer_,
IFeePolicy feePolicy_
) external initializer {
__ERC20_init(name, symbol);
__ERC20Burnable_init();
__Ownable_init();
__Pausable_init();
__ReentrancyGuard_init();
_decimals = IERC20MetadataUpgradeable(address(collateral_)).decimals();
// NOTE: `_reserveAt(0)` always points to the underling collateral token
// and is to be never updated.
_reserves.add(address(collateral_));
_syncReserve(collateral_);
updateKeeper(owner());
updateFeePolicy(feePolicy_);
updateBondIssuer(bondIssuer_);
updateTolerableTrancheMaturity(1, type(uint256).max);
updateMintingLimits(type(uint256).max, type(uint256).max);
}
//--------------------------------------------------------------------------
// ADMIN only methods
/// @notice Updates the reference to the rollover vault.
/// @param vault_ The address of the new vault.
function updateVault(IRolloverVault vault_) external onlyOwner {
vault = vault_;
}
/// @notice Updates the reference to the keeper.
/// @param keeper_ The address of the new keeper.
function updateKeeper(address keeper_) public onlyOwner {
keeper = keeper_;
}
/// @notice Update the reference to the bond issuer contract.
/// @param bondIssuer_ New bond issuer address.
function updateBondIssuer(IBondIssuer bondIssuer_) public onlyOwner {
if (bondIssuer_.collateral() != address(_reserveAt(0))) {
revert UnexpectedAsset();
}
bondIssuer = bondIssuer_;
}
/// @notice Update the reference to the fee policy contract.
/// @param feePolicy_ New strategy address.
function updateFeePolicy(IFeePolicy feePolicy_) public onlyOwner {
if (feePolicy_.decimals() != FEE_POLICY_DECIMALS) {
revert UnexpectedDecimals();
}
feePolicy = feePolicy_;
}
/// @notice Update the maturity tolerance parameters.
/// @param minTrancheMaturitySec_ New minimum maturity time.
/// @param maxTrancheMaturitySec_ New maximum maturity time.
function updateTolerableTrancheMaturity(
uint256 minTrancheMaturitySec_,
uint256 maxTrancheMaturitySec_
) public onlyOwner {
if (minTrancheMaturitySec_ > maxTrancheMaturitySec_) {
revert UnacceptableParams();
}
minTrancheMaturitySec = minTrancheMaturitySec_;
maxTrancheMaturitySec = maxTrancheMaturitySec_;
}
/// @notice Allows the owner to transfer non-critical assets out of the system if required.
/// @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 afterStateUpdate nonReentrant onlyOwner {
if (_inReserve(token)) {
revert UnauthorizedTransferOut();
}
token.safeTransfer(to, amount);
}
//--------------------------------------------------------------------------
// Keeper only methods
/// @notice Pauses deposits, withdrawals and rollovers.
/// @dev ERC-20 functions, like transfers will always remain operational.
function pause() external onlyKeeper {
_pause();
}
/// @notice Unpauses deposits, withdrawals and rollovers.
/// @dev ERC-20 functions, like transfers will always remain operational.
function unpause() external onlyKeeper {
_unpause();
}
/// @notice Update parameters controlling the perp token mint limits.
/// @param maxSupply_ New max total supply.
/// @param maxMintAmtPerTranche_ New max total for per tranche in minting bond.
function updateMintingLimits(uint256 maxSupply_, uint256 maxMintAmtPerTranche_) public onlyKeeper {
maxSupply = maxSupply_;
maxMintAmtPerTranche = maxMintAmtPerTranche_;
}
//--------------------------------------------------------------------------
// External methods
/// @inheritdoc IPerpetualTranche
function deposit(
ITranche trancheIn,
uint256 trancheInAmt
) external override afterStateUpdate nonReentrant whenNotPaused returns (uint256) {
if (!_isDepositTranche(trancheIn)) {
revert UnexpectedAsset();
}
// Calculates the fee adjusted amount of perp tokens minted when depositing `trancheInAmt` of tranche tokens
// NOTE: This operation should precede any token transfers.
uint256 perpAmtMint = _computeMintAmt(trancheIn, trancheInAmt);
if (trancheInAmt <= 0 || perpAmtMint <= 0) {
return 0;
}
// transfers tranche tokens from the sender to the reserve
_transferIntoReserve(trancheIn, trancheInAmt);
// mints perp tokens to the sender
_mint(msg.sender, perpAmtMint);
// post-deposit checks
mintedSupplyPerTranche[trancheIn] += perpAmtMint;
_enforceMintCaps(trancheIn);
return perpAmtMint;
}
/// @inheritdoc IPerpetualTranche
function redeem(
uint256 perpAmtBurnt
) external override afterStateUpdate nonReentrant whenNotPaused returns (TokenAmount[] memory) {
// verifies if burn amount is acceptable
if (perpAmtBurnt <= 0) {
return new TokenAmount[](0);
}
// Calculates the fee adjusted share of reserve tokens to be redeemed
// NOTE: This operation should precede any token transfers.
TokenAmount[] memory tokensOut = _computeRedemptionAmts(perpAmtBurnt);
// burns perp tokens from the sender
_burn(msg.sender, perpAmtBurnt);
// transfers reserve tokens out
uint8 tokensOutCount = uint8(tokensOut.length);
for (uint8 i = 0; i < tokensOutCount; ++i) {
if (tokensOut[i].amount > 0) {
_transferOutOfReserve(tokensOut[i].token, tokensOut[i].amount);
}
}
return tokensOut;
}
/// @inheritdoc IPerpetualTranche
function rollover(
ITranche trancheIn,
IERC20Upgradeable tokenOut,
uint256 trancheInAmtAvailable
) external override onlyVault afterStateUpdate nonReentrant whenNotPaused returns (RolloverData memory) {
// verifies if rollover is acceptable
if (!_isAcceptableRollover(trancheIn, tokenOut)) {
revert UnacceptableRollover();
}
// Calculates the fee adjusted amount of tranches exchanged during a rolled over
// NOTE: This operation should precede any token transfers.
RolloverData memory r = _computeRolloverAmt(trancheIn, tokenOut, trancheInAmtAvailable);
// Verifies if rollover amount is acceptable
if (r.trancheInAmt <= 0 || r.tokenOutAmt <= 0) {
return r;
}
// transfers tranche tokens from the sender to the reserve
_transferIntoReserve(trancheIn, r.trancheInAmt);
// transfers tranche from the reserve to the sender
_transferOutOfReserve(tokenOut, r.tokenOutAmt);
return r;
}
/// @inheritdoc IPerpetualTranche
function getDepositBond() external override afterStateUpdate returns (IBondController) {
return _depositBond;
}
/// @inheritdoc IPerpetualTranche
function getDepositTranche() external override afterStateUpdate returns (ITranche) {
return _depositBond.getSeniorTranche();
}
/// @inheritdoc IPerpetualTranche
function getDepositTrancheRatio() external override afterStateUpdate returns (uint256) {
return _depositBond.getSeniorTrancheRatio();
}
/// @inheritdoc IPerpetualTranche
function getReserveCount() external override afterStateUpdate returns (uint256) {
return _reserves.length();
}
/// @inheritdoc IPerpetualTranche
function getReserveAt(uint256 i) external override afterStateUpdate returns (IERC20Upgradeable) {
return _reserveAt(i);
}
/// @inheritdoc IPerpetualTranche
function inReserve(IERC20Upgradeable token) external override afterStateUpdate returns (bool) {
return _inReserve(token);
}
/// @inheritdoc IPerpetualTranche
function getReserveTokenBalance(IERC20Upgradeable token) external override afterStateUpdate returns (uint256) {
if (!_inReserve(token)) {
return 0;
}
return token.balanceOf(address(this));
}
/// @inheritdoc IPerpetualTranche
function getReserveTokenValue(IERC20Upgradeable token) external override afterStateUpdate returns (uint256) {
if (!_inReserve(token)) {
return 0;
}
if (_isUnderlying(token)) {
return token.balanceOf(address(this));
}
ITranche tranche = ITranche(address(token));
IBondController parentBond = IBondController(tranche.bond());
return _computeReserveTrancheValue(tranche, parentBond, _reserveAt(0), tranche.balanceOf(address(this)), true);
}
/// @inheritdoc IPerpetualTranche
function getReserveTokensUpForRollover() external override afterStateUpdate returns (IERC20Upgradeable[] memory) {
uint8 reserveCount = uint8(_reserves.length());
IERC20Upgradeable[] memory activeRolloverTokens = new IERC20Upgradeable[](reserveCount);
// We count the number of tokens up for rollover.
uint8 numTokensUpForRollover = 0;
// If any underlying collateral exists it can be rolled over.
IERC20Upgradeable underlying_ = _reserveAt(0);
if (underlying_.balanceOf(address(this)) > 0) {
activeRolloverTokens[0] = underlying_;
numTokensUpForRollover++;
}
// Iterating through the reserve to find tranches that are ready to be rolled out.
for (uint8 i = 1; i < reserveCount; ++i) {
IERC20Upgradeable token = _reserveAt(i);
if (_isTimeForRollout(ITranche(address(token)))) {
activeRolloverTokens[i] = token;
numTokensUpForRollover++;
}
}
// We recreate a smaller array with just the tokens up for rollover.
IERC20Upgradeable[] memory rolloverTokens = new IERC20Upgradeable[](numTokensUpForRollover);
uint8 j = 0;
for (uint8 i = 0; i < reserveCount; ++i) {
if (address(activeRolloverTokens[i]) != address(0)) {
rolloverTokens[j++] = activeRolloverTokens[i];
}
}
return rolloverTokens;
}
/// @inheritdoc IPerpetualTranche
/// @dev Returns a fixed point with the same decimals as the underlying collateral.
function getTVL() external override afterStateUpdate returns (uint256) {
return _reserveValue();
}
/// @inheritdoc IPerpetualTranche
function computeMintAmt(
ITranche trancheIn,
uint256 trancheInAmt
) external override afterStateUpdate returns (uint256) {
if (!_isDepositTranche(trancheIn)) {
revert UnexpectedAsset();
}
return _computeMintAmt(trancheIn, trancheInAmt);
}
/// @inheritdoc IPerpetualTranche
function computeRedemptionAmts(
uint256 perpAmtBurnt
) external override afterStateUpdate returns (TokenAmount[] memory) {
return _computeRedemptionAmts(perpAmtBurnt);
}
/// @inheritdoc IPerpetualTranche
function computeRolloverAmt(
ITranche trancheIn,
IERC20Upgradeable tokenOut,
uint256 trancheInAmtAvailable
) external override afterStateUpdate returns (RolloverData memory) {
if (!_isAcceptableRollover(trancheIn, tokenOut)) {
revert UnacceptableRollover();
}
return _computeRolloverAmt(trancheIn, tokenOut, trancheInAmtAvailable);
}
//--------------------------------------------------------------------------
// Public methods
/// @inheritdoc IPerpetualTranche
/// @dev Lazily updates time-dependent reserve storage state.
/// This function is to be invoked on all external function entry points which are
/// read the reserve storage. This function is intended to be idempotent.
function updateState() public override nonReentrant {
// Skip state update when system is paused.
if (paused()) {
return;
}
// Lazily queries the bond issuer to get the most recently issued bond
// and updates with the new deposit bond if it's "acceptable".
IBondController newBond = bondIssuer.getLatestBond();
// If the new bond has been issued by the issuer and is "acceptable"
if (_depositBond != newBond && _isValidDepositBond(newBond)) {
// updates `_depositBond` with the new bond
_depositBond = newBond;
emit UpdatedDepositBond(newBond);
}
// Lazily checks if every reserve tranche has reached maturity.
// If so redeems the tranche balance for the underlying collateral and
// removes the tranche from the reserve set.
// NOTE: We traverse the reserve set in the reverse order
// as deletions involve swapping the deleted element to the
// end of the set and removing the last element.
// We also skip the `reserveAt(0)`, i.e) the underlying collateral,
// which is never removed.
uint8 reserveCount = uint8(_reserves.length());
for (uint8 i = reserveCount - 1; i > 0; i--) {
ITranche tranche = ITranche(address(_reserveAt(i)));
IBondController bond = IBondController(tranche.bond());
// If bond is not mature yet, move to the next tranche
if (bond.secondsToMaturity() > 0) {
continue;
}
// If bond has reached maturity but hasn't been poked
if (!bond.isMature()) {
bond.mature();
}
// Redeeming the underlying collateral token
bond.redeemMature(address(tranche), tranche.balanceOf(address(this)));
_syncReserve(tranche);
}
// Keeps track of the underlying collateral balance
_syncReserve(_reserveAt(0));
}
//--------------------------------------------------------------------------
// External view methods
/// @inheritdoc IPerpetualTranche
function underlying() external view override returns (IERC20Upgradeable) {
return _reserveAt(0);
}
//--------------------------------------------------------------------------
// Public view methods
/// @notice Returns the number of decimals used to get its user representation.
/// @dev For example, if `decimals` equals `2`, a balance of `505` tokens should
/// be displayed to a user as `5.05` (`505 / 10 ** 2`).
function decimals() public view override returns (uint8) {
return _decimals;
}
//--------------------------------------------------------------------------
// Private methods
/// @dev Transfers tokens from the caller (msg.sender) and updates the reserve set.
/// @return Reserve's token balance after transfer in.
function _transferIntoReserve(IERC20Upgradeable token, uint256 trancheAmt) private returns (uint256) {
token.safeTransferFrom(msg.sender, address(this), trancheAmt);
return _syncReserve(token);
}
/// @dev Transfers tokens from self into the caller (msg.sender) and updates the reserve set.
/// @return Reserve's token balance after transfer out.
function _transferOutOfReserve(IERC20Upgradeable token, uint256 tokenAmt) private returns (uint256) {
token.safeTransfer(msg.sender, tokenAmt);
return _syncReserve(token);
}
/// @dev Keeps the reserve storage up to date. Logs the token balance held by the reserve.
/// @return The Reserve's token balance.
function _syncReserve(IERC20Upgradeable token) private returns (uint256) {
uint256 balance = token.balanceOf(address(this));
emit ReserveSynced(token, balance);
// The underlying collateral NEVER gets removed from the `_reserves` set.
if (_isUnderlying(token)) {
return balance;
}
// Otherwise `_reserves` set gets updated.
bool inReserve_ = _inReserve(token);
if (balance > 0 && !inReserve_) {
// Inserts new tranche into reserve set.
_reserves.add(address(token));
if (_reserves.length() > MAX_RESERVE_COUNT) {
revert ReserveCountOverLimit();
}
} else if (balance <= 0 && inReserve_) {
// Removes tranche from reserve set.
_reserves.remove(address(token));
// Frees up minted supply.
delete mintedSupplyPerTranche[ITranche(address(token))];
}
return balance;
}
/// @dev Computes the fee adjusted perp mint amount for given amount of tranche tokens deposited into the reserve.
function _computeMintAmt(ITranche trancheIn, uint256 trancheInAmt) private view returns (uint256) {
uint256 valueIn = _computeReserveTrancheValue(trancheIn, _depositBond, _reserveAt(0), trancheInAmt, false);
//-----------------------------------------------------------------------------
// We charge no mint fee when interacting with other callers within the system.
uint256 feePerc = _isProtocolCaller() ? 0 : feePolicy.computePerpMintFeePerc();
//-----------------------------------------------------------------------------
// Compute mint amt
uint256 perpSupply = totalSupply();
uint256 perpAmtMint = valueIn;
if (perpSupply > 0) {
perpAmtMint = perpAmtMint.mulDiv(perpSupply, _reserveValue());
}
// The mint fees are settled by simply minting fewer perps.
if (feePerc > 0) {
perpAmtMint = perpAmtMint.mulDiv(FEE_ONE - feePerc, FEE_ONE);
}
return perpAmtMint;
}
/// @dev Computes the reserve token amounts redeemed when a given number of perps are burnt.
function _computeRedemptionAmts(uint256 perpAmtBurnt) private view returns (TokenAmount[] memory) {
uint256 perpSupply = totalSupply();
//-----------------------------------------------------------------------------
// We charge no burn fee when interacting with other parts of the system.
uint256 feePerc = _isProtocolCaller() ? 0 : feePolicy.computePerpBurnFeePerc();
//-----------------------------------------------------------------------------
// Compute redemption amounts
uint8 reserveCount = uint8(_reserves.length());
TokenAmount[] memory reserveTokens = new TokenAmount[](reserveCount);
for (uint8 i = 0; i < reserveCount; ++i) {
IERC20Upgradeable tokenOut = _reserveAt(i);
reserveTokens[i] = TokenAmount({
token: tokenOut,
amount: tokenOut.balanceOf(address(this)).mulDiv(perpAmtBurnt, perpSupply)
});
// The burn fees are settled by simply redeeming for fewer tranches.
if (feePerc > 0) {
reserveTokens[i].amount = reserveTokens[i].amount.mulDiv(FEE_ONE - feePerc, FEE_ONE);
}
}
return (reserveTokens);
}
/// @dev Computes the amount of reserve tokens that can be rolled out for the given amount of tranches deposited.
/// The relative ratios of tokens In/Out are adjusted based on the current rollover fee perc.
function _computeRolloverAmt(
ITranche trancheIn,
IERC20Upgradeable tokenOut,
uint256 trancheInAmtAvailable
) private view returns (RolloverData memory) {
//-----------------------------------------------------------------------------
// The rollover fees are settled by, adjusting the exchange rate
// between `trancheInAmt` and `tokenOutAmt`.
//
int256 feePerc = feePolicy.computePerpRolloverFeePerc(
feePolicy.computeDeviationRatio(
SubscriptionParams({
perpTVL: _reserveValue(),
vaultTVL: vault.getTVL(),
seniorTR: _depositBond.getSeniorTrancheRatio()
})
)
);
//-----------------------------------------------------------------------------
// We compute "price" as the value of a unit token.
// The perp, tranche tokens and the underlying are denominated as fixed point numbers
// with the same number of decimals.
IERC20Upgradeable underlying_ = _reserveAt(0);
uint256 unitTokenAmt = (10 ** _decimals);
uint256 trancheInPrice = _computeReserveTrancheValue(trancheIn, _depositBond, underlying_, unitTokenAmt, false);
uint256 tokenOutPrice = unitTokenAmt;
if (tokenOut != underlying_) {
ITranche trancheOut = ITranche(address(tokenOut));
tokenOutPrice = _computeReserveTrancheValue(
trancheOut,
IBondController(trancheOut.bond()),
underlying_,
unitTokenAmt,
true
);
}
uint256 tokenOutBalance = tokenOut.balanceOf(address(this));
if (trancheInAmtAvailable <= 0 || tokenOutBalance <= 0 || trancheInPrice <= 0 || tokenOutPrice <= 0) {
return RolloverData({ trancheInAmt: 0, tokenOutAmt: 0 });
}
//-----------------------------------------------------------------------------
// Basic rollover with fees:
// (1 +/- f) . (trancheInAmt . trancheInPrice) = (tokenOutAmt . tokenOutPrice)
//-----------------------------------------------------------------------------
// Using perp's tokenOutBalance, we calculate the amount of tokens in to rollover
// the entire balance.
RolloverData memory r = RolloverData({
tokenOutAmt: tokenOutBalance,
trancheInAmt: tokenOutBalance.mulDiv(tokenOutPrice, trancheInPrice, MathUpgradeable.Rounding.Up)
});
// A positive fee percentage implies that perp charges rotators by
// offering tranchesOut for a premium, i.e) more tranches in.
if (feePerc > 0) {
r.trancheInAmt = r.trancheInAmt.mulDiv(FEE_ONE, FEE_ONE - feePerc.toUint256(), MathUpgradeable.Rounding.Up);
}
// A negative fee percentage (or a reward) implies that perp pays the rotators by
// offering tranchesOut at a discount, i.e) fewer tranches in.
else if (feePerc < 0) {
r.trancheInAmt = r.trancheInAmt.mulDiv(FEE_ONE, FEE_ONE + feePerc.abs(), MathUpgradeable.Rounding.Up);
}
//-----------------------------------------------------------------------------
// When the trancheInAmt exceeds trancheInAmtAvailable:
// we fix trancheInAmt = trancheInAmtAvailable and re-calculate tokenOutAmt
if (r.trancheInAmt > trancheInAmtAvailable) {
// Given the amount of tranches In, we compute the amount of tokens out
r.trancheInAmt = trancheInAmtAvailable;
r.tokenOutAmt = trancheInAmtAvailable.mulDiv(trancheInPrice, tokenOutPrice);
// A positive fee percentage implies that perp charges rotators by
// accepting tranchesIn at a discount, i.e) fewer tokens out.
// This results in perp enrichment.
if (feePerc > 0) {
r.tokenOutAmt = r.tokenOutAmt.mulDiv(FEE_ONE - feePerc.abs(), FEE_ONE);
}
// A negative fee percentage (or a reward) implies that perp pays the rotators by
// accepting tranchesIn at a premium, i.e) more tokens out.
// This results in perp debasement.
else if (feePerc < 0) {
r.tokenOutAmt = r.tokenOutAmt.mulDiv(FEE_ONE + feePerc.abs(), FEE_ONE);
}
}
return r;
}
/// @dev Checks if the given token pair is a valid rollover.
/// * When rolling out underlying collateral,
/// - expects incoming tranche to be part of the deposit bond
/// * When rolling out immature tranches,
/// - expects incoming tranche to be part of the deposit bond
/// - expects outgoing tranche to NOT be part of the deposit bond, (ie bondIn != bondOut)
/// - expects outgoing tranche to be in the reserve
/// - expects outgoing tranche to be ready for rollout.
function _isAcceptableRollover(ITranche trancheIn, IERC20Upgradeable tokenOut) private view returns (bool) {
// when rolling out the underlying collateral
if (_isUnderlying(tokenOut)) {
return _isDepositTranche(trancheIn);
}
// when rolling out a normal tranche
ITranche trancheOut = ITranche(address(tokenOut));
return (_isDepositTranche(trancheIn) &&
_inReserve(trancheOut) &&
!_isDepositTranche(trancheOut) &&
_isTimeForRollout(trancheOut));
}
/// @dev Checks if the given bond is valid and can be accepted into the reserve.
/// * Expects the bond to to have the same collateral token as perp.
/// * Expects the bond to have only two tranches.
/// * Expects the bond controller to not withhold any fees.
/// * Expects the bond's time to maturity to be within the max safety bound.
/// * Expects the bond's senior and junior tranches to point back to the bond.
/// @return True if the bond is valid.
function _isValidDepositBond(IBondController bond) private view returns (bool) {
return (bond.collateralToken() == address(_reserveAt(0)) &&
bond.trancheCount() == 2 &&
bond.feeBps() == 0 &&
bond.secondsToMaturity() < maxTrancheMaturitySec &&
(bond.trancheAt(0)).bond() == address(bond) &&
(bond.trancheAt(1)).bond() == address(bond));
}
/// @dev Checks if the given tranche's parent bond's time remaining to maturity is less than `minTrancheMaturitySec`.
/// @return True if the tranche can be rolled out of perp.
function _isTimeForRollout(ITranche tranche) private view returns (bool) {
// NOTE: `secondsToMaturity` will be 0 if the bond is past maturity.
return (IBondController(tranche.bond()).secondsToMaturity() <= minTrancheMaturitySec);
}
/// @dev Checks if the given tranche is the most senior tranche of the current deposit bond.
/// @return True if the tranche is the deposit tranche.
function _isDepositTranche(ITranche tranche) private view returns (bool) {
return (_depositBond.getSeniorTranche() == tranche);
}
/// @dev Enforces the total supply and per tranche mint cap. To be invoked AFTER the mint operation.
function _enforceMintCaps(ITranche trancheIn) private view {
// checks if supply minted using the given tranche is within the cap
if (mintedSupplyPerTranche[trancheIn] > maxMintAmtPerTranche) {
revert ExceededMaxMintPerTranche();
}
// checks if new total supply is within the max supply cap
uint256 newSupply = totalSupply();
if (newSupply > maxSupply) {
revert ExceededMaxSupply();
}
}
/// @dev Fetches the reserve token by index.
function _reserveAt(uint256 i) private view returns (IERC20Upgradeable) {
return IERC20Upgradeable(_reserves.at(i));
}
/// @dev Checks if the given token is in the reserve.
function _inReserve(IERC20Upgradeable token) private view returns (bool) {
return _reserves.contains(address(token));
}
/// @dev Calculates the total value of all the tranches in the reserve.
/// Value of each reserve tranche is denominated in the underlying collateral.
function _reserveValue() private view returns (uint256) {
IERC20Upgradeable underlying_ = _reserveAt(0);
uint256 totalVal = underlying_.balanceOf(address(this));
uint8 reserveCount = uint8(_reserves.length());
for (uint8 i = 1; i < reserveCount; ++i) {
ITranche tranche = ITranche(address(_reserveAt(i)));
IBondController parentBond = IBondController(tranche.bond());
totalVal += _computeReserveTrancheValue(
tranche,
parentBond,
underlying_,
tranche.balanceOf(address(this)),
true
);
}
return totalVal;
}
/// @dev Computes the value of the given amount reserve tranche tokens (i.e ones already accepted in the reserve or to be accepted),
/// based on it's current CDR.
/// NOTE: Callers should round up when valuing reserve assets and round down for incoming assets.
function _computeReserveTrancheValue(
ITranche tranche,
IBondController parentBond,
IERC20Upgradeable collateralToken,
uint256 trancheAmt,
bool roundUp
) private view returns (uint256) {
// NOTE: As an optimization here, we assume that the reserve tranche is immature and has the most senior claim.
uint256 parentBondCollateralBalance = collateralToken.balanceOf(address(parentBond));
uint256 trancheSupply = tranche.totalSupply();
uint256 trancheClaim = MathUpgradeable.min(trancheSupply, parentBondCollateralBalance);
// Tranche supply is zero (its parent bond has no deposits yet);
// the tranche's CDR is assumed 1.0.
return
(trancheSupply > 0)
? trancheClaim.mulDiv(
trancheAmt,
trancheSupply,
roundUp ? MathUpgradeable.Rounding.Up : MathUpgradeable.Rounding.Down
)
: trancheAmt;
}
/// @dev Checks if the given token is the underlying collateral token.
function _isUnderlying(IERC20Upgradeable token) private view returns (bool) {
return (token == _reserveAt(0));
}
/// @dev Checks if caller is another module within the protocol.
/// If so, we do not charge mint/burn for internal operations.
function _isProtocolCaller() private view returns (bool) {
return (msg.sender == address(vault));
}
}// 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.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// 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;
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;
}// 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);
}// 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;
}
}{
"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":"ExceededMaxMintPerTranche","type":"error"},{"inputs":[],"name":"ExceededMaxSupply","type":"error"},{"inputs":[],"name":"ReserveCountOverLimit","type":"error"},{"inputs":[],"name":"UnacceptableParams","type":"error"},{"inputs":[],"name":"UnacceptableRollover","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":"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":false,"internalType":"contract IERC20Upgradeable","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"ReserveSynced","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IBondController","name":"bond","type":"address"}],"name":"UpdatedDepositBond","type":"event"},{"inputs":[],"name":"FEE_ONE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_POLICY_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_RESERVE_COUNT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"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":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bondIssuer","outputs":[{"internalType":"contract IBondIssuer","name":"","type":"address"}],"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":"contract ITranche","name":"trancheIn","type":"address"},{"internalType":"uint256","name":"trancheInAmt","type":"uint256"}],"name":"computeMintAmt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"perpAmtBurnt","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":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ITranche","name":"trancheIn","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"trancheInAmtAvailable","type":"uint256"}],"name":"computeRolloverAmt","outputs":[{"components":[{"internalType":"uint256","name":"tokenOutAmt","type":"uint256"},{"internalType":"uint256","name":"trancheInAmt","type":"uint256"}],"internalType":"struct RolloverData","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":[{"internalType":"contract ITranche","name":"trancheIn","type":"address"},{"internalType":"uint256","name":"trancheInAmt","type":"uint256"}],"name":"deposit","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":"getDepositBond","outputs":[{"internalType":"contract IBondController","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDepositTranche","outputs":[{"internalType":"contract ITranche","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDepositTrancheRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"name":"getReserveAt","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getReserveCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"}],"name":"getReserveTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"}],"name":"getReserveTokenValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getReserveTokensUpForRollover","outputs":[{"internalType":"contract IERC20Upgradeable[]","name":"","type":"address[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getTVL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"}],"name":"inReserve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","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 IERC20Upgradeable","name":"collateral_","type":"address"},{"internalType":"contract IBondIssuer","name":"bondIssuer_","type":"address"},{"internalType":"contract IFeePolicy","name":"feePolicy_","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintAmtPerTranche","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTrancheMaturitySec","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minTrancheMaturitySec","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITranche","name":"","type":"address"}],"name":"mintedSupplyPerTranche","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":[{"internalType":"uint256","name":"perpAmtBurnt","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":[{"internalType":"contract ITranche","name":"trancheIn","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"trancheInAmtAvailable","type":"uint256"}],"name":"rollover","outputs":[{"components":[{"internalType":"uint256","name":"tokenOutAmt","type":"uint256"},{"internalType":"uint256","name":"trancheInAmt","type":"uint256"}],"internalType":"struct RolloverData","name":"","type":"tuple"}],"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 IBondIssuer","name":"bondIssuer_","type":"address"}],"name":"updateBondIssuer","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":"maxSupply_","type":"uint256"},{"internalType":"uint256","name":"maxMintAmtPerTranche_","type":"uint256"}],"name":"updateMintingLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minTrancheMaturitySec_","type":"uint256"},{"internalType":"uint256","name":"maxTrancheMaturitySec_","type":"uint256"}],"name":"updateTolerableTrancheMaturity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRolloverVault","name":"vault_","type":"address"}],"name":"updateVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IRolloverVault","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6146f080620000f36000396000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c8063729256eb116101de57806397b3fcaa1161010f578063d5abeb01116100ad578063eca05e961161007c578063eca05e961461076f578063ef98f88414610779578063f2fde38b1461078c578063fbfa77cf1461079f57600080fd5b8063d5abeb01146106f9578063db006a7514610703578063dd62ed3e14610723578063e7563f3f1461075c57600080fd5b8063a457c2d7116100e9578063a457c2d7146106a7578063a9059cbb146106ba578063aced1661146106cd578063b4abecc7146106e657600080fd5b806397b3fcaa14610684578063998065461461068c5780639db5dbe41461069457600080fd5b8063876853aa1161017c5780638fb69c4b116101565780638fb69c4b1461064e57806392a18b441461065657806395d89b4114610669578063977902171461067157600080fd5b8063876853aa1461062b5780638b539382146106355780638da5cb5b1461063d57600080fd5b806378f3ae74116101b857806378f3ae74146105e957806379cc6790146105fc578063825890381461060f5780638456cb591461062357600080fd5b8063729256eb146105ba57806376500c17146105ce57806377da7d8d146105d657600080fd5b806342966c68116102b85780636048d4911161025657806369f6f92c1161023057806369f6f92c1461056e5780636f307dc31461058157806370a0823114610589578063715018a6146105b257600080fd5b80636048d4911461054b578063614b4a431461055357806361902ffc1461055b57600080fd5b80634ce2f3ca116102925780634ce2f3ca146105105780635c975abb146105235780635dcc45b71461052e5780635ec572511461054157600080fd5b806342966c68146104d757806343cda19d146104ea57806347e7ef24146104fd57600080fd5b80632cff15ce11610325578063332d83d5116102ff578063332d83d51461049f578063364d22fc146104a757806339509351146104bc5780633f4ba83a146104cf57600080fd5b80632cff15ce146104515780632e5d55e114610464578063313ce5671461048557600080fd5b806318160ddd1161036157806318160ddd146103f45780631d8557d71461040657806323b872dd146104105780632bf8f1a51461042357600080fd5b806306fdde0314610388578063095ea7b3146103a6578063107c0418146103c9575b600080fd5b6103906107b3565b60405161039d9190613f8d565b60405180910390f35b6103b96103b4366004613fd5565b610845565b604051901515815260200161039d565b6103dc6103d7366004614001565b61085f565b6040516001600160a01b03909116815260200161039d565b6035545b60405190815260200161039d565b61040e61087a565b005b6103b961041e36600461401a565b610c08565b61043661043136600461401a565b610c2e565b6040805182518152602092830151928101929092520161039d565b61040e61045f36600461405b565b610d04565b6103f861047236600461407d565b6101386020526000908152604090205481565b61012d5460ff165b60405160ff909116815260200161039d565b6103dc610d3a565b6104af610d5f565b60405161039d919061409a565b6103b96104ca366004613fd5565b611007565b61040e611046565b61040e6104e5366004614001565b61107f565b6103f86104f836600461407d565b61108c565b6103f861050b366004613fd5565b611114565b61043661051e36600461401a565b6111d6565b60c95460ff166103b9565b6103b961053c36600461407d565b61122c565b6103f86101335481565b61048d600881565b6103f861123f565b6103f8610569366004613fd5565b61124e565b61040e61057c36600461407d565b611288565b6103dc61133b565b6103f861059736600461407d565b6001600160a01b031660009081526033602052604090205490565b61040e611347565b610131546103dc906001600160a01b031681565b61048d600b81565b6103f86105e436600461407d565b611359565b61040e6105f736600461418a565b61149c565b61040e61060a366004613fd5565b6116b6565b61012e546103dc906001600160a01b031681565b61040e6116cf565b6103f86101375481565b6103f8611708565b6097546001600160a01b03166103dc565b6103dc611728565b61040e61066436600461407d565b611743565b61039061180a565b61040e61067f36600461407d565b611819565b6103f8611861565b6103f8611873565b61040e6106a236600461401a565b611888565b6103b96106b5366004613fd5565b6118ea565b6103b96106c8366004613fd5565b611987565b61012d546103dc9061010090046001600160a01b031681565b61040e6106f436600461405b565b611995565b6103f86101365481565b610716610711366004614001565b6119d3565b60405161039d9190614228565b6103f8610731366004614280565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b61040e61076a36600461407d565b611af9565b6103f86101345481565b610716610787366004614001565b611b24565b61040e61079a36600461407d565b611b37565b61013d546103dc906001600160a01b031681565b6060603680546107c2906142b9565b80601f01602080910402602001604051908101604052809291908181526020018280546107ee906142b9565b801561083b5780601f106108105761010080835404028352916020019161083b565b820191906000526020600020905b81548152906001019060200180831161081e57829003601f168201915b5050505050905090565b600033610853818585611bad565b60019150505b92915050565b600061086961087a565b61087282611cd1565b90505b919050565b610882611cdf565b60c95460ff16610bfc57610131546040805163d5eb27a160e01b815290516000926001600160a01b03169163d5eb27a1916004808301926020929190829003018187875af11580156108d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fc91906142f3565b610132549091506001600160a01b03808316911614801590610922575061092281611d38565b1561097a5761013280546001600160a01b0319166001600160a01b0383169081179091556040519081527f63e01b6b930f6bd3789aab43a62005627cb8a43517cd0569f997fd6b343b80239060200160405180910390a15b600061098761013a611fc5565b90506000610996600183614326565b90505b60ff811615610be55760006109b08260ff16611cd1565b90506000816001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1691906142f3565b90506000610a2c826001600160a01b0316611fcf565b1115610a39575050610bd3565b806001600160a01b031663ae4e7fdf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9b919061433f565b610af357806001600160a01b03166387b652076040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ada57600080fd5b505af1158015610aee573d6000803e3d6000fd5b505050505b6040516370a0823160e01b81523060048201526001600160a01b03808316916333d20e34918591908216906370a0823190602401602060405180830381865afa158015610b44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b689190614361565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610bae57600080fd5b505af1158015610bc2573d6000803e3d6000fd5b50505050610bcf8261204e565b5050505b80610bdd8161437a565b915050610999565b50610bf8610bf36000611cd1565b61204e565b5050505b610c06600160fb55565b565b600033610c168582856121b8565b610c2185858561224a565b60019150505b9392505050565b604080518082019091526000808252602082015261013d546001600160a01b03163314610c6e57604051637bf6a16f60e01b815260040160405180910390fd5b610c7661087a565b610c7e611cdf565b610c866123f5565b610c908484612448565b610cad57604051633c37540f60e21b815260040160405180910390fd5b6000610cba8585856124a4565b60208101519091501580610ccd57508051155b15610cd9579050610cfa565b610ce785826020015161292a565b50610cf684826000015161294a565b5090505b610c27600160fb55565b610d0c612960565b80821115610d2d57604051638d2e9ded60e01b815260040160405180910390fd5b6101339190915561013455565b6000610d4461087a565b61013254610d5a906001600160a01b03166129ba565b905090565b6060610d6961087a565b6000610d7661013a611fc5565b905060008160ff1667ffffffffffffffff811115610d9657610d966140e7565b604051908082528060200260200182016040528015610dbf578160200160208202803683370190505b509050600080610dcf6000611cd1565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610e19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3d9190614361565b1115610e7d578083600081518110610e5757610e57614397565b6001600160a01b039092166020928302919091019091015281610e79816143ad565b9250505b60015b8460ff168160ff161015610ef9576000610e9c8260ff16611cd1565b9050610ea781612a25565b15610ee85780858360ff1681518110610ec257610ec2614397565b6001600160a01b039092166020928302919091019091015283610ee4816143ad565b9450505b50610ef2816143ad565b9050610e80565b5060008260ff1667ffffffffffffffff811115610f1857610f186140e7565b604051908082528060200260200182016040528015610f41578160200160208202803683370190505b5090506000805b8660ff168160ff161015610ffb5760006001600160a01b0316868260ff1681518110610f7657610f76614397565b60200260200101516001600160a01b031614610feb57858160ff1681518110610fa157610fa1614397565b6020026020010151838380610fb5906143ad565b945060ff1681518110610fca57610fca614397565b60200260200101906001600160a01b031690816001600160a01b0316815250505b610ff4816143ad565b9050610f48565b50909550505050505090565b3360008181526034602090815260408083206001600160a01b038716845290915281205490919061085390829086906110419087906143cc565b611bad565b61012d5461010090046001600160a01b0316331461107757604051637bf6a16f60e01b815260040160405180910390fd5b610c06612aa6565b6110893382612af8565b50565b600061109661087a565b61109f82612c2c565b6110ab57506000919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a08231906024015b602060405180830381865afa1580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614361565b600061111e61087a565b611126611cdf565b61112e6123f5565b61113783612c3a565b61115457604051632c88119960e11b815260040160405180910390fd5b60006111608484612c57565b905082158061116d575080155b1561117c5760009150506111cc565b611186848461292a565b506111913382612d7f565b6001600160a01b03841660009081526101386020526040812080548392906111ba9084906143cc565b909155506111c9905084612e40565b90505b610859600160fb55565b60408051808201909152600080825260208201526111f261087a565b6111fc8484612448565b61121957604051633c37540f60e21b815260040160405180910390fd5b6112248484846124a4565b949350505050565b600061123661087a565b61087282612c2c565b61124b6008600a6144c3565b81565b600061125861087a565b61126183612c3a565b61127e57604051632c88119960e11b815260040160405180910390fd5b610c278383612c57565b611290612960565b600860ff16816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f791906144d2565b60ff16146113185760405163c51d798560e01b815260040160405180910390fd5b61012e80546001600160a01b0319166001600160a01b0392909216919091179055565b6000610d5a6000611cd1565b61134f612960565b610c066000612eae565b600061136361087a565b61136c82612c2c565b61137857506000919050565b61138182612f00565b156113b2576040516370a0823160e01b81523060048201526001600160a01b038316906370a08231906024016110d3565b60008290506000816001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141b91906142f3565b9050611224828261142c6000611cd1565b6040516370a0823160e01b81523060048201526001600160a01b038716906370a08231906024015b602060405180830381865afa158015611471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114959190614361565b6001612f27565b600054610100900460ff16158080156114bc5750600054600160ff909116105b806114d65750303b1580156114d6575060005460ff166001145b61154d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b6000805460ff191660011790558015611570576000805461ff0019166101001790555b61157a8686613044565b6115826130a7565b61158a613100565b611592613161565b61159a6131c2565b836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fc91906144d2565b61012d805460ff191660ff9290921691909117905561161d61013a85613223565b506116278461204e565b5061163d61067f6097546001600160a01b031690565b61164682611288565b61164f83611743565b61165c6001600019610d04565b61166860001980611995565b80156116ae576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6116c18233836121b8565b6116cb8282612af8565b5050565b61012d5461010090046001600160a01b0316331461170057604051637bf6a16f60e01b815260040160405180910390fd5b610c06613238565b600061171261087a565b61013254610d5a906001600160a01b0316613275565b600061173261087a565b50610132546001600160a01b031690565b61174b612960565b6117556000611cd1565b6001600160a01b0316816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561179c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c091906142f3565b6001600160a01b0316146117e757604051632c88119960e11b815260040160405180910390fd5b61013180546001600160a01b0319166001600160a01b0392909216919091179055565b6060603780546107c2906142b9565b611821612960565b61012d80546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b600061186b61087a565b610d5a6132e0565b600061187d61087a565b610d5a61013a611fc5565b61189061087a565b611898611cdf565b6118a0612960565b6118a983612c2c565b156118c7576040516328071e2f60e11b815260040160405180910390fd5b6118db6001600160a01b0384168383613452565b6118e5600160fb55565b505050565b3360008181526034602090815260408083206001600160a01b03871684529091528120549091908381101561196f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401611544565b61197c8286868403611bad565b506001949350505050565b60003361085381858561224a565b61012d5461010090046001600160a01b031633146119c657604051637bf6a16f60e01b815260040160405180910390fd5b6101369190915561013755565b60606119dd61087a565b6119e5611cdf565b6119ed6123f5565b60008211611a3a576040805160008082526020820190925290611a32565b6040805180820190915260008082526020820152815260200190600190039081611a0b5790505b509050611aef565b6000611a45836134ca565b9050611a513384612af8565b805160005b8160ff168160ff161015611ae9576000838260ff1681518110611a7b57611a7b614397565b6020026020010151602001511115611ad957611ad7838260ff1681518110611aa557611aa5614397565b602002602001015160000151848360ff1681518110611ac657611ac6614397565b60200260200101516020015161294a565b505b611ae2816143ad565b9050611a56565b50909150505b610875600160fb55565b611b01612960565b61013d80546001600160a01b0319166001600160a01b0392909216919091179055565b6060611b2e61087a565b610872826134ca565b611b3f612960565b6001600160a01b038116611ba45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401611544565b61108981612eae565b6001600160a01b038316611c0f5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401611544565b6001600160a01b038216611c705760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401611544565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061087261013a83613750565b600260fb5403611d315760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611544565b600260fb55565b6000611d446000611cd1565b6001600160a01b0316826001600160a01b031663b2016bd46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611daf91906142f3565b6001600160a01b0316148015611e265750816001600160a01b03166359eb82246040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e229190614361565b6002145b8015611e915750816001600160a01b03166324a9d8536040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f9190614361565b155b8015611eb0575061013454611eae836001600160a01b0316611fcf565b105b8015611f3857506001600160a01b038216611ecc81600061375c565b6001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2d91906142f3565b6001600160a01b0316145b801561087257506001600160a01b038216611f5481600161375c565b6001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb591906142f3565b6001600160a01b03161492915050565b6000610872825490565b600080826001600160a01b031663d59624b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612010573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120349190614361565b9050428111612044576000610c27565b610c2742826144f5565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a0823190602401602060405180830381865afa158015612097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bb9190614361565b604080516001600160a01b0386168152602081018390529192507fd1fbbd81a5fd46d869b5cd6883d99108cd295072be1b09d36381bbc78b686939910160405180910390a161210983612f00565b156121145792915050565b600061211f84612c2c565b905060008211801561212f575080155b156121725761214061013a85613223565b50600b61214e61013a611fc5565b111561216d57604051630aadf0b960e41b815260040160405180910390fd5b6121aa565b8115801561217d5750805b156121aa5761218e61013a856137d1565b506001600160a01b038416600090815261013860205260408120555b5092915050565b600160fb55565b6001600160a01b03838116600090815260346020908152604080832093861683529290522054600019811461224457818110156122375760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401611544565b6122448484848403611bad565b50505050565b6001600160a01b0383166122ae5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401611544565b6001600160a01b0382166123105760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401611544565b6001600160a01b038316600090815260336020526040902054818110156123885760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401611544565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906123e89086815260200190565b60405180910390a3612244565b60c95460ff1615610c065760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611544565b600061245382612f00565b156124685761246183612c3a565b9050610859565b8161247284612c3a565b8015612482575061248281612c2c565b8015612494575061249281612c3a565b155b8015611224575061122481612a25565b604080518082019091526000808252602082015261012e5460408051606081019091526000916001600160a01b031690638b83535b9082906301356c8c90806124eb6132e0565b815261013d5460408051634bd9fe5560e11b815290516020938401936001600160a01b03909316926397b3fcaa92600480820193918290030181865afa158015612539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061255d9190614361565b81526101325460209091019061257b906001600160a01b0316613275565b9052604080516001600160e01b031960e085901b16815282516004820152602083015160248201529101516044820152606401602060405180830381865afa1580156125cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ef9190614361565b6040518263ffffffff1660e01b815260040161260d91815260200190565b602060405180830381865afa15801561262a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061264e9190614361565b9050600061265c6000611cd1565b61012d549091506000906126749060ff16600a6144c3565b610132549091506000906126959089906001600160a01b0316858585612f27565b9050816001600160a01b038881169085161461272357600088905061271f81826001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061271691906142f3565b87876001612f27565b9150505b6040516370a0823160e01b81523060048201526000906001600160a01b038a16906370a0823190602401602060405180830381865afa15801561276a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278e9190614361565b905087158061279b575080155b806127a4575082155b806127ad575081155b156127d65760405180604001604052806000815260200160008152509650505050505050610c27565b60408051808201909152818152600090602081016127f784868860016137e6565b90529050600087131561284a576128406128136008600a6144c3565b61281c89613843565b6128286008600a6144c3565b61283291906144f5565b6020840151919060016137e6565b6020820152612887565b6000871215612887576128816128626008600a6144c3565b61286b89613899565b6128776008600a6144c3565b61283291906143cc565b60208201525b888160200151111561291c57602081018990526128a58985856138ac565b815260008713156128ee576128e76128bc88613899565b6128c86008600a6144c3565b6128d291906144f5565b6128de6008600a6144c3565b835191906138ac565b815261291c565b600087121561291c5761291961290388613899565b61290f6008600a6144c3565b6128d291906143cc565b81525b9a9950505050505050505050565b60006129416001600160a01b03841633308561399e565b610c278361204e565b60006129416001600160a01b0384163384613452565b6097546001600160a01b03163314610c065760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611544565b6040516313612cb160e11b8152600060048201819052906001600160a01b038316906326c25962906024016040805180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121aa9190614508565b600061013354612a9e836001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9091906142f3565b6001600160a01b0316611fcf565b111592915050565b612aae6139d6565b60c9805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038216612b585760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401611544565b6001600160a01b03821660009081526033602052604090205481811015612bcc5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401611544565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b600061087261013a83613a28565b610132546000906001600160a01b0380841691611fb591166129ba565b610132546000908190612c809085906001600160a01b0316612c7884611cd1565b866000612f27565b61013d549091506000906001600160a01b03163314612d165761012e60009054906101000a90046001600160a01b03166001600160a01b0316630a98b70d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ced573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d119190614361565b612d19565b60005b90506000612d2660355490565b9050828115612d4657612d4382612d3b6132e0565b8391906138ac565b90505b8215612d7557612d7283612d5c6008600a6144c3565b612d6691906144f5565b612d3b6008600a6144c3565b90505b9695505050505050565b6001600160a01b038216612dd55760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401611544565b8060356000828254612de791906143cc565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b610137546001600160a01b038216600090815261013860205260409020541115612e7d57604051630381ed1760e31b815260040160405180910390fd5b6000612e8860355490565b9050610136548111156116cb5760405163fb88d21560e01b815260040160405180910390fd5b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000612f0c6000611cd1565b6001600160a01b0316826001600160a01b0316149050919050565b6040516370a0823160e01b81526001600160a01b03858116600483015260009182918616906370a0823190602401602060405180830381865afa158015612f72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f969190614361565b90506000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ffc9190614361565b9050600061300a8284613a4a565b90506000821161301a5785613037565b61303786838761302b57600061302e565b60015b849291906137e6565b9998505050505050505050565b600054610100900460ff1661309d5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b6116cb8282613a60565b600054610100900460ff16610c065760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b600054610100900460ff166131595760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b610c06613ad2565b600054610100900460ff166131ba5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b610c06613b34565b600054610100900460ff1661321b5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b610c06613b99565b6000610c27836001600160a01b038416613bf2565b6132406123f5565b60c9805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612adb3390565b6040516313612cb160e11b8152600060048201819052906001600160a01b038316906326c25962906024016040805180830381865afa1580156132bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c279190614508565b6000806132ed6000611cd1565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015613337573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061335b9190614361565b9050600061336a61013a611fc5565b905060015b8160ff168160ff16101561344957600061338b8260ff16611cd1565b90506000816001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f191906142f3565b6040516370a0823160e01b815230600482015290915061342a908390839089906001600160a01b038416906370a0823190602401611454565b61343490866143cc565b9450505080613442906143ad565b905061336f565b50909392505050565b6040516001600160a01b0383166024820152604481018290526118e590849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152613c41565b606060006134d760355490565b61013d549091506000906001600160a01b0316331461356d5761012e60009054906101000a90046001600160a01b03166001600160a01b031663ca9cbcbe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135689190614361565b613570565b60005b9050600061357f61013a611fc5565b905060008160ff1667ffffffffffffffff81111561359f5761359f6140e7565b6040519080825280602002602001820160405280156135e457816020015b60408051808201909152600080825260208201528152602001906001900390816135bd5790505b50905060005b8260ff168160ff1610156137465760006136068260ff16611cd1565b6040805180820182526001600160a01b03831680825291516370a0823160e01b8152306004820152929350916020830191613690918c918b916370a0823190602401602060405180830381865afa158015613665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136899190614361565b91906138ac565b815250838360ff16815181106136a8576136a8614397565b602090810291909101015284156137355761370f856136c96008600a6144c3565b6136d391906144f5565b6136df6008600a6144c3565b858560ff16815181106136f4576136f4614397565b6020026020010151602001516138ac9092919063ffffffff16565b838360ff168151811061372457613724614397565b602002602001015160200181815250505b5061373f816143ad565b90506135ea565b5095945050505050565b6000610c278383613d29565b6040516313612cb160e11b815260ff821660048201526000906001600160a01b038416906326c25962906024016040805180830381865afa1580156137a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c99190614508565b509392505050565b6000610c27836001600160a01b038416613d53565b6000806137f48686866138ac565b9050600183600281111561380a5761380a614536565b1480156138275750600084806138225761382261454c565b868809115b1561383a576138376001826143cc565b90505b95945050505050565b6000808212156138955760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401611544565b5090565b6000808212156138955781600003610872565b60008080600019858709858702925082811083820303915050806000036138e6578382816138dc576138dc61454c565b0492505050610c27565b8084116139355760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152606401611544565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526122449085906323b872dd60e01b9060840161347e565b60c95460ff16610c065760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401611544565b6001600160a01b03811660009081526001830160205260408120541515610c27565b6000818310613a595781610c27565b5090919050565b600054610100900460ff16613ab95760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b6036613ac583826145a8565b5060376118e582826145a8565b600054610100900460ff16613b2b5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b610c0633612eae565b600054610100900460ff16613b8d5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b60c9805460ff19169055565b600054610100900460ff166121b15760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b6000818152600183016020526040812054613c3957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610859565b506000610859565b6000613c96826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e469092919063ffffffff16565b9050805160001480613cb7575080806020019051810190613cb7919061433f565b6118e55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611544565b6000826000018281548110613d4057613d40614397565b9060005260206000200154905092915050565b60008181526001830160205260408120548015613e3c576000613d776001836144f5565b8554909150600090613d8b906001906144f5565b9050818114613df0576000866000018281548110613dab57613dab614397565b9060005260206000200154905080876000018481548110613dce57613dce614397565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613e0157613e01614668565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610859565b6000915050610859565b6060611224848460008585600080866001600160a01b03168587604051613e6d919061467e565b60006040518083038185875af1925050503d8060008114613eaa576040519150601f19603f3d011682016040523d82523d6000602084013e613eaf565b606091505b5091509150613ec087838387613ecb565b979650505050505050565b60608315613f3a578251600003613f33576001600160a01b0385163b613f335760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611544565b5081611224565b6112248383815115613f4f5781518083602001fd5b8060405162461bcd60e51b81526004016115449190613f8d565b60005b83811015613f84578181015183820152602001613f6c565b50506000910152565b6020815260008251806020840152613fac816040850160208701613f69565b601f01601f19169190910160400192915050565b6001600160a01b038116811461108957600080fd5b60008060408385031215613fe857600080fd5b8235613ff381613fc0565b946020939093013593505050565b60006020828403121561401357600080fd5b5035919050565b60008060006060848603121561402f57600080fd5b833561403a81613fc0565b9250602084013561404a81613fc0565b929592945050506040919091013590565b6000806040838503121561406e57600080fd5b50508035926020909101359150565b60006020828403121561408f57600080fd5b8135610c2781613fc0565b6020808252825182820181905260009190848201906040850190845b818110156140db5783516001600160a01b0316835292840192918401916001016140b6565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261410e57600080fd5b813567ffffffffffffffff80821115614129576141296140e7565b604051601f8301601f19908116603f01168101908282118183101715614151576141516140e7565b8160405283815286602085880101111561416a57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156141a257600080fd5b853567ffffffffffffffff808211156141ba57600080fd5b6141c689838a016140fd565b965060208801359150808211156141dc57600080fd5b506141e9888289016140fd565b94505060408601356141fa81613fc0565b9250606086013561420a81613fc0565b9150608086013561421a81613fc0565b809150509295509295909350565b602080825282518282018190526000919060409081850190868401855b8281101561427357815180516001600160a01b03168552860151868501529284019290850190600101614245565b5091979650505050505050565b6000806040838503121561429357600080fd5b823561429e81613fc0565b915060208301356142ae81613fc0565b809150509250929050565b600181811c908216806142cd57607f821691505b6020821081036142ed57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561430557600080fd5b8151610c2781613fc0565b634e487b7160e01b600052601160045260246000fd5b60ff828116828216039081111561085957610859614310565b60006020828403121561435157600080fd5b81518015158114610c2757600080fd5b60006020828403121561437357600080fd5b5051919050565b600060ff82168061438d5761438d614310565b6000190192915050565b634e487b7160e01b600052603260045260246000fd5b600060ff821660ff81036143c3576143c3614310565b60010192915050565b8082018082111561085957610859614310565b600181815b8085111561441a57816000190482111561440057614400614310565b8085161561440d57918102915b93841c93908002906143e4565b509250929050565b60008261443157506001610859565b8161443e57506000610859565b8160018114614454576002811461445e5761447a565b6001915050610859565b60ff84111561446f5761446f614310565b50506001821b610859565b5060208310610133831016604e8410600b841016171561449d575081810a610859565b6144a783836143df565b80600019048211156144bb576144bb614310565b029392505050565b6000610c2760ff841683614422565b6000602082840312156144e457600080fd5b815160ff81168114610c2757600080fd5b8181038181111561085957610859614310565b6000806040838503121561451b57600080fd5b825161452681613fc0565b6020939093015192949293505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b601f8211156118e557600081815260208120601f850160051c810160208610156145895750805b601f850160051c820191505b818110156116ae57828155600101614595565b815167ffffffffffffffff8111156145c2576145c26140e7565b6145d6816145d084546142b9565b84614562565b602080601f83116001811461460b57600084156145f35750858301515b600019600386901b1c1916600185901b1785556116ae565b600085815260208120601f198616915b8281101561463a5788860151825594840194600190910190840161461b565b50858210156146585787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603160045260246000fd5b60008251614690818460208701613f69565b919091019291505056fe496e697469616c697a61626c653a20636f6e7472616374206973206e6f742069a2646970667358221220117437feaf340e0dba3091f1ecdc2dc97a8597e7902ee832f48f151e08b9e97d64736f6c63430008140033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103835760003560e01c8063729256eb116101de57806397b3fcaa1161010f578063d5abeb01116100ad578063eca05e961161007c578063eca05e961461076f578063ef98f88414610779578063f2fde38b1461078c578063fbfa77cf1461079f57600080fd5b8063d5abeb01146106f9578063db006a7514610703578063dd62ed3e14610723578063e7563f3f1461075c57600080fd5b8063a457c2d7116100e9578063a457c2d7146106a7578063a9059cbb146106ba578063aced1661146106cd578063b4abecc7146106e657600080fd5b806397b3fcaa14610684578063998065461461068c5780639db5dbe41461069457600080fd5b8063876853aa1161017c5780638fb69c4b116101565780638fb69c4b1461064e57806392a18b441461065657806395d89b4114610669578063977902171461067157600080fd5b8063876853aa1461062b5780638b539382146106355780638da5cb5b1461063d57600080fd5b806378f3ae74116101b857806378f3ae74146105e957806379cc6790146105fc578063825890381461060f5780638456cb591461062357600080fd5b8063729256eb146105ba57806376500c17146105ce57806377da7d8d146105d657600080fd5b806342966c68116102b85780636048d4911161025657806369f6f92c1161023057806369f6f92c1461056e5780636f307dc31461058157806370a0823114610589578063715018a6146105b257600080fd5b80636048d4911461054b578063614b4a431461055357806361902ffc1461055b57600080fd5b80634ce2f3ca116102925780634ce2f3ca146105105780635c975abb146105235780635dcc45b71461052e5780635ec572511461054157600080fd5b806342966c68146104d757806343cda19d146104ea57806347e7ef24146104fd57600080fd5b80632cff15ce11610325578063332d83d5116102ff578063332d83d51461049f578063364d22fc146104a757806339509351146104bc5780633f4ba83a146104cf57600080fd5b80632cff15ce146104515780632e5d55e114610464578063313ce5671461048557600080fd5b806318160ddd1161036157806318160ddd146103f45780631d8557d71461040657806323b872dd146104105780632bf8f1a51461042357600080fd5b806306fdde0314610388578063095ea7b3146103a6578063107c0418146103c9575b600080fd5b6103906107b3565b60405161039d9190613f8d565b60405180910390f35b6103b96103b4366004613fd5565b610845565b604051901515815260200161039d565b6103dc6103d7366004614001565b61085f565b6040516001600160a01b03909116815260200161039d565b6035545b60405190815260200161039d565b61040e61087a565b005b6103b961041e36600461401a565b610c08565b61043661043136600461401a565b610c2e565b6040805182518152602092830151928101929092520161039d565b61040e61045f36600461405b565b610d04565b6103f861047236600461407d565b6101386020526000908152604090205481565b61012d5460ff165b60405160ff909116815260200161039d565b6103dc610d3a565b6104af610d5f565b60405161039d919061409a565b6103b96104ca366004613fd5565b611007565b61040e611046565b61040e6104e5366004614001565b61107f565b6103f86104f836600461407d565b61108c565b6103f861050b366004613fd5565b611114565b61043661051e36600461401a565b6111d6565b60c95460ff166103b9565b6103b961053c36600461407d565b61122c565b6103f86101335481565b61048d600881565b6103f861123f565b6103f8610569366004613fd5565b61124e565b61040e61057c36600461407d565b611288565b6103dc61133b565b6103f861059736600461407d565b6001600160a01b031660009081526033602052604090205490565b61040e611347565b610131546103dc906001600160a01b031681565b61048d600b81565b6103f86105e436600461407d565b611359565b61040e6105f736600461418a565b61149c565b61040e61060a366004613fd5565b6116b6565b61012e546103dc906001600160a01b031681565b61040e6116cf565b6103f86101375481565b6103f8611708565b6097546001600160a01b03166103dc565b6103dc611728565b61040e61066436600461407d565b611743565b61039061180a565b61040e61067f36600461407d565b611819565b6103f8611861565b6103f8611873565b61040e6106a236600461401a565b611888565b6103b96106b5366004613fd5565b6118ea565b6103b96106c8366004613fd5565b611987565b61012d546103dc9061010090046001600160a01b031681565b61040e6106f436600461405b565b611995565b6103f86101365481565b610716610711366004614001565b6119d3565b60405161039d9190614228565b6103f8610731366004614280565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b61040e61076a36600461407d565b611af9565b6103f86101345481565b610716610787366004614001565b611b24565b61040e61079a36600461407d565b611b37565b61013d546103dc906001600160a01b031681565b6060603680546107c2906142b9565b80601f01602080910402602001604051908101604052809291908181526020018280546107ee906142b9565b801561083b5780601f106108105761010080835404028352916020019161083b565b820191906000526020600020905b81548152906001019060200180831161081e57829003601f168201915b5050505050905090565b600033610853818585611bad565b60019150505b92915050565b600061086961087a565b61087282611cd1565b90505b919050565b610882611cdf565b60c95460ff16610bfc57610131546040805163d5eb27a160e01b815290516000926001600160a01b03169163d5eb27a1916004808301926020929190829003018187875af11580156108d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fc91906142f3565b610132549091506001600160a01b03808316911614801590610922575061092281611d38565b1561097a5761013280546001600160a01b0319166001600160a01b0383169081179091556040519081527f63e01b6b930f6bd3789aab43a62005627cb8a43517cd0569f997fd6b343b80239060200160405180910390a15b600061098761013a611fc5565b90506000610996600183614326565b90505b60ff811615610be55760006109b08260ff16611cd1565b90506000816001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1691906142f3565b90506000610a2c826001600160a01b0316611fcf565b1115610a39575050610bd3565b806001600160a01b031663ae4e7fdf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9b919061433f565b610af357806001600160a01b03166387b652076040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ada57600080fd5b505af1158015610aee573d6000803e3d6000fd5b505050505b6040516370a0823160e01b81523060048201526001600160a01b03808316916333d20e34918591908216906370a0823190602401602060405180830381865afa158015610b44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b689190614361565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610bae57600080fd5b505af1158015610bc2573d6000803e3d6000fd5b50505050610bcf8261204e565b5050505b80610bdd8161437a565b915050610999565b50610bf8610bf36000611cd1565b61204e565b5050505b610c06600160fb55565b565b600033610c168582856121b8565b610c2185858561224a565b60019150505b9392505050565b604080518082019091526000808252602082015261013d546001600160a01b03163314610c6e57604051637bf6a16f60e01b815260040160405180910390fd5b610c7661087a565b610c7e611cdf565b610c866123f5565b610c908484612448565b610cad57604051633c37540f60e21b815260040160405180910390fd5b6000610cba8585856124a4565b60208101519091501580610ccd57508051155b15610cd9579050610cfa565b610ce785826020015161292a565b50610cf684826000015161294a565b5090505b610c27600160fb55565b610d0c612960565b80821115610d2d57604051638d2e9ded60e01b815260040160405180910390fd5b6101339190915561013455565b6000610d4461087a565b61013254610d5a906001600160a01b03166129ba565b905090565b6060610d6961087a565b6000610d7661013a611fc5565b905060008160ff1667ffffffffffffffff811115610d9657610d966140e7565b604051908082528060200260200182016040528015610dbf578160200160208202803683370190505b509050600080610dcf6000611cd1565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610e19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3d9190614361565b1115610e7d578083600081518110610e5757610e57614397565b6001600160a01b039092166020928302919091019091015281610e79816143ad565b9250505b60015b8460ff168160ff161015610ef9576000610e9c8260ff16611cd1565b9050610ea781612a25565b15610ee85780858360ff1681518110610ec257610ec2614397565b6001600160a01b039092166020928302919091019091015283610ee4816143ad565b9450505b50610ef2816143ad565b9050610e80565b5060008260ff1667ffffffffffffffff811115610f1857610f186140e7565b604051908082528060200260200182016040528015610f41578160200160208202803683370190505b5090506000805b8660ff168160ff161015610ffb5760006001600160a01b0316868260ff1681518110610f7657610f76614397565b60200260200101516001600160a01b031614610feb57858160ff1681518110610fa157610fa1614397565b6020026020010151838380610fb5906143ad565b945060ff1681518110610fca57610fca614397565b60200260200101906001600160a01b031690816001600160a01b0316815250505b610ff4816143ad565b9050610f48565b50909550505050505090565b3360008181526034602090815260408083206001600160a01b038716845290915281205490919061085390829086906110419087906143cc565b611bad565b61012d5461010090046001600160a01b0316331461107757604051637bf6a16f60e01b815260040160405180910390fd5b610c06612aa6565b6110893382612af8565b50565b600061109661087a565b61109f82612c2c565b6110ab57506000919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a08231906024015b602060405180830381865afa1580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614361565b600061111e61087a565b611126611cdf565b61112e6123f5565b61113783612c3a565b61115457604051632c88119960e11b815260040160405180910390fd5b60006111608484612c57565b905082158061116d575080155b1561117c5760009150506111cc565b611186848461292a565b506111913382612d7f565b6001600160a01b03841660009081526101386020526040812080548392906111ba9084906143cc565b909155506111c9905084612e40565b90505b610859600160fb55565b60408051808201909152600080825260208201526111f261087a565b6111fc8484612448565b61121957604051633c37540f60e21b815260040160405180910390fd5b6112248484846124a4565b949350505050565b600061123661087a565b61087282612c2c565b61124b6008600a6144c3565b81565b600061125861087a565b61126183612c3a565b61127e57604051632c88119960e11b815260040160405180910390fd5b610c278383612c57565b611290612960565b600860ff16816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f791906144d2565b60ff16146113185760405163c51d798560e01b815260040160405180910390fd5b61012e80546001600160a01b0319166001600160a01b0392909216919091179055565b6000610d5a6000611cd1565b61134f612960565b610c066000612eae565b600061136361087a565b61136c82612c2c565b61137857506000919050565b61138182612f00565b156113b2576040516370a0823160e01b81523060048201526001600160a01b038316906370a08231906024016110d3565b60008290506000816001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141b91906142f3565b9050611224828261142c6000611cd1565b6040516370a0823160e01b81523060048201526001600160a01b038716906370a08231906024015b602060405180830381865afa158015611471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114959190614361565b6001612f27565b600054610100900460ff16158080156114bc5750600054600160ff909116105b806114d65750303b1580156114d6575060005460ff166001145b61154d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b6000805460ff191660011790558015611570576000805461ff0019166101001790555b61157a8686613044565b6115826130a7565b61158a613100565b611592613161565b61159a6131c2565b836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fc91906144d2565b61012d805460ff191660ff9290921691909117905561161d61013a85613223565b506116278461204e565b5061163d61067f6097546001600160a01b031690565b61164682611288565b61164f83611743565b61165c6001600019610d04565b61166860001980611995565b80156116ae576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6116c18233836121b8565b6116cb8282612af8565b5050565b61012d5461010090046001600160a01b0316331461170057604051637bf6a16f60e01b815260040160405180910390fd5b610c06613238565b600061171261087a565b61013254610d5a906001600160a01b0316613275565b600061173261087a565b50610132546001600160a01b031690565b61174b612960565b6117556000611cd1565b6001600160a01b0316816001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561179c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c091906142f3565b6001600160a01b0316146117e757604051632c88119960e11b815260040160405180910390fd5b61013180546001600160a01b0319166001600160a01b0392909216919091179055565b6060603780546107c2906142b9565b611821612960565b61012d80546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b600061186b61087a565b610d5a6132e0565b600061187d61087a565b610d5a61013a611fc5565b61189061087a565b611898611cdf565b6118a0612960565b6118a983612c2c565b156118c7576040516328071e2f60e11b815260040160405180910390fd5b6118db6001600160a01b0384168383613452565b6118e5600160fb55565b505050565b3360008181526034602090815260408083206001600160a01b03871684529091528120549091908381101561196f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401611544565b61197c8286868403611bad565b506001949350505050565b60003361085381858561224a565b61012d5461010090046001600160a01b031633146119c657604051637bf6a16f60e01b815260040160405180910390fd5b6101369190915561013755565b60606119dd61087a565b6119e5611cdf565b6119ed6123f5565b60008211611a3a576040805160008082526020820190925290611a32565b6040805180820190915260008082526020820152815260200190600190039081611a0b5790505b509050611aef565b6000611a45836134ca565b9050611a513384612af8565b805160005b8160ff168160ff161015611ae9576000838260ff1681518110611a7b57611a7b614397565b6020026020010151602001511115611ad957611ad7838260ff1681518110611aa557611aa5614397565b602002602001015160000151848360ff1681518110611ac657611ac6614397565b60200260200101516020015161294a565b505b611ae2816143ad565b9050611a56565b50909150505b610875600160fb55565b611b01612960565b61013d80546001600160a01b0319166001600160a01b0392909216919091179055565b6060611b2e61087a565b610872826134ca565b611b3f612960565b6001600160a01b038116611ba45760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401611544565b61108981612eae565b6001600160a01b038316611c0f5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401611544565b6001600160a01b038216611c705760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401611544565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061087261013a83613750565b600260fb5403611d315760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611544565b600260fb55565b6000611d446000611cd1565b6001600160a01b0316826001600160a01b031663b2016bd46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611daf91906142f3565b6001600160a01b0316148015611e265750816001600160a01b03166359eb82246040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e229190614361565b6002145b8015611e915750816001600160a01b03166324a9d8536040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f9190614361565b155b8015611eb0575061013454611eae836001600160a01b0316611fcf565b105b8015611f3857506001600160a01b038216611ecc81600061375c565b6001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2d91906142f3565b6001600160a01b0316145b801561087257506001600160a01b038216611f5481600161375c565b6001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb591906142f3565b6001600160a01b03161492915050565b6000610872825490565b600080826001600160a01b031663d59624b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612010573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120349190614361565b9050428111612044576000610c27565b610c2742826144f5565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a0823190602401602060405180830381865afa158015612097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bb9190614361565b604080516001600160a01b0386168152602081018390529192507fd1fbbd81a5fd46d869b5cd6883d99108cd295072be1b09d36381bbc78b686939910160405180910390a161210983612f00565b156121145792915050565b600061211f84612c2c565b905060008211801561212f575080155b156121725761214061013a85613223565b50600b61214e61013a611fc5565b111561216d57604051630aadf0b960e41b815260040160405180910390fd5b6121aa565b8115801561217d5750805b156121aa5761218e61013a856137d1565b506001600160a01b038416600090815261013860205260408120555b5092915050565b600160fb55565b6001600160a01b03838116600090815260346020908152604080832093861683529290522054600019811461224457818110156122375760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401611544565b6122448484848403611bad565b50505050565b6001600160a01b0383166122ae5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401611544565b6001600160a01b0382166123105760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401611544565b6001600160a01b038316600090815260336020526040902054818110156123885760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401611544565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906123e89086815260200190565b60405180910390a3612244565b60c95460ff1615610c065760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611544565b600061245382612f00565b156124685761246183612c3a565b9050610859565b8161247284612c3a565b8015612482575061248281612c2c565b8015612494575061249281612c3a565b155b8015611224575061122481612a25565b604080518082019091526000808252602082015261012e5460408051606081019091526000916001600160a01b031690638b83535b9082906301356c8c90806124eb6132e0565b815261013d5460408051634bd9fe5560e11b815290516020938401936001600160a01b03909316926397b3fcaa92600480820193918290030181865afa158015612539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061255d9190614361565b81526101325460209091019061257b906001600160a01b0316613275565b9052604080516001600160e01b031960e085901b16815282516004820152602083015160248201529101516044820152606401602060405180830381865afa1580156125cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ef9190614361565b6040518263ffffffff1660e01b815260040161260d91815260200190565b602060405180830381865afa15801561262a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061264e9190614361565b9050600061265c6000611cd1565b61012d549091506000906126749060ff16600a6144c3565b610132549091506000906126959089906001600160a01b0316858585612f27565b9050816001600160a01b038881169085161461272357600088905061271f81826001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061271691906142f3565b87876001612f27565b9150505b6040516370a0823160e01b81523060048201526000906001600160a01b038a16906370a0823190602401602060405180830381865afa15801561276a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278e9190614361565b905087158061279b575080155b806127a4575082155b806127ad575081155b156127d65760405180604001604052806000815260200160008152509650505050505050610c27565b60408051808201909152818152600090602081016127f784868860016137e6565b90529050600087131561284a576128406128136008600a6144c3565b61281c89613843565b6128286008600a6144c3565b61283291906144f5565b6020840151919060016137e6565b6020820152612887565b6000871215612887576128816128626008600a6144c3565b61286b89613899565b6128776008600a6144c3565b61283291906143cc565b60208201525b888160200151111561291c57602081018990526128a58985856138ac565b815260008713156128ee576128e76128bc88613899565b6128c86008600a6144c3565b6128d291906144f5565b6128de6008600a6144c3565b835191906138ac565b815261291c565b600087121561291c5761291961290388613899565b61290f6008600a6144c3565b6128d291906143cc565b81525b9a9950505050505050505050565b60006129416001600160a01b03841633308561399e565b610c278361204e565b60006129416001600160a01b0384163384613452565b6097546001600160a01b03163314610c065760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611544565b6040516313612cb160e11b8152600060048201819052906001600160a01b038316906326c25962906024016040805180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121aa9190614508565b600061013354612a9e836001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9091906142f3565b6001600160a01b0316611fcf565b111592915050565b612aae6139d6565b60c9805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b038216612b585760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401611544565b6001600160a01b03821660009081526033602052604090205481811015612bcc5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401611544565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b600061087261013a83613a28565b610132546000906001600160a01b0380841691611fb591166129ba565b610132546000908190612c809085906001600160a01b0316612c7884611cd1565b866000612f27565b61013d549091506000906001600160a01b03163314612d165761012e60009054906101000a90046001600160a01b03166001600160a01b0316630a98b70d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ced573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d119190614361565b612d19565b60005b90506000612d2660355490565b9050828115612d4657612d4382612d3b6132e0565b8391906138ac565b90505b8215612d7557612d7283612d5c6008600a6144c3565b612d6691906144f5565b612d3b6008600a6144c3565b90505b9695505050505050565b6001600160a01b038216612dd55760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401611544565b8060356000828254612de791906143cc565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b610137546001600160a01b038216600090815261013860205260409020541115612e7d57604051630381ed1760e31b815260040160405180910390fd5b6000612e8860355490565b9050610136548111156116cb5760405163fb88d21560e01b815260040160405180910390fd5b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000612f0c6000611cd1565b6001600160a01b0316826001600160a01b0316149050919050565b6040516370a0823160e01b81526001600160a01b03858116600483015260009182918616906370a0823190602401602060405180830381865afa158015612f72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f969190614361565b90506000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ffc9190614361565b9050600061300a8284613a4a565b90506000821161301a5785613037565b61303786838761302b57600061302e565b60015b849291906137e6565b9998505050505050505050565b600054610100900460ff1661309d5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b6116cb8282613a60565b600054610100900460ff16610c065760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b600054610100900460ff166131595760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b610c06613ad2565b600054610100900460ff166131ba5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b610c06613b34565b600054610100900460ff1661321b5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b610c06613b99565b6000610c27836001600160a01b038416613bf2565b6132406123f5565b60c9805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612adb3390565b6040516313612cb160e11b8152600060048201819052906001600160a01b038316906326c25962906024016040805180830381865afa1580156132bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c279190614508565b6000806132ed6000611cd1565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015613337573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061335b9190614361565b9050600061336a61013a611fc5565b905060015b8160ff168160ff16101561344957600061338b8260ff16611cd1565b90506000816001600160a01b03166364c9ec6f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f191906142f3565b6040516370a0823160e01b815230600482015290915061342a908390839089906001600160a01b038416906370a0823190602401611454565b61343490866143cc565b9450505080613442906143ad565b905061336f565b50909392505050565b6040516001600160a01b0383166024820152604481018290526118e590849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152613c41565b606060006134d760355490565b61013d549091506000906001600160a01b0316331461356d5761012e60009054906101000a90046001600160a01b03166001600160a01b031663ca9cbcbe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135689190614361565b613570565b60005b9050600061357f61013a611fc5565b905060008160ff1667ffffffffffffffff81111561359f5761359f6140e7565b6040519080825280602002602001820160405280156135e457816020015b60408051808201909152600080825260208201528152602001906001900390816135bd5790505b50905060005b8260ff168160ff1610156137465760006136068260ff16611cd1565b6040805180820182526001600160a01b03831680825291516370a0823160e01b8152306004820152929350916020830191613690918c918b916370a0823190602401602060405180830381865afa158015613665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136899190614361565b91906138ac565b815250838360ff16815181106136a8576136a8614397565b602090810291909101015284156137355761370f856136c96008600a6144c3565b6136d391906144f5565b6136df6008600a6144c3565b858560ff16815181106136f4576136f4614397565b6020026020010151602001516138ac9092919063ffffffff16565b838360ff168151811061372457613724614397565b602002602001015160200181815250505b5061373f816143ad565b90506135ea565b5095945050505050565b6000610c278383613d29565b6040516313612cb160e11b815260ff821660048201526000906001600160a01b038416906326c25962906024016040805180830381865afa1580156137a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c99190614508565b509392505050565b6000610c27836001600160a01b038416613d53565b6000806137f48686866138ac565b9050600183600281111561380a5761380a614536565b1480156138275750600084806138225761382261454c565b868809115b1561383a576138376001826143cc565b90505b95945050505050565b6000808212156138955760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152606401611544565b5090565b6000808212156138955781600003610872565b60008080600019858709858702925082811083820303915050806000036138e6578382816138dc576138dc61454c565b0492505050610c27565b8084116139355760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152606401611544565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526122449085906323b872dd60e01b9060840161347e565b60c95460ff16610c065760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401611544565b6001600160a01b03811660009081526001830160205260408120541515610c27565b6000818310613a595781610c27565b5090919050565b600054610100900460ff16613ab95760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b6036613ac583826145a8565b5060376118e582826145a8565b600054610100900460ff16613b2b5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b610c0633612eae565b600054610100900460ff16613b8d5760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b60c9805460ff19169055565b600054610100900460ff166121b15760405162461bcd60e51b815260206004820152602b602482015260008051602061469b83398151915260448201526a6e697469616c697a696e6760a81b6064820152608401611544565b6000818152600183016020526040812054613c3957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610859565b506000610859565b6000613c96826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e469092919063ffffffff16565b9050805160001480613cb7575080806020019051810190613cb7919061433f565b6118e55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611544565b6000826000018281548110613d4057613d40614397565b9060005260206000200154905092915050565b60008181526001830160205260408120548015613e3c576000613d776001836144f5565b8554909150600090613d8b906001906144f5565b9050818114613df0576000866000018281548110613dab57613dab614397565b9060005260206000200154905080876000018481548110613dce57613dce614397565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613e0157613e01614668565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610859565b6000915050610859565b6060611224848460008585600080866001600160a01b03168587604051613e6d919061467e565b60006040518083038185875af1925050503d8060008114613eaa576040519150601f19603f3d011682016040523d82523d6000602084013e613eaf565b606091505b5091509150613ec087838387613ecb565b979650505050505050565b60608315613f3a578251600003613f33576001600160a01b0385163b613f335760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611544565b5081611224565b6112248383815115613f4f5781518083602001fd5b8060405162461bcd60e51b81526004016115449190613f8d565b60005b83811015613f84578181015183820152602001613f6c565b50506000910152565b6020815260008251806020840152613fac816040850160208701613f69565b601f01601f19169190910160400192915050565b6001600160a01b038116811461108957600080fd5b60008060408385031215613fe857600080fd5b8235613ff381613fc0565b946020939093013593505050565b60006020828403121561401357600080fd5b5035919050565b60008060006060848603121561402f57600080fd5b833561403a81613fc0565b9250602084013561404a81613fc0565b929592945050506040919091013590565b6000806040838503121561406e57600080fd5b50508035926020909101359150565b60006020828403121561408f57600080fd5b8135610c2781613fc0565b6020808252825182820181905260009190848201906040850190845b818110156140db5783516001600160a01b0316835292840192918401916001016140b6565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261410e57600080fd5b813567ffffffffffffffff80821115614129576141296140e7565b604051601f8301601f19908116603f01168101908282118183101715614151576141516140e7565b8160405283815286602085880101111561416a57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156141a257600080fd5b853567ffffffffffffffff808211156141ba57600080fd5b6141c689838a016140fd565b965060208801359150808211156141dc57600080fd5b506141e9888289016140fd565b94505060408601356141fa81613fc0565b9250606086013561420a81613fc0565b9150608086013561421a81613fc0565b809150509295509295909350565b602080825282518282018190526000919060409081850190868401855b8281101561427357815180516001600160a01b03168552860151868501529284019290850190600101614245565b5091979650505050505050565b6000806040838503121561429357600080fd5b823561429e81613fc0565b915060208301356142ae81613fc0565b809150509250929050565b600181811c908216806142cd57607f821691505b6020821081036142ed57634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561430557600080fd5b8151610c2781613fc0565b634e487b7160e01b600052601160045260246000fd5b60ff828116828216039081111561085957610859614310565b60006020828403121561435157600080fd5b81518015158114610c2757600080fd5b60006020828403121561437357600080fd5b5051919050565b600060ff82168061438d5761438d614310565b6000190192915050565b634e487b7160e01b600052603260045260246000fd5b600060ff821660ff81036143c3576143c3614310565b60010192915050565b8082018082111561085957610859614310565b600181815b8085111561441a57816000190482111561440057614400614310565b8085161561440d57918102915b93841c93908002906143e4565b509250929050565b60008261443157506001610859565b8161443e57506000610859565b8160018114614454576002811461445e5761447a565b6001915050610859565b60ff84111561446f5761446f614310565b50506001821b610859565b5060208310610133831016604e8410600b841016171561449d575081810a610859565b6144a783836143df565b80600019048211156144bb576144bb614310565b029392505050565b6000610c2760ff841683614422565b6000602082840312156144e457600080fd5b815160ff81168114610c2757600080fd5b8181038181111561085957610859614310565b6000806040838503121561451b57600080fd5b825161452681613fc0565b6020939093015192949293505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b601f8211156118e557600081815260208120601f850160051c810160208610156145895750805b601f850160051c820191505b818110156116ae57828155600101614595565b815167ffffffffffffffff8111156145c2576145c26140e7565b6145d6816145d084546142b9565b84614562565b602080601f83116001811461460b57600084156145f35750858301515b600019600386901b1c1916600185901b1785556116ae565b600085815260208120601f198616915b8281101561463a5788860151825594840194600190910190840161461b565b50858210156146585787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603160045260246000fd5b60008251614690818460208701613f69565b919091019291505056fe496e697469616c697a61626c653a20636f6e7472616374206973206e6f742069a2646970667358221220117437feaf340e0dba3091f1ecdc2dc97a8597e7902ee832f48f151e08b9e97d64736f6c63430008140033
Loading...
Loading
Loading...
Loading
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.