Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PriceFeedCurvePTAssetBounded
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import {BaseFeedCurvePTAssetBounded} from "src/spectra-oracles/chainlinkFeeds/stableswap-ng/BaseFeedCurvePTAssetBounded.sol";
/**
* @title PriceFeedCurvePTAssetBounded contract
* @author Spectra Finance
* @notice Price feed for the PT in asset upper bounded by the redemption value and lower bounded by the ZCB model
*/
contract PriceFeedCurvePTAssetBounded is BaseFeedCurvePTAssetBounded {
string public constant description =
"IBT/PT Curve Pool Oracle: TWAP PT price in asset. Lower bounded by the ZCB model according to _impliedRateand upper bounded by the redemption value";
constructor() BaseFeedCurvePTAssetBounded() {}
function initialize(address _pt, address _pool, uint256 _impliedRate) external initializer {
super.__BaseFeedCurvePTAssetBounded_init(_pt, _pool, _impliedRate);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @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 Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 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 in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._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 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._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() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @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 {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.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.
*
* The initial owner is set to the address provided by the deployer. 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 Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @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 {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156FlashBorrower.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC3156 FlashBorrower, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*/
interface IERC3156FlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156FlashLender.sol)
pragma solidity ^0.8.20;
import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol";
/**
* @dev Interface of the ERC3156 FlashLender, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*/
interface IERC3156FlashLender {
/**
* @dev The amount of currency available to be lended.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(address token) external view returns (uint256);
/**
* @dev The fee to be charged for a given loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(address token, uint256 amount) external view returns (uint256);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @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 v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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 Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (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 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
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.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 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.
uint256 twos = denominator & (0 - denominator);
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 (unsignedRoundsUp(rounding) && 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
* towards zero.
*
* 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @dev Interface of Chainlink v3 aggregator, as defined in
// https://github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol
// solhint-disable-next-line interface-starts-with-i
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import {IERC20Metadata} from "openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface for Curve TwoCrypto-NG pool
*/
interface ICurveNGPool is IERC20Metadata {
function coins(uint256 index) external view returns (address);
function balances(uint256 index) external view returns (uint256);
function A() external view returns (uint256);
function gamma() external view returns (uint256);
function D() external view returns (uint256);
function token() external view returns (address);
function price_scale() external view returns (uint256);
function price_oracle() external view returns (uint256);
function future_A_gamma_time() external view returns (uint256);
function future_A_gamma() external view returns (uint256);
function initial_A_gamma_time() external view returns (uint256);
function initial_A_gamma() external view returns (uint256);
function fee_gamma() external view returns (uint256);
function mid_fee() external view returns (uint256);
function out_fee() external view returns (uint256);
function allowed_extra_profit() external view returns (uint256);
function adjustment_step() external view returns (uint256);
function admin_fee() external view returns (uint256);
function ma_time() external view returns (uint256);
function get_virtual_price() external view returns (uint256);
function fee() external view returns (uint256);
function get_dy(uint256 i, uint256 j, uint256 dx) external view returns (uint256);
function get_dx(uint256 i, uint256 j, uint256 dy) external view returns (uint256);
function last_prices() external view returns (uint256);
function calc_token_amount(
uint256[2] calldata amounts,
bool deposit
) external view returns (uint256);
function calc_withdraw_one_coin(
uint256 _token_amount,
uint256 i
) external view returns (uint256);
function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external returns (uint256);
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy,
address receiver
) external returns (uint256);
function add_liquidity(
uint256[2] calldata amounts,
uint256 min_mint_amount
) external returns (uint256);
function add_liquidity(
uint256[2] calldata amounts,
uint256 min_mint_amount,
address receiver
) external returns (uint256);
function remove_liquidity(uint256 amount, uint256[2] calldata min_amounts) external;
function remove_liquidity(
uint256 amount,
uint256[2] calldata min_amounts,
address receiver
) external;
function remove_liquidity_one_coin(
uint256 token_amount,
uint256 i,
uint256 min_amount
) external;
function remove_liquidity_one_coin(
uint256 token_amount,
uint256 i,
uint256 min_amount,
address receiver
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import "openzeppelin-contracts/interfaces/IERC20.sol";
import "openzeppelin-contracts/interfaces/IERC20Metadata.sol";
import "openzeppelin-contracts/interfaces/IERC3156FlashLender.sol";
interface IPrincipalToken is IERC20, IERC20Metadata, IERC3156FlashLender {
/* ERRORS
*****************************************************************************************************************/
error InvalidDecimals();
error BeaconNotSet();
error PTExpired();
error PTNotExpired();
error RateError();
error AddressError();
error UnauthorizedCaller();
error RatesAtExpiryAlreadyStored();
error ERC5143SlippageProtectionFailed();
error InsufficientBalance();
error FlashLoanExceedsMaxAmount();
error FlashLoanCallbackFailed();
error NoRewardsProxy();
error ClaimRewardsFailed();
/* Functions
*****************************************************************************************************************/
function initialize(address _ibt, uint256 _duration, address initialAuthority) external;
/**
* @notice Toggle Pause
* @dev Should only be called in extraordinary situations by the admin of the contract
*/
function pause() external;
/**
* @notice Toggle UnPause
* @dev Should only be called in extraordinary situations by the admin of the contract
*/
function unPause() external;
/**
* @notice Deposits amount of assets in the PT vault
* @param assets The amount of assets being deposited
* @param receiver The receiver address of the shares
* @return shares The amount of shares minted (same amount for PT & yt)
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @notice Deposits amount of assets in the PT vault
* @param assets The amount of assets being deposited
* @param ptReceiver The receiver address of the PTs
* @param ytReceiver the receiver address of the YTs
* @return shares The amount of shares minted (same amount for PT & yt)
*/
function deposit(
uint256 assets,
address ptReceiver,
address ytReceiver
) external returns (uint256 shares);
/**
* @notice Deposits amount of assets with a lower bound on shares received
* @param assets The amount of assets being deposited
* @param ptReceiver The receiver address of the PTs
* @param ytReceiver The receiver address of the YTs
* @param minShares The minimum allowed shares from this deposit
* @return shares The amount of shares actually minted to the receiver
*/
function deposit(
uint256 assets,
address ptReceiver,
address ytReceiver,
uint256 minShares
) external returns (uint256 shares);
/**
* @notice Same as normal deposit but with IBTs
* @param ibts The amount of IBT being deposited
* @param receiver The receiver address of the shares
* @return shares The amount of shares minted to the receiver
*/
function depositIBT(uint256 ibts, address receiver) external returns (uint256 shares);
/**
* @notice Same as normal deposit but with IBTs
* @param ibts The amount of IBT being deposited
* @param ptReceiver The receiver address of the PTs
* @param ytReceiver the receiver address of the YTs
* @return shares The amount of shares minted to the receiver
*/
function depositIBT(
uint256 ibts,
address ptReceiver,
address ytReceiver
) external returns (uint256 shares);
/**
* @notice Same as normal deposit but with IBTs
* @param ibts The amount of IBT being deposited
* @param ptReceiver The receiver address of the PTs
* @param ytReceiver The receiver address of the YTs
* @param minShares The minimum allowed shares from this deposit
* @return shares The amount of shares minted to the receiver
*/
function depositIBT(
uint256 ibts,
address ptReceiver,
address ytReceiver,
uint256 minShares
) external returns (uint256 shares);
/**
* @notice Burns owner's shares (PTs and YTs before expiry, PTs after expiry)
* and sends assets to receiver
* @param shares The amount of shares to burn
* @param receiver The address that will receive the assets
* @param owner The owner of the shares
* @return assets The actual amount of assets received for burning the shares
*/
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/**
* @notice Burns owner's shares (PTs and YTs before expiry, PTs after expiry)
* and sends assets to receiver
* @param shares The amount of shares to burn
* @param receiver The address that will receive the assets
* @param owner The owner of the shares
* @param minAssets The minimum assets that should be returned to user
* @return assets The actual amount of assets received for burning the shares
*/
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 minAssets
) external returns (uint256 assets);
/**
* @notice Burns owner's shares (PTs and YTs before expiry, PTs after expiry)
* and sends IBTs to receiver
* @param shares The amount of shares to burn
* @param receiver The address that will receive the IBTs
* @param owner The owner of the shares
* @return ibts The actual amount of IBT received for burning the shares
*/
function redeemForIBT(
uint256 shares,
address receiver,
address owner
) external returns (uint256 ibts);
/**
* @notice Burns owner's shares (PTs and YTs before expiry, PTs after expiry)
* and sends IBTs to receiver
* @param shares The amount of shares to burn
* @param receiver The address that will receive the IBTs
* @param owner The owner of the shares
* @param minIbts The minimum IBTs that should be returned to user
* @return ibts The actual amount of IBT received for burning the shares
*/
function redeemForIBT(
uint256 shares,
address receiver,
address owner,
uint256 minIbts
) external returns (uint256 ibts);
/**
* @notice Burns owner's shares (before expiry : PTs and YTs) and sends assets to receiver
* @param assets The amount of assets to be received
* @param receiver The address that will receive the assets
* @param owner The owner of the shares (PTs and YTs)
* @return shares The actual amount of shares burnt for receiving the assets
*/
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256 shares);
/**
* @notice Burns owner's shares (before expiry : PTs and YTs) and sends assets to receiver
* @param assets The amount of assets to be received
* @param receiver The address that will receive the assets
* @param owner The owner of the shares (PTs and YTs)
* @param maxShares The maximum shares allowed to be burnt
* @return shares The actual amount of shares burnt for receiving the assets
*/
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 maxShares
) external returns (uint256 shares);
/**
* @notice Burns owner's shares (before expiry : PTs and YTs) and sends IBTs to receiver
* @param ibts The amount of IBT to be received
* @param receiver The address that will receive the IBTs
* @param owner The owner of the shares (PTs and YTs)
* @return shares The actual amount of shares burnt for receiving the IBTs
*/
function withdrawIBT(
uint256 ibts,
address receiver,
address owner
) external returns (uint256 shares);
/**
* @notice Burns owner's shares (before expiry : PTs and YTs) and sends IBTs to receiver
* @param ibts The amount of IBT to be received
* @param receiver The address that will receive the IBTs
* @param owner The owner of the shares (PTs and YTs)
* @param maxShares The maximum shares allowed to be burnt
* @return shares The actual amount of shares burnt for receiving the IBTs
*/
function withdrawIBT(
uint256 ibts,
address receiver,
address owner,
uint256 maxShares
) external returns (uint256 shares);
/**
* @notice Updates _user's yield since last update
* @param _user The user whose yield will be updated
* @return updatedUserYieldInIBT The unclaimed yield of the user in IBT (not just the updated yield)
*/
function updateYield(address _user) external returns (uint256 updatedUserYieldInIBT);
/**
* @notice Claims caller's unclaimed yield in asset
* @param _receiver The receiver of yield
* @param _minAssets The minimum amount of assets that should be received
* @return yieldInAsset The amount of yield claimed in asset
*/
function claimYield(
address _receiver,
uint256 _minAssets
) external returns (uint256 yieldInAsset);
/**
* @notice Claims caller's unclaimed yield in IBT
* @param _receiver The receiver of yield
* @param _minIBT The minimum amount of IBT that should be received
* @return yieldInIBT The amount of yield claimed in IBT
*/
function claimYieldInIBT(
address _receiver,
uint256 _minIBT
) external returns (uint256 yieldInIBT);
/**
* @notice Claims the collected ibt fees and redeems them to the fee collector
* @return ibts The amount of IBTs sent to the fee collector
*/
function claimFees() external returns (uint256 ibts);
/**
* @notice Updates yield of both sender and receiver of YTs
* @param _from the sender of YTs
* @param _to the receiver of YTs
*/
function beforeYtTransfer(address _from, address _to) external;
/**
* Call the claimRewards function of the rewards contract
* @param data The optional data to be passed to the rewards contract
*/
function claimRewards(bytes memory data) external;
/* SETTERS
*****************************************************************************************************************/
/**
* @notice Stores PT and IBT rates at expiry. Ideally, it should be called the day of expiry
*/
function storeRatesAtExpiry() external;
/** Set a new Rewards Proxy
* @param _rewardsProxy The address of the new reward proxy
*/
function setRewardsProxy(address _rewardsProxy) external;
/* GETTERS
*****************************************************************************************************************/
/**
* @notice Returns the amount of shares minted for the theorical deposited amount of assets
* @param assets The amount of assets deposited
* @return The amount of shares minted
*/
function previewDeposit(uint256 assets) external view returns (uint256);
/**
* @notice Returns the amount of shares minted for the theorical deposited amount of IBT
* @param ibts The amount of IBT deposited
* @return The amount of shares minted
*/
function previewDepositIBT(uint256 ibts) external view returns (uint256);
/**
* @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
* @param receiver The receiver of the shares
* @return The maximum amount of assets that can be deposited
*/
function maxDeposit(address receiver) external view returns (uint256);
/**
* @notice Returns the theorical amount of shares that need to be burnt to receive assets of underlying
* @param assets The amount of assets to receive
* @return The amount of shares burnt
*/
function previewWithdraw(uint256 assets) external view returns (uint256);
/**
* @notice Returns the theorical amount of shares that need to be burnt to receive amount of IBT
* @param ibts The amount of IBT to receive
* @return The amount of shares burnt
*/
function previewWithdrawIBT(uint256 ibts) external view returns (uint256);
/**
* @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
* @param owner The owner of the Vault shares
* @return The maximum amount of assets that can be withdrawn
*/
function maxWithdraw(address owner) external view returns (uint256);
/**
* @notice Returns the maximum amount of the IBT that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
* @param owner The owner of the Vault shares
* @return The maximum amount of IBT that can be withdrawn
*/
function maxWithdrawIBT(address owner) external view returns (uint256);
/**
* @notice Returns the amount of assets received for the theorical amount of burnt shares
* @param shares The amount of shares to burn
* @return The amount of assets received
*/
function previewRedeem(uint256 shares) external view returns (uint256);
/**
* @notice Returns the amount of IBT received for the theorical amount of burnt shares
* @param shares The amount of shares to burn
* @return The amount of IBT received
*/
function previewRedeemForIBT(uint256 shares) external view returns (uint256);
/**
* @notice Returns the maximum amount of Vault shares that can be redeemed by the owner
* @notice This function behaves differently before and after expiry. Before expiry an equal amount of PT and YT
* needs to be burnt, while after expiry only PTs are burnt.
* @param owner The owner of the shares
* @return The maximum amount of shares that can be redeemed
*/
function maxRedeem(address owner) external view returns (uint256);
/**
* Returns the total amount of the underlying asset that is owned by the Vault in the form of IBT.
*/
function totalAssets() external view returns (uint256);
/**
* @notice Converts an underlying amount in principal. Equivalent to ERC-4626's convertToShares method.
* @param underlyingAmount The amount of underlying (or assets) to convert
* @return The resulting amount of principal (or shares)
*/
function convertToPrincipal(uint256 underlyingAmount) external view returns (uint256);
/**
* @notice Converts a principal amount in underlying. Equivalent to ERC-4626's convertToAssets method.
* @param principalAmount The amount of principal (or shares) to convert
* @return The resulting amount of underlying (or assets)
*/
function convertToUnderlying(uint256 principalAmount) external view returns (uint256);
/**
* @notice Returns whether or not the contract is paused.
* @return true if the contract is paused, and false otherwise
*/
function paused() external view returns (bool);
/**
* @notice Returns the unix timestamp (uint256) at which the PT contract expires
* @return The unix timestamp (uint256) when PTs become redeemable
*/
function maturity() external view returns (uint256);
/**
* @notice Returns the duration of the PT contract
* @return The duration (in s) to expiry/maturity of the PT contract
*/
function getDuration() external view returns (uint256);
/**
* @notice Returns the address of the underlying token (or asset). Equivalent to ERC-4626's asset method.
* @return The address of the underlying token (or asset)
*/
function underlying() external view returns (address);
/**
* @notice Returns the IBT address of the PT contract
* @return ibt The address of the IBT
*/
function getIBT() external view returns (address ibt);
/**
* @notice Returns the yt address of the PT contract
* @return yt The address of the yt
*/
function getYT() external view returns (address yt);
/**
* @notice Returns the current ibtRate
* @return The current ibtRate
*/
function getIBTRate() external view returns (uint256);
/**
* @notice Returns the current ptRate
* @return The current ptRate
*/
function getPTRate() external view returns (uint256);
/**
* @notice Returns 1 unit of IBT
* @return The IBT unit
*/
function getIBTUnit() external view returns (uint256);
/**
* @notice Get the unclaimed fees in IBT
* @return The unclaimed fees in IBT
*/
function getUnclaimedFeesInIBT() external view returns (uint256);
/**
* @notice Get the total collected fees in IBT (claimed and unclaimed)
* @return The total fees in IBT
*/
function getTotalFeesInIBT() external view returns (uint256);
/**
* @notice Get the tokenization fee of the PT
* @return The tokenization fee
*/
function getTokenizationFee() external view returns (uint256);
/**
* @notice Get the current IBT yield of the user
* @param _user The address of the user to get the current yield from
* @return The yield of the user in IBT
*/
function getCurrentYieldOfUserInIBT(address _user) external view returns (uint256);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
interface IStableSwapNG {
function A() external view returns (uint256);
function A_precise() external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function D_ma_time() external view returns (uint256);
function D_oracle() external view returns (uint256);
function N_COINS() external view returns (uint256);
function add_liquidity(
uint256[] memory _amounts,
uint256 _min_mint_amount,
address _receiver
) external returns (uint256);
function admin_balances(uint256 arg0) external view returns (uint256);
function admin_fee() external view returns (uint256);
function allowance(address arg0, address arg1) external view returns (uint256);
function approve(address _spender, uint256 _value) external returns (bool);
function balanceOf(address arg0) external view returns (uint256);
function balances(uint256 i) external view returns (uint256);
function calc_token_amount(
uint256[] memory _amounts,
bool _is_deposit
) external view returns (uint256);
function calc_withdraw_one_coin(uint256 _burn_amount, int128 i) external view returns (uint256);
function coins(uint256 arg0) external view returns (address);
function decimals() external view returns (uint8);
function dynamic_fee(int128 i, int128 j) external view returns (uint256);
function ema_price(uint256 i) external view returns (uint256);
function exchange(int128 i, int128 j, uint256 _dx, uint256 _min_dy) external returns (uint256);
function exchange(
int128 i,
int128 j,
uint256 _dx,
uint256 _min_dy,
address _receiver
) external returns (uint256);
function exchange_received(
int128 i,
int128 j,
uint256 _dx,
uint256 _min_dy
) external returns (uint256);
function exchange_received(
int128 i,
int128 j,
uint256 _dx,
uint256 _min_dy,
address _receiver
) external returns (uint256);
function fee() external view returns (uint256);
function future_A() external view returns (uint256);
function future_A_time() external view returns (uint256);
function get_balances() external view returns (uint256[] memory);
function get_dx(int128 i, int128 j, uint256 dy) external view returns (uint256);
function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256);
function get_p(uint256 i) external view returns (uint256);
function get_virtual_price() external view returns (uint256);
function initial_A() external view returns (uint256);
function initial_A_time() external view returns (uint256);
function last_price(uint256 i) external view returns (uint256);
function ma_exp_time() external view returns (uint256);
function ma_last_time() external view returns (uint256);
function name() external view returns (string memory);
function nonces(address arg0) external view returns (uint256);
function offpeg_fee_multiplier() external view returns (uint256);
function permit(
address _owner,
address _spender,
uint256 _value,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) external returns (bool);
function price_oracle(uint256 i) external view returns (uint256);
function ramp_A(uint256 _future_A, uint256 _future_time) external;
function remove_liquidity(
uint256 _burn_amount,
uint256[] memory _min_amounts
) external returns (uint256[] memory);
function remove_liquidity(
uint256 _burn_amount,
uint256[] memory _min_amounts,
address _receiver
) external returns (uint256[] memory);
function remove_liquidity(
uint256 _burn_amount,
uint256[] memory _min_amounts,
address _receiver,
bool _claim_admin_fees
) external returns (uint256[] memory);
function remove_liquidity_imbalance(
uint256[] memory _amounts,
uint256 _max_burn_amount
) external returns (uint256);
function remove_liquidity_imbalance(
uint256[] memory _amounts,
uint256 _max_burn_amount,
address _receiver
) external returns (uint256);
function remove_liquidity_one_coin(
uint256 _burn_amount,
int128 i,
uint256 _min_received
) external returns (uint256);
function remove_liquidity_one_coin(
uint256 _burn_amount,
int128 i,
uint256 _min_received,
address _receiver
) external returns (uint256);
function salt() external view returns (bytes32);
function set_ma_exp_time(uint256 _ma_exp_time, uint256 _D_ma_time) external;
function set_new_fee(uint256 _new_fee, uint256 _new_offpeg_fee_multiplier) external;
function stop_ramp_A() external;
function stored_rates() external view returns (uint256[] memory);
function symbol() external view returns (string memory);
function totalSupply() external view returns (uint256);
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
function version() external view returns (string memory);
function withdraw_admin_fees() external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import {Math} from "openzeppelin-math/Math.sol";
import {IERC20} from "openzeppelin-contracts/interfaces/IERC20.sol";
import {IERC4626} from "openzeppelin-contracts/interfaces/IERC4626.sol";
import {ICurveNGPool} from "../interfaces/ICurveNGPool.sol";
import {IStableSwapNG} from "../interfaces/IStableSwapNG.sol";
import {IPrincipalToken} from "../interfaces/IPrincipalToken.sol";
import {PTPricingLib} from "./PTPricingLib.sol";
/**
* @dev Utilities for computing prices of Spectra PTs, YTs and LP tokens in Curve CryptoSwap pools.
*/
library CurveOracleLib {
using Math for uint256;
error PoolLiquidityError();
uint256 public constant CURVE_UNIT = 1e18;
/**
* This function returns the TWAP rate PT/Asset on a Curve StableSwap NG pool, but takes into account the current rate of IBT
* This accounts for special cases where underlying asset becomes insolvent and has decreasing exchangeRate
* @param pool Address of the Curve Pool to get rate from
* @return PT/Underlying exchange rate
*/
function getPTToAssetRateSNG(address pool) public view returns (uint256) {
uint256 ptToIBTRate = getPTToIBTRateSNG(pool);
IERC4626 ibt = IERC4626(ICurveNGPool(pool).coins(0));
return ibt.previewRedeem(ptToIBTRate);
}
/**
* @dev This function returns the TWAP rate PT/IBT on a Curve StableSwap NG pool
* This accounts for special cases where underlying asset becomes insolvent and has decreasing exchangeRate
* @param pool Address of the Curve Pool to get rate from
* @return PT/IBT exchange rate
*/
function getPTToIBTRateSNG(address pool) public view returns (uint256) {
IPrincipalToken pt = IPrincipalToken(ICurveNGPool(pool).coins(1));
uint256 maturity = pt.maturity();
if (maturity <= block.timestamp) {
return pt.previewRedeemForIBT(pt.getIBTUnit());
} else {
uint256[] memory storedRates = IStableSwapNG(pool).stored_rates();
return
pt.getIBTUnit().mulDiv(storedRates[1], storedRates[0]).mulDiv(
IStableSwapNG(pool).price_oracle(0),
CURVE_UNIT
);
}
}
/**
* This function returns the TWAP rate YT/Asset on a Curve StableSwap NG pool
* @param pool Curve Pool to get rate from
* @return YT/Underlying exchange rate
*/
function getYTToAssetRateSNG(address pool) internal view returns (uint256) {
IPrincipalToken pt = IPrincipalToken(IStableSwapNG(pool).coins(1));
uint256 ptToAssetRateCore = pt.previewRedeem(pt.getIBTUnit());
uint256 ptToAssetRateOracle = getPTToAssetRateSNG(pool);
if (ptToAssetRateOracle > ptToAssetRateCore) {
revert PoolLiquidityError();
}
return (ptToAssetRateCore - ptToAssetRateOracle);
}
/**
* @dev This function returns the TWAP rate YT/IBT on a Curve StableSwap NG pool
* @param pool Curve Pool to get rate from
* @return YT/IBT exchange rate
*/
function getYTToIBTRateSNG(address pool) internal view returns (uint256) {
IPrincipalToken pt = IPrincipalToken(IStableSwapNG(pool).coins(1));
uint256 ptToIBTRateCore = pt.previewRedeemForIBT(pt.getIBTUnit());
uint256 ptToIBTRateOracle = getPTToIBTRateSNG(pool);
if (ptToIBTRateOracle > ptToIBTRateCore) {
revert PoolLiquidityError();
}
return ptToIBTRateCore - ptToIBTRateOracle;
}
/**
* This function returns the TWAP rate LP/Asset on a Curve StableSwap NG pool, and takes into account the current rate of IBT
* @param pool Address of the Curve Pool to get rate from
* @return LP/Underlying exchange rate
*/
function getLPTToAssetRateSNG(address pool) internal view returns (uint256) {
uint256 lptToIBTRate = getLPTToIBTRateSNG(pool);
IERC4626 ibt = IERC4626(IStableSwapNG(pool).coins(0));
return ibt.previewRedeem(lptToIBTRate);
}
/**
* @dev This function returns the TWAP rate LP/IBT on a Curve StableSwap NG pool
* @param pool Address of the Curve Pool to get rate from
* @return LP/IBT exchange rate
*/
function getLPTToIBTRateSNG(address pool) internal view returns (uint256) {
IPrincipalToken pt = IPrincipalToken(IStableSwapNG(pool).coins(1));
uint256 maturity = pt.maturity();
uint256 balIBT = IStableSwapNG(pool).balances(0);
uint256 balPT = IStableSwapNG(pool).balances(1);
uint256 supplyLPT = IERC20(pool).totalSupply();
if (maturity <= block.timestamp) {
return
pt.previewRedeemForIBT(balPT.mulDiv(CURVE_UNIT, supplyLPT)) +
balIBT.mulDiv(CURVE_UNIT, supplyLPT);
} else {
uint256 ptToIBTRate = getPTToIBTRateSNG(pool);
return
((balPT.mulDiv(ptToIBTRate, pt.getIBTUnit())) + balIBT).mulDiv(
CURVE_UNIT,
supplyLPT
);
}
}
/**
* @notice Computes the price of the Principal Token in asset upper bounded by the redemption value and lower bounded by the ZCB model
* @param pool The address of the Curve Pool to get rate from
* @param impliedRate The implied rate expressed in 18 decimals. For example 30% is expressed as 3e17
* @return The price of the Principal Token in asset
*/
function getBoundedPTPrice(address pool, uint256 impliedRate) internal view returns (uint256) {
IPrincipalToken pt = IPrincipalToken(IStableSwapNG(pool).coins(1));
uint256 maturity = pt.maturity();
if (maturity <= block.timestamp) {
return pt.previewRedeem(pt.getIBTUnit());
}
uint256 futurePTValue = pt.previewRedeem(pt.getIBTUnit());
uint256 ptToAssetRate = getPTToAssetRateSNG(pool);
uint256 ptZCB = PTPricingLib.getPTPriceZCBModel(
pt.previewRedeem(pt.getIBTUnit()),
impliedRate,
block.timestamp,
maturity
);
uint256 lowerBound = Math.max(ptToAssetRate, ptZCB);
uint256 upperBound = Math.min(lowerBound, futurePTValue);
return upperBound;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pragma solidity ^0.8.0;
/* solhint-disable */
/**
* @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).
*
* Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural
* exponentiation and logarithm (where the base is Euler's number).
*
* @author Fernando Martinelli - @fernandomartinelli
* @author Sergio Yuhjtman - @sergioyuhjtman
* @author Daniel Fernandez - @dmf7z
*/
library LogExpMath {
// All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying
// two numbers, and multiply by ONE when dividing them.
// All arguments and return values are 18 decimal fixed point numbers.
int256 constant ONE_18 = 1e18;
// Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the
// case of ln36, 36 decimals.
int256 constant ONE_20 = 1e20;
int256 constant ONE_36 = 1e36;
// The domain of natural exponentiation is bound by the word size and number of decimals used.
//
// Because internally the result will be stored using 20 decimals, the largest possible result is
// (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.
// The smallest possible result is 10^(-18), which makes largest negative argument
// ln(10^(-18)) = -41.446531673892822312.
// We use 130.0 and -41.0 to have some safety margin.
int256 constant MAX_NATURAL_EXPONENT = 130e18;
int256 constant MIN_NATURAL_EXPONENT = -41e18;
// Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point
// 256 bit integer.
int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;
int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;
uint256 constant MILD_EXPONENT_BOUND = 2 ** 254 / uint256(ONE_20);
// 18 decimal constants
int256 constant x0 = 128000000000000000000; // 2ˆ7
int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)
int256 constant x1 = 64000000000000000000; // 2ˆ6
int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)
// 20 decimal constants
int256 constant x2 = 3200000000000000000000; // 2ˆ5
int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)
int256 constant x3 = 1600000000000000000000; // 2ˆ4
int256 constant a3 = 888611052050787263676000000; // eˆ(x3)
int256 constant x4 = 800000000000000000000; // 2ˆ3
int256 constant a4 = 298095798704172827474000; // eˆ(x4)
int256 constant x5 = 400000000000000000000; // 2ˆ2
int256 constant a5 = 5459815003314423907810; // eˆ(x5)
int256 constant x6 = 200000000000000000000; // 2ˆ1
int256 constant a6 = 738905609893065022723; // eˆ(x6)
int256 constant x7 = 100000000000000000000; // 2ˆ0
int256 constant a7 = 271828182845904523536; // eˆ(x7)
int256 constant x8 = 50000000000000000000; // 2ˆ-1
int256 constant a8 = 164872127070012814685; // eˆ(x8)
int256 constant x9 = 25000000000000000000; // 2ˆ-2
int256 constant a9 = 128402541668774148407; // eˆ(x9)
int256 constant x10 = 12500000000000000000; // 2ˆ-3
int256 constant a10 = 113314845306682631683; // eˆ(x10)
int256 constant x11 = 6250000000000000000; // 2ˆ-4
int256 constant a11 = 106449445891785942956; // eˆ(x11)
/**
* @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.
*
* Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.
*/
function exp(int256 x) internal pure returns (int256) {
unchecked {
require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, "Invalid exponent");
if (x < 0) {
// We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it
// fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).
// Fixed point division requires multiplying by ONE_18.
return ((ONE_18 * ONE_18) / exp(-x));
}
// First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,
// where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7
// because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the
// decomposition.
// At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this
// decomposition, which will be lower than the smallest x_n.
// exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.
// We mutate x by subtracting x_n, making it the remainder of the decomposition.
// The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause
// intermediate overflows. Instead we store them as plain integers, with 0 decimals.
// Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the
// decomposition.
// For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct
// it and compute the accumulated product.
int256 firstAN;
if (x >= x0) {
x -= x0;
firstAN = a0;
} else if (x >= x1) {
x -= x1;
firstAN = a1;
} else {
firstAN = 1; // One with no decimal places
}
// We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the
// smaller terms.
x *= 100;
// `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point
// one. Recall that fixed point multiplication requires dividing by ONE_20.
int256 product = ONE_20;
if (x >= x2) {
x -= x2;
product = (product * a2) / ONE_20;
}
if (x >= x3) {
x -= x3;
product = (product * a3) / ONE_20;
}
if (x >= x4) {
x -= x4;
product = (product * a4) / ONE_20;
}
if (x >= x5) {
x -= x5;
product = (product * a5) / ONE_20;
}
if (x >= x6) {
x -= x6;
product = (product * a6) / ONE_20;
}
if (x >= x7) {
x -= x7;
product = (product * a7) / ONE_20;
}
if (x >= x8) {
x -= x8;
product = (product * a8) / ONE_20;
}
if (x >= x9) {
x -= x9;
product = (product * a9) / ONE_20;
}
// x10 and x11 are unnecessary here since we have high enough precision already.
// Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series
// expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).
int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.
int256 term; // Each term in the sum, where the nth term is (x^n / n!).
// The first term is simply x.
term = x;
seriesSum += term;
// Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,
// multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.
term = ((term * x) / ONE_20) / 2;
seriesSum += term;
term = ((term * x) / ONE_20) / 3;
seriesSum += term;
term = ((term * x) / ONE_20) / 4;
seriesSum += term;
term = ((term * x) / ONE_20) / 5;
seriesSum += term;
term = ((term * x) / ONE_20) / 6;
seriesSum += term;
term = ((term * x) / ONE_20) / 7;
seriesSum += term;
term = ((term * x) / ONE_20) / 8;
seriesSum += term;
term = ((term * x) / ONE_20) / 9;
seriesSum += term;
term = ((term * x) / ONE_20) / 10;
seriesSum += term;
term = ((term * x) / ONE_20) / 11;
seriesSum += term;
term = ((term * x) / ONE_20) / 12;
seriesSum += term;
// 12 Taylor terms are sufficient for 18 decimal precision.
// We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor
// approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply
// all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),
// and then drop two digits to return an 18 decimal value.
return (((product * seriesSum) / ONE_20) * firstAN) / 100;
}
}
/**
* @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
*/
function ln(int256 a) internal pure returns (int256) {
unchecked {
// The real natural logarithm is not defined for negative numbers or zero.
require(a > 0, "out of bounds");
if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {
return _ln_36(a) / ONE_18;
} else {
return _ln(a);
}
}
}
/**
* @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.
*
* Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.
*/
function pow(uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
if (y == 0) {
// We solve the 0^0 indetermination by making it equal one.
return uint256(ONE_18);
}
if (x == 0) {
return 0;
}
// Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to
// arrive at that r`esult. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means
// x^y = exp(y * ln(x)).
// The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.
require(x < 2 ** 255, "x out of bounds");
int256 x_int256 = int256(x);
// We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In
// both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.
// This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.
require(y < MILD_EXPONENT_BOUND, "y out of bounds");
int256 y_int256 = int256(y);
int256 logx_times_y;
if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {
int256 ln_36_x = _ln_36(x_int256);
// ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just
// bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal
// multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the
// (downscaled) last 18 decimals.
logx_times_y = ((ln_36_x / ONE_18) *
y_int256 +
((ln_36_x % ONE_18) * y_int256) /
ONE_18);
} else {
logx_times_y = _ln(x_int256) * y_int256;
}
logx_times_y /= ONE_18;
// Finally, we compute exp(y * ln(x)) to arrive at x^y
require(
MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT,
"product out of bounds"
);
return uint256(exp(logx_times_y));
}
}
/**
* @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
*/
function _ln(int256 a) private pure returns (int256) {
unchecked {
if (a < ONE_18) {
// Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less
// than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.
// Fixed point division requires multiplying by ONE_18.
return (-_ln((ONE_18 * ONE_18) / a));
}
// First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which
// we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,
// ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot
// be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.
// At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this
// decomposition, which will be lower than the smallest a_n.
// ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.
// We mutate a by subtracting a_n, making it the remainder of the decomposition.
// For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point
// numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by
// ONE_18 to convert them to fixed point.
// For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide
// by it and compute the accumulated sum.
int256 sum = 0;
if (a >= a0 * ONE_18) {
a /= a0; // Integer, not fixed point division
sum += x0;
}
if (a >= a1 * ONE_18) {
a /= a1; // Integer, not fixed point division
sum += x1;
}
// All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.
sum *= 100;
a *= 100;
// Because further a_n are 20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.
if (a >= a2) {
a = (a * ONE_20) / a2;
sum += x2;
}
if (a >= a3) {
a = (a * ONE_20) / a3;
sum += x3;
}
if (a >= a4) {
a = (a * ONE_20) / a4;
sum += x4;
}
if (a >= a5) {
a = (a * ONE_20) / a5;
sum += x5;
}
if (a >= a6) {
a = (a * ONE_20) / a6;
sum += x6;
}
if (a >= a7) {
a = (a * ONE_20) / a7;
sum += x7;
}
if (a >= a8) {
a = (a * ONE_20) / a8;
sum += x8;
}
if (a >= a9) {
a = (a * ONE_20) / a9;
sum += x9;
}
if (a >= a10) {
a = (a * ONE_20) / a10;
sum += x10;
}
if (a >= a11) {
a = (a * ONE_20) / a11;
sum += x11;
}
// a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series
// that converges rapidly for values of `a` close to one - the same one used in ln_36.
// Let z = (a - 1) / (a + 1).
// ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))
// Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires
// division by ONE_20.
int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
int256 z_squared = (z * z) / ONE_20;
// num is the numerator of the series: the z^(2 * n + 1) term
int256 num = z;
// seriesSum holds the accumulated sum of each term in the series, starting with the initial z
int256 seriesSum = num;
// In each step, the numerator is multiplied by z^2
num = (num * z_squared) / ONE_20;
seriesSum += num / 3;
num = (num * z_squared) / ONE_20;
seriesSum += num / 5;
num = (num * z_squared) / ONE_20;
seriesSum += num / 7;
num = (num * z_squared) / ONE_20;
seriesSum += num / 9;
num = (num * z_squared) / ONE_20;
seriesSum += num / 11;
// 6 Taylor terms are sufficient for 36 decimal precision.
// Finally, we multiply by 2 (non fixed point) to compute ln(remainder)
seriesSum *= 2;
// We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both
// with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal
// value.
return (sum + seriesSum) / 100;
}
}
/**
* @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,
* for x close to one.
*
* Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.
*/
function _ln_36(int256 x) private pure returns (int256) {
unchecked {
// Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits
// worthwhile.
// First, we transform x to a 36 digit fixed point value.
x *= ONE_18;
// We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).
// ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))
// Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires
// division by ONE_36.
int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);
int256 z_squared = (z * z) / ONE_36;
// num is the numerator of the series: the z^(2 * n + 1) term
int256 num = z;
// seriesSum holds the accumulated sum of each term in the series, starting with the initial z
int256 seriesSum = num;
// In each step, the numerator is multiplied by z^2
num = (num * z_squared) / ONE_36;
seriesSum += num / 3;
num = (num * z_squared) / ONE_36;
seriesSum += num / 5;
num = (num * z_squared) / ONE_36;
seriesSum += num / 7;
num = (num * z_squared) / ONE_36;
seriesSum += num / 9;
num = (num * z_squared) / ONE_36;
seriesSum += num / 11;
num = (num * z_squared) / ONE_36;
seriesSum += num / 13;
num = (num * z_squared) / ONE_36;
seriesSum += num / 15;
// 8 Taylor terms are sufficient for 36 decimal precision.
// All that remains is multiplying by 2 (non fixed point).
return seriesSum * 2;
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import {LogExpMath} from "./LogExpMath.sol";
/**
* @title PTPricingLib library
* @author Spectra Finance
* @notice Provides miscellaneous utils for computations related to Principal Token pricing.
*/
library PTPricingLib {
uint256 public constant UNIT = 10 ** 18;
uint256 public constant YEAR = 365 days;
/**
* @notice Computes the price of the Principal Token in the ZCB model
* @param futurePTValue The redemption value of the Principal Token
* @param impliedRate The implied rate expressed in 18 decimals. For example 30% is expressed as 3e17
* @param currentTimestamp The current timestamp
* @param maturity The maturity timestamp
*/
function getPTPriceZCBModel(
uint256 futurePTValue,
uint256 impliedRate,
uint256 currentTimestamp,
uint256 maturity
) internal view returns (uint256) {
if (currentTimestamp >= maturity) {
return futurePTValue;
}
uint256 timeLeft = maturity - currentTimestamp;
int256 t = int256((timeLeft * UNIT) / YEAR);
int256 unitInt = int256(UNIT);
int256 base = unitInt + int256(impliedRate);
int256 ratePerSecond = LogExpMath.ln(base);
int256 denominator = LogExpMath.exp((ratePerSecond * t) / unitInt);
int256 presentValue = (int256(futurePTValue) * unitInt) / denominator;
return uint256(presentValue);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import {CurveOracleLib} from "src/libraries/CurveOracleLib.sol";
import {BaseOracleCurvePT} from "src/spectra-oracles/oracles/BaseOracleCurvePT.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
/**
* @title BaseFeedCurvePTAssetBounded contract
* @author Spectra Finance
* @notice Base contract to implement the AggregatorV3Interface feed for the PT in asset upper bounded by the redemption value and lower bounded by the ZCB model
*/
abstract contract BaseFeedCurvePTAssetBounded is BaseOracleCurvePT {
uint256 private impliedRate;
constructor() {
_disableInitializers();
}
/* INITIALIZERS
*****************************************************************************************************************/
/**
* @notice Initializes the oracle
* @param _pt The principal token address
* @param _pool The pool address
* @param _impliedRate The implied rate used for the linear discount model
*/
function __BaseFeedCurvePTAssetBounded_init(
address _pt,
address _pool,
uint256 _impliedRate
) internal onlyInitializing {
super.__BaseOracleCurvePT_init(_pt, _pool);
impliedRate = _impliedRate;
}
/* INTERNAL
*****************************************************************************************************************/
function _PTPrice() internal view override returns (uint256) {
return CurveOracleLib.getBoundedPTPrice(pool, impliedRate);
}
function decimals() external view override returns (uint8) {
return IERC20Metadata(asset).decimals();
}
/* PUBLIC FUNCTIONS
*****************************************************************************************************************/
/**
* @notice Get the implied rate
* @return The implied rate
*/
function getImpliedRate() external view returns (uint256) {
return impliedRate;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import {Initializable} from "openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IPrincipalToken} from "src/interfaces/IPrincipalToken.sol";
import {AggregatorV3Interface} from "src/interfaces/AggregatorV3Interface.sol";
/**
* @title BaseOracle contract
* @author Spectra Finance
* @notice A base oracle implementation
*/
abstract contract BaseOracle is AggregatorV3Interface, Initializable {
address public pool;
address public pt;
uint256 public maturity;
address public asset;
address public ibt;
/**
* @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;
constructor() {
_disableInitializers();
}
/**
* @notice First function to be called after deployment
* @param _pt The principal token address
* @param _pool The pool address
*/
function __BaseOracle_init(address _pt, address _pool) internal onlyInitializing {
pool = _pool;
pt = _pt;
maturity = IPrincipalToken(_pt).maturity();
asset = IPrincipalToken(_pt).underlying();
ibt = IPrincipalToken(_pt).getIBT();
}
/* AggregatorV3Interface
*****************************************************************************************************************/
/** @dev See {AggregatorV3Interface-version}. */
function version() external pure virtual returns (uint256) {
return 1;
}
/** @dev See {AggregatorV3Interface-decimals}. */
function decimals() external view virtual returns (uint8);
/** @dev See {AggregatorV3Interface-getQuoteAmount}. */
function _getQuoteAmount() internal view virtual returns (uint256);
/** @dev See {AggregatorV3Interface-getRoundData}. */
function getRoundData(
uint80
)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return (0, int256(_getQuoteAmount()), 0, 0, 0);
}
/** @dev See {AggregatorV3Interface-latestRoundData}. */
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return (0, int256(_getQuoteAmount()), 0, 0, 0);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import {BaseOracle} from "src/spectra-oracles/oracles/BaseOracle.sol";
import {Initializable} from "openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @title BaseOracleCurvePT contract
* @author Spectra Finance
* @notice A base oracle implementation for the PT
*/
abstract contract BaseOracleCurvePT is BaseOracle {
/**
* @notice First function to be called after deployment
*/
constructor() {
_disableInitializers();
}
/**
* @notice Initializes the oracle
* @param _pt The principal token address
* @param _pool The pool address
*/
function __BaseOracleCurvePT_init(address _pt, address _pool) internal onlyInitializing {
super.__BaseOracle_init(_pt, _pool);
}
/* INTERNAL
*****************************************************************************************************************/
function _getQuoteAmount() internal view override returns (uint256) {
return _PTPrice();
}
/**
* @dev Depending on the pool you should use:
* getPTToAssetRate() should be used,
* or getPTToIBTRate() if the asset is not easily tradable with IBT
*/
function _PTPrice() internal view virtual returns (uint256);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "shanghai",
"remappings": [
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
"openzeppelin-math/=lib/openzeppelin-contracts/contracts/utils/math/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/"
],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getImpliedRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ibt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pt","type":"address"},{"internalType":"address","name":"_pool","type":"address"},{"internalType":"uint256","name":"_impliedRate","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"roundId","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
608060405234801562000010575f80fd5b506200001b62000035565b6200002562000035565b6200002f62000035565b620000e9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000865760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000e65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b611be980620000f75f395ff3fe608060405234801561000f575f80fd5b50600436106100b1575f3560e01c80637284e4161161006e5780637284e416146101445780639a6fc8f514610159578063c185f58f146101a3578063c43f357b146101ab578063dc263022146101be578063feaf968c146101d1575f80fd5b806316f0115b146100b55780631794bb3c146100e4578063204f83f9146100f9578063313ce5671461011057806338d52e0f1461012a57806354fd4d501461013d575b5f80fd5b5f546100c7906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100f76100f2366004611854565b6101d9565b005b61010260025481565b6040519081526020016100db565b6101186102eb565b60405160ff90911681526020016100db565b6003546100c7906001600160a01b031681565b6001610102565b61014c61035b565b6040516100db9190611892565b61016c6101673660046118dd565b610377565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016100db565b603254610102565b6004546100c7906001600160a01b031681565b6001546100c7906001600160a01b031681565b61016c610398565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f8115801561021e5750825b90505f8267ffffffffffffffff16600114801561023a5750303b155b905081158015610248575080155b156102665760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561029057845460ff60401b1916600160401b1785555b61029b8888886103b8565b83156102e157845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6003546040805163313ce56760e01b815290515f926001600160a01b03169163313ce5679160048083019260209291908290030181865afa158015610332573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103569190611906565b905090565b6040518060c0016040528060938152602001611b216093913981565b5f805f805f806103856103d1565b90979096505f9550859450849350915050565b5f805f805f806103a66103d1565b90969095505f94508493508392509050565b6103c06103da565b6103ca8383610425565b6032555050565b5f61035661043b565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661042357604051631afcd79f60e31b815260040160405180910390fd5b565b61042d6103da565b6104378282610454565b5050565b5f8054603254610356916001600160a01b0316906105f5565b61045c6103da565b5f80546001600160a01b038084166001600160a01b0319928316179092556001805492851692909116821790556040805163204f83f960e01b8152905163204f83f9916004808201926020929091908290030181865afa1580156104c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e69190611926565b600281905550816001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610528573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061054c919061193d565b60035f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105d1919061193d565b600480546001600160a01b0319166001600160a01b03929092169190911790555050565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0385169063c661065790602401602060405180830381865afa15801561063c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610660919061193d565b90505f816001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561069f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c39190611926565b90504281116107a157816001600160a01b0316634cdad506836001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610717573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073b9190611926565b6040518263ffffffff1660e01b815260040161075991815260200190565b602060405180830381865afa158015610774573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107989190611926565b92505050610978565b5f826001600160a01b0316634cdad506846001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107ed573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108119190611926565b6040518263ffffffff1660e01b815260040161082f91815260200190565b602060405180830381865afa15801561084a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086e9190611926565b90505f61087a8761097e565b90505f610954856001600160a01b0316634cdad506876001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108ef9190611926565b6040518263ffffffff1660e01b815260040161090d91815260200190565b602060405180830381865afa158015610928573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061094c9190611926565b884287610a67565b90505f6109618383610b0f565b90505f61096e8286610b26565b9750505050505050505b92915050565b5f8061098983610b34565b60405163c661065760e01b81525f600482018190529192506001600160a01b0385169063c661065790602401602060405180830381865afa1580156109d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109f4919061193d565b60405163266d6a8360e11b8152600481018490529091506001600160a01b03821690634cdad506906024015b602060405180830381865afa158015610a3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a5f9190611926565b949350505050565b5f818310610a76575083610a5f565b5f610a81848461196c565b90505f6301e13380610a9b670de0b6b3a76400008461197f565b610aa591906119aa565b9050670de0b6b3a76400005f610abb88836119bd565b90505f610ac782610e19565b90505f610ae784610ad887856119e4565b610ae29190611a13565b610eb0565b90505f81610af5868e6119e4565b610aff9190611a13565b9c9b505050505050505050505050565b5f818311610b1d5781610b1f565b825b9392505050565b5f818310610b1d5781610b1f565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0384169063c661065790602401602060405180830381865afa158015610b7b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9f919061193d565b90505f816001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bde573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c029190611926565b9050428111610c9857816001600160a01b03166368c1f7f6836001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7a9190611926565b6040518263ffffffff1660e01b8152600401610a2091815260200190565b5f846001600160a01b031663fd0684b16040518163ffffffff1660e01b81526004015f60405180830381865afa158015610cd4573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610cfb9190810190611a53565b604051636872765360e01b81525f6004820152909150610e10906001600160a01b03871690636872765390602401602060405180830381865afa158015610d44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d689190611926565b670de0b6b3a7640000610e0984600181518110610d8757610d87611b0c565b6020026020010151855f81518110610da157610da1611b0c565b6020026020010151886001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e099190611926565b91906112bc565b95945050505050565b5f808213610e5e5760405162461bcd60e51b815260206004820152600d60248201526c6f7574206f6620626f756e647360981b60448201526064015b60405180910390fd5b670c7d713b49da000082138015610e7c5750670f43fc2c04ee000082125b15610ea757670de0b6b3a7640000610e938361137b565b81610ea057610ea0611996565b0592915050565b61097882611498565b5f680238fd42c5cf03ffff198212158015610ed4575068070c1cc73b00c800008213155b610f135760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a5908195e1c1bdb995b9d60821b6044820152606401610e55565b5f821215610f4257610f26825f03610eb0565b6a0c097ce7bc90715b34b9f160241b81610ea057610ea0611996565b5f6806f05b59d3b20000008312610f8157506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000610fb7565b6803782dace9d90000008312610fb357506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380610fb7565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac6200000084126110075768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412611043576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b18800000841261107d57682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c40000084126110b7576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac620000084126110f057680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d6310000084126111295768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412611162576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c40000841261119b5768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b5f838302815f1985870982811083820303915050805f036112f0578382816112e6576112e6611996565b0492505050610b1f565b8084116113105760405163227bc15360e01b815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b670de0b6b3a7640000025f806a0c097ce7bc90715b34b9f160241b808401906ec097ce7bc90715b34b9f0fffffffff19850102816113bb576113bb611996565b0590505f6a0c097ce7bc90715b34b9f160241b82800205905081806a0c097ce7bc90715b34b9f160241b81840205915060038205016a0c097ce7bc90715b34b9f160241b82840205915060058205016a0c097ce7bc90715b34b9f160241b82840205915060078205016a0c097ce7bc90715b34b9f160241b82840205915060098205016a0c097ce7bc90715b34b9f160241b828402059150600b8205016a0c097ce7bc90715b34b9f160241b828402059150600d8205016a0c097ce7bc90715b34b9f160241b828402059150600f82050160020295945050505050565b5f670de0b6b3a76400008212156114d7576114cf826a0c097ce7bc90715b34b9f160241b816114c9576114c9611996565b05611498565b5f0392915050565b5f7e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261152757770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261155f576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126115a7576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126115e2576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261161957693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e2831261165057690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126116855768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb4174612111083126116b057680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d83126116e5576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f1775788937937831261171a576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b286603831261174e576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac8312611782576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b5f68056bc75e2d63100000840168056bc75e2d6310000080860302816117aa576117aa611996565b0590505f68056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6001600160a01b0381168114611851575f80fd5b50565b5f805f60608486031215611866575f80fd5b83356118718161183d565b925060208401356118818161183d565b929592945050506040919091013590565b5f6020808352835180828501525f5b818110156118bd578581018301518582016040015282016118a1565b505f604082860101526040601f19601f8301168501019250505092915050565b5f602082840312156118ed575f80fd5b813569ffffffffffffffffffff81168114610b1f575f80fd5b5f60208284031215611916575f80fd5b815160ff81168114610b1f575f80fd5b5f60208284031215611936575f80fd5b5051919050565b5f6020828403121561194d575f80fd5b8151610b1f8161183d565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561097857610978611958565b808202811582820484141761097857610978611958565b634e487b7160e01b5f52601260045260245ffd5b5f826119b8576119b8611996565b500490565b8082018281125f8312801582168215821617156119dc576119dc611958565b505092915050565b8082025f8212600160ff1b841416156119ff576119ff611958565b818105831482151761097857610978611958565b5f82611a2157611a21611996565b600160ff1b82145f1984141615611a3a57611a3a611958565b500590565b634e487b7160e01b5f52604160045260245ffd5b5f6020808385031215611a64575f80fd5b825167ffffffffffffffff80821115611a7b575f80fd5b818501915085601f830112611a8e575f80fd5b815181811115611aa057611aa0611a3f565b8060051b604051601f19603f83011681018181108582111715611ac557611ac5611a3f565b604052918252848201925083810185019188831115611ae2575f80fd5b938501935b82851015611b0057845184529385019392850192611ae7565b98975050505050505050565b634e487b7160e01b5f52603260045260245ffdfe4942542f505420437572766520506f6f6c204f7261636c653a205457415020505420707269636520696e2061737365742e204c6f77657220626f756e64656420627920746865205a4342206d6f64656c206163636f7264696e6720746f205f696d706c69656452617465616e6420757070657220626f756e6465642062792074686520726564656d7074696f6e2076616c7565a264697066735822122012dc97c76f0978a7ca1bfad4ada2837cb47bde11cc6b84f8dc206076fc55724c64736f6c63430008140033
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106100b1575f3560e01c80637284e4161161006e5780637284e416146101445780639a6fc8f514610159578063c185f58f146101a3578063c43f357b146101ab578063dc263022146101be578063feaf968c146101d1575f80fd5b806316f0115b146100b55780631794bb3c146100e4578063204f83f9146100f9578063313ce5671461011057806338d52e0f1461012a57806354fd4d501461013d575b5f80fd5b5f546100c7906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100f76100f2366004611854565b6101d9565b005b61010260025481565b6040519081526020016100db565b6101186102eb565b60405160ff90911681526020016100db565b6003546100c7906001600160a01b031681565b6001610102565b61014c61035b565b6040516100db9190611892565b61016c6101673660046118dd565b610377565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016100db565b603254610102565b6004546100c7906001600160a01b031681565b6001546100c7906001600160a01b031681565b61016c610398565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f8115801561021e5750825b90505f8267ffffffffffffffff16600114801561023a5750303b155b905081158015610248575080155b156102665760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561029057845460ff60401b1916600160401b1785555b61029b8888886103b8565b83156102e157845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6003546040805163313ce56760e01b815290515f926001600160a01b03169163313ce5679160048083019260209291908290030181865afa158015610332573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103569190611906565b905090565b6040518060c0016040528060938152602001611b216093913981565b5f805f805f806103856103d1565b90979096505f9550859450849350915050565b5f805f805f806103a66103d1565b90969095505f94508493508392509050565b6103c06103da565b6103ca8383610425565b6032555050565b5f61035661043b565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661042357604051631afcd79f60e31b815260040160405180910390fd5b565b61042d6103da565b6104378282610454565b5050565b5f8054603254610356916001600160a01b0316906105f5565b61045c6103da565b5f80546001600160a01b038084166001600160a01b0319928316179092556001805492851692909116821790556040805163204f83f960e01b8152905163204f83f9916004808201926020929091908290030181865afa1580156104c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e69190611926565b600281905550816001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610528573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061054c919061193d565b60035f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105d1919061193d565b600480546001600160a01b0319166001600160a01b03929092169190911790555050565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0385169063c661065790602401602060405180830381865afa15801561063c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610660919061193d565b90505f816001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561069f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c39190611926565b90504281116107a157816001600160a01b0316634cdad506836001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610717573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073b9190611926565b6040518263ffffffff1660e01b815260040161075991815260200190565b602060405180830381865afa158015610774573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107989190611926565b92505050610978565b5f826001600160a01b0316634cdad506846001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107ed573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108119190611926565b6040518263ffffffff1660e01b815260040161082f91815260200190565b602060405180830381865afa15801561084a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086e9190611926565b90505f61087a8761097e565b90505f610954856001600160a01b0316634cdad506876001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108ef9190611926565b6040518263ffffffff1660e01b815260040161090d91815260200190565b602060405180830381865afa158015610928573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061094c9190611926565b884287610a67565b90505f6109618383610b0f565b90505f61096e8286610b26565b9750505050505050505b92915050565b5f8061098983610b34565b60405163c661065760e01b81525f600482018190529192506001600160a01b0385169063c661065790602401602060405180830381865afa1580156109d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109f4919061193d565b60405163266d6a8360e11b8152600481018490529091506001600160a01b03821690634cdad506906024015b602060405180830381865afa158015610a3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a5f9190611926565b949350505050565b5f818310610a76575083610a5f565b5f610a81848461196c565b90505f6301e13380610a9b670de0b6b3a76400008461197f565b610aa591906119aa565b9050670de0b6b3a76400005f610abb88836119bd565b90505f610ac782610e19565b90505f610ae784610ad887856119e4565b610ae29190611a13565b610eb0565b90505f81610af5868e6119e4565b610aff9190611a13565b9c9b505050505050505050505050565b5f818311610b1d5781610b1f565b825b9392505050565b5f818310610b1d5781610b1f565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0384169063c661065790602401602060405180830381865afa158015610b7b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9f919061193d565b90505f816001600160a01b031663204f83f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bde573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c029190611926565b9050428111610c9857816001600160a01b03166368c1f7f6836001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7a9190611926565b6040518263ffffffff1660e01b8152600401610a2091815260200190565b5f846001600160a01b031663fd0684b16040518163ffffffff1660e01b81526004015f60405180830381865afa158015610cd4573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610cfb9190810190611a53565b604051636872765360e01b81525f6004820152909150610e10906001600160a01b03871690636872765390602401602060405180830381865afa158015610d44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d689190611926565b670de0b6b3a7640000610e0984600181518110610d8757610d87611b0c565b6020026020010151855f81518110610da157610da1611b0c565b6020026020010151886001600160a01b0316631f2b4f246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e099190611926565b91906112bc565b95945050505050565b5f808213610e5e5760405162461bcd60e51b815260206004820152600d60248201526c6f7574206f6620626f756e647360981b60448201526064015b60405180910390fd5b670c7d713b49da000082138015610e7c5750670f43fc2c04ee000082125b15610ea757670de0b6b3a7640000610e938361137b565b81610ea057610ea0611996565b0592915050565b61097882611498565b5f680238fd42c5cf03ffff198212158015610ed4575068070c1cc73b00c800008213155b610f135760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a5908195e1c1bdb995b9d60821b6044820152606401610e55565b5f821215610f4257610f26825f03610eb0565b6a0c097ce7bc90715b34b9f160241b81610ea057610ea0611996565b5f6806f05b59d3b20000008312610f8157506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000610fb7565b6803782dace9d90000008312610fb357506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380610fb7565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac6200000084126110075768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412611043576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b18800000841261107d57682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c40000084126110b7576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac620000084126110f057680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d6310000084126111295768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412611162576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c40000841261119b5768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b5f838302815f1985870982811083820303915050805f036112f0578382816112e6576112e6611996565b0492505050610b1f565b8084116113105760405163227bc15360e01b815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b670de0b6b3a7640000025f806a0c097ce7bc90715b34b9f160241b808401906ec097ce7bc90715b34b9f0fffffffff19850102816113bb576113bb611996565b0590505f6a0c097ce7bc90715b34b9f160241b82800205905081806a0c097ce7bc90715b34b9f160241b81840205915060038205016a0c097ce7bc90715b34b9f160241b82840205915060058205016a0c097ce7bc90715b34b9f160241b82840205915060078205016a0c097ce7bc90715b34b9f160241b82840205915060098205016a0c097ce7bc90715b34b9f160241b828402059150600b8205016a0c097ce7bc90715b34b9f160241b828402059150600d8205016a0c097ce7bc90715b34b9f160241b828402059150600f82050160020295945050505050565b5f670de0b6b3a76400008212156114d7576114cf826a0c097ce7bc90715b34b9f160241b816114c9576114c9611996565b05611498565b5f0392915050565b5f7e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261152757770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261155f576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126115a7576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126115e2576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261161957693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e2831261165057690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126116855768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb4174612111083126116b057680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d83126116e5576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f1775788937937831261171a576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b286603831261174e576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac8312611782576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b5f68056bc75e2d63100000840168056bc75e2d6310000080860302816117aa576117aa611996565b0590505f68056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6001600160a01b0381168114611851575f80fd5b50565b5f805f60608486031215611866575f80fd5b83356118718161183d565b925060208401356118818161183d565b929592945050506040919091013590565b5f6020808352835180828501525f5b818110156118bd578581018301518582016040015282016118a1565b505f604082860101526040601f19601f8301168501019250505092915050565b5f602082840312156118ed575f80fd5b813569ffffffffffffffffffff81168114610b1f575f80fd5b5f60208284031215611916575f80fd5b815160ff81168114610b1f575f80fd5b5f60208284031215611936575f80fd5b5051919050565b5f6020828403121561194d575f80fd5b8151610b1f8161183d565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561097857610978611958565b808202811582820484141761097857610978611958565b634e487b7160e01b5f52601260045260245ffd5b5f826119b8576119b8611996565b500490565b8082018281125f8312801582168215821617156119dc576119dc611958565b505092915050565b8082025f8212600160ff1b841416156119ff576119ff611958565b818105831482151761097857610978611958565b5f82611a2157611a21611996565b600160ff1b82145f1984141615611a3a57611a3a611958565b500590565b634e487b7160e01b5f52604160045260245ffd5b5f6020808385031215611a64575f80fd5b825167ffffffffffffffff80821115611a7b575f80fd5b818501915085601f830112611a8e575f80fd5b815181811115611aa057611aa0611a3f565b8060051b604051601f19603f83011681018181108582111715611ac557611ac5611a3f565b604052918252848201925083810185019188831115611ae2575f80fd5b938501935b82851015611b0057845184529385019392850192611ae7565b98975050505050505050565b634e487b7160e01b5f52603260045260245ffdfe4942542f505420437572766520506f6f6c204f7261636c653a205457415020505420707269636520696e2061737365742e204c6f77657220626f756e64656420627920746865205a4342206d6f64656c206163636f7264696e6720746f205f696d706c69656452617465616e6420757070657220626f756e6465642062792074686520726564656d7074696f6e2076616c7565a264697066735822122012dc97c76f0978a7ca1bfad4ada2837cb47bde11cc6b84f8dc206076fc55724c64736f6c63430008140033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.