Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AmmSwapsLensArbitrum
Compiler Version
v0.8.20+commit.a1b79de6
Contract Source Code (Solidity)
/**
*Submitted for verification at Arbiscan.io on 2024-02-10
*/
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
/// @notice Interface of the AmmTreasury contract.
interface IAmmTreasuryBaseV1 {
/// @notice Gets router address.
function router() external view returns (address);
/// @notice Retrieves the version number of the contract.
/// @return The version number of the contract.
/// @dev This function provides a way to access the version information of the contract.
/// Currently, the version is set to 1.
function getVersion() external pure returns (uint256);
/// @notice Gets the balance of the liquidity pool.
/// @dev Liquidity Pool balance not take into account following balances: collateral, ipor publication fee, treasury
function getLiquidityPoolBalance() external view returns (uint256);
/// @notice Pauses the contract and revokes the approval of stEth tokens for the router.
/// @dev This function can only be called by the pause guardian.
/// It revokes the approval of stEth tokens for the router and then pauses the contract.
/// require Caller must be the pause guardian.
function pause() external;
/// @notice Unpauses the contract and forcefully approves the router to transfer an unlimited amount of stEth tokens.
/// @dev This function can only be called by the contract owner.
/// It unpauses the contract and then forcefully sets the approval of stEth tokens for the router to the maximum possible value.
/// require Caller must be the contract owner.
function unpause() external;
/// @notice Checks if the given account is a pause guardian.
/// @param account Address to be checked.
/// @return A boolean indicating whether the provided account is a pause guardian.
/// @dev This function queries the PauseManager to determine if the provided account is a pause guardian.
function isPauseGuardian(address account) external view returns (bool);
/// @notice Adds a new pause guardian to the contract.
/// @param guardians List Addresses of the accounts to be added as a pause guardian.
/// @dev This function can only be called by the contract owner.
/// It delegates the addition of a new pause guardian to the PauseManager.
/// require Caller must be the contract owner.
function addPauseGuardians(address[] calldata guardians) external;
/// @notice Removes an existing pause guardian from the contract.
/// @param guardians List addresses of the accounts to be removed as a pause guardian.
/// @dev This function can only be called by the contract owner.
/// It delegates the removal of a pause guardian to the PauseManager.
/// require Caller must be the contract owner.
function removePauseGuardians(address[] calldata guardians) external;
}
/// @title Interface for interaction with Asset Management DSR smart contract.
/// @notice Asset Management is responsible for delegating assets stored in AmmTreasury to Asset Management and forward to money market where they can earn interest.
interface IAssetManagement {
/// @notice Gets total balance of AmmTreasury, transferred assets to Asset Management.
/// @return Total balance for specific account given as a parameter, represented in 18 decimals.
function totalBalance() external view returns (uint256);
/// @notice Deposits ERC20 underlying assets to AssetManagement. Function available only for AmmTreasury.
/// @dev Emits {Deposit} event from AssetManagement, emits {Transfer} event from ERC20 asset.
/// Input and output values are represented in 18 decimals.
/// @param amount amount deposited by AmmTreasury to AssetManagement.
/// @return vaultBalance current balance including amount deposited on AssteManagement.
/// @return depositedAmount final deposited amount.
function deposit(uint256 amount) external returns (uint256 vaultBalance, uint256 depositedAmount);
/// @notice Withdraws declared amount of asset from AssetManagement to AmmTreasury. Function available only for AmmTreasury.
/// @dev Emits {Withdraw} event from AssetManagement, emits {Transfer} event from ERC20 asset.
/// All input and output values are represented in 18 decimals.
/// @param amount deposited amount of underlying asset represented in 18 decimals.
/// @return withdrawnAmount final withdrawn amount of asset from AssetManagement, can be different than input amount due to passing time.
/// @return vaultBalance current asset balance on AssetManagement
function withdraw(uint256 amount) external returns (uint256 withdrawnAmount, uint256 vaultBalance);
/// @notice Withdraws all of the asset from AssetManagement to AmmTreasury. Function available only for AmmTreasury.
/// @dev Emits {Withdraw} event from AssetManagement, emits {Transfer} event from ERC20 asset.
/// Output values are represented in 18 decimals.
/// @return withdrawnAmount final withdrawn amount of the asset.
/// @return vaultBalance current asset's balance on AssetManagement
function withdrawAll() external returns (uint256 withdrawnAmount, uint256 vaultBalance);
/// @notice Emitted after AmmTreasury has executed deposit function.
/// @param from account address from which assets are transferred
/// @param to account address where assets are transferred to
/// @param amount of asset transferred from AmmTreasury to AssetManagement, represented in 18 decimals
event Deposit(address from, address to, uint256 amount);
/// @notice Emitted when AmmTreasury executes withdraw function.
/// @param to account address where assets are transferred to
/// @param amount of asset transferred from AmmTreasury to AssetManagement, represented in 18 decimals
event Withdraw(address to, uint256 amount);
}
/// @title Types used in AmmStorage smart contract
library AmmStorageTypes {
/// @notice struct representing swap's ID and direction
/// @dev direction = 0 - Pay Fixed - Receive Floating, direction = 1 - Receive Fixed - Pay Floating
struct IporSwapId {
/// @notice Swap's ID
uint256 id;
/// @notice Swap's direction, 0 - Pay Fixed Receive Floating, 1 - Receive Fixed Pay Floating
uint8 direction;
}
/// @notice Struct containing extended balance information.
/// @dev extended information includes: opening fee balance, liquidation deposit balance,
/// IPOR publication fee balance, treasury balance, all values are with 18 decimals
struct ExtendedBalancesMemory {
/// @notice Swap's balance for Pay Fixed leg
uint256 totalCollateralPayFixed;
/// @notice Swap's balance for Receive Fixed leg
uint256 totalCollateralReceiveFixed;
/// @notice Liquidity Pool's Balance
uint256 liquidityPool;
/// @notice AssetManagement's (Asset Management) balance
uint256 vault;
/// @notice IPOR publication fee balance. This balance is used to subsidise the oracle operations
uint256 iporPublicationFee;
/// @notice Balance of the DAO's treasury. Fed by portion of the opening fee set by the DAO
uint256 treasury;
}
/// @notice A struct with parameters required to calculate SOAP for pay fixed and receive fixed legs.
/// @dev Committed to the memory.
struct SoapIndicators {
/// @notice Value of interest accrued on a fixed leg of all derivatives for this particular type of swap.
/// @dev Represented in 18 decimals.
uint256 hypotheticalInterestCumulative;
/// @notice Sum of all swaps' notional amounts for a given leg.
/// @dev Represented in 18 decimals.
uint256 totalNotional;
/// @notice Sum of all IBTs on a given leg.
/// @dev Represented in 18 decimals.
uint256 totalIbtQuantity;
/// @notice The notional-weighted average interest rate of all swaps on a given leg combined.
/// @dev Represented in 18 decimals.
uint256 averageInterestRate;
/// @notice EPOCH timestamp of when the most recent rebalancing took place
uint256 rebalanceTimestamp;
}
}
/// @title Struct used across various interfaces in IPOR Protocol.
library IporTypes {
/// @notice enum describing Swap's state, ACTIVE - when the swap is opened, INACTIVE when it's closed
enum SwapState {
INACTIVE,
ACTIVE
}
/// @notice enum describing Swap's duration, 28 days, 60 days or 90 days
enum SwapTenor {
DAYS_28,
DAYS_60,
DAYS_90
}
/// @notice The struct describing the IPOR and its params calculated for the time when it was most recently updated and the change that took place since the update.
/// Namely, the interest that would be computed into IBT should the rebalance occur.
struct AccruedIpor {
/// @notice IPOR Index Value
/// @dev value represented in 18 decimals
uint256 indexValue;
/// @notice IBT Price (IBT - Interest Bearing Token). For more information refer to the documentation:
/// https://ipor-labs.gitbook.io/ipor-labs/interest-rate-derivatives/ibt
/// @dev value represented in 18 decimals
uint256 ibtPrice;
}
/// @notice Struct representing balances used internally for asset calculations
/// @dev all balances in 18 decimals
struct AmmBalancesMemory {
/// @notice Sum of all collateral put forward by the derivative buyer's on Pay Fixed & Receive Floating leg.
uint256 totalCollateralPayFixed;
/// @notice Sum of all collateral put forward by the derivative buyer's on Pay Floating & Receive Fixed leg.
uint256 totalCollateralReceiveFixed;
/// @notice Liquidity Pool Balance. This balance is where the liquidity from liquidity providers and the opening fee are accounted for,
/// @dev Amount of opening fee accounted in this balance is defined by _OPENING_FEE_FOR_TREASURY_PORTION_RATE param.
uint256 liquidityPool;
/// @notice Vault's balance, describes how much asset has been transferred to Asset Management Vault (AssetManagement)
uint256 vault;
}
struct AmmBalancesForOpenSwapMemory {
/// @notice Sum of all collateral put forward by the derivative buyer's on Pay Fixed & Receive Floating leg.
uint256 totalCollateralPayFixed;
/// @notice Total notional amount of all swaps on Pay Fixed leg (denominated in 18 decimals).
uint256 totalNotionalPayFixed;
/// @notice Sum of all collateral put forward by the derivative buyer's on Pay Floating & Receive Fixed leg.
uint256 totalCollateralReceiveFixed;
/// @notice Total notional amount of all swaps on Receive Fixed leg (denominated in 18 decimals).
uint256 totalNotionalReceiveFixed;
/// @notice Liquidity Pool Balance.
uint256 liquidityPool;
}
struct SpreadInputs {
//// @notice Swap's assets DAI/USDC/USDT
address asset;
/// @notice Swap's notional value
uint256 swapNotional;
/// @notice demand spread factor used in demand spread calculation
uint256 demandSpreadFactor;
/// @notice Base spread
int256 baseSpreadPerLeg;
/// @notice Swap's balance for Pay Fixed leg
uint256 totalCollateralPayFixed;
/// @notice Swap's balance for Receive Fixed leg
uint256 totalCollateralReceiveFixed;
/// @notice Liquidity Pool's Balance
uint256 liquidityPoolBalance;
/// @notice Ipor index value at the time of swap creation
uint256 iporIndexValue;
// @notice fixed rate cap for given leg for offered rate without demandSpread in 18 decimals
uint256 fixedRateCapPerLeg;
}
}
library Constants {
uint256 public constant MAX_VALUE = type(uint256).max;
uint256 public constant WAD_LEVERAGE_1000 = 1_000e18;
uint256 public constant YEAR_IN_SECONDS = 365 days;
uint256 public constant MAX_CHUNK_SIZE = 50;
}
/// @title Storage ID's associated with the IPOR Protocol Router.
library StorageLib {
uint256 constant STORAGE_SLOT_BASE = 1_000_000;
// append only
enum StorageId {
/// @dev The address of the contract owner.
Owner,
AppointedOwner,
Paused,
PauseGuardian,
ReentrancyStatus,
RouterFunctionPaused,
AmmSwapsLiquidators,
AmmPoolsAppointedToRebalance,
AmmPoolsParams
}
/// @notice Struct which contains owner address of IPOR Protocol Router.
struct OwnerStorage {
address owner;
}
/// @notice Struct which contains appointed owner address of IPOR Protocol Router.
struct AppointedOwnerStorage {
address appointedOwner;
}
/// @notice Struct which contains reentrancy status of IPOR Protocol Router.
struct ReentrancyStatusStorage {
uint256 value;
}
/// @notice Struct which contains information about swap liquidators.
/// @dev First key is an asset (pool), second key is an liquidator address in the asset pool,
/// value is a flag to indicate whether account is a liquidator.
/// True - account is a liquidator, False - account is not a liquidator.
struct AmmSwapsLiquidatorsStorage {
mapping(address => mapping(address => bool)) value;
}
/// @notice Struct which contains information about accounts appointed to rebalance.
/// @dev first key - asset address, second key - account address which is allowed to rebalance in the asset pool,
/// value - flag to indicate whether account is allowed to rebalance. True - allowed, False - not allowed.
struct AmmPoolsAppointedToRebalanceStorage {
mapping(address => mapping(address => bool)) value;
}
struct AmmPoolsParamsValue {
/// @dev max liquidity pool balance in the asset pool, represented without 18 decimals
uint32 maxLiquidityPoolBalance;
/// @dev The threshold for auto-rebalancing the pool. Value represented without 18 decimals.
/// Value represents multiplication of 1000.
uint32 autoRebalanceThresholdInThousands;
/// @dev asset management ratio, represented without 18 decimals, value represents percentage with 2 decimals
/// 65% = 6500, 99,99% = 9999, this is a percentage which stay in Amm Treasury in opposite to Asset Management
/// based on AMM Treasury balance (100%).
uint16 ammTreasuryAndAssetManagementRatio;
}
/// @dev key - asset address, value - struct AmmOpenSwapParamsValue
struct AmmPoolsParamsStorage {
mapping(address => AmmPoolsParamsValue) value;
}
/// @dev key - function sig, value - 1 if function is paused, 0 if not
struct RouterFunctionPausedStorage {
mapping(bytes4 => uint256) value;
}
/// @notice Gets Ipor Protocol Router owner address.
function getOwner() internal pure returns (OwnerStorage storage owner) {
uint256 slot = _getStorageSlot(StorageId.Owner);
assembly {
owner.slot := slot
}
}
/// @notice Gets Ipor Protocol Router appointed owner address.
function getAppointedOwner() internal pure returns (AppointedOwnerStorage storage appointedOwner) {
uint256 slot = _getStorageSlot(StorageId.AppointedOwner);
assembly {
appointedOwner.slot := slot
}
}
/// @notice Gets Ipor Protocol Router reentrancy status.
function getReentrancyStatus() internal pure returns (ReentrancyStatusStorage storage reentrancyStatus) {
uint256 slot = _getStorageSlot(StorageId.ReentrancyStatus);
assembly {
reentrancyStatus.slot := slot
}
}
/// @notice Gets information if function is paused in Ipor Protocol Router.
function getRouterFunctionPaused() internal pure returns (RouterFunctionPausedStorage storage paused) {
uint256 slot = _getStorageSlot(StorageId.RouterFunctionPaused);
assembly {
paused.slot := slot
}
}
/// @notice Gets point to pause guardian storage.
function getPauseGuardianStorage() internal pure returns (mapping(address => bool) storage store) {
uint256 slot = _getStorageSlot(StorageId.PauseGuardian);
assembly {
store.slot := slot
}
}
/// @notice Gets point to liquidators storage.
/// @return store - point to liquidators storage.
function getAmmSwapsLiquidatorsStorage() internal pure returns (AmmSwapsLiquidatorsStorage storage store) {
uint256 slot = _getStorageSlot(StorageId.AmmSwapsLiquidators);
assembly {
store.slot := slot
}
}
/// @notice Gets point to accounts appointed to rebalance storage.
/// @return store - point to accounts appointed to rebalance storage.
function getAmmPoolsAppointedToRebalanceStorage()
internal
pure
returns (AmmPoolsAppointedToRebalanceStorage storage store)
{
uint256 slot = _getStorageSlot(StorageId.AmmPoolsAppointedToRebalance);
assembly {
store.slot := slot
}
}
/// @notice Gets point to amm pools params storage.
/// @return store - point to amm pools params storage.
function getAmmPoolsParamsStorage() internal pure returns (AmmPoolsParamsStorage storage store) {
uint256 slot = _getStorageSlot(StorageId.AmmPoolsParams);
assembly {
store.slot := slot
}
}
function _getStorageSlot(StorageId storageId) private pure returns (uint256 slot) {
return uint256(storageId) + STORAGE_SLOT_BASE;
}
}
/// @title Errors which occur inside AmmTreasury's method execution.
library AmmErrors {
// 300-399-AMM
/// @notice Liquidity Pool balance is equal 0.
string public constant LIQUIDITY_POOL_IS_EMPTY = "IPOR_300";
/// @notice Liquidity Pool balance is too low, should be equal or higher than 0.
string public constant LIQUIDITY_POOL_AMOUNT_TOO_LOW = "IPOR_301";
/// @notice Liquidity Pool Collateral Ratio exceeded. Liquidity Pool Collateral Ratio is higher than configured in AmmTreasury maximum liquidity pool collateral ratio.
string public constant LP_COLLATERAL_RATIO_EXCEEDED = "IPOR_302";
/// @notice Liquidity Pool Collateral Ratio Per Leg exceeded. Liquidity Pool Collateral Ratio per leg is higher than configured in AmmTreasury maximum liquidity pool collateral ratio per leg.
string public constant LP_COLLATERAL_RATIO_PER_LEG_EXCEEDED = "IPOR_303";
/// @notice Liquidity Pool Balance is too high
string public constant LIQUIDITY_POOL_BALANCE_IS_TOO_HIGH = "IPOR_304";
/// @notice Swap cannot be closed because liquidity pool is too low for payid out cash. Situation should never happen where Liquidity Pool is insolvent.
string public constant CANNOT_CLOSE_SWAP_LP_IS_TOO_LOW = "IPOR_305";
/// @notice Swap id used in input has incorrect value (like 0) or not exists.
string public constant INCORRECT_SWAP_ID = "IPOR_306";
/// @notice Swap has incorrect status.
string public constant INCORRECT_SWAP_STATUS = "IPOR_307";
/// @notice Leverage given as a parameter when opening swap is lower than configured in AmmTreasury minimum leverage.
string public constant LEVERAGE_TOO_LOW = "IPOR_308";
/// @notice Leverage given as a parameter when opening swap is higher than configured in AmmTreasury maxumum leverage.
string public constant LEVERAGE_TOO_HIGH = "IPOR_309";
/// @notice Total amount given as a parameter when opening swap is too low. Cannot be equal zero.
string public constant TOTAL_AMOUNT_TOO_LOW = "IPOR_310";
/// @notice Total amount given as a parameter when opening swap is lower than sum of liquidation deposit amount and ipor publication fee.
string public constant TOTAL_AMOUNT_LOWER_THAN_FEE = "IPOR_311";
/// @notice Amount of collateral used to open swap is higher than configured in AmmTreasury max swap collateral amount
string public constant COLLATERAL_AMOUNT_TOO_HIGH = "IPOR_312";
/// @notice Acceptable fixed interest rate defined by traded exceeded.
string public constant ACCEPTABLE_FIXED_INTEREST_RATE_EXCEEDED = "IPOR_313";
/// @notice Swap Notional Amount is higher than Total Notional for specific leg.
string public constant SWAP_NOTIONAL_HIGHER_THAN_TOTAL_NOTIONAL = "IPOR_314";
/// @notice Number of swaps per leg which are going to be liquidated is too high, is higher than configured in AmmTreasury liquidation leg limit.
string public constant MAX_LENGTH_LIQUIDATED_SWAPS_PER_LEG_EXCEEDED = "IPOR_315";
/// @notice Sum of SOAP and Liquidity Pool Balance is lower than zero.
/// @dev SOAP can be negative, Sum of SOAP and Liquidity Pool Balance can be negative, but this is undesirable.
string public constant SOAP_AND_LP_BALANCE_SUM_IS_TOO_LOW = "IPOR_316";
/// @notice Calculation timestamp is earlier than last SOAP rebalance timestamp.
string public constant CALC_TIMESTAMP_LOWER_THAN_SOAP_REBALANCE_TIMESTAMP = "IPOR_317";
/// @notice Calculation timestamp is lower than Swap's open timestamp.
string public constant CALC_TIMESTAMP_LOWER_THAN_SWAP_OPEN_TIMESTAMP = "IPOR_318";
/// @notice Closing timestamp is lower than Swap's open timestamp.
string public constant CLOSING_TIMESTAMP_LOWER_THAN_SWAP_OPEN_TIMESTAMP = "IPOR_319";
/// @notice Swap cannot be closed because sender is not a buyer nor liquidator.
string public constant CANNOT_CLOSE_SWAP_SENDER_IS_NOT_BUYER_NOR_LIQUIDATOR = "IPOR_320";
/// @notice Interest from Strategy is below zero.
string public constant INTEREST_FROM_STRATEGY_EXCEEDED_THRESHOLD = "IPOR_321";
/// @notice IPOR publication fee balance is too low.
string public constant PUBLICATION_FEE_BALANCE_IS_TOO_LOW = "IPOR_322";
/// @notice The caller must be the Token Manager (Smart Contract responsible for managing token total supply).
string public constant CALLER_NOT_TOKEN_MANAGER = "IPOR_323";
/// @notice Deposit amount is too low.
string public constant DEPOSIT_AMOUNT_IS_TOO_LOW = "IPOR_324";
/// @notice Vault balance is lower than deposit value.
string public constant VAULT_BALANCE_LOWER_THAN_DEPOSIT_VALUE = "IPOR_325";
/// @notice Treasury balance is too low.
string public constant TREASURY_BALANCE_IS_TOO_LOW = "IPOR_326";
/// @notice Swap cannot be closed because closing timestamp is lower than swap's open timestamp in general.
string public constant CANNOT_CLOSE_SWAP_CLOSING_IS_TOO_EARLY = "IPOR_327";
/// @notice Swap cannot be closed because closing timestamp is lower than swap's open timestamp for buyer.
string public constant CANNOT_CLOSE_SWAP_CLOSING_IS_TOO_EARLY_FOR_BUYER = "IPOR_328";
/// @notice Swap cannot be closed and unwind because is too late
string public constant CANNOT_UNWIND_CLOSING_TOO_LATE = "IPOR_329";
/// @notice Unsupported swap tenor
string public constant UNSUPPORTED_SWAP_TENOR = "IPOR_330";
/// @notice Sender is not AMM (is not a IporProtocolRouter contract)
string public constant SENDER_NOT_AMM = "IPOR_331";
/// @notice Storage id is not time weighted notional group
string public constant STORAGE_ID_IS_NOT_TIME_WEIGHTED_NOTIONAL = "IPOR_332";
/// @notice Spread function is not supported
string public constant FUNCTION_NOT_SUPPORTED = "IPOR_333";
/// @notice Unsupported direction
string public constant UNSUPPORTED_DIRECTION = "IPOR_334";
/// @notice Invalid notional
string public constant INVALID_NOTIONAL = "IPOR_335";
/// @notice Average interest rate cannot be zero when open swap
string public constant AVERAGE_INTEREST_RATE_WHEN_OPEN_SWAP_CANNOT_BE_ZERO = "IPOR_336";
/// @notice Average interest rate cannot be zero when close swap
string public constant AVERAGE_INTEREST_RATE_WHEN_CLOSE_SWAP_CANNOT_BE_ZERO = "IPOR_337";
/// @notice Submit ETH to stETH contract failed.
string public constant STETH_SUBMIT_FAILED = "IPOR_338";
/// @notice Collateral is not sufficient to cover unwind swap
string public constant COLLATERAL_IS_NOT_SUFFICIENT_TO_COVER_UNWIND_SWAP = "IPOR_339";
/// @notice Error when withdraw from asset management is not enough to cover transfer amount to buyer and/or beneficiary
string public constant ASSET_MANAGEMENT_WITHDRAW_NOT_ENOUGH = "IPOR_340";
/// @notice Swap cannot be closed with unwind because action is too early, depends on value of configuration parameter `timeAfterOpenAllowedToCloseSwapWithUnwinding`
string public constant CANNOT_CLOSE_SWAP_WITH_UNWIND_ACTION_IS_TOO_EARLY = "IPOR_341";
}
library AmmPoolsErrors {
// 400-499-Amm Pools
/// @notice IP Token Value which should be minted is too low
string public constant IP_TOKEN_MINT_AMOUNT_TOO_LOW = "IPOR_400";
/// @notice Amount which should be burned is too low
string public constant IP_TOKEN_BURN_AMOUNT_TOO_LOW = "IPOR_401";
/// @notice Liquidity Pool Collateral Ration is exceeded when redeeming
string public constant REDEEM_LP_COLLATERAL_RATIO_EXCEEDED = "IPOR_402";
/// @notice User cannot redeem underlying tokens because ipToken on his balance is too low
string public constant CANNOT_REDEEM_IP_TOKEN_TOO_LOW = "IPOR_403";
/// @notice Caller is not a treasury manager, not match address defined in IPOR Protocol configuration
string public constant CALLER_NOT_TREASURY_MANAGER = "IPOR_404";
/// @notice Account cannot redeem ip tokens because amount of underlying tokens for transfer to beneficiary is too low.
string public constant CANNOT_REDEEM_ASSET_AMOUNT_TOO_LOW = "IPOR_405";
/// @notice Sender is not a publication fee transferer, not match address defined in IporConfiguration in key AMM_TREASURY_PUBLICATION_FEE_TRANSFERER
string public constant CALLER_NOT_PUBLICATION_FEE_TRANSFERER = "IPOR_406";
/// @notice Asset Management Balance is empty
string public constant ASSET_MANAGEMENT_BALANCE_IS_EMPTY = "IPOR_407";
/// @notice Incorrect AMM Treasury and Asset Management Ratio
string public constant AMM_TREASURY_ASSET_MANAGEMENT_RATIO = "IPOR_408";
/// @notice Insufficient ERC20 balance
string public constant INSUFFICIENT_ERC20_BALANCE = "IPOR_409";
/// @notice Caller is not appointed to rebalance
string public constant CALLER_NOT_APPOINTED_TO_REBALANCE = "IPOR_410";
/// @notice Invalid redeem fee rate
string public constant CFG_INVALID_REDEEM_FEE_RATE = "IPOR_411";
/// @notice Invalid redeem lp max collateral ratio
string public constant CFG_INVALID_REDEEM_LP_MAX_COLLATERAL_RATIO = "IPOR_412";
}
library IporErrors {
/// @notice Error when address is wrong
error WrongAddress(string errorCode, address wrongAddress, string message);
/// @notice Error when amount is wrong
error WrongAmount(string errorCode, uint256 value);
/// @notice Error when caller is not an ipor protocol router
error CallerNotIporProtocolRouter(string errorCode, address caller);
/// @notice Error when caller is not a pause guardian
error CallerNotPauseGuardian(string errorCode, address caller);
/// @notice Error when caller is not a AmmTreasury contract
error CallerNotAmmTreasury(string errorCode, address caller);
/// @notice Error when given direction is not supported
error UnsupportedDirection(string errorCode, uint256 direction);
/// @notice Error when given asset is not supported
error UnsupportedAsset(string errorCode, address asset);
/// @notice Error when given module is not supported
error UnsupportedModule(string errorCode, address asset);
/// @notice Error when given tenor is not supported
error UnsupportedTenor(string errorCode, uint256 tenor);
/// @notice Error when Input Asset total amount is too low
error InputAssetTotalAmountTooLow(string errorCode, uint256 value);
/// @dev Error appears if user/account doesn't have enough balance to open a swap with a specific totalAmount
error InputAssetBalanceTooLow(string errorCode, address inputAsset, uint256 inputAssetBalance, uint256 totalAmount);
// 000-199 - general codes
/// @notice General problem, address is wrong
string public constant WRONG_ADDRESS = "IPOR_000";
/// @notice General problem. Wrong decimals
string public constant WRONG_DECIMALS = "IPOR_001";
/// @notice General problem, addresses mismatch
string public constant ADDRESSES_MISMATCH = "IPOR_002";
/// @notice Sender's asset balance is too low to transfer and to open a swap
string public constant SENDER_ASSET_BALANCE_TOO_LOW = "IPOR_003";
/// @notice Value is not greater than zero
string public constant VALUE_NOT_GREATER_THAN_ZERO = "IPOR_004";
/// @notice Input arrays length mismatch
string public constant INPUT_ARRAYS_LENGTH_MISMATCH = "IPOR_005";
/// @notice Amount is too low to transfer
string public constant NOT_ENOUGH_AMOUNT_TO_TRANSFER = "IPOR_006";
/// @notice msg.sender is not an appointed owner, so cannot confirm his appointment to be an owner of a specific smart contract
string public constant SENDER_NOT_APPOINTED_OWNER = "IPOR_007";
/// @notice only Router can have access to function
string public constant CALLER_NOT_IPOR_PROTOCOL_ROUTER = "IPOR_008";
/// @notice Chunk size is equal to zero
string public constant CHUNK_SIZE_EQUAL_ZERO = "IPOR_009";
/// @notice Chunk size is too big
string public constant CHUNK_SIZE_TOO_BIG = "IPOR_010";
/// @notice Caller is not a pause guardian
string public constant CALLER_NOT_PAUSE_GUARDIAN = "IPOR_011";
/// @notice Request contains invalid method signature, which is not supported by the Ipor Protocol Router
string public constant ROUTER_INVALID_SIGNATURE = "IPOR_012";
/// @notice Only AMM Treasury can have access to function
string public constant CALLER_NOT_AMM_TREASURY = "IPOR_013";
/// @notice Caller is not an owner
string public constant CALLER_NOT_OWNER = "IPOR_014";
/// @notice Method is paused
string public constant METHOD_PAUSED = "IPOR_015";
/// @notice Reentrancy appears
string public constant REENTRANCY = "IPOR_016";
/// @notice Asset is not supported
string public constant ASSET_NOT_SUPPORTED = "IPOR_017";
/// @notice Return back ETH failed in Ipor Protocol Router
string public constant ROUTER_RETURN_BACK_ETH_FAILED = "IPOR_018";
/// @notice Risk indicators are expired
string public constant RISK_INDICATORS_EXPIRED = "IPOR_019";
/// @notice Signature is invalid for risk indicators
string public constant RISK_INDICATORS_SIGNATURE_INVALID = "IPOR_020";
/// @notice Input Asset used by user is not supported
string public constant INPUT_ASSET_NOT_SUPPORTED = "IPOR_021";
/// @notice Module Asset Management is not supported
string public constant UNSUPPORTED_MODULE_ASSET_MANAGEMENT = "IPOR_022";
}
library IporMath {
uint256 private constant RAY = 1e27;
//@notice Division with rounding up on last position, x, and y is with MD
function division(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = (x + (y / 2)) / y;
}
function divisionInt(int256 x, int256 y) internal pure returns (int256 z) {
uint256 absX = uint256(x < 0 ? -x : x);
uint256 absY = uint256(y < 0 ? -y : y);
// Use bitwise XOR to get the sign on MBS bit then shift to LSB
// sign == 0x0000...0000 == 0 if the number is non-negative
// sign == 0xFFFF...FFFF == -1 if the number is negative
int256 sign = (x ^ y) >> 255;
uint256 divAbs;
uint256 remainder;
unchecked {
divAbs = absX / absY;
remainder = absX % absY;
}
// Check if we need to round
if (sign < 0) {
// remainder << 1 left shift is equivalent to multiplying by 2
if (remainder << 1 > absY) {
++divAbs;
}
} else {
if (remainder << 1 >= absY) {
++divAbs;
}
}
// (sign | 1) is cheaper than (sign < 0) ? -1 : 1;
unchecked {
z = int256(divAbs) * (sign | 1);
}
}
function divisionWithoutRound(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x / y;
}
function convertWadToAssetDecimals(uint256 value, uint256 assetDecimals) internal pure returns (uint256) {
if (assetDecimals == 18) {
return value;
} else if (assetDecimals > 18) {
return value * 10 ** (assetDecimals - 18);
} else {
return division(value, 10 ** (18 - assetDecimals));
}
}
function convertWadToAssetDecimalsWithoutRound(
uint256 value,
uint256 assetDecimals
) internal pure returns (uint256) {
if (assetDecimals == 18) {
return value;
} else if (assetDecimals > 18) {
return value * 10 ** (assetDecimals - 18);
} else {
return divisionWithoutRound(value, 10 ** (18 - assetDecimals));
}
}
function convertToWad(uint256 value, uint256 assetDecimals) internal pure returns (uint256) {
if (value > 0) {
if (assetDecimals == 18) {
return value;
} else if (assetDecimals > 18) {
return division(value, 10 ** (assetDecimals - 18));
} else {
return value * 10 ** (18 - assetDecimals);
}
} else {
return value;
}
}
function absoluteValue(int256 value) internal pure returns (uint256) {
return (uint256)(value < 0 ? -value : value);
}
function percentOf(uint256 value, uint256 rate) internal pure returns (uint256) {
return division(value * rate, 1e18);
}
/// @notice Calculates x^n where x and y are represented in RAY (27 decimals)
/// @param x base, represented in 27 decimals
/// @param n exponent, represented in 27 decimals
/// @return z x^n represented in 27 decimals
function rayPow(uint256 x, uint256 n) internal pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 {
z := RAY
}
default {
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
z := RAY
}
default {
z := x
}
let half := div(RAY, 2) // for rounding.
for {
n := div(n, 2)
} n {
n := div(n, 2)
} {
let xx := mul(x, x)
if iszero(eq(div(xx, x), x)) {
revert(0, 0)
}
let xxRound := add(xx, half)
if lt(xxRound, xx) {
revert(0, 0)
}
x := div(xxRound, RAY)
if mod(n, 2) {
let zx := mul(z, x)
if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) {
revert(0, 0)
}
let zxRound := add(zx, half)
if lt(zxRound, zx) {
revert(0, 0)
}
z := div(zxRound, RAY)
}
}
}
}
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}
/*
* ABDK Math Quad Smart Contract Library. Copyright © 2019 by ABDK Consulting.
* Author: Mikhail Vladimirov <[email protected]>
*/
/**
* Smart contract library of mathematical functions operating with IEEE 754
* quadruple-precision binary floating-point numbers (quadruple precision
* numbers). As long as quadruple precision numbers are 16-bytes long, they are
* represented by bytes16 type.
*/
library ABDKMathQuad {
/*
* 0.
*/
bytes16 private constant POSITIVE_ZERO = 0x00000000000000000000000000000000;
/*
* -0.
*/
bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000;
/*
* +Infinity.
*/
bytes16 private constant POSITIVE_INFINITY = 0x7FFF0000000000000000000000000000;
/*
* -Infinity.
*/
bytes16 private constant NEGATIVE_INFINITY = 0xFFFF0000000000000000000000000000;
/*
* Canonical NaN value.
*/
bytes16 private constant NaN = 0x7FFF8000000000000000000000000000;
/**
* Convert signed 256-bit integer number into quadruple precision number.
*
* @param x signed 256-bit integer number
* @return quadruple precision number
*/
function fromInt (int256 x) internal pure returns (bytes16) {
unchecked {
if (x == 0) return bytes16 (0);
else {
// We rely on overflow behavior here
uint256 result = uint256 (x > 0 ? x : -x);
uint256 msb = mostSignificantBit (result);
if (msb < 112) result <<= 112 - msb;
else if (msb > 112) result >>= msb - 112;
result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112;
if (x < 0) result |= 0x80000000000000000000000000000000;
return bytes16 (uint128 (result));
}
}
}
/**
* Convert quadruple precision number into signed 256-bit integer number
* rounding towards zero. Revert on overflow.
*
* @param x quadruple precision number
* @return signed 256-bit integer number
*/
function toInt (bytes16 x) internal pure returns (int256) {
unchecked {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
require (exponent <= 16638); // Overflow
if (exponent < 16383) return 0; // Underflow
uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
0x10000000000000000000000000000;
if (exponent < 16495) result >>= 16495 - exponent;
else if (exponent > 16495) result <<= exponent - 16495;
if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000);
return -int256 (result); // We rely on overflow behavior here
} else {
require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int256 (result);
}
}
}
/**
* Convert unsigned 256-bit integer number into quadruple precision number.
*
* @param x unsigned 256-bit integer number
* @return quadruple precision number
*/
function fromUInt (uint256 x) internal pure returns (bytes16) {
unchecked {
if (x == 0) return bytes16 (0);
else {
uint256 result = x;
uint256 msb = mostSignificantBit (result);
if (msb < 112) result <<= 112 - msb;
else if (msb > 112) result >>= msb - 112;
result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112;
return bytes16 (uint128 (result));
}
}
}
/**
* Convert quadruple precision number into unsigned 256-bit integer number
* rounding towards zero. Revert on underflow. Note, that negative floating
* point numbers in range (-1.0 .. 0.0) may be converted to unsigned integer
* without error, because they are rounded to zero.
*
* @param x quadruple precision number
* @return unsigned 256-bit integer number
*/
function toUInt (bytes16 x) internal pure returns (uint256) {
unchecked {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
if (exponent < 16383) return 0; // Underflow
require (uint128 (x) < 0x80000000000000000000000000000000); // Negative
require (exponent <= 16638); // Overflow
uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
0x10000000000000000000000000000;
if (exponent < 16495) result >>= 16495 - exponent;
else if (exponent > 16495) result <<= exponent - 16495;
return result;
}
}
/**
* Convert signed 128.128 bit fixed point number into quadruple precision
* number.
*
* @param x signed 128.128 bit fixed point number
* @return quadruple precision number
*/
function from128x128 (int256 x) internal pure returns (bytes16) {
unchecked {
if (x == 0) return bytes16 (0);
else {
// We rely on overflow behavior here
uint256 result = uint256 (x > 0 ? x : -x);
uint256 msb = mostSignificantBit (result);
if (msb < 112) result <<= 112 - msb;
else if (msb > 112) result >>= msb - 112;
result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16255 + msb << 112;
if (x < 0) result |= 0x80000000000000000000000000000000;
return bytes16 (uint128 (result));
}
}
}
/**
* Convert quadruple precision number into signed 128.128 bit fixed point
* number. Revert on overflow.
*
* @param x quadruple precision number
* @return signed 128.128 bit fixed point number
*/
function to128x128 (bytes16 x) internal pure returns (int256) {
unchecked {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
require (exponent <= 16510); // Overflow
if (exponent < 16255) return 0; // Underflow
uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
0x10000000000000000000000000000;
if (exponent < 16367) result >>= 16367 - exponent;
else if (exponent > 16367) result <<= exponent - 16367;
if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000);
return -int256 (result); // We rely on overflow behavior here
} else {
require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int256 (result);
}
}
}
/**
* Convert signed 64.64 bit fixed point number into quadruple precision
* number.
*
* @param x signed 64.64 bit fixed point number
* @return quadruple precision number
*/
function from64x64 (int128 x) internal pure returns (bytes16) {
unchecked {
if (x == 0) return bytes16 (0);
else {
// We rely on overflow behavior here
uint256 result = uint128 (x > 0 ? x : -x);
uint256 msb = mostSignificantBit (result);
if (msb < 112) result <<= 112 - msb;
else if (msb > 112) result >>= msb - 112;
result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16319 + msb << 112;
if (x < 0) result |= 0x80000000000000000000000000000000;
return bytes16 (uint128 (result));
}
}
}
/**
* Convert quadruple precision number into signed 64.64 bit fixed point
* number. Revert on overflow.
*
* @param x quadruple precision number
* @return signed 64.64 bit fixed point number
*/
function to64x64 (bytes16 x) internal pure returns (int128) {
unchecked {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
require (exponent <= 16446); // Overflow
if (exponent < 16319) return 0; // Underflow
uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
0x10000000000000000000000000000;
if (exponent < 16431) result >>= 16431 - exponent;
else if (exponent > 16431) result <<= exponent - 16431;
if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
require (result <= 0x80000000000000000000000000000000);
return -int128 (int256 (result)); // We rely on overflow behavior here
} else {
require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int128 (int256 (result));
}
}
}
/**
* Convert octuple precision number into quadruple precision number.
*
* @param x octuple precision number
* @return quadruple precision number
*/
function fromOctuple (bytes32 x) internal pure returns (bytes16) {
unchecked {
bool negative = x & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0;
uint256 exponent = uint256 (x) >> 236 & 0x7FFFF;
uint256 significand = uint256 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (exponent == 0x7FFFF) {
if (significand > 0) return NaN;
else return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
}
if (exponent > 278526)
return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
else if (exponent < 245649)
return negative ? NEGATIVE_ZERO : POSITIVE_ZERO;
else if (exponent < 245761) {
significand = (significand | 0x100000000000000000000000000000000000000000000000000000000000) >> 245885 - exponent;
exponent = 0;
} else {
significand >>= 124;
exponent -= 245760;
}
uint128 result = uint128 (significand | exponent << 112);
if (negative) result |= 0x80000000000000000000000000000000;
return bytes16 (result);
}
}
/**
* Convert quadruple precision number into octuple precision number.
*
* @param x quadruple precision number
* @return octuple precision number
*/
function toOctuple (bytes16 x) internal pure returns (bytes32) {
unchecked {
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
uint256 result = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (exponent == 0x7FFF) exponent = 0x7FFFF; // Infinity or NaN
else if (exponent == 0) {
if (result > 0) {
uint256 msb = mostSignificantBit (result);
result = result << 236 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
exponent = 245649 + msb;
}
} else {
result <<= 124;
exponent += 245760;
}
result |= exponent << 236;
if (uint128 (x) >= 0x80000000000000000000000000000000)
result |= 0x8000000000000000000000000000000000000000000000000000000000000000;
return bytes32 (result);
}
}
/**
* Convert double precision number into quadruple precision number.
*
* @param x double precision number
* @return quadruple precision number
*/
function fromDouble (bytes8 x) internal pure returns (bytes16) {
unchecked {
uint256 exponent = uint64 (x) >> 52 & 0x7FF;
uint256 result = uint64 (x) & 0xFFFFFFFFFFFFF;
if (exponent == 0x7FF) exponent = 0x7FFF; // Infinity or NaN
else if (exponent == 0) {
if (result > 0) {
uint256 msb = mostSignificantBit (result);
result = result << 112 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
exponent = 15309 + msb;
}
} else {
result <<= 60;
exponent += 15360;
}
result |= exponent << 112;
if (x & 0x8000000000000000 > 0)
result |= 0x80000000000000000000000000000000;
return bytes16 (uint128 (result));
}
}
/**
* Convert quadruple precision number into double precision number.
*
* @param x quadruple precision number
* @return double precision number
*/
function toDouble (bytes16 x) internal pure returns (bytes8) {
unchecked {
bool negative = uint128 (x) >= 0x80000000000000000000000000000000;
uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
uint256 significand = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (exponent == 0x7FFF) {
if (significand > 0) return 0x7FF8000000000000; // NaN
else return negative ?
bytes8 (0xFFF0000000000000) : // -Infinity
bytes8 (0x7FF0000000000000); // Infinity
}
if (exponent > 17406)
return negative ?
bytes8 (0xFFF0000000000000) : // -Infinity
bytes8 (0x7FF0000000000000); // Infinity
else if (exponent < 15309)
return negative ?
bytes8 (0x8000000000000000) : // -0
bytes8 (0x0000000000000000); // 0
else if (exponent < 15361) {
significand = (significand | 0x10000000000000000000000000000) >> 15421 - exponent;
exponent = 0;
} else {
significand >>= 60;
exponent -= 15360;
}
uint64 result = uint64 (significand | exponent << 52);
if (negative) result |= 0x8000000000000000;
return bytes8 (result);
}
}
/**
* Test whether given quadruple precision number is NaN.
*
* @param x quadruple precision number
* @return true if x is NaN, false otherwise
*/
function isNaN (bytes16 x) internal pure returns (bool) {
unchecked {
return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF >
0x7FFF0000000000000000000000000000;
}
}
/**
* Test whether given quadruple precision number is positive or negative
* infinity.
*
* @param x quadruple precision number
* @return true if x is positive or negative infinity, false otherwise
*/
function isInfinity (bytes16 x) internal pure returns (bool) {
unchecked {
return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ==
0x7FFF0000000000000000000000000000;
}
}
/**
* Calculate sign of x, i.e. -1 if x is negative, 0 if x if zero, and 1 if x
* is positive. Note that sign (-0) is zero. Revert if x is NaN.
*
* @param x quadruple precision number
* @return sign of x
*/
function sign (bytes16 x) internal pure returns (int8) {
unchecked {
uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN
if (absoluteX == 0) return 0;
else if (uint128 (x) >= 0x80000000000000000000000000000000) return -1;
else return 1;
}
}
/**
* Calculate sign (x - y). Revert if either argument is NaN, or both
* arguments are infinities of the same sign.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return sign (x - y)
*/
function cmp (bytes16 x, bytes16 y) internal pure returns (int8) {
unchecked {
uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN
uint128 absoluteY = uint128 (y) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
require (absoluteY <= 0x7FFF0000000000000000000000000000); // Not NaN
// Not infinities of the same sign
require (x != y || absoluteX < 0x7FFF0000000000000000000000000000);
if (x == y) return 0;
else {
bool negativeX = uint128 (x) >= 0x80000000000000000000000000000000;
bool negativeY = uint128 (y) >= 0x80000000000000000000000000000000;
if (negativeX) {
if (negativeY) return absoluteX > absoluteY ? -1 : int8 (1);
else return -1;
} else {
if (negativeY) return 1;
else return absoluteX > absoluteY ? int8 (1) : -1;
}
}
}
}
/**
* Test whether x equals y. NaN, infinity, and -infinity are not equal to
* anything.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return true if x equals to y, false otherwise
*/
function eq (bytes16 x, bytes16 y) internal pure returns (bool) {
unchecked {
if (x == y) {
return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF <
0x7FFF0000000000000000000000000000;
} else return false;
}
}
/**
* Calculate x + y. Special values behave in the following way:
*
* NaN + x = NaN for any x.
* Infinity + x = Infinity for any finite x.
* -Infinity + x = -Infinity for any finite x.
* Infinity + Infinity = Infinity.
* -Infinity + -Infinity = -Infinity.
* Infinity + -Infinity = -Infinity + Infinity = NaN.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return quadruple precision number
*/
function add (bytes16 x, bytes16 y) internal pure returns (bytes16) {
unchecked {
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;
if (xExponent == 0x7FFF) {
if (yExponent == 0x7FFF) {
if (x == y) return x;
else return NaN;
} else return x;
} else if (yExponent == 0x7FFF) return y;
else {
bool xSign = uint128 (x) >= 0x80000000000000000000000000000000;
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0) xExponent = 1;
else xSignifier |= 0x10000000000000000000000000000;
bool ySign = uint128 (y) >= 0x80000000000000000000000000000000;
uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (yExponent == 0) yExponent = 1;
else ySignifier |= 0x10000000000000000000000000000;
if (xSignifier == 0) return y == NEGATIVE_ZERO ? POSITIVE_ZERO : y;
else if (ySignifier == 0) return x == NEGATIVE_ZERO ? POSITIVE_ZERO : x;
else {
int256 delta = int256 (xExponent) - int256 (yExponent);
if (xSign == ySign) {
if (delta > 112) return x;
else if (delta > 0) ySignifier >>= uint256 (delta);
else if (delta < -112) return y;
else if (delta < 0) {
xSignifier >>= uint256 (-delta);
xExponent = yExponent;
}
xSignifier += ySignifier;
if (xSignifier >= 0x20000000000000000000000000000) {
xSignifier >>= 1;
xExponent += 1;
}
if (xExponent == 0x7FFF)
return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
else {
if (xSignifier < 0x10000000000000000000000000000) xExponent = 0;
else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
return bytes16 (uint128 (
(xSign ? 0x80000000000000000000000000000000 : 0) |
(xExponent << 112) |
xSignifier));
}
} else {
if (delta > 0) {
xSignifier <<= 1;
xExponent -= 1;
} else if (delta < 0) {
ySignifier <<= 1;
xExponent = yExponent - 1;
}
if (delta > 112) ySignifier = 1;
else if (delta > 1) ySignifier = (ySignifier - 1 >> uint256 (delta - 1)) + 1;
else if (delta < -112) xSignifier = 1;
else if (delta < -1) xSignifier = (xSignifier - 1 >> uint256 (-delta - 1)) + 1;
if (xSignifier >= ySignifier) xSignifier -= ySignifier;
else {
xSignifier = ySignifier - xSignifier;
xSign = ySign;
}
if (xSignifier == 0)
return POSITIVE_ZERO;
uint256 msb = mostSignificantBit (xSignifier);
if (msb == 113) {
xSignifier = xSignifier >> 1 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
xExponent += 1;
} else if (msb < 112) {
uint256 shift = 112 - msb;
if (xExponent > shift) {
xSignifier = xSignifier << shift & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
xExponent -= shift;
} else {
xSignifier <<= xExponent - 1;
xExponent = 0;
}
} else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0x7FFF)
return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
else return bytes16 (uint128 (
(xSign ? 0x80000000000000000000000000000000 : 0) |
(xExponent << 112) |
xSignifier));
}
}
}
}
}
/**
* Calculate x - y. Special values behave in the following way:
*
* NaN - x = NaN for any x.
* Infinity - x = Infinity for any finite x.
* -Infinity - x = -Infinity for any finite x.
* Infinity - -Infinity = Infinity.
* -Infinity - Infinity = -Infinity.
* Infinity - Infinity = -Infinity - -Infinity = NaN.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return quadruple precision number
*/
function sub (bytes16 x, bytes16 y) internal pure returns (bytes16) {
unchecked {
return add (x, y ^ 0x80000000000000000000000000000000);
}
}
/**
* Calculate x * y. Special values behave in the following way:
*
* NaN * x = NaN for any x.
* Infinity * x = Infinity for any finite positive x.
* Infinity * x = -Infinity for any finite negative x.
* -Infinity * x = -Infinity for any finite positive x.
* -Infinity * x = Infinity for any finite negative x.
* Infinity * 0 = NaN.
* -Infinity * 0 = NaN.
* Infinity * Infinity = Infinity.
* Infinity * -Infinity = -Infinity.
* -Infinity * Infinity = -Infinity.
* -Infinity * -Infinity = Infinity.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return quadruple precision number
*/
function mul (bytes16 x, bytes16 y) internal pure returns (bytes16) {
unchecked {
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;
if (xExponent == 0x7FFF) {
if (yExponent == 0x7FFF) {
if (x == y) return x ^ y & 0x80000000000000000000000000000000;
else if (x ^ y == 0x80000000000000000000000000000000) return x | y;
else return NaN;
} else {
if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
else return x ^ y & 0x80000000000000000000000000000000;
}
} else if (yExponent == 0x7FFF) {
if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
else return y ^ x & 0x80000000000000000000000000000000;
} else {
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0) xExponent = 1;
else xSignifier |= 0x10000000000000000000000000000;
uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (yExponent == 0) yExponent = 1;
else ySignifier |= 0x10000000000000000000000000000;
xSignifier *= ySignifier;
if (xSignifier == 0)
return (x ^ y) & 0x80000000000000000000000000000000 > 0 ?
NEGATIVE_ZERO : POSITIVE_ZERO;
xExponent += yExponent;
uint256 msb =
xSignifier >= 0x200000000000000000000000000000000000000000000000000000000 ? 225 :
xSignifier >= 0x100000000000000000000000000000000000000000000000000000000 ? 224 :
mostSignificantBit (xSignifier);
if (xExponent + msb < 16496) { // Underflow
xExponent = 0;
xSignifier = 0;
} else if (xExponent + msb < 16608) { // Subnormal
if (xExponent < 16496)
xSignifier >>= 16496 - xExponent;
else if (xExponent > 16496)
xSignifier <<= xExponent - 16496;
xExponent = 0;
} else if (xExponent + msb > 49373) {
xExponent = 0x7FFF;
xSignifier = 0;
} else {
if (msb > 112)
xSignifier >>= msb - 112;
else if (msb < 112)
xSignifier <<= 112 - msb;
xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
xExponent = xExponent + msb - 16607;
}
return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) |
xExponent << 112 | xSignifier));
}
}
}
/**
* Calculate x / y. Special values behave in the following way:
*
* NaN / x = NaN for any x.
* x / NaN = NaN for any x.
* Infinity / x = Infinity for any finite non-negative x.
* Infinity / x = -Infinity for any finite negative x including -0.
* -Infinity / x = -Infinity for any finite non-negative x.
* -Infinity / x = Infinity for any finite negative x including -0.
* x / Infinity = 0 for any finite non-negative x.
* x / -Infinity = -0 for any finite non-negative x.
* x / Infinity = -0 for any finite non-negative x including -0.
* x / -Infinity = 0 for any finite non-negative x including -0.
*
* Infinity / Infinity = NaN.
* Infinity / -Infinity = -NaN.
* -Infinity / Infinity = -NaN.
* -Infinity / -Infinity = NaN.
*
* Division by zero behaves in the following way:
*
* x / 0 = Infinity for any finite positive x.
* x / -0 = -Infinity for any finite positive x.
* x / 0 = -Infinity for any finite negative x.
* x / -0 = Infinity for any finite negative x.
* 0 / 0 = NaN.
* 0 / -0 = NaN.
* -0 / 0 = NaN.
* -0 / -0 = NaN.
*
* @param x quadruple precision number
* @param y quadruple precision number
* @return quadruple precision number
*/
function div (bytes16 x, bytes16 y) internal pure returns (bytes16) {
unchecked {
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;
if (xExponent == 0x7FFF) {
if (yExponent == 0x7FFF) return NaN;
else return x ^ y & 0x80000000000000000000000000000000;
} else if (yExponent == 0x7FFF) {
if (y & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) return NaN;
else return POSITIVE_ZERO | (x ^ y) & 0x80000000000000000000000000000000;
} else if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) {
if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
else return POSITIVE_INFINITY | (x ^ y) & 0x80000000000000000000000000000000;
} else {
uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (yExponent == 0) yExponent = 1;
else ySignifier |= 0x10000000000000000000000000000;
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0) {
if (xSignifier != 0) {
uint shift = 226 - mostSignificantBit (xSignifier);
xSignifier <<= shift;
xExponent = 1;
yExponent += shift - 114;
}
}
else {
xSignifier = (xSignifier | 0x10000000000000000000000000000) << 114;
}
xSignifier = xSignifier / ySignifier;
if (xSignifier == 0)
return (x ^ y) & 0x80000000000000000000000000000000 > 0 ?
NEGATIVE_ZERO : POSITIVE_ZERO;
assert (xSignifier >= 0x1000000000000000000000000000);
uint256 msb =
xSignifier >= 0x80000000000000000000000000000 ? mostSignificantBit (xSignifier) :
xSignifier >= 0x40000000000000000000000000000 ? 114 :
xSignifier >= 0x20000000000000000000000000000 ? 113 : 112;
if (xExponent + msb > yExponent + 16497) { // Overflow
xExponent = 0x7FFF;
xSignifier = 0;
} else if (xExponent + msb + 16380 < yExponent) { // Underflow
xExponent = 0;
xSignifier = 0;
} else if (xExponent + msb + 16268 < yExponent) { // Subnormal
if (xExponent + 16380 > yExponent)
xSignifier <<= xExponent + 16380 - yExponent;
else if (xExponent + 16380 < yExponent)
xSignifier >>= yExponent - xExponent - 16380;
xExponent = 0;
} else { // Normal
if (msb > 112)
xSignifier >>= msb - 112;
xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
xExponent = xExponent + msb + 16269 - yExponent;
}
return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) |
xExponent << 112 | xSignifier));
}
}
}
/**
* Calculate -x.
*
* @param x quadruple precision number
* @return quadruple precision number
*/
function neg (bytes16 x) internal pure returns (bytes16) {
unchecked {
return x ^ 0x80000000000000000000000000000000;
}
}
/**
* Calculate |x|.
*
* @param x quadruple precision number
* @return quadruple precision number
*/
function abs (bytes16 x) internal pure returns (bytes16) {
unchecked {
return x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
}
}
/**
* Calculate square root of x. Return NaN on negative x excluding -0.
*
* @param x quadruple precision number
* @return quadruple precision number
*/
function sqrt (bytes16 x) internal pure returns (bytes16) {
unchecked {
if (uint128 (x) > 0x80000000000000000000000000000000) return NaN;
else {
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
if (xExponent == 0x7FFF) return x;
else {
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0) xExponent = 1;
else xSignifier |= 0x10000000000000000000000000000;
if (xSignifier == 0) return POSITIVE_ZERO;
bool oddExponent = xExponent & 0x1 == 0;
xExponent = xExponent + 16383 >> 1;
if (oddExponent) {
if (xSignifier >= 0x10000000000000000000000000000)
xSignifier <<= 113;
else {
uint256 msb = mostSignificantBit (xSignifier);
uint256 shift = (226 - msb) & 0xFE;
xSignifier <<= shift;
xExponent -= shift - 112 >> 1;
}
} else {
if (xSignifier >= 0x10000000000000000000000000000)
xSignifier <<= 112;
else {
uint256 msb = mostSignificantBit (xSignifier);
uint256 shift = (225 - msb) & 0xFE;
xSignifier <<= shift;
xExponent -= shift - 112 >> 1;
}
}
uint256 r = 0x10000000000000000000000000000;
r = (r + xSignifier / r) >> 1;
r = (r + xSignifier / r) >> 1;
r = (r + xSignifier / r) >> 1;
r = (r + xSignifier / r) >> 1;
r = (r + xSignifier / r) >> 1;
r = (r + xSignifier / r) >> 1;
r = (r + xSignifier / r) >> 1; // Seven iterations should be enough
uint256 r1 = xSignifier / r;
if (r1 < r) r = r1;
return bytes16 (uint128 (xExponent << 112 | r & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
}
}
}
}
/**
* Calculate binary logarithm of x. Return NaN on negative x excluding -0.
*
* @param x quadruple precision number
* @return quadruple precision number
*/
function log_2 (bytes16 x) internal pure returns (bytes16) {
unchecked {
if (uint128 (x) > 0x80000000000000000000000000000000) return NaN;
else if (x == 0x3FFF0000000000000000000000000000) return POSITIVE_ZERO;
else {
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
if (xExponent == 0x7FFF) return x;
else {
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0) xExponent = 1;
else xSignifier |= 0x10000000000000000000000000000;
if (xSignifier == 0) return NEGATIVE_INFINITY;
bool resultNegative;
uint256 resultExponent = 16495;
uint256 resultSignifier;
if (xExponent >= 0x3FFF) {
resultNegative = false;
resultSignifier = xExponent - 0x3FFF;
xSignifier <<= 15;
} else {
resultNegative = true;
if (xSignifier >= 0x10000000000000000000000000000) {
resultSignifier = 0x3FFE - xExponent;
xSignifier <<= 15;
} else {
uint256 msb = mostSignificantBit (xSignifier);
resultSignifier = 16493 - msb;
xSignifier <<= 127 - msb;
}
}
if (xSignifier == 0x80000000000000000000000000000000) {
if (resultNegative) resultSignifier += 1;
uint256 shift = 112 - mostSignificantBit (resultSignifier);
resultSignifier <<= shift;
resultExponent -= shift;
} else {
uint256 bb = resultNegative ? 1 : 0;
while (resultSignifier < 0x10000000000000000000000000000) {
resultSignifier <<= 1;
resultExponent -= 1;
xSignifier *= xSignifier;
uint256 b = xSignifier >> 255;
resultSignifier += b ^ bb;
xSignifier >>= 127 + b;
}
}
return bytes16 (uint128 ((resultNegative ? 0x80000000000000000000000000000000 : 0) |
resultExponent << 112 | resultSignifier & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
}
}
}
}
/**
* Calculate natural logarithm of x. Return NaN on negative x excluding -0.
*
* @param x quadruple precision number
* @return quadruple precision number
*/
function ln (bytes16 x) internal pure returns (bytes16) {
unchecked {
return mul (log_2 (x), 0x3FFE62E42FEFA39EF35793C7673007E5);
}
}
/**
* Calculate 2^x.
*
* @param x quadruple precision number
* @return quadruple precision number
*/
function pow_2 (bytes16 x) internal pure returns (bytes16) {
unchecked {
bool xNegative = uint128 (x) > 0x80000000000000000000000000000000;
uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xExponent == 0x7FFF && xSignifier != 0) return NaN;
else if (xExponent > 16397)
return xNegative ? POSITIVE_ZERO : POSITIVE_INFINITY;
else if (xExponent < 16255)
return 0x3FFF0000000000000000000000000000;
else {
if (xExponent == 0) xExponent = 1;
else xSignifier |= 0x10000000000000000000000000000;
if (xExponent > 16367)
xSignifier <<= xExponent - 16367;
else if (xExponent < 16367)
xSignifier >>= 16367 - xExponent;
if (xNegative && xSignifier > 0x406E00000000000000000000000000000000)
return POSITIVE_ZERO;
if (!xNegative && xSignifier > 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
return POSITIVE_INFINITY;
uint256 resultExponent = xSignifier >> 128;
xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
if (xNegative && xSignifier != 0) {
xSignifier = ~xSignifier;
resultExponent += 1;
}
uint256 resultSignifier = 0x80000000000000000000000000000000;
if (xSignifier & 0x80000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
if (xSignifier & 0x40000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
if (xSignifier & 0x20000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
if (xSignifier & 0x10000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
if (xSignifier & 0x8000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
if (xSignifier & 0x4000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
if (xSignifier & 0x2000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
if (xSignifier & 0x1000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
if (xSignifier & 0x800000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
if (xSignifier & 0x400000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
if (xSignifier & 0x200000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
if (xSignifier & 0x100000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
if (xSignifier & 0x80000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
if (xSignifier & 0x40000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
if (xSignifier & 0x20000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000162E525EE054754457D5995292026 >> 128;
if (xSignifier & 0x10000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
if (xSignifier & 0x8000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
if (xSignifier & 0x4000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
if (xSignifier & 0x2000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000162E43F4F831060E02D839A9D16D >> 128;
if (xSignifier & 0x1000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
if (xSignifier & 0x800000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
if (xSignifier & 0x400000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
if (xSignifier & 0x200000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
if (xSignifier & 0x100000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
if (xSignifier & 0x80000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
if (xSignifier & 0x40000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
if (xSignifier & 0x20000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
if (xSignifier & 0x10000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
if (xSignifier & 0x8000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
if (xSignifier & 0x4000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
if (xSignifier & 0x2000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
if (xSignifier & 0x1000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
if (xSignifier & 0x800000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
if (xSignifier & 0x400000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
if (xSignifier & 0x200000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000162E42FEFB2FED257559BDAA >> 128;
if (xSignifier & 0x100000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
if (xSignifier & 0x80000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
if (xSignifier & 0x40000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
if (xSignifier & 0x20000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
if (xSignifier & 0x10000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000B17217F7D20CF927C8E94C >> 128;
if (xSignifier & 0x8000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
if (xSignifier & 0x4000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000002C5C85FDF477B662B26945 >> 128;
if (xSignifier & 0x2000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000162E42FEFA3AE53369388C >> 128;
if (xSignifier & 0x1000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000B17217F7D1D351A389D40 >> 128;
if (xSignifier & 0x800000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
if (xSignifier & 0x400000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
if (xSignifier & 0x200000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000162E42FEFA39FE95583C2 >> 128;
if (xSignifier & 0x100000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
if (xSignifier & 0x80000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
if (xSignifier & 0x40000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000002C5C85FDF473E242EA38 >> 128;
if (xSignifier & 0x20000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000162E42FEFA39F02B772C >> 128;
if (xSignifier & 0x10000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
if (xSignifier & 0x8000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
if (xSignifier & 0x4000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000002C5C85FDF473DEA871F >> 128;
if (xSignifier & 0x2000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000162E42FEFA39EF44D91 >> 128;
if (xSignifier & 0x1000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000B17217F7D1CF79E949 >> 128;
if (xSignifier & 0x800000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
if (xSignifier & 0x400000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
if (xSignifier & 0x200000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000162E42FEFA39EF366F >> 128;
if (xSignifier & 0x100000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000B17217F7D1CF79AFA >> 128;
if (xSignifier & 0x80000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
if (xSignifier & 0x40000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
if (xSignifier & 0x20000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000162E42FEFA39EF358 >> 128;
if (xSignifier & 0x10000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000B17217F7D1CF79AB >> 128;
if (xSignifier & 0x8000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000058B90BFBE8E7BCD5 >> 128;
if (xSignifier & 0x4000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000002C5C85FDF473DE6A >> 128;
if (xSignifier & 0x2000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000162E42FEFA39EF34 >> 128;
if (xSignifier & 0x1000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000B17217F7D1CF799 >> 128;
if (xSignifier & 0x800000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000058B90BFBE8E7BCC >> 128;
if (xSignifier & 0x400000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000002C5C85FDF473DE5 >> 128;
if (xSignifier & 0x200000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000162E42FEFA39EF2 >> 128;
if (xSignifier & 0x100000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000B17217F7D1CF78 >> 128;
if (xSignifier & 0x80000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000058B90BFBE8E7BB >> 128;
if (xSignifier & 0x40000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000002C5C85FDF473DD >> 128;
if (xSignifier & 0x20000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000162E42FEFA39EE >> 128;
if (xSignifier & 0x10000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000B17217F7D1CF6 >> 128;
if (xSignifier & 0x8000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000058B90BFBE8E7A >> 128;
if (xSignifier & 0x4000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000002C5C85FDF473C >> 128;
if (xSignifier & 0x2000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000162E42FEFA39D >> 128;
if (xSignifier & 0x1000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000B17217F7D1CE >> 128;
if (xSignifier & 0x800000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000058B90BFBE8E6 >> 128;
if (xSignifier & 0x400000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000002C5C85FDF472 >> 128;
if (xSignifier & 0x200000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000162E42FEFA38 >> 128;
if (xSignifier & 0x100000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000B17217F7D1B >> 128;
if (xSignifier & 0x80000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000058B90BFBE8D >> 128;
if (xSignifier & 0x40000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000002C5C85FDF46 >> 128;
if (xSignifier & 0x20000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000162E42FEFA2 >> 128;
if (xSignifier & 0x10000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000B17217F7D0 >> 128;
if (xSignifier & 0x8000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000058B90BFBE7 >> 128;
if (xSignifier & 0x4000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000002C5C85FDF3 >> 128;
if (xSignifier & 0x2000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000162E42FEF9 >> 128;
if (xSignifier & 0x1000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000B17217F7C >> 128;
if (xSignifier & 0x800000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000058B90BFBD >> 128;
if (xSignifier & 0x400000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000002C5C85FDE >> 128;
if (xSignifier & 0x200000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000162E42FEE >> 128;
if (xSignifier & 0x100000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000B17217F6 >> 128;
if (xSignifier & 0x80000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000058B90BFA >> 128;
if (xSignifier & 0x40000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000002C5C85FC >> 128;
if (xSignifier & 0x20000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000162E42FD >> 128;
if (xSignifier & 0x10000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000B17217E >> 128;
if (xSignifier & 0x8000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000058B90BE >> 128;
if (xSignifier & 0x4000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000002C5C85E >> 128;
if (xSignifier & 0x2000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000162E42E >> 128;
if (xSignifier & 0x1000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000B17216 >> 128;
if (xSignifier & 0x800000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000058B90A >> 128;
if (xSignifier & 0x400000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000002C5C84 >> 128;
if (xSignifier & 0x200000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000162E41 >> 128;
if (xSignifier & 0x100000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000B1720 >> 128;
if (xSignifier & 0x80000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000058B8F >> 128;
if (xSignifier & 0x40000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000002C5C7 >> 128;
if (xSignifier & 0x20000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000162E3 >> 128;
if (xSignifier & 0x10000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000B171 >> 128;
if (xSignifier & 0x8000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000058B8 >> 128;
if (xSignifier & 0x4000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000002C5B >> 128;
if (xSignifier & 0x2000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000162D >> 128;
if (xSignifier & 0x1000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000B16 >> 128;
if (xSignifier & 0x800 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000058A >> 128;
if (xSignifier & 0x400 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000002C4 >> 128;
if (xSignifier & 0x200 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000161 >> 128;
if (xSignifier & 0x100 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000000B0 >> 128;
if (xSignifier & 0x80 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000057 >> 128;
if (xSignifier & 0x40 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000002B >> 128;
if (xSignifier & 0x20 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000015 >> 128;
if (xSignifier & 0x10 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000000A >> 128;
if (xSignifier & 0x8 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000004 >> 128;
if (xSignifier & 0x4 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000001 >> 128;
if (!xNegative) {
resultSignifier = resultSignifier >> 15 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
resultExponent += 0x3FFF;
} else if (resultExponent <= 0x3FFE) {
resultSignifier = resultSignifier >> 15 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
resultExponent = 0x3FFF - resultExponent;
} else {
resultSignifier = resultSignifier >> resultExponent - 16367;
resultExponent = 0;
}
return bytes16 (uint128 (resultExponent << 112 | resultSignifier));
}
}
}
/**
* Calculate e^x.
*
* @param x quadruple precision number
* @return quadruple precision number
*/
function exp (bytes16 x) internal pure returns (bytes16) {
unchecked {
return pow_2 (mul (x, 0x3FFF71547652B82FE1777D0FFDA0D23A));
}
}
/**
* Get index of the most significant non-zero bit in binary representation of
* x. Reverts if x is zero.
*
* @return index of the most significant non-zero bit in binary representation
* of x
*/
function mostSignificantBit (uint256 x) private pure returns (uint256) {
unchecked {
require (x > 0);
uint256 result = 0;
if (x >= 0x100000000000000000000000000000000) { x >>= 128; result += 128; }
if (x >= 0x10000000000000000) { x >>= 64; result += 64; }
if (x >= 0x100000000) { x >>= 32; result += 32; }
if (x >= 0x10000) { x >>= 16; result += 16; }
if (x >= 0x100) { x >>= 8; result += 8; }
if (x >= 0x10) { x >>= 4; result += 4; }
if (x >= 0x4) { x >>= 2; result += 2; }
if (x >= 0x2) result += 1; // No need to shift x anymore
return result;
}
}
}
/// @title Spread interface for tenor 28 days lens
interface ISpread28DaysLens {
/// @notice Calculates the quote value for pay fixed 28-day period on the pay-fixed side based on the provided spread inputs.
/// @param spreadInputs The spread inputs required for the calculation.
/// @return quoteValue The calculated quote value for the pay-fixed side.
function calculateOfferedRatePayFixed28Days(
IporTypes.SpreadInputs calldata spreadInputs
) external view returns (uint256 quoteValue);
/// @notice Calculates the quote value for a fixed 28-day period on the receive-fixed side based on the provided spread inputs.
/// @param spreadInputs The spread inputs required for the calculation.
/// @return quoteValue The calculated quote value for the receive-fixed side.
function calculateOfferedRateReceiveFixed28Days(
IporTypes.SpreadInputs calldata spreadInputs
) external view returns (uint256 quoteValue);
/// @notice Returns the configuration values for the spread function used in the 28-day imbalance spread calculation.
/// @return An array of configuration values for the spread function.
function spreadFunction28DaysConfig() external pure returns (uint256[] memory);
}
/// @title Spread interface for tenor 60 days lens
interface ISpread60DaysLens {
/// @notice Calculates the quote value for a fixed 60-day period on the pay-fixed side based on the provided spread inputs.
/// @param spreadInputs The spread inputs required for the calculation.
/// @return quoteValue The calculated quote value for the pay-fixed side.
function calculateOfferedRatePayFixed60Days(
IporTypes.SpreadInputs calldata spreadInputs
) external returns (uint256 quoteValue);
/// @notice Calculates the quote value for a fixed 60-day period on the receive-fixed side based on the provided spread inputs.
/// @param spreadInputs The spread inputs required for the calculation.
/// @return quoteValue The calculated quote value for the receive-fixed side.
function calculateOfferedRateReceiveFixed60Days(
IporTypes.SpreadInputs calldata spreadInputs
) external returns (uint256 quoteValue);
/// @notice Returns the configuration values for the spread function used in the 60-day imbalance spread calculation.
/// @return An array of configuration values for the spread function.
function spreadFunction60DaysConfig() external pure returns (uint256[] memory);
}
/// @title Spread interface for tenor 90 days lens
interface ISpread90DaysLens {
/// @notice Calculates the quote value for a fixed 90-day period on the pay-fixed side based on the provided spread inputs.
/// @param spreadInputs The spread inputs required for the calculation.
/// @return quoteValue The calculated quote value for the pay-fixed side.
function calculateOfferedRatePayFixed90Days(
IporTypes.SpreadInputs calldata spreadInputs
) external returns (uint256 quoteValue);
/// @notice Calculates the quote value for a fixed 90-day period on the receive-fixed side based on the provided spread inputs.
/// @param spreadInputs The spread inputs required for the calculation.
/// @return quoteValue The calculated quote value for the receive-fixed side.
function calculateOfferedRateReceiveFixed90Days(
IporTypes.SpreadInputs calldata spreadInputs
) external returns (uint256 quoteValue);
/// @notice Returns the configuration values for the spread function used in the 90-day imbalance spread calculation.
/// @return An array of configuration values for the spread function.
function spreadFunction90DaysConfig() external pure returns (uint256[] memory);
}
/// @title Interface of ipToken - Liquidity Pool Token managed by Router in IPOR Protocol for a given asset.
/// For more information refer to the documentation https://ipor-labs.gitbook.io/ipor-labs/automated-market-maker/liquidity-provisioning#liquidity-tokens
interface IIpToken is IERC20 {
/// @notice Gets the asset / stablecoin address which is associated with particular ipToken smart contract instance
/// @return asset / stablecoin address
function getAsset() external view returns (address);
/// @notice Gets the Token Manager's address.
function getTokenManager() external view returns (address);
/// @notice Sets token manager's address. IpToken contract Owner only
/// @dev only Token Manager can mint or burn ipTokens. Function emits `TokenManagerChanged` event.
/// @param newTokenManager Token Managers's address
function setTokenManager(address newTokenManager) external;
/// @notice Creates the ipTokens in the `amount` given and assigns them to the `account`
/// @dev Emits {Transfer} from ERC20 asset and {Mint} event from ipToken
/// @param account to which the created ipTokens were assigned
/// @param amount volume of ipTokens created
function mint(address account, uint256 amount) external;
/// @notice Burns the `amount` of ipTokens from `account`, reducing the total supply
/// @dev Emits {Transfer} from ERC20 asset and {Burn} event from ipToken
/// @param account from which burned ipTokens are taken
/// @param amount volume of ipTokens that will be burned, represented in 18 decimals
function burn(address account, uint256 amount) external;
/// @notice Emitted after the `amount` ipTokens were mint and transferred to `account`.
/// @param account address where ipTokens are transferred after minting
/// @param amount of ipTokens minted, represented in 18 decimals
event Mint(address indexed account, uint256 amount);
/// @notice Emitted after `amount` ipTokens were transferred from `account` and burnt.
/// @param account address from which ipTokens are transferred to be burned
/// @param amount volume of ipTokens burned
event Burn(address indexed account, uint256 amount);
/// @notice Emitted when Token Manager address is changed by its owner.
/// @param newTokenManager new address of Token Manager
event TokenManagerChanged(address indexed newTokenManager);
}
/// @title Interface for interaction with IporOracle, smart contract responsible for managing IPOR Index.
interface IIporOracle {
/// @notice Structure representing parameters required to update an IPOR index for a given asset.
/// @dev This structure is used in the `updateIndexes` method to provide necessary details for updating IPOR indexes.
/// For assets other than '_stEth', the 'quasiIbtPrice' field is not utilized in the update process.
/// @param asset The address of the underlying asset/stablecoin supported by the IPOR Protocol.
/// @param indexValue The new value of the IPOR index to be set for the specified asset.
/// @param updateTimestamp The timestamp at which the index value is updated, used to calculate accrued interest.
/// @param quasiIbtPrice The quasi interest-bearing token (IBT) price, applicable only for the '_stEth' asset.
/// Represents a specialized value used in calculations for staked Ethereum.
struct UpdateIndexParams {
address asset;
uint256 indexValue;
uint256 updateTimestamp;
uint256 quasiIbtPrice;
}
/// @notice Returns current version of IporOracle's
/// @dev Increase number when implementation inside source code is different that implementation deployed on Mainnet
/// @return current IporOracle version
function getVersion() external pure returns (uint256);
/// @notice Gets IPOR Index indicators for a given asset
/// @dev all returned values represented in 18 decimals
/// @param asset underlying / stablecoin address supported in Ipor Protocol
/// @return indexValue IPOR Index value for a given asset calculated for time lastUpdateTimestamp
/// @return ibtPrice Interest Bearing Token Price for a given IPOR Index calculated for time lastUpdateTimestamp
/// @return lastUpdateTimestamp Last IPOR Index update done by off-chain service
/// @dev For calculation accrued IPOR Index indicators (indexValue and ibtPrice) for a specified timestamp use {getAccruedIndex} function.
/// Method {getIndex} calculates IPOR Index indicators for a moment when last update was done by off-chain service,
/// this timestamp is stored in lastUpdateTimestamp variable.
function getIndex(
address asset
) external view returns (uint256 indexValue, uint256 ibtPrice, uint256 lastUpdateTimestamp);
/// @notice Gets accrued IPOR Index indicators for a given timestamp and asset.
/// @param calculateTimestamp time of accrued IPOR Index calculation
/// @param asset underlying / stablecoin address supported by IPOR Protocol.
/// @return accruedIpor structure {IporTypes.AccruedIpor}
/// @dev ibtPrice included in accruedIpor structure is calculated using continuous compounding interest formula
function getAccruedIndex(
uint256 calculateTimestamp,
address asset
) external view returns (IporTypes.AccruedIpor memory accruedIpor);
/// @notice Calculates accrued Interest Bearing Token price for a given asset and timestamp.
/// @param asset underlying / stablecoin address supported by IPOR Protocol.
/// @param calculateTimestamp time of accrued Interest Bearing Token price calculation
/// @return accrued IBT price, represented in 18 decimals
function calculateAccruedIbtPrice(address asset, uint256 calculateTimestamp) external view returns (uint256);
/// @notice Updates the Indexes based on the provided parameters.
/// It is marked as 'onlyUpdater' meaning it has restricted access, and 'whenNotPaused' indicating it only operates when the contract is not paused.
/// @param indexesToUpdate An array of `IIporOracle.UpdateIndexParams` to be updated.
/// The structure typically contains fields like 'asset', 'indexValue', 'updateTimestamp', and 'quasiIbtPrice'.
/// However, 'updateTimestamp' and 'quasiIbtPrice' are not used in this function.
function updateIndexes(UpdateIndexParams[] calldata indexesToUpdate) external;
/// @notice Updates both the Indexes and the Quasi IBT (Interest Bearing Token) Price based on the provided parameters.
/// @param indexesToUpdate An array of `IIporOracle.UpdateIndexParams` to be updated.
/// The structure contains fields such as 'asset', 'indexValue', 'updateTimestamp', and 'quasiIbtPrice', all of which are utilized in this update process.
function updateIndexesAndQuasiIbtPrice(IIporOracle.UpdateIndexParams[] calldata indexesToUpdate) external;
/// @notice Adds new Updater. Updater has right to update IPOR Index. Function available only for Owner.
/// @param newUpdater new updater address
function addUpdater(address newUpdater) external;
/// @notice Removes Updater. Function available only for Owner.
/// @param updater updater address
function removeUpdater(address updater) external;
/// @notice Checks if given account is an Updater.
/// @param account account for checking
/// @return 0 if account is not updater, 1 if account is updater.
function isUpdater(address account) external view returns (uint256);
/// @notice Adds new asset which IPOR Protocol will support. Function available only for Owner.
/// @param newAsset new asset address
/// @param updateTimestamp Time when start to accrue interest for Interest Bearing Token price.
function addAsset(address newAsset, uint256 updateTimestamp) external;
/// @notice Removes asset which IPOR Protocol will not support. Function available only for Owner.
/// @param asset underlying / stablecoin address which current is supported by IPOR Protocol.
function removeAsset(address asset) external;
/// @notice Checks if given asset is supported by IPOR Protocol.
/// @param asset underlying / stablecoin address
function isAssetSupported(address asset) external view returns (bool);
/// @notice Emmited when Charlie update IPOR Index.
/// @param asset underlying / stablecoin address
/// @param indexValue IPOR Index value represented in 18 decimals
/// @param quasiIbtPrice quasi Interest Bearing Token price represented in 18 decimals.
/// @param updateTimestamp moment when IPOR Index was updated.
event IporIndexUpdate(address asset, uint256 indexValue, uint256 quasiIbtPrice, uint256 updateTimestamp);
/// @notice event emitted when IPOR Index Updater is added by Owner
/// @param newUpdater new Updater address
event IporIndexAddUpdater(address newUpdater);
/// @notice event emitted when IPOR Index Updater is removed by Owner
/// @param updater updater address
event IporIndexRemoveUpdater(address updater);
/// @notice event emitted when new asset is added by Owner to list of assets supported in IPOR Protocol.
/// @param newAsset new asset address
/// @param updateTimestamp update timestamp
event IporIndexAddAsset(address newAsset, uint256 updateTimestamp);
/// @notice event emitted when asset is removed by Owner from list of assets supported in IPOR Protocol.
/// @param asset asset address
event IporIndexRemoveAsset(address asset);
}
library IporContractValidator {
function checkAddress(address addr) internal pure returns (address) {
require(addr != address(0), IporErrors.WRONG_ADDRESS);
return addr;
}
}
/// @title Interface of the CloseSwap Lens.
interface IAmmCloseSwapLens {
/// @notice Structure representing the configuration of the AmmCloseSwapService for a given pool (asset).
struct AmmCloseSwapServicePoolConfiguration {
/// @notice asset address
address asset;
/// @notice asset decimals
uint256 decimals;
/// @notice Amm Storage contract address
address ammStorage;
/// @notice Amm Treasury contract address
address ammTreasury;
/// @notice Asset Management contract address, for stETH is empty, because stETH doesn't have asset management module
address assetManagement;
/// @notice Spread address, for USDT, USDC, DAI is a spread router address, for stETH is a spread address
address spread;
/// @notice Unwinding Fee Rate for unwinding the swap, represented in 18 decimals, 1e18 = 100%
uint256 unwindingFeeRate;
/// @notice Unwinding Fee Rate for unwinding the swap, part earmarked for the treasury, represented in 18 decimals, 1e18 = 100%
uint256 unwindingFeeTreasuryPortionRate;
/// @notice Max number of swaps (per leg) that can be liquidated in one call, represented without decimals
uint256 maxLengthOfLiquidatedSwapsPerLeg;
/// @notice Time before maturity when the community is allowed to close the swap, represented in seconds
uint256 timeBeforeMaturityAllowedToCloseSwapByCommunity;
/// @notice Time before maturity then the swap owner can close it, for tenor 28 days, represented in seconds
uint256 timeBeforeMaturityAllowedToCloseSwapByBuyerTenor28days;
/// @notice Time before maturity then the swap owner can close it, for tenor 60 days, represented in seconds
uint256 timeBeforeMaturityAllowedToCloseSwapByBuyerTenor60days;
/// @notice Time before maturity then the swap owner can close it, for tenor 90 days, represented in seconds
uint256 timeBeforeMaturityAllowedToCloseSwapByBuyerTenor90days;
/// @notice Min liquidation threshold allowing community to close the swap ahead of maturity, represented in 18 decimals
uint256 minLiquidationThresholdToCloseBeforeMaturityByCommunity;
/// @notice Min liquidation threshold allowing the owner to close the swap ahead of maturity, represented in 18 decimals
uint256 minLiquidationThresholdToCloseBeforeMaturityByBuyer;
/// @notice Min leverage of the virtual swap used in unwinding, represented in 18 decimals
uint256 minLeverage;
/// @notice Time after open swap when it is allowed to close swap with unwinding, for tenor 28 days, represented in seconds
uint256 timeAfterOpenAllowedToCloseSwapWithUnwindingTenor28days;
/// @notice Time after open swap when it is allowed to close swap with unwinding, for tenor 60 days, represented in seconds
uint256 timeAfterOpenAllowedToCloseSwapWithUnwindingTenor60days;
/// @notice Time after open swap when it is allowed to close swap with unwinding, for tenor 90 days, represented in seconds
uint256 timeAfterOpenAllowedToCloseSwapWithUnwindingTenor90days;
}
/// @notice Returns the configuration of the AmmCloseSwapService for a given pool (asset).
/// @param asset asset address
/// @return AmmCloseSwapServicePoolConfiguration struct representing the configuration of the AmmCloseSwapService for a given pool (asset).
function getAmmCloseSwapServicePoolConfiguration(
address asset
) external view returns (AmmCloseSwapServicePoolConfiguration memory);
/// @notice Returns the closing swap details for a given swap and closing timestamp.
/// @param asset asset address
/// @param account account address for which are returned closing swap details, for example closableStatus depends on the account
/// @param direction swap direction
/// @param swapId swap id
/// @param closeTimestamp closing timestamp
/// @param riskIndicatorsInput risk indicators input
/// @return closingSwapDetails struct representing the closing swap details for a given swap and closing timestamp.
function getClosingSwapDetails(
address asset,
address account,
AmmTypes.SwapDirection direction,
uint256 swapId,
uint256 closeTimestamp,
AmmTypes.CloseSwapRiskIndicatorsInput calldata riskIndicatorsInput
) external view returns (AmmTypes.ClosingSwapDetails memory closingSwapDetails);
}
/// @title Types used in interfaces strictly related to AMM (Automated Market Maker).
/// @dev Used by IAmmTreasury and IAmmStorage interfaces.
library AmmTypes {
/// @notice Struct describing AMM Pool's core addresses.
struct AmmPoolCoreModel {
/// @notice asset address
address asset;
/// @notice asset decimals
uint256 assetDecimals;
/// @notice ipToken address associated to the asset
address ipToken;
/// @notice AMM Storage address
address ammStorage;
/// @notice AMM Treasury address
address ammTreasury;
/// @notice Asset Management address
address assetManagement;
/// @notice IPOR Oracle address
address iporOracle;
}
/// @notice Structure which represents Swap's data that will be saved in the storage.
/// Refer to the documentation https://ipor-labs.gitbook.io/ipor-labs/automated-market-maker/ipor-swaps for more information.
struct NewSwap {
/// @notice Account / trader who opens the Swap
address buyer;
/// @notice Epoch timestamp of when position was opened by the trader.
uint256 openTimestamp;
/// @notice Swap's collateral amount.
/// @dev value represented in 18 decimals
uint256 collateral;
/// @notice Swap's notional amount.
/// @dev value represented in 18 decimals
uint256 notional;
/// @notice Quantity of Interest Bearing Token (IBT) at moment when position was opened.
/// @dev value represented in 18 decimals
uint256 ibtQuantity;
/// @notice Fixed interest rate at which the position has been opened.
/// @dev value represented in 18 decimals
uint256 fixedInterestRate;
/// @notice Liquidation deposit is retained when the swap is opened. It is then paid back to agent who closes the derivative at maturity.
/// It can be both trader or community member. Trader receives the deposit back when he chooses to close the derivative before maturity.
/// @dev value represented WITHOUT 18 decimals for USDT, USDC, DAI pool. Notice! Value represented in 6 decimals for stETH pool.
/// @dev Example value in 6 decimals: 25000000 (in 6 decimals) = 25 stETH = 25.000000
uint256 liquidationDepositAmount;
/// @notice Opening fee amount part which is allocated in Liquidity Pool Balance. This fee is calculated as a rate of the swap's collateral.
/// @dev value represented in 18 decimals
uint256 openingFeeLPAmount;
/// @notice Opening fee amount part which is allocated in Treasury Balance. This fee is calculated as a rate of the swap's collateral.
/// @dev value represented in 18 decimals
uint256 openingFeeTreasuryAmount;
/// @notice Swap's tenor, 0 - 28 days, 1 - 60 days or 2 - 90 days
IporTypes.SwapTenor tenor;
}
/// @notice Struct representing swap item, used for listing and in internal calculations
struct Swap {
/// @notice Swap's unique ID
uint256 id;
/// @notice Swap's buyer
address buyer;
/// @notice Swap opening epoch timestamp
uint256 openTimestamp;
/// @notice Swap's tenor
IporTypes.SwapTenor tenor;
/// @notice Index position of this Swap in an array of swaps' identification associated to swap buyer
/// @dev Field used for gas optimization purposes, it allows for quick removal by id in the array.
/// During removal the last item in the array is switched with the one that just has been removed.
uint256 idsIndex;
/// @notice Swap's collateral
/// @dev value represented in 18 decimals
uint256 collateral;
/// @notice Swap's notional amount
/// @dev value represented in 18 decimals
uint256 notional;
/// @notice Swap's notional amount denominated in the Interest Bearing Token (IBT)
/// @dev value represented in 18 decimals
uint256 ibtQuantity;
/// @notice Fixed interest rate at which the position has been opened
/// @dev value represented in 18 decimals
uint256 fixedInterestRate;
/// @notice Liquidation deposit amount
/// @dev value represented in 18 decimals
uint256 liquidationDepositAmount;
/// @notice State of the swap
/// @dev 0 - INACTIVE, 1 - ACTIVE
IporTypes.SwapState state;
}
/// @notice Struct representing amounts related to Swap that is presently being opened.
/// @dev all values represented in 18 decimals
struct OpenSwapAmount {
/// @notice Total Amount of asset that is sent from buyer to AmmTreasury when opening swap.
uint256 totalAmount;
/// @notice Swap's collateral
uint256 collateral;
/// @notice Swap's notional
uint256 notional;
/// @notice Opening Fee - part allocated as a profit of the Liquidity Pool
uint256 openingFeeLPAmount;
/// @notice Part of the fee set aside for subsidizing the oracle that publishes IPOR rate. Flat fee set by the DAO.
/// @notice Opening Fee - part allocated in Treasury balance. Part of the fee set asside for subsidising the oracle that publishes IPOR rate. Flat fee set by the DAO.
uint256 openingFeeTreasuryAmount;
/// @notice Fee set aside for subsidizing the oracle that publishes IPOR rate. Flat fee set by the DAO.
uint256 iporPublicationFee;
/// @notice Liquidation deposit is retained when the swap is opened. Value represented in 18 decimals.
uint256 liquidationDepositAmount;
}
/// @notice Structure describes one swap processed by closeSwaps method, information about swap ID and flag if this swap was closed during execution closeSwaps method.
struct IporSwapClosingResult {
/// @notice Swap ID
uint256 swapId;
/// @notice Flag describe if swap was closed during this execution
bool closed;
}
/// @notice Technical structure used for storing information about amounts used during redeeming assets from liquidity pool.
struct RedeemAmount {
/// @notice Asset amount represented in 18 decimals
/// @dev Asset amount is a sum of wadRedeemFee and wadRedeemAmount
uint256 wadAssetAmount;
/// @notice Redeemed amount represented in decimals of asset
uint256 redeemAmount;
/// @notice Redeem fee value represented in 18 decimals
uint256 wadRedeemFee;
/// @notice Redeem amount represented in 18 decimals
uint256 wadRedeemAmount;
}
struct UnwindParams {
/// @notice Risk Indicators Inputs signer
address messageSigner;
/// @notice Spread Router contract address
address spreadRouter;
address ammStorage;
address ammTreasury;
SwapDirection direction;
uint256 closeTimestamp;
int256 swapPnlValueToDate;
uint256 indexValue;
Swap swap;
IAmmCloseSwapLens.AmmCloseSwapServicePoolConfiguration poolCfg;
CloseSwapRiskIndicatorsInput riskIndicatorsInputs;
}
/// @notice Swap direction (long = Pay Fixed and Receive a Floating or short = receive fixed and pay a floating)
enum SwapDirection {
/// @notice When taking the "long" position the trader will pay a fixed rate and receive a floating rate.
/// for more information refer to the documentation https://ipor-labs.gitbook.io/ipor-labs/automated-market-maker/ipor-swaps
PAY_FIXED_RECEIVE_FLOATING,
/// @notice When taking the "short" position the trader will pay a floating rate and receive a fixed rate.
PAY_FLOATING_RECEIVE_FIXED
}
/// @notice List of closable statuses for a given swap
/// @dev Closable status is a one of the following values:
/// 0 - Swap is closable
/// 1 - Swap is already closed
/// 2 - Swap state required Buyer or Liquidator to close. Sender is not Buyer nor Liquidator.
/// 3 - Cannot close swap, closing is too early for Community
/// 4 - Cannot close swap with unwind because action is too early from the moment when swap was opened, validation based on Close Service configuration
enum SwapClosableStatus {
SWAP_IS_CLOSABLE,
SWAP_ALREADY_CLOSED,
SWAP_REQUIRED_BUYER_OR_LIQUIDATOR_TO_CLOSE,
SWAP_CANNOT_CLOSE_CLOSING_TOO_EARLY_FOR_COMMUNITY,
SWAP_CANNOT_CLOSE_WITH_UNWIND_ACTION_IS_TOO_EARLY
}
/// @notice Collection of swap attributes connected with IPOR Index and swap itself.
/// @dev all values are in 18 decimals
struct IporSwapIndicator {
/// @notice IPOR Index value at the time of swap opening
uint256 iporIndexValue;
/// @notice IPOR Interest Bearing Token (IBT) price at the time of swap opening
uint256 ibtPrice;
/// @notice Swap's notional denominated in IBT
uint256 ibtQuantity;
/// @notice Fixed interest rate at which the position has been opened,
/// it is quote from spread documentation
uint256 fixedInterestRate;
}
/// @notice Risk indicators calculated for swap opening
struct OpenSwapRiskIndicators {
/// @notice Maximum collateral ratio in general
uint256 maxCollateralRatio;
/// @notice Maximum collateral ratio for a given leg
uint256 maxCollateralRatioPerLeg;
/// @notice Maximum leverage for a given leg
uint256 maxLeveragePerLeg;
/// @notice Base Spread for a given leg (without demand part)
int256 baseSpreadPerLeg;
/// @notice Fixed rate cap
uint256 fixedRateCapPerLeg;
/// @notice Demand spread factor used to calculate demand spread
uint256 demandSpreadFactor;
}
/// @notice Risk indicators calculated for swap opening
struct RiskIndicatorsInputs {
/// @notice Maximum collateral ratio in general
uint256 maxCollateralRatio;
/// @notice Maximum collateral ratio for a given leg
uint256 maxCollateralRatioPerLeg;
/// @notice Maximum leverage for a given leg
uint256 maxLeveragePerLeg;
/// @notice Base Spread for a given leg (without demand part)
int256 baseSpreadPerLeg;
/// @notice Fixed rate cap
uint256 fixedRateCapPerLeg;
/// @notice Demand spread factor used to calculate demand spread
uint256 demandSpreadFactor;
/// @notice expiration date in seconds
uint256 expiration;
/// @notice signature of data (maxCollateralRatio, maxCollateralRatioPerLeg,maxLeveragePerLeg,baseSpreadPerLeg,fixedRateCapPerLeg,demandSpreadFactor,expiration,asset,tenor,direction)
/// asset - address
/// tenor - uint256
/// direction - uint256
bytes signature;
}
struct CloseSwapRiskIndicatorsInput {
RiskIndicatorsInputs payFixed;
RiskIndicatorsInputs receiveFixed;
}
/// @notice Structure containing information about swap's closing status, unwind values and PnL for a given swap and time.
struct ClosingSwapDetails {
/// @notice Swap's closing status
AmmTypes.SwapClosableStatus closableStatus;
/// @notice Flag indicating if swap unwind is required
bool swapUnwindRequired;
/// @notice Swap's unwind PnL Value, part of PnL corresponded to virtual swap (unwinded swap), represented in 18 decimals
int256 swapUnwindPnlValue;
/// @notice Unwind opening fee amount it is a sum of `swapUnwindFeeLPAmount` and `swapUnwindFeeTreasuryAmount`
uint256 swapUnwindOpeningFeeAmount;
/// @notice Part of unwind opening fee allocated as a profit of the Liquidity Pool
uint256 swapUnwindFeeLPAmount;
/// @notice Part of unwind opening fee allocated in Treasury Balance
uint256 swapUnwindFeeTreasuryAmount;
/// @notice Final Profit and Loss which takes into account the swap unwind and limits the PnL to the collateral amount. Represented in 18 decimals.
int256 pnlValue;
}
}
/// @title Ipor Protocol Router Owner Manager library
library OwnerManager {
/// @notice Emitted when account is appointed to transfer ownership
/// @param appointedOwner Address of appointed owner
event AppointedToTransferOwnership(address indexed appointedOwner);
/// @notice Emitted when ownership is transferred
/// @param previousOwner Address of previous owner
/// @param newOwner Address of new owner
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/// @notice Gets the current owner of Ipor Protocol Router
function getOwner() internal view returns (address) {
return StorageLib.getOwner().owner;
}
/// @notice Oppoint account to transfer ownership
/// @param newAppointedOwner Address of appointed owner
function appointToOwnership(address newAppointedOwner) internal {
require(newAppointedOwner != address(0), IporErrors.WRONG_ADDRESS);
StorageLib.AppointedOwnerStorage storage appointedOwnerStorage = StorageLib.getAppointedOwner();
appointedOwnerStorage.appointedOwner = newAppointedOwner;
emit AppointedToTransferOwnership(newAppointedOwner);
}
/// @notice Confirm appointment to ownership
/// @dev This is real transfer ownership in second step by appointed account
function confirmAppointmentToOwnership() internal {
StorageLib.AppointedOwnerStorage storage appointedOwnerStorage = StorageLib.getAppointedOwner();
appointedOwnerStorage.appointedOwner = address(0);
transferOwnership(msg.sender);
}
/// @notice Renounce ownership
function renounceOwnership() internal {
transferOwnership(address(0));
StorageLib.AppointedOwnerStorage storage appointedOwnerStorage = StorageLib.getAppointedOwner();
appointedOwnerStorage.appointedOwner = address(0);
}
/// @notice Immediately transfers ownership
function transferOwnership(address newOwner) internal {
StorageLib.OwnerStorage storage ownerStorage = StorageLib.getOwner();
address oldOwner = ownerStorage.owner;
ownerStorage.owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
/// @notice The types used in the AmmTreasury's interface.
/// @dev All values, where applicable, are represented in 18 decimals.
library AmmInternalTypes {
struct PnlValueStruct {
/// @notice PnL Value of the swap.
int256 pnlValue;
/// @notice flag indicating if unwind is required when closing swap.
bool swapUnwindRequired;
/// @notice Unwind amount of the swap.
int256 swapUnwindAmount;
/// @notice Unwind fee of the swap that will be added to the AMM liquidity pool balance.
uint256 swapUnwindFeeLPAmount;
/// @notice Unwind fee of the swap that will be added to the AMM treasury balance.
uint256 swapUnwindFeeTreasuryAmount;
}
struct BeforeOpenSwapStruct {
/// @notice Sum of all asset transferred when opening swap. It includes the collateral, fees and deposits.
/// @dev The amount is represented in 18 decimals regardless of the decimals of the asset.
uint256 wadTotalAmount;
/// @notice Swap's collateral.
uint256 collateral;
/// @notice Swap's notional amount.
uint256 notional;
/// @notice The part of the opening fee that will be added to the liquidity pool balance.
uint256 openingFeeLPAmount;
/// @notice Part of the opening fee that will be added to the treasury balance.
uint256 openingFeeTreasuryAmount;
/// @notice Amount of asset set aside for the oracle subsidization.
uint256 iporPublicationFeeAmount;
/// @notice Refundable deposit blocked for the entity that will close the swap.
/// For more information on how the liquidations work refer to the documentation.
/// https://ipor-labs.gitbook.io/ipor-labs/automated-market-maker/liquidations
/// @dev value represented without decimals for USDT, USDC, DAI, with 6 decimals for stETH, as an integer.
uint256 liquidationDepositAmount;
/// @notice The struct describing the IPOR and its params calculated for the time when it was most recently updated and the change that took place since the update.
/// Namely, the interest that would be computed into IBT should the rebalance occur.
IporTypes.AccruedIpor accruedIpor;
}
/// @notice Risk indicators context data
struct RiskIndicatorsContext {
/// @notice Asset address for which the risk indicators are calculated.
address asset;
/// @notice Tenor of the swap.
IporTypes.SwapTenor tenor;
/// @notice AMM Liquidity Pool balance.
uint256 liquidityPoolBalance;
/// @notice AMM Min Leverage allowed for a swap.
uint256 minLeverage;
}
/// @notice Spread context data
struct SpreadContext {
/// @notice Asset address for which the spread is calculated.
address asset;
/// @notice Signature of spread method used to calculate spread.
bytes4 spreadFunctionSig;
/// @notice Tenor of the swap.
IporTypes.SwapTenor tenor;
/// @notice Swap's notional
uint256 notional;
/// @notice Minimum leverage allowed for a swap.
uint256 minLeverage;
/// @notice Ipor Index Value
uint256 indexValue;
/// @notice Risk Indicators data for a opened swap used to calculate spread.
AmmTypes.OpenSwapRiskIndicators riskIndicators;
/// @notice AMM Balance for a opened swap used to calculate spread.
IporTypes.AmmBalancesForOpenSwapMemory balance;
}
/// @notice Open swap item - element of linked list of swaps
struct OpenSwapItem {
/// @notice Swap ID
uint32 swapId;
/// @notcie Next swap ID in linked list
uint32 nextSwapId;
/// @notice Previous swap ID in linked list
uint32 previousSwapId;
/// @notice Timestamp of the swap opening
uint32 openSwapTimestamp;
}
/// @notice Open swap list structure
struct OpenSwapList {
/// @notice Head swap ID
uint32 headSwapId;
/// @notice Swaps mapping, where key is swap ID
mapping(uint32 => OpenSwapItem) swaps;
}
}
/// @title Spread storage library
library SpreadStorageLibsBaseV1 {
using SafeCast for uint256;
uint256 private constant STORAGE_SLOT_BASE = 10_000;
/// Only allowed to append new value to the end of the enum
enum StorageId {
// WeightedNotionalStorage
TimeWeightedNotional28Days,
TimeWeightedNotional60Days,
TimeWeightedNotional90Days
}
/// @notice Saves time weighted notional for a specific asset and tenor
/// @param timeWeightedNotionalStorageId The storage ID of the time weighted notional
/// @param timeWeightedNotional The time weighted notional to save
function saveTimeWeightedNotionalForAssetAndTenor(
StorageId timeWeightedNotionalStorageId,
SpreadTypesBaseV1.TimeWeightedNotionalMemory memory timeWeightedNotional
) internal {
checkTimeWeightedNotional(timeWeightedNotionalStorageId);
uint256 timeWeightedNotionalPayFixedTemp;
uint256 timeWeightedNotionalReceiveFixedTemp;
unchecked {
timeWeightedNotionalPayFixedTemp = timeWeightedNotional.timeWeightedNotionalPayFixed / 1e18;
timeWeightedNotionalReceiveFixedTemp = timeWeightedNotional.timeWeightedNotionalReceiveFixed / 1e18;
}
uint96 timeWeightedNotionalPayFixed = timeWeightedNotionalPayFixedTemp.toUint96();
uint32 lastUpdateTimePayFixed = timeWeightedNotional.lastUpdateTimePayFixed.toUint32();
uint96 timeWeightedNotionalReceiveFixed = timeWeightedNotionalReceiveFixedTemp.toUint96();
uint32 lastUpdateTimeReceiveFixed = timeWeightedNotional.lastUpdateTimeReceiveFixed.toUint32();
uint256 slotAddress = _getStorageSlot(timeWeightedNotionalStorageId);
assembly {
let value := add(
timeWeightedNotionalPayFixed,
add(
shl(96, lastUpdateTimePayFixed),
add(shl(128, timeWeightedNotionalReceiveFixed), shl(224, lastUpdateTimeReceiveFixed))
)
)
sstore(slotAddress, value)
}
}
/// @notice Gets the time-weighted notional for a specific storage ID representing an asset and tenor
/// @param timeWeightedNotionalStorageId The storage ID of the time weighted notional
function getTimeWeightedNotionalForAssetAndTenor(
StorageId timeWeightedNotionalStorageId
) internal view returns (SpreadTypesBaseV1.TimeWeightedNotionalMemory memory weightedNotional28Days) {
checkTimeWeightedNotional(timeWeightedNotionalStorageId);
uint256 timeWeightedNotionalPayFixed;
uint256 lastUpdateTimePayFixed;
uint256 timeWeightedNotionalReceiveFixed;
uint256 lastUpdateTimeReceiveFixed;
uint256 slotAddress = _getStorageSlot(timeWeightedNotionalStorageId);
assembly {
let slotValue := sload(slotAddress)
timeWeightedNotionalPayFixed := mul(and(slotValue, 0xFFFFFFFFFFFFFFFFFFFFFFFF), 1000000000000000000)
lastUpdateTimePayFixed := and(shr(96, slotValue), 0xFFFFFFFF)
timeWeightedNotionalReceiveFixed := mul(
and(shr(128, slotValue), 0xFFFFFFFFFFFFFFFFFFFFFFFF),
1000000000000000000
)
lastUpdateTimeReceiveFixed := and(shr(224, slotValue), 0xFFFFFFFF)
}
return
SpreadTypesBaseV1.TimeWeightedNotionalMemory({
timeWeightedNotionalPayFixed: timeWeightedNotionalPayFixed,
lastUpdateTimePayFixed: lastUpdateTimePayFixed,
timeWeightedNotionalReceiveFixed: timeWeightedNotionalReceiveFixed,
lastUpdateTimeReceiveFixed: lastUpdateTimeReceiveFixed,
storageId: timeWeightedNotionalStorageId
});
}
/// @notice Gets all time weighted notional storage IDs
function getAllStorageId() internal pure returns (StorageId[] memory storageIds, string[] memory keys) {
storageIds = new StorageId[](3);
keys = new string[](3);
storageIds[0] = StorageId.TimeWeightedNotional28Days;
keys[0] = "TimeWeightedNotional28Days";
storageIds[1] = StorageId.TimeWeightedNotional60Days;
keys[1] = "TimeWeightedNotional60Days";
storageIds[2] = StorageId.TimeWeightedNotional90Days;
keys[2] = "TimeWeightedNotional90Days";
}
function checkTimeWeightedNotional(StorageId storageId) internal pure {
require(
storageId == StorageId.TimeWeightedNotional28Days ||
storageId == StorageId.TimeWeightedNotional60Days ||
storageId == StorageId.TimeWeightedNotional90Days,
AmmErrors.STORAGE_ID_IS_NOT_TIME_WEIGHTED_NOTIONAL
);
}
function _getStorageSlot(StorageId storageId) private pure returns (uint256 slot) {
slot = uint256(storageId) + STORAGE_SLOT_BASE;
}
}
/// @title Types used in interfaces strictly related to AMM (Automated Market Maker).
/// @dev Used by IAmmTreasury and IAmmStorage interfaces.
library AmmTypesBaseV1 {
/// @notice Struct representing swap item, used for listing and in internal calculations
struct Swap {
/// @notice Swap's unique ID
uint256 id;
/// @notice Swap's buyer
address buyer;
/// @notice Swap opening epoch timestamp
uint256 openTimestamp;
/// @notice Swap's tenor
IporTypes.SwapTenor tenor;
/// @notice Swap's direction
AmmTypes.SwapDirection direction;
/// @notice Index position of this Swap in an array of swaps' identification associated to swap buyer
/// @dev Field used for gas optimization purposes, it allows for quick removal by id in the array.
/// During removal the last item in the array is switched with the one that just has been removed.
uint256 idsIndex;
/// @notice Swap's collateral
/// @dev value represented in 18 decimals
uint256 collateral;
/// @notice Swap's notional amount
/// @dev value represented in 18 decimals
uint256 notional;
/// @notice Swap's notional amount denominated in the Interest Bearing Token (IBT)
/// @dev value represented in 18 decimals
uint256 ibtQuantity;
/// @notice Fixed interest rate at which the position has been opened
/// @dev value represented in 18 decimals
uint256 fixedInterestRate;
/// @notice Liquidation deposit amount
/// @dev value represented in 18 decimals
uint256 wadLiquidationDepositAmount;
/// @notice State of the swap
/// @dev 0 - INACTIVE, 1 - ACTIVE
IporTypes.SwapState state;
}
/// @notice Structure representing configuration of the AmmOpenSwapServicePool for specific asset (pool).
struct AmmOpenSwapServicePoolConfiguration {
/// @notice address of the asset
address asset;
/// @notice asset decimals
uint256 decimals;
/// @notice address of the AMM Storage
address ammStorage;
/// @notice address of the AMM Treasury
address ammTreasury;
/// @notice spread contract address
address spread;
/// @notice ipor publication fee, fee used when opening swap, represented in 18 decimals.
uint256 iporPublicationFee;
/// @notice maximum swap collateral amount, represented in 18 decimals.
uint256 maxSwapCollateralAmount;
/// @notice liquidation deposit amount, represented with 6 decimals. Example 25000000 = 25 units = 25.000000, 1000 = 0.001
uint256 liquidationDepositAmount;
/// @notice minimum leverage, represented in 18 decimals.
uint256 minLeverage;
/// @notice swap's opening fee rate, represented in 18 decimals. 1e18 = 100%
uint256 openingFeeRate;
/// @notice swap's opening fee rate, portion of the rate which is allocated to "treasury" balance
/// @dev Value describes what percentage of opening fee amount is allocated to "treasury" balance. Value represented in 18 decimals. 1e18 = 100%
uint256 openingFeeTreasuryPortionRate;
}
/// @notice Technical structure with unwinding parameters.
struct UnwindParams {
address asset;
/// @notice Risk Indicators Inputs signer
address messageSigner;
address spread;
address ammStorage;
address ammTreasury;
/// @notice Moment when the swap is closing
uint256 closeTimestamp;
/// @notice Swap's PnL value to moment when the swap is closing
int256 swapPnlValueToDate;
/// @notice Actual IPOR index value
uint256 indexValue;
/// @notice Swap data
AmmTypesBaseV1.Swap swap;
uint256 unwindingFeeRate;
uint256 unwindingFeeTreasuryPortionRate;
/// @notice Risk indicators for both legs pay fixed and receive fixed
AmmTypes.CloseSwapRiskIndicatorsInput riskIndicatorsInputs;
}
struct BeforeOpenSwapStruct {
/// @notice Amount of entered asset that is sent from buyer to AmmTreasury when opening swap.
/// @dev Notice! Input Asset can be different than the asset that is used as a collateral. Value represented in decimals of input asset.
uint256 inputAssetTotalAmount;
/// @notice Amount of entered asset that is sent from buyer to AmmTreasury when opening swap.
/// @dev Notice! Input Asset can be different than the asset that is used as a collateral. Value represented in 18 decimals.
uint256 wadInputAssetTotalAmount;
/// @notice Amount of underlying asset that is used as a collateral and other costs related to swap opening.
/// @dev The amount is represented in decimals of the asset.
uint256 assetTotalAmount;
/// @notice Amount of underlying asset that is used as a collateral and other costs related to swap opening.
/// @dev The amount is represented in 18 decimals regardless of the decimals of the asset.
uint256 wadAssetTotalAmount;
/// @notice Swap's collateral.
uint256 collateral;
/// @notice Swap's notional amount.
uint256 notional;
/// @notice The part of the opening fee that will be added to the liquidity pool balance.
uint256 openingFeeLPAmount;
/// @notice Part of the opening fee that will be added to the treasury balance.
uint256 openingFeeTreasuryAmount;
/// @notice Amount of asset set aside for the oracle subsidization.
uint256 iporPublicationFeeAmount;
/// @notice Refundable deposit blocked for the entity that will close the swap.
/// For more information on how the liquidations work refer to the documentation.
/// https://ipor-labs.gitbook.io/ipor-labs/automated-market-maker/liquidations
/// @dev value represented without decimals for USDT, USDC, DAI, with 6 decimals for stETH, as an integer.
uint256 liquidationDepositAmount;
/// @notice The struct describing the IPOR and its params calculated for the time when it was most recently updated and the change that took place since the update.
/// Namely, the interest that would be computed into IBT should the rebalance occur.
IporTypes.AccruedIpor accruedIpor;
}
struct ClosableSwapInput {
address account;
address asset;
uint256 closeTimestamp;
address swapBuyer;
uint256 swapOpenTimestamp;
uint256 swapCollateral;
IporTypes.SwapTenor swapTenor;
IporTypes.SwapState swapState;
int256 swapPnlValueToDate;
uint256 minLiquidationThresholdToCloseBeforeMaturityByCommunity;
uint256 minLiquidationThresholdToCloseBeforeMaturityByBuyer;
uint256 timeBeforeMaturityAllowedToCloseSwapByCommunity;
uint256 timeBeforeMaturityAllowedToCloseSwapByBuyer;
uint256 timeAfterOpenAllowedToCloseSwapWithUnwinding;
}
/// @notice Struct representing amounts related to Swap that is presently being opened.
/// @dev all values represented in 18 decimals
struct OpenSwapAmount {
/// @notice Amount of entered asset that is sent from buyer to AmmTreasury when opening swap.
/// @dev Notice. Input Asset can be different than the asset that is used as a collateral. Represented in 18 decimals.
uint256 inputAssetTotalAmount;
/// @notice Total Amount of underlying asset that is used as a collateral.
uint256 assetTotalAmount;
/// @notice Swap's collateral, represented in underlying asset, represented in 18 decimals.
uint256 collateral;
/// @notice Swap's notional, represented in underlying asset, represented in 18 decimals.
uint256 notional;
/// @notice Opening Fee - part allocated as a profit of the Liquidity Pool, represented in underlying asset, represented in 18 decimals.
uint256 openingFeeLPAmount;
/// @notice Part of the fee set aside for subsidizing the oracle that publishes IPOR rate. Flat fee set by the DAO. Represented in underlying asset, represented in 18 decimals.
/// @notice Opening Fee - part allocated in Treasury balance. Part of the fee set asside for subsidising the oracle that publishes IPOR rate. Flat fee set by the DAO.
uint256 openingFeeTreasuryAmount;
/// @notice Fee set aside for subsidizing the oracle that publishes IPOR rate. Flat fee set by the DAO. Represented in underlying asset, represented in 18 decimals.
uint256 iporPublicationFee;
/// @notice Liquidation deposit is retained when the swap is opened. Notice! Value represented in 18 decimals. Represents in underlying asset, represented in 18 decimals.
uint256 liquidationDepositAmount;
}
struct AmmBalanceForOpenSwap {
/// @notice Sum of all collateral put forward by the derivative buyer's on Pay Fixed & Receive Floating leg.
uint256 totalCollateralPayFixed;
/// @notice Total notional amount of all swaps on Pay Fixed leg (denominated in 18 decimals).
uint256 totalNotionalPayFixed;
/// @notice Sum of all collateral put forward by the derivative buyer's on Pay Floating & Receive Fixed leg.
uint256 totalCollateralReceiveFixed;
/// @notice Total notional amount of all swaps on Receive Fixed leg (denominated in 18 decimals).
uint256 totalNotionalReceiveFixed;
}
struct Balance {
/// @notice Sum of all collateral put forward by the derivative buyer's on Pay Fixed & Receive Floating leg.
uint256 totalCollateralPayFixed;
/// @notice Sum of all collateral put forward by the derivative buyer's on Pay Floating & Receive Fixed leg.
uint256 totalCollateralReceiveFixed;
/// @notice This balance is used to track the funds accounted for IporOracle subsidization.
uint256 iporPublicationFee;
/// @notice Treasury is the balance that belongs to IPOR DAO and funds up to this amount can be transferred to the DAO-appointed multi-sig wallet.
/// this ballance is fed by part of the opening fee appointed by the DAO. For more information refer to the documentation:
/// https://ipor-labs.gitbook.io/ipor-labs/automated-market-maker/ipor-swaps#fees
uint256 treasury;
/// @notice Sum of all liquidation deposits for all opened swaps.
/// @dev Value represented in 18 decimals.
uint256 totalLiquidationDepositBalance;
}
}
library SpreadTypesBaseV1 {
/// @notice structure used to save the weighted notional for the 28 days into storage
/// timeWeightedNotionalPayFixed without decimals - uint96 - bytes 0-96
/// lastUpdateTimePayFixed - uint32 - bytes 96-128
/// timeWeightedNotionalReceiveFixed without decimals - uint96 - bytes 128-224
/// lastUpdateTimeReceiveFixed - uint32 - bytes 224-256
struct WeightedNotionalStorage {
bytes32 weightedNotional;
}
/// @notice Dto for the Weighted Notional
struct TimeWeightedNotionalMemory {
/// @notice timeWeightedNotionalPayFixed with 18 decimals
uint256 timeWeightedNotionalPayFixed;
/// @notice lastUpdateTimePayFixed timestamp in seconds
uint256 lastUpdateTimePayFixed;
/// @notice timeWeightedNotionalReceiveFixed with 18 decimals
uint256 timeWeightedNotionalReceiveFixed;
/// @notice lastUpdateTimeReceiveFixed timestamp in seconds
uint256 lastUpdateTimeReceiveFixed;
/// @notice storageId from SpreadStorageLibs
SpreadStorageLibsBaseV1.StorageId storageId;
}
/// @notice Technical structure used in Lens for the Weighted Notional params
struct TimeWeightedNotionalResponse {
/// @notice timeWeightedNotionalPayFixed time weighted notional params
TimeWeightedNotionalMemory timeWeightedNotional;
string key;
}
}
/// @title Configuration manager for AMM
library AmmConfigurationManager {
/// @notice Emitted when new liquidator is added to the list of SwapLiquidators.
/// @param asset address of the asset (pool)
/// @param liquidator address of the new liquidator
event AmmSwapsLiquidatorChanged(address indexed asset, address indexed liquidator, bool status);
/// @notice Emitted when new account is added to the list of AppointedToRebalance.
/// @param asset address of the asset (pool)
/// @param account address of account appointed to rebalance
/// @param status true if account is appointed to rebalance, false otherwise
event AmmAppointedToRebalanceChanged(address indexed asset, address indexed account, bool status);
/// @notice Emitted when AMM Pools Params are changed.
/// @param asset address of the asset (pool)
/// @param maxLiquidityPoolBalance maximum liquidity pool balance
/// @param autoRebalanceThresholdInThousands auto rebalance threshold in thousands
/// @param ammTreasuryAndAssetManagementRatio AMM treasury and asset management ratio
/// @dev Params autoRebalanceThresholdInThousands and ammTreasuryAndAssetManagementRatio are not supported in stETH pool. Because stETH pool doesn't have asset management.
event AmmPoolsParamsChanged(
address indexed asset,
uint32 maxLiquidityPoolBalance,
uint32 autoRebalanceThresholdInThousands,
uint16 ammTreasuryAndAssetManagementRatio
);
/// @notice Adds new liquidator to the list of SwapLiquidators.
/// @param asset address of the asset (pool)
/// @param account address of the new liquidator
/// @dev Allowed only for the owner of the Ipor Protocol Router
function addSwapLiquidator(address asset, address account) internal {
require(account != address(0), IporErrors.WRONG_ADDRESS);
require(asset != address(0), IporErrors.WRONG_ADDRESS);
mapping(address => mapping(address => bool)) storage swapLiquidators = StorageLib
.getAmmSwapsLiquidatorsStorage()
.value;
swapLiquidators[asset][account] = true;
emit AmmSwapsLiquidatorChanged(asset, account, true);
}
/// @notice Removes liquidator from the list of SwapLiquidators.
/// @param asset address of the asset (pool)
/// @param account address of the liquidator
/// @dev Allowed only for the owner of the Ipor Protocol Router
function removeSwapLiquidator(address asset, address account) internal {
require(account != address(0), IporErrors.WRONG_ADDRESS);
require(asset != address(0), IporErrors.WRONG_ADDRESS);
mapping(address => mapping(address => bool)) storage swapLiquidators = StorageLib
.getAmmSwapsLiquidatorsStorage()
.value;
swapLiquidators[asset][account] = false;
emit AmmSwapsLiquidatorChanged(asset, account, false);
}
/// @notice Checks if account is a SwapLiquidator.
/// @param asset address of the asset (pool)
/// @param account address of the account
/// @return true if account is a SwapLiquidator, false otherwise
function isSwapLiquidator(address asset, address account) internal view returns (bool) {
mapping(address => mapping(address => bool)) storage swapLiquidators = StorageLib
.getAmmSwapsLiquidatorsStorage()
.value;
return swapLiquidators[asset][account];
}
/// @notice Adds new account to the list of AppointedToRebalance in AMM.
/// @param asset address of the asset (pool)
/// @param account address added to appointed to rebalance
/// @dev Allowed only for the owner of the Ipor Protocol Router
function addAppointedToRebalanceInAmm(address asset, address account) internal {
require(asset != address(0), IporErrors.WRONG_ADDRESS);
require(account != address(0), IporErrors.WRONG_ADDRESS);
mapping(address => mapping(address => bool)) storage appointedToRebalance = StorageLib
.getAmmPoolsAppointedToRebalanceStorage()
.value;
appointedToRebalance[asset][account] = true;
emit AmmAppointedToRebalanceChanged(asset, account, true);
}
/// @notice Removes account from the list of AppointedToRebalance in AMM.
/// @param asset address of the asset (pool)
/// @param account address removed from appointed to rebalance
/// @dev Allowed only for the owner of the Ipor Protocol Router
function removeAppointedToRebalanceInAmm(address asset, address account) internal {
require(asset != address(0), IporErrors.WRONG_ADDRESS);
require(account != address(0), IporErrors.WRONG_ADDRESS);
mapping(address => mapping(address => bool)) storage appointedToRebalance = StorageLib
.getAmmPoolsAppointedToRebalanceStorage()
.value;
appointedToRebalance[asset][account] = false;
emit AmmAppointedToRebalanceChanged(asset, account, false);
}
/// @notice Checks if account is appointed to rebalance in AMM.
/// @param asset address of the asset (pool)
/// @param account address of the account
/// @return true if account is appointed to rebalance, false otherwise
function isAppointedToRebalanceInAmm(address asset, address account) internal view returns (bool) {
mapping(address => mapping(address => bool)) storage appointedToRebalance = StorageLib
.getAmmPoolsAppointedToRebalanceStorage()
.value;
return appointedToRebalance[asset][account];
}
/// @notice Sets AMM Pools Params.
/// @param asset address of the asset (pool)
/// @param newMaxLiquidityPoolBalance maximum liquidity pool balance
/// @param newAutoRebalanceThresholdInThousands auto rebalance threshold (for USDT, USDC, DAI in thousands)
/// @param newAmmTreasuryAndAssetManagementRatio AMM treasury and asset management ratio
/// @dev Allowed only for the owner of the Ipor Protocol Router
function setAmmPoolsParams(
address asset,
uint32 newMaxLiquidityPoolBalance,
uint32 newAutoRebalanceThresholdInThousands,
uint16 newAmmTreasuryAndAssetManagementRatio
) internal {
require(asset != address(0), IporErrors.WRONG_ADDRESS);
/// @dev newAmmTreasuryAndAssetManagementRatio is percentage with 2 decimals, example: 65% = 6500, (see description in StorageLib.AmmPoolsParamsValue)
/// value cannot be greater than 10000 which is 100%
require(newAmmTreasuryAndAssetManagementRatio < 1e4, AmmPoolsErrors.AMM_TREASURY_ASSET_MANAGEMENT_RATIO);
StorageLib.getAmmPoolsParamsStorage().value[asset] = StorageLib.AmmPoolsParamsValue({
maxLiquidityPoolBalance: newMaxLiquidityPoolBalance,
autoRebalanceThresholdInThousands: newAutoRebalanceThresholdInThousands,
ammTreasuryAndAssetManagementRatio: newAmmTreasuryAndAssetManagementRatio
});
emit AmmPoolsParamsChanged(
asset,
newMaxLiquidityPoolBalance,
newAutoRebalanceThresholdInThousands,
newAmmTreasuryAndAssetManagementRatio
);
}
/// @notice Gets AMM Pools Params.
/// @param asset address of the asset (pool)
/// @return AMM Pools Params struct
function getAmmPoolsParams(address asset) internal view returns (StorageLib.AmmPoolsParamsValue memory) {
return StorageLib.getAmmPoolsParamsStorage().value[asset];
}
}
/// @title AmmSwapsLens interface responsible for reading data related with swaps.
interface IAmmSwapsLens {
/// @notice IPOR Swap structure.
struct IporSwap {
/// @notice Swap's ID.
uint256 id;
/// @notice Swap's asset (stablecoin / underlying token)
address asset;
/// @notice Swap's buyer address
address buyer;
/// @notice Swap's collateral, represented in 18 decimals.
uint256 collateral;
/// @notice Notional amount, represented in 18 decimals.
uint256 notional;
/// @notice Swap's leverage, represented in 18 decimals.
uint256 leverage;
/// @notice Swap's direction
/// @dev 0 - Pay Fixed-Receive Floating, 1 - Receive Fixed - Pay Floading
uint256 direction;
/// @notice Swap's notional amount denominated in the Interest Bearing Token (IBT)
/// @dev value represented in 18 decimals
uint256 ibtQuantity;
/// @notice Fixed interest rate.
uint256 fixedInterestRate;
/// @notice Current PnL value (Profit and Loss Value), represented in 18 decimals.
int256 pnlValue;
/// @notice Moment when swap was opened.
uint256 openTimestamp;
/// @notice Moment when swap achieve its maturity.
uint256 endTimestamp;
/// @notice Liquidation deposit value on day when swap was opened. Value represented in 18 decimals.
uint256 liquidationDepositAmount;
/// @notice State of the swap
/// @dev 0 - INACTIVE, 1 - ACTIVE
uint256 state;
}
/// @notice Lens Configuration structure for AmmSwapsLens for a given asset (ppol)
struct SwapLensPoolConfiguration {
/// @notice Asset address
address asset;
/// @notice Address of the AMM (Automated Market Maker) storage contract
address ammStorage;
/// @notice Address of the AMM Treasury contract
address ammTreasury;
/// @notice Spread module
address spread;
}
/// @notice Gets pool configuration for AmmSwapsLens
/// @param asset asset address
/// @return SwapLensPoolConfiguration pool configuration
function getSwapLensPoolConfiguration(address asset) external view returns (SwapLensPoolConfiguration memory);
/// @notice Gets active swaps for a given asset sender address (aka buyer).
/// @param asset asset address
/// @param offset offset for paging
/// @param chunkSize page size for paging
/// @return totalCount total number of sender's active swaps in AmmTreasury
/// @return swaps list of active sender's swaps
function getSwaps(
address asset,
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, IporSwap[] memory swaps);
/// @notice Gets the swap's PnL (Profit and Loss) for a pay-fixed, given asset and swap ID.
/// @param asset asset address
/// @param swapId swap ID
/// @return pnlValue PnL for a pay fixed swap
function getPnlPayFixed(address asset, uint256 swapId) external view returns (int256 pnlValue);
/// @notice Gets the swap's PnL (Profit and Loss) for a receive-fixed, given asset and swap ID.
/// @param asset asset address
/// @param swapId swap ID
/// @return pnlValue PnL for a receive fixed swap
function getPnlReceiveFixed(address asset, uint256 swapId) external view returns (int256 pnlValue);
/// @notice Gets the balances structure required to open a swap.
/// @param asset The address of the asset.
/// @return AmmBalancesForOpenSwapMemory The balances required for opening a swap.
function getBalancesForOpenSwap(
address asset
) external view returns (IporTypes.AmmBalancesForOpenSwapMemory memory);
/// @notice Gets the SOAP value for a given asset.
/// @param asset The address of the asset.
/// @return soapPayFixed SOAP value for pay fixed swaps.
/// @return soapReceiveFixed SOAP value for receive fixed swaps.
/// @return soap SOAP value which is a sum of soapPayFixed and soapReceiveFixed.
function getSoap(address asset) external view returns (int256 soapPayFixed, int256 soapReceiveFixed, int256 soap);
/// @notice Gets the offered rate value for a given asset, tenor and notional.
/// @param asset The address of the asset.
/// @param tenor The duration of the swap.
/// @param notional The notional amount of the swap, represented in 18 decimals.
/// @param payFixedRiskIndicatorsInputs The risk indicators inputs for pay fixed swaps.
/// @param receiveFixedRiskIndicatorsInputs The risk indicators inputs for receive fixed swaps.
/// @return offeredRatePayFixed The offered rate for pay fixed swaps.
/// @return offeredRateReceiveFixed The offered rate for receive fixed swaps.
function getOfferedRate(
address asset,
IporTypes.SwapTenor tenor,
uint256 notional,
AmmTypes.RiskIndicatorsInputs calldata payFixedRiskIndicatorsInputs,
AmmTypes.RiskIndicatorsInputs calldata receiveFixedRiskIndicatorsInputs
) external view returns (uint256 offeredRatePayFixed, uint256 offeredRateReceiveFixed);
}
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}
library InterestRates {
using SafeCast for uint256;
/// @notice Adds interest to given value using continuous compounding formula: v2 = value * e^(interestRate * time)
/// @param value value to which interest is added, value represented in 18 decimals
/// @param interestRatePeriodMultiplication interest rate * time, interest rate in 18 decimals, time in seconds
/// @return value with interest, value represented in 18 decimals
function addContinuousCompoundInterestUsingRatePeriodMultiplication(
uint256 value,
uint256 interestRatePeriodMultiplication
) internal pure returns (uint256) {
uint256 interestRateYearsMultiplication = IporMath.division(
interestRatePeriodMultiplication,
Constants.YEAR_IN_SECONDS
);
bytes16 floatValue = _toQuadruplePrecision(value, 1e18);
bytes16 floatIpm = _toQuadruplePrecision(interestRateYearsMultiplication, 1e18);
bytes16 valueWithInterest = ABDKMathQuad.mul(floatValue, ABDKMathQuad.exp(floatIpm));
return _toUint256(valueWithInterest);
}
/// @notice Adds interest to given value using continuous compounding formula: v2 = value * e^(interestRate * time)
/// @param value value to which interest is added, value represented in 18 decimals
/// @param interestRatePeriodMultiplication interest rate * time, interest rate in 18 decimals, time in seconds
/// @return value with interest, value represented in 18 decimals
function addContinuousCompoundInterestUsingRatePeriodMultiplicationInt(
int256 value,
int256 interestRatePeriodMultiplication
) internal pure returns (int256) {
int256 interestRateYearsMultiplication = IporMath.divisionInt(
interestRatePeriodMultiplication,
Constants.YEAR_IN_SECONDS.toInt256()
);
bytes16 floatValue = _toQuadruplePrecisionInt(value, 1e18);
bytes16 floatIpm = _toQuadruplePrecisionInt(interestRateYearsMultiplication, 1e18);
bytes16 valueWithInterest = ABDKMathQuad.mul(floatValue, ABDKMathQuad.exp(floatIpm));
return _toInt256(valueWithInterest);
}
/// @notice Calculates interest to given value using continuous compounding formula: v2 = value * e^(interestRate * time)
/// @param value value to which interest is added, value represented in 18 decimals
/// @param interestRatePeriodMultiplication interest rate * time, interest rate in 18 decimals, time in seconds
/// @return interest, value represented in 18 decimals
function calculateContinuousCompoundInterestUsingRatePeriodMultiplication(
uint256 value,
uint256 interestRatePeriodMultiplication
) internal pure returns (uint256) {
return
addContinuousCompoundInterestUsingRatePeriodMultiplication(value, interestRatePeriodMultiplication) - value;
}
/// @notice Calculates interest to given value using continuous compounding formula: v2 = value * e^(interestRate * time)
/// @param value value to which interest is added, value represented in 18 decimals
/// @param interestRatePeriodMultiplication interest rate * time, interest rate in 18 decimals, time in seconds
/// @return interest, value represented in 18 decimals
function calculateContinuousCompoundInterestUsingRatePeriodMultiplicationInt(
int256 value,
int256 interestRatePeriodMultiplication
) internal pure returns (int256) {
return
addContinuousCompoundInterestUsingRatePeriodMultiplicationInt(value, interestRatePeriodMultiplication) -
value;
}
/// @dev Quadruple precision, 128 bits
function _toQuadruplePrecision(uint256 number, uint256 decimals) private pure returns (bytes16) {
if (number % decimals > 0) {
/// @dev during calculation this value is lost in the conversion
number += 1;
}
bytes16 nominator = ABDKMathQuad.fromUInt(number);
bytes16 denominator = ABDKMathQuad.fromUInt(decimals);
bytes16 fraction = ABDKMathQuad.div(nominator, denominator);
return fraction;
}
/// @dev Quadruple precision, 128 bits
function _toQuadruplePrecisionInt(int256 number, int256 decimals) private pure returns (bytes16) {
if (number % decimals > 0) {
/// @dev during calculation this value is lost in the conversion
number += 1;
}
bytes16 nominator = ABDKMathQuad.fromInt(number);
bytes16 denominator = ABDKMathQuad.fromInt(decimals);
bytes16 fraction = ABDKMathQuad.div(nominator, denominator);
return fraction;
}
function _toUint256(bytes16 value) private pure returns (uint256) {
bytes16 decimals = ABDKMathQuad.fromUInt(1e18);
bytes16 resultD18 = ABDKMathQuad.mul(value, decimals);
return ABDKMathQuad.toUInt(resultD18);
}
function _toInt256(bytes16 value) private pure returns (int256) {
bytes16 decimals = ABDKMathQuad.fromUInt(1e18);
bytes16 resultD18 = ABDKMathQuad.mul(value, decimals);
return ABDKMathQuad.toInt(resultD18);
}
}
/// @title Interface for interaction with the IPOR AMM Storage, contract responsible for managing AMM storage.
interface IAmmStorage {
/// @notice Returns the current version of AmmTreasury Storage
/// @dev Increase number when the implementation inside source code is different that the implementation deployed on the Mainnet
/// @return current AmmTreasury Storage version, integer
function getVersion() external pure returns (uint256);
/// @notice Gets the configuration of the IPOR AMM Storage.
/// @return ammTreasury address of the AmmTreasury contract
/// @return router address of the IPOR Protocol Router contract
function getConfiguration() external view returns (address ammTreasury, address router);
/// @notice Gets last swap ID.
/// @dev swap ID is incremented when new position is opened, last swap ID is used in Pay Fixed and Receive Fixed swaps.
/// @dev ID is global for all swaps, regardless if they are Pay Fixed or Receive Fixed in tenor 28, 60 or 90 days.
/// @return last swap ID, integer
function getLastSwapId() external view returns (uint256);
/// @notice Gets the last opened swap for a given tenor and direction.
/// @param tenor tenor of the swap
/// @param direction direction of the swap: 0 for Pay Fixed, 1 for Receive Fixed
/// @return last opened swap {AmmInternalTypes.OpenSwapItem}
function getLastOpenedSwap(
IporTypes.SwapTenor tenor,
uint256 direction
) external view returns (AmmInternalTypes.OpenSwapItem memory);
/// @notice Gets the AMM balance struct
/// @dev Balance contains:
/// # Pay Fixed Total Collateral
/// # Receive Fixed Total Collateral
/// # Liquidity Pool and Vault balances.
/// @return balance structure {IporTypes.AmmBalancesMemory}
function getBalance() external view returns (IporTypes.AmmBalancesMemory memory);
/// @notice Gets the balance for open swap
/// @dev Balance contains:
/// # Pay Fixed Total Collateral
/// # Receive Fixed Total Collateral
/// # Liquidity Pool balance
/// # Total Notional Pay Fixed
/// # Total Notional Receive Fixed
/// @return balance structure {IporTypes.AmmBalancesForOpenSwapMemory}
function getBalancesForOpenSwap() external view returns (IporTypes.AmmBalancesForOpenSwapMemory memory);
/// @notice Gets the balance with the extended information: IPOR publication fee balance and Treasury balance.
/// @return balance structure {AmmStorageTypes.ExtendedBalancesMemory}
function getExtendedBalance() external view returns (AmmStorageTypes.ExtendedBalancesMemory memory);
/// @notice gets the SOAP indicators.
/// @dev SOAP is a Sum Of All Payouts, aka undealised PnL.
/// @return indicatorsPayFixed structure {AmmStorageTypes.SoapIndicators} indicators for Pay Fixed swaps
/// @return indicatorsReceiveFixed structure {AmmStorageTypes.SoapIndicators} indicators for Receive Fixed swaps
function getSoapIndicators()
external
view
returns (
AmmStorageTypes.SoapIndicators memory indicatorsPayFixed,
AmmStorageTypes.SoapIndicators memory indicatorsReceiveFixed
);
/// @notice Gets swap based on the direction and swap ID.
/// @param direction direction of the swap: 0 for Pay Fixed, 1 for Receive Fixed
/// @param swapId swap ID
/// @return swap structure {AmmTypes.Swap}
function getSwap(AmmTypes.SwapDirection direction, uint256 swapId) external view returns (AmmTypes.Swap memory);
/// @notice Gets the active Pay-Fixed swaps for a given account address.
/// @param account account address
/// @param offset offset for paging
/// @param chunkSize page size for paging
/// @return totalCount total number of active Pay-Fixed swaps
/// @return swaps array where each element has structure {AmmTypes.Swap}
function getSwapsPayFixed(
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, AmmTypes.Swap[] memory swaps);
/// @notice Gets the active Receive-Fixed swaps for a given account address.
/// @param account account address
/// @param offset offset for paging
/// @param chunkSize page size for paging
/// @return totalCount total number of active Receive Fixed swaps
/// @return swaps array where each element has structure {AmmTypes.Swap}
function getSwapsReceiveFixed(
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, AmmTypes.Swap[] memory swaps);
/// @notice Gets the active Pay-Fixed and Receive-Fixed swaps IDs for a given account address.
/// @param account account address
/// @param offset offset for paging
/// @param chunkSize page size for paging
/// @return totalCount total number of active Pay-Fixed and Receive-Fixed IDs.
/// @return ids array where each element has structure {AmmStorageTypes.IporSwapId}
function getSwapIds(
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, AmmStorageTypes.IporSwapId[] memory ids);
/// @notice adds liquidity to the Liquidity Pool. Function available only to Router.
/// @param account account address executing request for redeem asset amount
/// @param assetAmount amount of asset added to balance of Liquidity Pool, represented in 18 decimals
/// @param cfgMaxLiquidityPoolBalance max liquidity pool balance taken from AmmPoolsService configuration, represented in 18 decimals.
/// @dev Function is only available to AmmPoolsService, can be executed only by IPOR Protocol Router as internal interaction.
function addLiquidityInternal(address account, uint256 assetAmount, uint256 cfgMaxLiquidityPoolBalance) external;
/// @notice subtract liquidity from the Liquidity Pool. Function available only to Router.
/// @param assetAmount amount of asset subtracted from Liquidity Pool, represented in 18 decimals
/// @dev Function is only available to AmmPoolsService, it can be executed only by IPOR Protocol Router as internal interaction.
function subtractLiquidityInternal(uint256 assetAmount) external;
/// @notice Updates structures in storage: balance, swaps, SOAP indicators when new Pay-Fixed swap is opened.
/// @dev Function is only available to AmmOpenSwapService, it can be executed only by IPOR Protocol Router as internal interaction.
/// @param newSwap new swap structure {AmmTypes.NewSwap}
/// @param cfgIporPublicationFee publication fee amount taken from AmmTreasury configuration, represented in 18 decimals.
/// @return new swap ID
function updateStorageWhenOpenSwapPayFixedInternal(
AmmTypes.NewSwap memory newSwap,
uint256 cfgIporPublicationFee
) external returns (uint256);
/// @notice Updates structures in the storage: balance, swaps, SOAP indicators when new Receive-Fixed swap is opened.
/// @dev Function is only available to AmmOpenSwapService, it can be executed only by IPOR Protocol Router as internal interaction.
/// @param newSwap new swap structure {AmmTypes.NewSwap}
/// @param cfgIporPublicationFee publication fee amount taken from AmmTreasury configuration, represented in 18 decimals.
/// @return new swap ID
function updateStorageWhenOpenSwapReceiveFixedInternal(
AmmTypes.NewSwap memory newSwap,
uint256 cfgIporPublicationFee
) external returns (uint256);
/// @notice Updates structures in the storage: balance, swaps, SOAP indicators when closing Pay-Fixed swap.
/// @dev Function is only available to AmmCloseSwapService, it can be executed only by IPOR Protocol Router as internal interaction.
/// @param swap The swap structure containing IPOR swap information.
/// @param pnlValue The amount that the trader has earned or lost on the swap, represented in 18 decimals.
/// pnValue can be negative, pnlValue NOT INCLUDE potential unwind fee.
/// @param swapUnwindFeeLPAmount unwind fee which is accounted on AMM Liquidity Pool balance.
/// @param swapUnwindFeeTreasuryAmount unwind fee which is accounted on AMM Treasury balance.
/// @param closingTimestamp The moment when the swap was closed.
/// @return closedSwap A memory struct representing the closed swap.
function updateStorageWhenCloseSwapPayFixedInternal(
AmmTypes.Swap memory swap,
int256 pnlValue,
uint256 swapUnwindFeeLPAmount,
uint256 swapUnwindFeeTreasuryAmount,
uint256 closingTimestamp
) external returns (AmmInternalTypes.OpenSwapItem memory closedSwap);
/// @notice Updates structures in the storage: swaps, balances, SOAP indicators when closing Receive-Fixed swap.
/// @dev Function is only available to AmmCloseSwapService, it can be executed only by IPOR Protocol Router as internal interaction.
/// @param swap The swap structure containing IPOR swap information.
/// @param pnlValue The amount that the trader has earned or lost on the swap, represented in 18 decimals.
/// pnValue can be negative, pnlValue NOT INCLUDE potential unwind fee.
/// @param swapUnwindFeeLPAmount unwind fee which is accounted on AMM Liquidity Pool balance.
/// @param swapUnwindFeeTreasuryAmount unwind fee which is accounted on AMM Treasury balance.
/// @param closingTimestamp The moment when the swap was closed.
/// @return closedSwap A memory struct representing the closed swap.
function updateStorageWhenCloseSwapReceiveFixedInternal(
AmmTypes.Swap memory swap,
int256 pnlValue,
uint256 swapUnwindFeeLPAmount,
uint256 swapUnwindFeeTreasuryAmount,
uint256 closingTimestamp
) external returns (AmmInternalTypes.OpenSwapItem memory closedSwap);
/// @notice Updates the balance when the AmmPoolsService withdraws AmmTreasury's assets from the AssetManagement.
/// @dev Function is only available to the AmmTreasury contract.
/// @param withdrawnAmount asset amount that was withdrawn from AssetManagement to AmmTreasury by AmmPoolsService, represented in 18 decimals.
/// @param vaultBalance Asset Management Vault (AssetManagement) balance, represented in 18 decimals
function updateStorageWhenWithdrawFromAssetManagement(uint256 withdrawnAmount, uint256 vaultBalance) external;
/// @notice Updates the balance when AmmPoolsService deposits AmmTreasury's assets to AssetManagement. Function is only available to AmmTreasury.
/// @param depositAmount asset amount deposited from AmmTreasury to AssetManagement by AmmPoolsService, represented in 18 decimals.
/// @param vaultBalance actual Asset Management Vault(AssetManagement) balance , represented in 18 decimals
function updateStorageWhenDepositToAssetManagement(uint256 depositAmount, uint256 vaultBalance) external;
/// @notice Updates the balance when AmmPoolsService transfers AmmTreasury's assets to Oracle Treasury's multisig wallet.
/// @dev Function is only available to the AmmGovernanceService, can be executed only by IPOR Protocol Router as internal interaction.
/// @param transferredAmount asset amount transferred to Charlie Treasury multisig wallet.
function updateStorageWhenTransferToCharlieTreasuryInternal(uint256 transferredAmount) external;
/// @notice Updates the balance when AmmPoolsService transfers AmmTreasury's assets to Treasury's multisig wallet.
/// @dev Function is only available to the AmmGovernanceService, can be executed only by IPOR Protocol Router as internal interaction.
/// @param transferredAmount asset amount transferred to Treasury's multisig wallet.
function updateStorageWhenTransferToTreasuryInternal(uint256 transferredAmount) external;
}
/// @title Interface for interaction with the IPOR AMM Storage, contract responsible for managing AMM storage.
interface IAmmStorageBaseV1 {
/// @notice Returns the current version of AmmTreasury Storage
/// @dev Increase number when the implementation inside source code is different that the implementation deployed on the Mainnet
/// @return current AmmTreasury Storage version, integer
function getVersion() external pure returns (uint256);
/// @notice Gets last swap ID.
/// @dev swap ID is incremented when new position is opened, last swap ID is used in Pay Fixed and Receive Fixed swaps.
/// @dev ID is global for all swaps, regardless if they are Pay Fixed or Receive Fixed in tenor 28, 60 or 90 days.
/// @return last swap ID, integer
function getLastSwapId() external view returns (uint256);
/// @notice Gets the last opened swap for a given tenor and direction.
/// @param tenor tenor of the swap
/// @param direction direction of the swap: 0 for Pay Fixed, 1 for Receive Fixed
/// @return last opened swap {AmmInternalTypes.OpenSwapItem}
function getLastOpenedSwap(
IporTypes.SwapTenor tenor,
uint256 direction
) external view returns (AmmInternalTypes.OpenSwapItem memory);
/// @notice Gets the AMM balance struct
/// @dev Balance contains:
/// # Pay Fixed Total Collateral
/// # Receive Fixed Total Collateral
/// # Liquidity Pool and Vault balances.
/// All balances are represented in 18 decimals.
/// @return balance structure {AmmTypesBaseV1.Balance}
function getBalance() external view returns (AmmTypesBaseV1.Balance memory);
/// @notice Gets the balance for open swap
/// @dev Balance contains:
/// # Pay Fixed Total Collateral
/// # Receive Fixed Total Collateral
/// # Liquidity Pool balance
/// # Total Notional Pay Fixed
/// # Total Notional Receive Fixed
/// @return balance structure {AmmTypesBaseV1.AmmBalanceForOpenSwap}
function getBalancesForOpenSwap() external view returns (AmmTypesBaseV1.AmmBalanceForOpenSwap memory);
/// @notice gets the SOAP indicators.
/// @dev SOAP is a Sum Of All Payouts, aka undealised PnL.
/// @return indicatorsPayFixed structure {AmmStorageTypes.SoapIndicators} indicators for Pay Fixed swaps
/// @return indicatorsReceiveFixed structure {AmmStorageTypes.SoapIndicators} indicators for Receive Fixed swaps
function getSoapIndicators()
external
view
returns (
AmmStorageTypes.SoapIndicators memory indicatorsPayFixed,
AmmStorageTypes.SoapIndicators memory indicatorsReceiveFixed
);
/// @notice Gets swap based on the direction and swap ID.
/// @param direction direction of the swap: 0 for Pay Fixed, 1 for Receive Fixed
/// @param swapId swap ID
/// @return swap structure {AmmTypesBaseV1.sol.Swap}
function getSwap(
AmmTypes.SwapDirection direction,
uint256 swapId
) external view returns (AmmTypesBaseV1.Swap memory);
/// @notice Gets the active Pay-Fixed swaps for a given account address.
/// @param account account address
/// @param offset offset for paging
/// @param chunkSize page size for paging
/// @return totalCount total number of active Pay-Fixed swaps
/// @return swaps array where each element has structure {AmmTypesBaseV1.sol.Swap}
function getSwapsPayFixed(
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, AmmTypesBaseV1.Swap[] memory swaps);
/// @notice Gets the active Receive-Fixed swaps for a given account address.
/// @param account account address
/// @param offset offset for paging
/// @param chunkSize page size for paging
/// @return totalCount total number of active Receive Fixed swaps
/// @return swaps array where each element has structure {AmmTypesBaseV1.sol.Swap}
function getSwapsReceiveFixed(
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, AmmTypesBaseV1.Swap[] memory swaps);
/// @notice Gets the active Pay-Fixed and Receive-Fixed swaps IDs for a given account address.
/// @param account account address
/// @param offset offset for paging
/// @param chunkSize page size for paging
/// @return totalCount total number of active Pay-Fixed and Receive-Fixed IDs.
/// @return ids array where each element has structure {AmmStorageTypes.IporSwapId}
function getSwapIds(
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, AmmStorageTypes.IporSwapId[] memory ids);
/// @notice Updates structures in storage: balance, swaps, SOAP indicators when new Pay-Fixed swap is opened.
/// @dev Function is only available to AmmOpenSwapService, it can be executed only by IPOR Protocol Router as internal interaction.
/// @param newSwap new swap structure {AmmTypesBaseV1.sol.NewSwap}
/// @param cfgIporPublicationFee publication fee amount taken from AmmTreasury configuration, represented in 18 decimals.
/// @return new swap ID
function updateStorageWhenOpenSwapPayFixedInternal(
AmmTypes.NewSwap memory newSwap,
uint256 cfgIporPublicationFee
) external returns (uint256);
/// @notice Updates structures in the storage: balance, swaps, SOAP indicators when new Receive-Fixed swap is opened.
/// @dev Function is only available to AmmOpenSwapService, it can be executed only by IPOR Protocol Router as internal interaction.
/// @param newSwap new swap structure {AmmTypesBaseV1.sol.NewSwap}
/// @param cfgIporPublicationFee publication fee amount taken from AmmTreasury configuration, represented in 18 decimals.
/// @return new swap ID
function updateStorageWhenOpenSwapReceiveFixedInternal(
AmmTypes.NewSwap memory newSwap,
uint256 cfgIporPublicationFee
) external returns (uint256);
/// @notice Updates structures in the storage: balance, swaps, SOAP indicators when closing Pay-Fixed swap.
/// @dev Function is only available to AmmCloseSwapService, it can be executed only by IPOR Protocol Router as internal interaction.
/// @param swap The swap structure containing IPOR swap information.
/// @param pnlValue The amount that the trader has earned or lost on the swap, represented in 18 decimals.
/// pnValue can be negative, pnlValue NOT INCLUDE potential unwind fee.
/// @param swapUnwindFeeLPAmount unwind fee which is accounted on AMM Liquidity Pool balance.
/// @param swapUnwindFeeTreasuryAmount unwind fee which is accounted on AMM Treasury balance.
/// @param closingTimestamp The moment when the swap was closed.
/// @return closedSwap A memory struct representing the closed swap.
function updateStorageWhenCloseSwapPayFixedInternal(
AmmTypesBaseV1.Swap memory swap,
int256 pnlValue,
uint256 swapUnwindFeeLPAmount,
uint256 swapUnwindFeeTreasuryAmount,
uint256 closingTimestamp
) external returns (AmmInternalTypes.OpenSwapItem memory closedSwap);
/// @notice Updates structures in the storage: swaps, balances, SOAP indicators when closing Receive-Fixed swap.
/// @dev Function is only available to AmmCloseSwapService, it can be executed only by IPOR Protocol Router as internal interaction.
/// @param swap The swap structure containing IPOR swap information.
/// @param pnlValue The amount that the trader has earned or lost on the swap, represented in 18 decimals.
/// pnValue can be negative, pnlValue NOT INCLUDE potential unwind fee.
/// @param swapUnwindFeeLPAmount unwind fee which is accounted on AMM Liquidity Pool balance.
/// @param swapUnwindFeeTreasuryAmount unwind fee which is accounted on AMM Treasury balance.
/// @param closingTimestamp The moment when the swap was closed.
/// @return closedSwap A memory struct representing the closed swap.
function updateStorageWhenCloseSwapReceiveFixedInternal(
AmmTypesBaseV1.Swap memory swap,
int256 pnlValue,
uint256 swapUnwindFeeLPAmount,
uint256 swapUnwindFeeTreasuryAmount,
uint256 closingTimestamp
) external returns (AmmInternalTypes.OpenSwapItem memory closedSwap);
/// @notice Updates the balance when AmmPoolsService transfers AmmTreasury's assets to Oracle Treasury's multisig wallet.
/// @dev Function is only available to the AmmGovernanceService, can be executed only by IPOR Protocol Router as internal interaction.
/// @param transferredAmount asset amount transferred to Charlie Treasury multisig wallet.
function updateStorageWhenTransferToCharlieTreasuryInternal(uint256 transferredAmount) external;
/// @notice Updates the balance when AmmPoolsService transfers AmmTreasury's assets to Treasury's multisig wallet.
/// @dev Function is only available to the AmmGovernanceService, can be executed only by IPOR Protocol Router as internal interaction.
/// @param transferredAmount asset amount transferred to Treasury's multisig wallet.
function updateStorageWhenTransferToTreasuryInternal(uint256 transferredAmount) external;
}
/// @title Basic logic related with SOAP indicators
library SoapIndicatorLogic {
using SafeCast for uint256;
using InterestRates for uint256;
/// @notice Calculate the SOAP for pay fixed leg
/// @param si SOAP indicators
/// @param calculateTimestamp timestamp to calculate the SOAP
/// @param ibtPrice IBT price
/// @return SOAP for pay fixed leg
function calculateSoapPayFixed(
AmmStorageTypes.SoapIndicators memory si,
uint256 calculateTimestamp,
uint256 ibtPrice
) internal pure returns (int256) {
return
IporMath.division(si.totalIbtQuantity * ibtPrice, 1e18).toInt256() -
(si.totalNotional + calculateHyphoteticalInterestTotal(si, calculateTimestamp)).toInt256();
}
/// @notice Calculate the SOAP for receive fixed leg
/// @param si SOAP indicators
/// @param calculateTimestamp timestamp to calculate the SOAP
/// @param ibtPrice IBT price
/// @return SOAP for receive fixed leg
function calculateSoapReceiveFixed(
AmmStorageTypes.SoapIndicators memory si,
uint256 calculateTimestamp,
uint256 ibtPrice
) internal pure returns (int256) {
return
(si.totalNotional + calculateHyphoteticalInterestTotal(si, calculateTimestamp)).toInt256() -
IporMath.division(si.totalIbtQuantity * ibtPrice, 1e18).toInt256();
}
/// @notice Calculate hypothetical interest total, value that is used to calculate the SOAP
/// @param si SOAP indicators
/// @param calculateTimestamp timestamp to calculate the value
/// @return hypothetical interest total
function calculateHyphoteticalInterestTotal(
AmmStorageTypes.SoapIndicators memory si,
uint256 calculateTimestamp
) internal pure returns (uint256) {
return
si.hypotheticalInterestCumulative +
calculateHypotheticalInterestDelta(
calculateTimestamp,
si.rebalanceTimestamp,
si.totalNotional + si.hypotheticalInterestCumulative,
si.averageInterestRate
);
}
/// @notice Calculate hypothetical interest delta, value that is used to calculate the SOAP
/// @param calculateTimestamp timestamp to calculate the value
/// @param lastRebalanceTimestamp last rebalance timestamp
/// @param totalNotional total notional
/// @param averageInterestRate average interest rate
/// @return hypothetical interest delta
function calculateHypotheticalInterestDelta(
uint256 calculateTimestamp,
uint256 lastRebalanceTimestamp,
uint256 totalNotional,
uint256 averageInterestRate
) internal pure returns (uint256) {
require(
calculateTimestamp >= lastRebalanceTimestamp,
AmmErrors.CALC_TIMESTAMP_LOWER_THAN_SOAP_REBALANCE_TIMESTAMP
);
return
totalNotional.calculateContinuousCompoundInterestUsingRatePeriodMultiplication(
averageInterestRate * (calculateTimestamp - lastRebalanceTimestamp)
);
}
}
interface ISpreadBaseV1 {
struct SpreadInputs {
//// @notice Swap's assets DAI/USDC/USDT/stETH/etc.
address asset;
/// @notice Swap's notional value
uint256 swapNotional;
/// @notice demand spread factor used in demand spread calculation
uint256 demandSpreadFactor;
/// @notice Base spread
int256 baseSpreadPerLeg;
/// @notice Swap's balance for Pay Fixed leg
uint256 totalCollateralPayFixed;
/// @notice Swap's balance for Receive Fixed leg
uint256 totalCollateralReceiveFixed;
/// @notice Liquidity Pool's Balance
uint256 liquidityPoolBalance;
/// @notice Ipor index value at the time of swap creation
uint256 iporIndexValue;
/// @notice fixed rate cap for given leg for offered rate without demandSpread in 18 decimals
uint256 fixedRateCapPerLeg;
/// @notice Swap's tenor
IporTypes.SwapTenor tenor;
}
/// @notice Calculates and updates the offered rate for Pay Fixed leg of a swap.
/// @dev This function should be called only through the Router contract as per the 'onlyRouter' modifier.
/// It calculates the offered rate for Pay Fixed swaps by taking into account various factors like
/// IPOR index value, base spread, demand spread, and rate cap.
/// The demand spread is updated based on the current market conditions and the swap's specifics.
/// @param spreadInputs A 'SpreadInputs' struct containing all necessary data for calculating the offered rate.
/// This includes the asset's address, swap's notional value, demand spread factor, base spread,
/// balances for Pay Fixed and Receive Fixed legs, liquidity pool balance, IPOR index value at swap creation,
/// fixed rate cap per leg, and the swap's tenor.
/// @return offeredRate The calculated offered rate for the Pay Fixed leg in the swap.
function calculateAndUpdateOfferedRatePayFixed(
SpreadInputs calldata spreadInputs
) external returns (uint256 offeredRate);
/// @notice Calculates the offered rate for a swap based on the specified direction (Pay Fixed or Receive Fixed).
/// @dev This function computes the offered rate for a swap, taking into account the swap's direction,
/// the current IPOR index value, base spread, demand spread, and the fixed rate cap.
/// It is a view function and does not modify the state of the contract.
/// @param direction An enum value from 'AmmTypes' specifying the swap direction -
/// either PAY_FIXED_RECEIVE_FLOATING or PAY_FLOATING_RECEIVE_FIXED.
/// @param spreadInputs A 'SpreadInputs' struct containing necessary data for calculating the offered rate,
/// such as the asset's address, swap's notional value, demand spread factor, base spread,
/// balances for Pay Fixed and Receive Fixed legs, liquidity pool balance, IPOR index value at the time of swap creation,
/// fixed rate cap per leg, and the swap's tenor.
/// @return The calculated offered rate for the specified swap direction.
/// The rate is returned as a uint256.
function calculateOfferedRate(
AmmTypes.SwapDirection direction,
SpreadInputs calldata spreadInputs
) external view returns (uint256);
/// @notice Calculates the offered rate for a Pay Fixed swap.
/// @dev This view function computes the offered rate specifically for swaps where the Pay Fixed leg is chosen.
/// It considers various inputs like the IPOR index value, base spread, demand spread, and the fixed rate cap
/// to determine the appropriate rate. As a view function, it does not alter the state of the contract.
/// @param spreadInputs A 'SpreadInputs' struct containing data essential for calculating the offered rate.
/// This includes information such as the asset's address, the notional value of the swap,
/// the demand spread factor, the base spread, balances of Pay Fixed and Receive Fixed legs,
/// the liquidity pool balance, the IPOR index value at the time of swap creation, the fixed rate cap per leg,
/// and the swap's tenor.
/// @return offeredRate The calculated offered rate for the Pay Fixed leg of the swap, returned as a uint256.
function calculateOfferedRatePayFixed(
SpreadInputs calldata spreadInputs
) external view returns (uint256 offeredRate);
/// @notice Calculates and updates the offered rate for the Receive Fixed leg of a swap.
/// @dev This function is accessible only through the Router contract, as enforced by the 'onlyRouter' modifier.
/// It calculates the offered rate for Receive Fixed swaps, considering various factors like the IPOR index value,
/// base spread, imbalance spread, and the fixed rate cap. This function also updates the time-weighted notional
/// based on the current market conditions and the specifics of the swap.
/// @param spreadInputs A 'SpreadInputs' struct containing all necessary data for calculating the offered rate.
/// This includes the asset's address, swap's notional value, demand spread factor, base spread,
/// balances for Pay Fixed and Receive Fixed legs, liquidity pool balance, IPOR index value at swap creation,
/// fixed rate cap per leg, and the swap's tenor.
/// @return offeredRate The calculated offered rate for the Receive Fixed leg in the swap, returned as a uint256.
function calculateAndUpdateOfferedRateReceiveFixed(
SpreadInputs calldata spreadInputs
) external returns (uint256 offeredRate);
/// @notice Calculates the offered rate for a Receive Fixed swap.
/// @dev This view function computes the offered rate specifically for swaps where the Receive Fixed leg is chosen.
/// It evaluates various inputs such as the IPOR index value, base spread, demand spread, and the fixed rate cap
/// to determine the appropriate rate. Being a view function, it does not modify the state of the contract.
/// @param spreadInputs A 'SpreadInputs' struct containing the necessary data for calculating the offered rate.
/// This includes the asset's address, swap's notional value, demand spread factor, base spread,
/// balances for Pay Fixed and Receive Fixed legs, liquidity pool balance, the IPOR index value at the time of swap creation,
/// fixed rate cap per leg, and the swap's tenor.
/// @return offeredRate The calculated offered rate for the Receive Fixed leg of the swap, returned as a uint256.
function calculateOfferedRateReceiveFixed(
SpreadInputs calldata spreadInputs
) external view returns (uint256 offeredRate);
/// @notice Updates the time-weighted notional values when a swap is closed.
/// @dev This function is called upon the closure of a swap to adjust the time-weighted notional values for Pay Fixed
/// or Receive Fixed legs, reflecting the change in the market conditions due to the closed swap.
/// It takes into account the swap's direction, tenor, notional, and the details of the closed swap to make the necessary adjustments.
/// @param direction A uint256 indicating the direction of the swap: 0 for Pay Fixed, 1 for Receive Fixed.
/// @param tenor The tenor of the swap, represented by an enum value from 'IporTypes'.
/// @param swapNotional The notional value of the swap that is being closed.
/// @param closedSwap An 'OpenSwapItem' struct from 'AmmInternalTypes' representing the details of the swap that was closed.
/// @param ammStorageAddress The address of the AMM (Automated Market Maker) storage contract where the swap data is maintained.
/// @dev This function should only be called by an authorized Router, as it can significantly impact the contract's state.
function updateTimeWeightedNotionalOnClose(
uint256 direction,
IporTypes.SwapTenor tenor,
uint256 swapNotional,
AmmInternalTypes.OpenSwapItem memory closedSwap,
address ammStorageAddress
) external;
/// @notice Retrieves time-weighted notional values for various asset-tenor pairs.
/// @dev Returns an array of `TimeWeightedNotionalResponse` containing time-weighted notional values and associated keys.
/// @return timeWeightedNotionalResponse An array of `TimeWeightedNotionalResponse` structures, each including a time-weighted notional value and a corresponding key.
function getTimeWeightedNotional()
external
view
returns (SpreadTypesBaseV1.TimeWeightedNotionalResponse[] memory timeWeightedNotionalResponse);
/// @notice Retrieves the configuration parameters for the spread function.
/// @dev This function provides access to the current configuration of the spread function used in the contract.
/// It returns an array of uint256 values, each representing a specific parameter or threshold used in
/// the calculation of spreads for different swap legs or conditions.
/// @return An array of uint256 values representing the configuration parameters of the spread function.
/// These parameters are critical in determining how spreads are calculated for Pay Fixed and Receive Fixed swaps.
function spreadFunctionConfig() external returns (uint256[] memory);
/// @notice Updates the time-weighted notional values for multiple assets and tenors.
/// @dev This function can only be called by the contract owner and overrides any existing implementation.
/// It iterates through an array of `TimeWeightedNotionalMemory` structures, checks each one for validity,
/// and then saves the updated time-weighted notional values.
/// @param timeWeightedNotionalMemories An array of `TimeWeightedNotionalMemory` structures, where each structure
/// contains information about the asset, tenor, and the new time-weighted notional value to be updated.
/// Each `TimeWeightedNotionalMemory` structure should have a `storageId` identifying the asset and tenor
/// combination, along with the notional values and other relevant information.
/// @dev The function employs an `unchecked` block for the loop iteration to optimize gas usage, assuming that
/// the arithmetic operation will not overflow under normal operation conditions.
function updateTimeWeightedNotional(
SpreadTypesBaseV1.TimeWeightedNotionalMemory[] calldata timeWeightedNotionalMemories
) external;
/// @notice Returns the version number of the contract.
/// @dev This function provides a simple way to retrieve the version number of the current contract.
/// It's useful for compatibility checks, upgradeability assessments, and tracking contract iterations.
/// The version number is returned as a uint256.
/// @return A uint256 value representing the version number of the contract.
function getVersion() external pure returns (uint256);
}
library RiskIndicatorsValidatorLib {
using ECDSA for bytes32;
function verify(
AmmTypes.RiskIndicatorsInputs memory inputs,
address asset,
uint256 tenor,
uint256 direction,
address signerAddress
) internal view returns (AmmTypes.OpenSwapRiskIndicators memory riskIndicators) {
bytes32 hash = hashRiskIndicatorsInputs(inputs, asset, tenor, direction);
require(
hash.recover(inputs.signature) == signerAddress,
IporErrors.RISK_INDICATORS_SIGNATURE_INVALID
);
require(inputs.expiration > block.timestamp, IporErrors.RISK_INDICATORS_EXPIRED);
return AmmTypes.OpenSwapRiskIndicators(
inputs.maxCollateralRatio,
inputs.maxCollateralRatioPerLeg,
inputs.maxLeveragePerLeg,
inputs.baseSpreadPerLeg,
inputs.fixedRateCapPerLeg,
inputs.demandSpreadFactor);
}
function hashRiskIndicatorsInputs(
AmmTypes.RiskIndicatorsInputs memory inputs,
address asset,
uint256 tenor,
uint256 direction
) private pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
inputs.maxCollateralRatio,
inputs.maxCollateralRatioPerLeg,
inputs.maxLeveragePerLeg,
inputs.baseSpreadPerLeg,
inputs.fixedRateCapPerLeg,
inputs.demandSpreadFactor,
inputs.expiration,
asset,
tenor,
direction
)
);
}
}
library RiskManagementLogic {
using Address for address;
/// @notice Stuct describing the context for calculating the offered rate
/// @param asset Asset address
/// @param ammStorage AMM storage address
/// @param spreadRouter Spread router address
/// @param minLeverage Minimum leverage
/// @param indexValue IPOR Index value
struct SpreadOfferedRateContext {
address asset;
address ammStorage;
address spreadRouter;
uint256 minLeverage;
uint256 indexValue;
}
/// @notice Calculates the offered rate
/// @param direction Swap direction
/// @param tenor Swap tenor
/// @param swapNotional Swap notional
/// @param spreadOfferedRateCtx Context for calculating the offered rate
/// @return Offered rate
function calculateOfferedRate(
uint256 direction,
IporTypes.SwapTenor tenor,
uint256 swapNotional,
SpreadOfferedRateContext memory spreadOfferedRateCtx,
AmmTypes.OpenSwapRiskIndicators memory riskIndicators
) internal view returns (uint256) {
IporTypes.AmmBalancesForOpenSwapMemory memory balance = IAmmStorage(spreadOfferedRateCtx.ammStorage)
.getBalancesForOpenSwap();
return
abi.decode(
spreadOfferedRateCtx.spreadRouter.functionStaticCall(
abi.encodeWithSelector(
determineSpreadMethodSig(direction, tenor),
spreadOfferedRateCtx.asset,
swapNotional,
riskIndicators.demandSpreadFactor,
riskIndicators.baseSpreadPerLeg,
balance.totalCollateralPayFixed,
balance.totalCollateralReceiveFixed,
balance.liquidityPool,
spreadOfferedRateCtx.indexValue,
riskIndicators.fixedRateCapPerLeg
)
),
(uint256)
);
}
/// @notice Determines the spread method signature based on the swap direction and tenor
/// @param direction Swap direction
/// @param tenor Swap tenor
/// @return Spread method signature
function determineSpreadMethodSig(uint256 direction, IporTypes.SwapTenor tenor) internal pure returns (bytes4) {
if (direction == 0) {
if (tenor == IporTypes.SwapTenor.DAYS_28) {
return ISpread28DaysLens.calculateOfferedRatePayFixed28Days.selector;
} else if (tenor == IporTypes.SwapTenor.DAYS_60) {
return ISpread60DaysLens.calculateOfferedRatePayFixed60Days.selector;
} else if (tenor == IporTypes.SwapTenor.DAYS_90) {
return ISpread90DaysLens.calculateOfferedRatePayFixed90Days.selector;
} else {
revert(AmmErrors.UNSUPPORTED_SWAP_TENOR);
}
} else if (direction == 1) {
if (tenor == IporTypes.SwapTenor.DAYS_28) {
return ISpread28DaysLens.calculateOfferedRateReceiveFixed28Days.selector;
} else if (tenor == IporTypes.SwapTenor.DAYS_60) {
return ISpread60DaysLens.calculateOfferedRateReceiveFixed60Days.selector;
} else if (tenor == IporTypes.SwapTenor.DAYS_90) {
return ISpread90DaysLens.calculateOfferedRateReceiveFixed90Days.selector;
} else {
revert(AmmErrors.UNSUPPORTED_SWAP_TENOR);
}
} else {
revert(AmmErrors.UNSUPPORTED_DIRECTION);
}
}
}
/// @title AMM basic logic library
library AmmLib {
using SafeCast for uint256;
using SafeCast for int256;
using SoapIndicatorLogic for AmmStorageTypes.SoapIndicators;
/// @notice Gets AMM exchange rate
/// @param model AMM model skeleton of the pool
/// @return AMM exchange rate
function getExchangeRate(AmmTypes.AmmPoolCoreModel memory model) internal view returns (uint256) {
return getExchangeRate(model, getAccruedBalance(model).liquidityPool);
}
/// @notice Gets AMM exchange rate
/// @param model AMM model skeleton of the pool
/// @param liquidityPoolBalance liquidity pool balance
/// @return AMM exchange rate
/// @dev For gas optimization with additional param liquidityPoolBalance with already calculated value
function getExchangeRate(
AmmTypes.AmmPoolCoreModel memory model,
uint256 liquidityPoolBalance
) internal view returns (uint256) {
(, , int256 soap) = getSoap(model);
int256 balance = liquidityPoolBalance.toInt256() - soap;
require(balance >= 0, AmmErrors.SOAP_AND_LP_BALANCE_SUM_IS_TOO_LOW);
uint256 ipTokenTotalSupply = IIpToken(model.ipToken).totalSupply();
if (ipTokenTotalSupply > 0) {
return IporMath.division(balance.toUint256() * 1e18, ipTokenTotalSupply);
} else {
return 1e18;
}
}
/// @notice Gets AMM SOAP Sum Of All Payouts
/// @param model AMM model skeleton of the pool
/// @return soapPayFixed SOAP Pay Fixed
/// @return soapReceiveFixed SOAP Receive Fixed
/// @return soap SOAP Sum Of All Payouts
function getSoap(
AmmTypes.AmmPoolCoreModel memory model
) internal view returns (int256 soapPayFixed, int256 soapReceiveFixed, int256 soap) {
uint256 timestamp = block.timestamp;
(
AmmStorageTypes.SoapIndicators memory indicatorsPayFixed,
AmmStorageTypes.SoapIndicators memory indicatorsReceiveFixed
) = IAmmStorage(model.ammStorage).getSoapIndicators();
uint256 ibtPrice = IIporOracle(model.iporOracle).calculateAccruedIbtPrice(model.asset, timestamp);
soapPayFixed = indicatorsPayFixed.calculateSoapPayFixed(timestamp, ibtPrice);
soapReceiveFixed = indicatorsReceiveFixed.calculateSoapReceiveFixed(timestamp, ibtPrice);
soap = soapPayFixed + soapReceiveFixed;
}
/// @notice Gets accrued balance of the pool
/// @param model AMM model skeleton of the pool
/// @return accrued balance of the pool
/// @dev balance takes into consideration asset management vault balance and their accrued interest
function getAccruedBalance(
AmmTypes.AmmPoolCoreModel memory model
) internal view returns (IporTypes.AmmBalancesMemory memory) {
require(model.ammTreasury != address(0), string.concat(IporErrors.WRONG_ADDRESS, " ammTreasury"));
IporTypes.AmmBalancesMemory memory accruedBalance = IAmmStorage(model.ammStorage).getBalance();
uint256 actualVaultBalance = IAssetManagement(model.assetManagement).totalBalance();
int256 liquidityPool = accruedBalance.liquidityPool.toInt256() +
actualVaultBalance.toInt256() -
accruedBalance.vault.toInt256();
require(liquidityPool >= 0, AmmErrors.LIQUIDITY_POOL_AMOUNT_TOO_LOW);
accruedBalance.liquidityPool = liquidityPool.toUint256();
accruedBalance.vault = actualVaultBalance;
return accruedBalance;
}
}
/// @title Core logic for IPOR Swap
library SwapLogicBaseV1 {
using SafeCast for uint256;
using SafeCast for int256;
using InterestRates for uint256;
using InterestRates for int256;
using RiskIndicatorsValidatorLib for AmmTypes.RiskIndicatorsInputs;
/// @notice Calculates core amounts related with swap
/// @param tenor swap duration, 0 = 28 days, 1 = 60 days, 2 = 90 days
/// @param wadTotalAmount total amount represented in 18 decimals
/// @param leverage swap leverage, represented in 18 decimals
/// @param wadLiquidationDepositAmount liquidation deposit amount, represented in 18 decimals
/// @param iporPublicationFeeAmount IPOR publication fee amount, represented in 18 decimals
/// @param openingFeeRate opening fee rate, represented in 18 decimals
/// @return collateral collateral amount, represented in 18 decimals
/// @return notional notional amount, represented in 18 decimals
/// @return openingFee opening fee amount, represented in 18 decimals
/// @dev wadTotalAmount = collateral + openingFee + wadLiquidationDepositAmount + iporPublicationFeeAmount
/// @dev Opening Fee is a multiplication openingFeeRate and notional
function calculateSwapAmount(
IporTypes.SwapTenor tenor,
uint256 wadTotalAmount,
uint256 leverage,
uint256 wadLiquidationDepositAmount,
uint256 iporPublicationFeeAmount,
uint256 openingFeeRate
) internal pure returns (uint256 collateral, uint256 notional, uint256 openingFee) {
require(
wadTotalAmount > wadLiquidationDepositAmount + iporPublicationFeeAmount,
AmmErrors.TOTAL_AMOUNT_LOWER_THAN_FEE
);
uint256 availableAmount = wadTotalAmount - wadLiquidationDepositAmount - iporPublicationFeeAmount;
collateral = IporMath.division(
availableAmount * 1e18,
1e18 + IporMath.division(leverage * openingFeeRate * getTenorInDays(tenor), 365 * 1e18)
);
notional = IporMath.division(leverage * collateral, 1e18);
openingFee = availableAmount - collateral;
}
function calculatePnl(
AmmTypesBaseV1.Swap memory swap,
uint256 closingTimestamp,
uint256 mdIbtPrice
) internal pure returns (int256 pnlValue) {
if (swap.direction == AmmTypes.SwapDirection.PAY_FIXED_RECEIVE_FLOATING) {
pnlValue = calculatePnlPayFixed(
swap.openTimestamp,
swap.collateral,
swap.notional,
swap.fixedInterestRate,
swap.ibtQuantity,
closingTimestamp,
mdIbtPrice
);
} else if (swap.direction == AmmTypes.SwapDirection.PAY_FLOATING_RECEIVE_FIXED) {
pnlValue = calculatePnlReceiveFixed(
swap.openTimestamp,
swap.collateral,
swap.notional,
swap.fixedInterestRate,
swap.ibtQuantity,
closingTimestamp,
mdIbtPrice
);
} else {
revert(AmmErrors.UNSUPPORTED_DIRECTION);
}
}
/// @notice Calculates Profit and Loss (PnL) for a pay fixed swap for a given swap closing timestamp and IBT price from IporOracle.
/// @param swapOpenTimestamp moment when swap is opened, represented in seconds
/// @param swapCollateral collateral value, represented in 18 decimals
/// @param swapNotional swap notional, represented in 18 decimals
/// @param swapFixedInterestRate fixed interest rate on a swap, represented in 18 decimals
/// @param swapIbtQuantity IBT quantity, represented in 18 decimals
/// @param closingTimestamp moment when swap is closed, represented in seconds
/// @param mdIbtPrice IBT price from IporOracle, represented in 18 decimals
/// @return pnlValue swap PnL, represented in 18 decimals
/// @dev Calculated PnL not taken into consideration potential unwinding of the swap.
function calculatePnlPayFixed(
uint256 swapOpenTimestamp,
uint256 swapCollateral,
uint256 swapNotional,
uint256 swapFixedInterestRate,
uint256 swapIbtQuantity,
uint256 closingTimestamp,
uint256 mdIbtPrice
) internal pure returns (int256 pnlValue) {
(uint256 interestFixed, uint256 interestFloating) = calculateInterest(
swapOpenTimestamp,
swapNotional,
swapFixedInterestRate,
swapIbtQuantity,
closingTimestamp,
mdIbtPrice
);
pnlValue = normalizePnlValue(swapCollateral, interestFloating.toInt256() - interestFixed.toInt256());
}
/// @notice Calculates Profit and Loss (PnL) for a receive fixed swap for a given swap closing timestamp and IBT price from IporOracle.
/// @param swapOpenTimestamp moment when swap is opened, represented in seconds
/// @param swapCollateral collateral value, represented in 18 decimals
/// @param swapNotional swap notional, represented in 18 decimals
/// @param swapFixedInterestRate fixed interest rate on a swap, represented in 18 decimals
/// @param swapIbtQuantity IBT quantity, represented in 18 decimals
/// @param closingTimestamp moment when swap is closed, represented in seconds
/// @param mdIbtPrice IBT price from IporOracle, represented in 18 decimals
/// @return pnlValue swap PnL, represented in 18 decimals
/// @dev Calculated PnL not taken into consideration potential unwinding of the swap.
function calculatePnlReceiveFixed(
uint256 swapOpenTimestamp,
uint256 swapCollateral,
uint256 swapNotional,
uint256 swapFixedInterestRate,
uint256 swapIbtQuantity,
uint256 closingTimestamp,
uint256 mdIbtPrice
) internal pure returns (int256 pnlValue) {
(uint256 interestFixed, uint256 interestFloating) = calculateInterest(
swapOpenTimestamp,
swapNotional,
swapFixedInterestRate,
swapIbtQuantity,
closingTimestamp,
mdIbtPrice
);
pnlValue = normalizePnlValue(swapCollateral, interestFixed.toInt256() - interestFloating.toInt256());
}
/// @notice Calculates interest including continuous capitalization for a given swap, closing timestamp and IBT price from IporOracle.
/// @param swapOpenTimestamp moment when swap is opened, represented in seconds without 18 decimals
/// @param swapNotional swap notional, represented in 18 decimals
/// @param swapFixedInterestRate fixed interest rate on a swap, represented in 18 decimals
/// @param swapIbtQuantity IBT quantity, represented in 18 decimals
/// @param closingTimestamp moment when swap is closed, represented in seconds without 18 decimals
/// @param mdIbtPrice IBT price from IporOracle, represented in 18 decimals
/// @return interestFixed fixed interest chunk, represented in 18 decimals
/// @return interestFloating floating interest chunk, represented in 18 decimals
function calculateInterest(
uint256 swapOpenTimestamp,
uint256 swapNotional,
uint256 swapFixedInterestRate,
uint256 swapIbtQuantity,
uint256 closingTimestamp,
uint256 mdIbtPrice
) internal pure returns (uint256 interestFixed, uint256 interestFloating) {
require(closingTimestamp >= swapOpenTimestamp, AmmErrors.CLOSING_TIMESTAMP_LOWER_THAN_SWAP_OPEN_TIMESTAMP);
interestFixed = calculateInterestFixed(
swapNotional,
swapFixedInterestRate,
closingTimestamp - swapOpenTimestamp
);
interestFloating = calculateInterestFloating(swapIbtQuantity, mdIbtPrice);
}
/// @notice Calculates fixed interest chunk including continuous capitalization for a given swap, closing timestamp and IBT price from IporOracle.
/// @param notional swap notional, represented in 18 decimals
/// @param swapFixedInterestRate fixed interest rate on a swap, represented in 18 decimals
/// @param swapPeriodInSeconds swap period in seconds
/// @return interestFixed fixed interest chunk, represented in 18 decimals
function calculateInterestFixed(
uint256 notional,
uint256 swapFixedInterestRate,
uint256 swapPeriodInSeconds
) internal pure returns (uint256) {
return
notional.addContinuousCompoundInterestUsingRatePeriodMultiplication(
swapFixedInterestRate * swapPeriodInSeconds
);
}
/// @notice Calculates floating interest chunk for a given ibt quantity and IBT current price
/// @param ibtQuantity IBT quantity, represented in 18 decimals
/// @param ibtCurrentPrice IBT price from IporOracle, represented in 18 decimals
/// @return interestFloating floating interest chunk, represented in 18 decimals
function calculateInterestFloating(uint256 ibtQuantity, uint256 ibtCurrentPrice) internal pure returns (uint256) {
//IBTQ * IBTPtc (IBTPtc - interest bearing token price in time when swap is closed)
return IporMath.division(ibtQuantity * ibtCurrentPrice, 1e18);
}
/// @notice Splits opening fee amount into liquidity pool and treasury portions
/// @param openingFeeAmount opening fee amount, represented in 18 decimals
/// @param openingFeeForTreasurePortionRate opening fee for treasury portion rate taken from Protocol configuration, represented in 18 decimals
/// @return feeForLiquidityPoolAmount liquidity pool portion of opening fee, represented in 18 decimals
/// @return feeForTreasuryAmount treasury portion of opening fee, represented in 18 decimals
function splitOpeningFeeAmount(
uint256 openingFeeAmount,
uint256 openingFeeForTreasurePortionRate
) internal pure returns (uint256 feeForLiquidityPoolAmount, uint256 feeForTreasuryAmount) {
feeForTreasuryAmount = IporMath.division(openingFeeAmount * openingFeeForTreasurePortionRate, 1e18);
feeForLiquidityPoolAmount = openingFeeAmount - feeForTreasuryAmount;
}
/// @notice Gets swap tenor in days
/// @param tenor Swap tenor
/// @return swap tenor in days
function getTenorInDays(IporTypes.SwapTenor tenor) internal pure returns (uint256) {
if (tenor == IporTypes.SwapTenor.DAYS_28) {
return 28;
} else if (tenor == IporTypes.SwapTenor.DAYS_60) {
return 60;
} else if (tenor == IporTypes.SwapTenor.DAYS_90) {
return 90;
} else {
revert(AmmErrors.UNSUPPORTED_SWAP_TENOR);
}
}
/// @notice Normalizes swap value to collateral value. Absolute value Swap PnL can't be higher than collateral.
/// @param collateral collateral value, represented in 18 decimals
/// @param pnlValue swap PnL, represented in 18 decimals
function normalizePnlValue(uint256 collateral, int256 pnlValue) internal pure returns (int256) {
int256 intCollateral = collateral.toInt256();
if (pnlValue > 0) {
if (pnlValue < intCollateral) {
return pnlValue;
} else {
return intCollateral;
}
} else {
if (pnlValue < -intCollateral) {
return -intCollateral;
} else {
return pnlValue;
}
}
}
/// @notice Gets swap tenor in seconds
/// @param tenor Swap tenor
/// @return swap tenor in seconds
function getTenorInSeconds(IporTypes.SwapTenor tenor) internal pure returns (uint256) {
if (tenor == IporTypes.SwapTenor.DAYS_28) {
return 28 days;
} else if (tenor == IporTypes.SwapTenor.DAYS_60) {
return 60 days;
} else if (tenor == IporTypes.SwapTenor.DAYS_90) {
return 90 days;
}
revert(AmmErrors.UNSUPPORTED_SWAP_TENOR);
}
}
library SwapCloseLogicLibBaseV1 {
using SafeCast for uint256;
using SafeCast for int256;
using InterestRates for uint256;
using InterestRates for int256;
using RiskIndicatorsValidatorLib for AmmTypes.RiskIndicatorsInputs;
function calculateSwapUnwindPnlValueNormalized(
AmmTypesBaseV1.UnwindParams memory unwindParams,
AmmTypes.SwapDirection oppositeDirection,
AmmTypes.OpenSwapRiskIndicators memory oppositeRiskIndicators
) internal view returns (int256) {
AmmTypesBaseV1.AmmBalanceForOpenSwap memory balance = IAmmStorageBaseV1(unwindParams.ammStorage)
.getBalancesForOpenSwap();
uint256 liquidityPoolBalance = IAmmTreasuryBaseV1(unwindParams.ammTreasury).getLiquidityPoolBalance();
return
SwapLogicBaseV1.normalizePnlValue(
unwindParams.swap.collateral,
calculateSwapUnwindPnlValue(
unwindParams.swap,
unwindParams.closeTimestamp,
ISpreadBaseV1(unwindParams.spread).calculateOfferedRate(
oppositeDirection,
ISpreadBaseV1.SpreadInputs({
asset: unwindParams.asset,
swapNotional: unwindParams.swap.notional,
demandSpreadFactor: oppositeRiskIndicators.demandSpreadFactor,
baseSpreadPerLeg: oppositeRiskIndicators.baseSpreadPerLeg,
totalCollateralPayFixed: balance.totalCollateralPayFixed,
totalCollateralReceiveFixed: balance.totalCollateralReceiveFixed,
liquidityPoolBalance: liquidityPoolBalance,
iporIndexValue: unwindParams.indexValue,
fixedRateCapPerLeg: oppositeRiskIndicators.fixedRateCapPerLeg,
tenor: unwindParams.swap.tenor
})
)
)
);
}
/// @notice Calculate swap unwind when unwind is required.
/// @param unwindParams unwind parameters required to calculate swap unwind pnl value.
/// @return swapUnwindPnlValue swap unwind PnL value
/// @return swapUnwindFeeAmount swap unwind opening fee amount, sum of swapUnwindFeeLPAmount and swapUnwindFeeTreasuryAmount
/// @return swapUnwindFeeLPAmount swap unwind opening fee LP amount
/// @return swapUnwindFeeTreasuryAmount swap unwind opening fee treasury amount
/// @return swapPnlValue swap PnL value includes swap PnL to date, swap unwind PnL value, this value NOT INCLUDE swap unwind fee amount.
function calculateSwapUnwindWhenUnwindRequired(
AmmTypesBaseV1.UnwindParams memory unwindParams
)
internal
view
returns (
int256 swapUnwindPnlValue,
uint256 swapUnwindFeeAmount,
uint256 swapUnwindFeeLPAmount,
uint256 swapUnwindFeeTreasuryAmount,
int256 swapPnlValue
)
{
AmmTypes.OpenSwapRiskIndicators memory oppositeRiskIndicators;
if (unwindParams.swap.direction == AmmTypes.SwapDirection.PAY_FIXED_RECEIVE_FLOATING) {
oppositeRiskIndicators = unwindParams.riskIndicatorsInputs.receiveFixed.verify(
unwindParams.asset,
uint256(unwindParams.swap.tenor),
uint256(AmmTypes.SwapDirection.PAY_FLOATING_RECEIVE_FIXED),
unwindParams.messageSigner
);
/// @dev Not allow to have swap unwind pnl absolute value larger than swap collateral.
swapUnwindPnlValue = calculateSwapUnwindPnlValueNormalized(
unwindParams,
AmmTypes.SwapDirection.PAY_FLOATING_RECEIVE_FIXED,
oppositeRiskIndicators
);
} else if (unwindParams.swap.direction == AmmTypes.SwapDirection.PAY_FLOATING_RECEIVE_FIXED) {
oppositeRiskIndicators = unwindParams.riskIndicatorsInputs.payFixed.verify(
unwindParams.asset,
uint256(unwindParams.swap.tenor),
uint256(AmmTypes.SwapDirection.PAY_FIXED_RECEIVE_FLOATING),
unwindParams.messageSigner
);
/// @dev Not allow to have swap unwind pnl absolute value larger than swap collateral.
swapUnwindPnlValue = calculateSwapUnwindPnlValueNormalized(
unwindParams,
AmmTypes.SwapDirection.PAY_FIXED_RECEIVE_FLOATING,
oppositeRiskIndicators
);
} else {
revert(AmmErrors.UNSUPPORTED_DIRECTION);
}
swapPnlValue = SwapLogicBaseV1.normalizePnlValue(
unwindParams.swap.collateral,
unwindParams.swapPnlValueToDate + swapUnwindPnlValue
);
/// @dev swap unwind fee amount is independent of the swap unwind pnl value, takes into consideration notional.
swapUnwindFeeAmount = calculateSwapUnwindOpeningFeeAmount(
unwindParams.swap,
unwindParams.closeTimestamp,
unwindParams.unwindingFeeRate
);
require(
unwindParams.swap.collateral.toInt256() + swapPnlValue > swapUnwindFeeAmount.toInt256(),
AmmErrors.COLLATERAL_IS_NOT_SUFFICIENT_TO_COVER_UNWIND_SWAP
);
(swapUnwindFeeLPAmount, swapUnwindFeeTreasuryAmount) = SwapLogicBaseV1.splitOpeningFeeAmount(
swapUnwindFeeAmount,
unwindParams.unwindingFeeTreasuryPortionRate
);
}
function getClosableStatusForSwap(
AmmTypesBaseV1.ClosableSwapInput memory closableSwapInput
) internal view returns (AmmTypes.SwapClosableStatus, bool) {
if (closableSwapInput.swapState != IporTypes.SwapState.ACTIVE) {
return (AmmTypes.SwapClosableStatus.SWAP_ALREADY_CLOSED, false);
}
if (closableSwapInput.account != OwnerManager.getOwner()) {
uint256 absPnlValue = IporMath.absoluteValue(closableSwapInput.swapPnlValueToDate);
uint256 minPnlValueToCloseBeforeMaturityByCommunity = IporMath.percentOf(
closableSwapInput.swapCollateral,
closableSwapInput.minLiquidationThresholdToCloseBeforeMaturityByCommunity
);
uint256 swapEndTimestamp = getSwapEndTimestamp(
closableSwapInput.swapOpenTimestamp,
closableSwapInput.swapTenor
);
if (closableSwapInput.closeTimestamp >= swapEndTimestamp) {
if (
absPnlValue < minPnlValueToCloseBeforeMaturityByCommunity ||
absPnlValue == closableSwapInput.swapCollateral
) {
if (
AmmConfigurationManager.isSwapLiquidator(closableSwapInput.asset, closableSwapInput.account) !=
true &&
closableSwapInput.account != closableSwapInput.swapBuyer
) {
return (AmmTypes.SwapClosableStatus.SWAP_REQUIRED_BUYER_OR_LIQUIDATOR_TO_CLOSE, false);
}
}
} else {
uint256 minPnlValueToCloseBeforeMaturityByBuyer = IporMath.percentOf(
closableSwapInput.swapCollateral,
closableSwapInput.minLiquidationThresholdToCloseBeforeMaturityByBuyer
);
if (
(absPnlValue >= minPnlValueToCloseBeforeMaturityByBuyer &&
absPnlValue < minPnlValueToCloseBeforeMaturityByCommunity) ||
absPnlValue == closableSwapInput.swapCollateral
) {
if (
AmmConfigurationManager.isSwapLiquidator(closableSwapInput.asset, closableSwapInput.account) !=
true &&
closableSwapInput.account != closableSwapInput.swapBuyer
) {
return (AmmTypes.SwapClosableStatus.SWAP_REQUIRED_BUYER_OR_LIQUIDATOR_TO_CLOSE, false);
}
}
if (absPnlValue < minPnlValueToCloseBeforeMaturityByBuyer) {
if (closableSwapInput.account == closableSwapInput.swapBuyer) {
if (
swapEndTimestamp - closableSwapInput.timeBeforeMaturityAllowedToCloseSwapByBuyer >
closableSwapInput.closeTimestamp
) {
if (
block.timestamp - closableSwapInput.swapOpenTimestamp <=
closableSwapInput.timeAfterOpenAllowedToCloseSwapWithUnwinding
) {
return (
AmmTypes.SwapClosableStatus.SWAP_CANNOT_CLOSE_WITH_UNWIND_ACTION_IS_TOO_EARLY,
true
);
}
return (AmmTypes.SwapClosableStatus.SWAP_IS_CLOSABLE, true);
}
} else {
if (
swapEndTimestamp - closableSwapInput.timeBeforeMaturityAllowedToCloseSwapByCommunity >
closableSwapInput.closeTimestamp
) {
return (
AmmTypes.SwapClosableStatus.SWAP_CANNOT_CLOSE_CLOSING_TOO_EARLY_FOR_COMMUNITY,
false
);
}
}
}
}
}
return (AmmTypes.SwapClosableStatus.SWAP_IS_CLOSABLE, false);
}
/// @notice Calculates the swap unwind PnL value.
/// @param swap Swap structure
/// @param closingTimestamp moment when user/account/client wants to close the swap, represented in seconds without 18 decimals
/// for particular swap at time when swap will be closed by the trader.
/// @dev Equation for this calculation is:
/// time - number of seconds left to swap until maturity divided by number of seconds in year
/// Opposite Leg Fixed Rate - calculated fixed rate of opposite leg used for the virtual swap
/// @dev If Swap is Pay Fixed Receive Floating then UnwindValue = Current Swap PnL + Notional * (e^(Opposite Leg Fixed Rate * time) - e^(Swap Fixed Rate * time))
/// @dev If Swap is Receive Fixed Pay Floating then UnwindValue = Current Swap PnL + Notional * (e^(Swap Fixed Rate * time) - e^(Opposite Leg Fixed Rate * time))
function calculateSwapUnwindPnlValue(
AmmTypesBaseV1.Swap memory swap,
uint256 closingTimestamp,
uint256 oppositeLegFixedRate
) internal pure returns (int256 swapUnwindPnlValue) {
uint256 endTimestamp = getSwapEndTimestamp(swap.openTimestamp, swap.tenor);
require(closingTimestamp <= endTimestamp, AmmErrors.CANNOT_UNWIND_CLOSING_TOO_LATE);
uint256 time = endTimestamp - closingTimestamp;
if (swap.direction == AmmTypes.SwapDirection.PAY_FIXED_RECEIVE_FLOATING) {
swapUnwindPnlValue =
swap.notional.toInt256().calculateContinuousCompoundInterestUsingRatePeriodMultiplicationInt(
(oppositeLegFixedRate * time).toInt256()
) -
swap.notional.toInt256().calculateContinuousCompoundInterestUsingRatePeriodMultiplicationInt(
(swap.fixedInterestRate * time).toInt256()
);
} else if (swap.direction == AmmTypes.SwapDirection.PAY_FLOATING_RECEIVE_FIXED) {
swapUnwindPnlValue =
swap.notional.toInt256().calculateContinuousCompoundInterestUsingRatePeriodMultiplicationInt(
(swap.fixedInterestRate * time).toInt256()
) -
swap.notional.toInt256().calculateContinuousCompoundInterestUsingRatePeriodMultiplicationInt(
(oppositeLegFixedRate * time).toInt256()
);
} else {
revert(AmmErrors.UNSUPPORTED_DIRECTION);
}
}
/// @notice Calculates the swap unwind opening fee amount for a given swap, closing timestamp and IBT price from IporOracle.
/// @param swapOpenTimestamp moment when swap is opened, represented in seconds without 18 decimals
/// @param swapNotional swap notional, represented in 18 decimals
/// @param swapTenor swap tenor
/// @param closingTimestamp moment when swap is closed, represented in seconds without 18 decimals
/// @param openingFeeRateCfg opening fee rate taken from Protocol configuration, represented in 18 decimals
/// @return swapOpeningFeeAmount swap opening fee amount, represented in 18 decimals
function calculateSwapUnwindOpeningFeeAmount(
uint256 swapOpenTimestamp,
uint256 swapNotional,
IporTypes.SwapTenor swapTenor,
uint256 closingTimestamp,
uint256 openingFeeRateCfg
) internal pure returns (uint256 swapOpeningFeeAmount) {
require(closingTimestamp >= swapOpenTimestamp, AmmErrors.CLOSING_TIMESTAMP_LOWER_THAN_SWAP_OPEN_TIMESTAMP);
/// @dev 1e36 = 1e18 * 1e18, To achieve result in 18 decimals when there is multiplication of 3 numbers in 18 decimals, we need to divide by 1e36.
swapOpeningFeeAmount = IporMath.division(
swapNotional *
openingFeeRateCfg *
IporMath.division(
(getSwapEndTimestamp(swapOpenTimestamp, swapTenor) - closingTimestamp) * 1e18,
365 days
),
1e36
);
}
/// @notice Calculates the swap unwind opening fee amount for a given swap, closing timestamp and IBT price from IporOracle.
/// @param swap Swap structure
/// @param closingTimestamp moment when swap is closed, represented in seconds without 18 decimals
/// @param openingFeeRateCfg opening fee rate taken from Protocol configuration, represented in 18 decimals
/// @return swapOpeningFeeAmount swap opening fee amount, represented in 18 decimals
function calculateSwapUnwindOpeningFeeAmount(
AmmTypesBaseV1.Swap memory swap,
uint256 closingTimestamp,
uint256 openingFeeRateCfg
) internal pure returns (uint256 swapOpeningFeeAmount) {
require(closingTimestamp >= swap.openTimestamp, AmmErrors.CLOSING_TIMESTAMP_LOWER_THAN_SWAP_OPEN_TIMESTAMP);
/// @dev 1e36 = 1e18 * 1e18, To achieve result in 18 decimals when there is multiplication of 3 numbers in 18 decimals, we need to divide by 1e36.
swapOpeningFeeAmount = IporMath.division(
swap.notional *
openingFeeRateCfg *
IporMath.division(
(getSwapEndTimestamp(swap.openTimestamp, swap.tenor) - closingTimestamp) * 1e18,
365 days
),
1e36
);
}
/// @notice Gets swap end timestamp based on swap tenor
/// @return swap end timestamp in seconds without 18 decimals
function getSwapEndTimestamp(uint256 openTimestamp, IporTypes.SwapTenor tenor) internal pure returns (uint256) {
if (tenor == IporTypes.SwapTenor.DAYS_28) {
return openTimestamp + 28 days;
} else if (tenor == IporTypes.SwapTenor.DAYS_60) {
return openTimestamp + 60 days;
} else if (tenor == IporTypes.SwapTenor.DAYS_90) {
return openTimestamp + 90 days;
} else {
revert(AmmErrors.UNSUPPORTED_SWAP_TENOR);
}
}
function validateAllowanceToCloseSwap(AmmTypes.SwapClosableStatus closableStatus) internal pure {
if (closableStatus == AmmTypes.SwapClosableStatus.SWAP_ALREADY_CLOSED) {
revert(AmmErrors.INCORRECT_SWAP_STATUS);
}
if (closableStatus == AmmTypes.SwapClosableStatus.SWAP_REQUIRED_BUYER_OR_LIQUIDATOR_TO_CLOSE) {
revert(AmmErrors.CANNOT_CLOSE_SWAP_SENDER_IS_NOT_BUYER_NOR_LIQUIDATOR);
}
if (closableStatus == AmmTypes.SwapClosableStatus.SWAP_CANNOT_CLOSE_CLOSING_TOO_EARLY_FOR_COMMUNITY) {
revert(AmmErrors.CANNOT_CLOSE_SWAP_CLOSING_IS_TOO_EARLY);
}
if (closableStatus == AmmTypes.SwapClosableStatus.SWAP_CANNOT_CLOSE_WITH_UNWIND_ACTION_IS_TOO_EARLY) {
revert(AmmErrors.CANNOT_CLOSE_SWAP_WITH_UNWIND_ACTION_IS_TOO_EARLY);
}
}
}
library AmmSwapsLensLibBaseV1 {
using RiskIndicatorsValidatorLib for AmmTypes.RiskIndicatorsInputs;
function getBalancesForOpenSwap(
address ammStorage,
address ammTreasury
) internal view returns (IporTypes.AmmBalancesForOpenSwapMemory memory) {
AmmTypesBaseV1.AmmBalanceForOpenSwap memory balance = IAmmStorageBaseV1(ammStorage).getBalancesForOpenSwap();
return
IporTypes.AmmBalancesForOpenSwapMemory({
totalCollateralPayFixed: balance.totalCollateralPayFixed,
totalNotionalPayFixed: balance.totalNotionalPayFixed,
totalCollateralReceiveFixed: balance.totalCollateralReceiveFixed,
totalNotionalReceiveFixed: balance.totalNotionalReceiveFixed,
liquidityPool: IAmmTreasuryBaseV1(ammTreasury).getLiquidityPoolBalance()
});
}
function getOfferedRate(
IAmmSwapsLens.SwapLensPoolConfiguration memory poolCfg,
uint256 indexValue,
IporTypes.SwapTenor tenor,
uint256 swapNotional,
address messageSigner,
AmmTypes.OpenSwapRiskIndicators memory swapRiskIndicatorsPayFixed,
AmmTypes.OpenSwapRiskIndicators memory swapRiskIndicatorsReceiveFixed
) internal view returns (uint256 offeredRatePayFixed, uint256 offeredRateReceiveFixed) {
AmmTypesBaseV1.AmmBalanceForOpenSwap memory balance = IAmmStorageBaseV1(poolCfg.ammStorage)
.getBalancesForOpenSwap();
uint256 liquidityPoolBalance = IAmmTreasuryBaseV1(poolCfg.ammTreasury).getLiquidityPoolBalance();
offeredRatePayFixed = ISpreadBaseV1(poolCfg.spread).calculateOfferedRatePayFixed(
ISpreadBaseV1.SpreadInputs({
asset: poolCfg.asset,
swapNotional: swapNotional,
demandSpreadFactor: swapRiskIndicatorsPayFixed.demandSpreadFactor,
baseSpreadPerLeg: swapRiskIndicatorsPayFixed.baseSpreadPerLeg,
totalCollateralPayFixed: balance.totalCollateralPayFixed,
totalCollateralReceiveFixed: balance.totalCollateralReceiveFixed,
liquidityPoolBalance: liquidityPoolBalance,
iporIndexValue: indexValue,
fixedRateCapPerLeg: swapRiskIndicatorsPayFixed.fixedRateCapPerLeg,
tenor: tenor
})
);
offeredRateReceiveFixed = ISpreadBaseV1(poolCfg.spread).calculateOfferedRateReceiveFixed(
ISpreadBaseV1.SpreadInputs({
asset: poolCfg.asset,
swapNotional: swapNotional,
demandSpreadFactor: swapRiskIndicatorsReceiveFixed.demandSpreadFactor,
baseSpreadPerLeg: swapRiskIndicatorsReceiveFixed.baseSpreadPerLeg,
totalCollateralPayFixed: balance.totalCollateralPayFixed,
totalCollateralReceiveFixed: balance.totalCollateralReceiveFixed,
liquidityPoolBalance: liquidityPoolBalance,
iporIndexValue: indexValue,
fixedRateCapPerLeg: swapRiskIndicatorsReceiveFixed.fixedRateCapPerLeg,
tenor: tenor
})
);
}
function getSwaps(
address iporOracle,
address ammStorage,
address asset,
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, IAmmSwapsLens.IporSwap[] memory swaps) {
IAmmStorageBaseV1 ammStorageBaseV1 = IAmmStorageBaseV1(ammStorage);
(uint256 count, AmmStorageTypes.IporSwapId[] memory swapIds) = ammStorageBaseV1.getSwapIds(
account,
offset,
chunkSize
);
return (count, _mapSwaps(iporOracle, asset, ammStorageBaseV1, swapIds));
}
function getPnlPayFixed(
address iporOracle,
address ammStorage,
address asset,
uint256 swapId
) internal view returns (int256) {
uint256 accruedIbtPrice = IIporOracle(iporOracle).calculateAccruedIbtPrice(asset, block.timestamp);
AmmTypesBaseV1.Swap memory swapBaseV1 = IAmmStorageBaseV1(ammStorage).getSwap(
AmmTypes.SwapDirection.PAY_FIXED_RECEIVE_FLOATING,
swapId
);
require(swapBaseV1.id > 0, AmmErrors.INCORRECT_SWAP_ID);
return
SwapLogicBaseV1.calculatePnlPayFixed(
swapBaseV1.openTimestamp,
swapBaseV1.collateral,
swapBaseV1.notional,
swapBaseV1.fixedInterestRate,
swapBaseV1.ibtQuantity,
block.timestamp,
accruedIbtPrice
);
}
function getPnlReceiveFixed(
address iporOracle,
address ammStorage,
address asset,
uint256 swapId
) internal view returns (int256) {
uint256 accruedIbtPrice = IIporOracle(iporOracle).calculateAccruedIbtPrice(asset, block.timestamp);
AmmTypesBaseV1.Swap memory swapBaseV1 = IAmmStorageBaseV1(ammStorage).getSwap(
AmmTypes.SwapDirection.PAY_FLOATING_RECEIVE_FIXED,
swapId
);
require(swapBaseV1.id > 0, AmmErrors.INCORRECT_SWAP_ID);
return
SwapLogicBaseV1.calculatePnlReceiveFixed(
swapBaseV1.openTimestamp,
swapBaseV1.collateral,
swapBaseV1.notional,
swapBaseV1.fixedInterestRate,
swapBaseV1.ibtQuantity,
block.timestamp,
accruedIbtPrice
);
}
function _mapSwaps(
address iporOracle,
address asset,
IAmmStorageBaseV1 ammStorage,
AmmStorageTypes.IporSwapId[] memory swapIds
) private view returns (IAmmSwapsLens.IporSwap[] memory swaps) {
uint256 accruedIbtPrice = IIporOracle(iporOracle).calculateAccruedIbtPrice(asset, block.timestamp);
uint256 swapCount = swapIds.length;
IAmmSwapsLens.IporSwap[] memory mappedSwaps = new IAmmSwapsLens.IporSwap[](swapCount);
AmmStorageTypes.IporSwapId memory swapId;
AmmTypesBaseV1.Swap memory swap;
int256 swapValue;
for (uint256 i; i != swapCount; ) {
swapId = swapIds[i];
if (swapId.direction == 0) {
swap = ammStorage.getSwap(AmmTypes.SwapDirection.PAY_FIXED_RECEIVE_FLOATING, swapId.id);
swapValue = SwapLogicBaseV1.calculatePnlPayFixed(
swap.openTimestamp,
swap.collateral,
swap.notional,
swap.fixedInterestRate,
swap.ibtQuantity,
block.timestamp,
accruedIbtPrice
);
mappedSwaps[i] = _mapSwap(asset, swap, swapValue);
} else {
swap = ammStorage.getSwap(AmmTypes.SwapDirection.PAY_FLOATING_RECEIVE_FIXED, swapId.id);
swapValue = SwapLogicBaseV1.calculatePnlReceiveFixed(
swap.openTimestamp,
swap.collateral,
swap.notional,
swap.fixedInterestRate,
swap.ibtQuantity,
block.timestamp,
accruedIbtPrice
);
mappedSwaps[i] = _mapSwap(asset, swap, swapValue);
}
unchecked {
++i;
}
}
return mappedSwaps;
}
function _mapSwap(
address asset,
AmmTypesBaseV1.Swap memory swap,
int256 pnlValue
) private pure returns (IAmmSwapsLens.IporSwap memory) {
return
IAmmSwapsLens.IporSwap({
id: swap.id,
asset: asset,
buyer: swap.buyer,
collateral: swap.collateral,
notional: swap.notional,
leverage: IporMath.division(swap.notional * 1e18, swap.collateral),
direction: uint256(swap.direction),
ibtQuantity: swap.ibtQuantity,
fixedInterestRate: swap.fixedInterestRate,
pnlValue: pnlValue,
openTimestamp: swap.openTimestamp,
endTimestamp: SwapCloseLogicLibBaseV1.getSwapEndTimestamp(swap.openTimestamp, swap.tenor),
liquidationDepositAmount: swap.wadLiquidationDepositAmount,
state: uint256(swap.state)
});
}
}
/// @dev It is not recommended to use lens contract directly, should be used only through IporProtocolRouter.
contract AmmSwapsLensArbitrum is IAmmSwapsLens {
using Address for address;
using IporContractValidator for address;
using AmmLib for AmmTypes.AmmPoolCoreModel;
using RiskIndicatorsValidatorLib for AmmTypes.RiskIndicatorsInputs;
address internal immutable _wstEthAsset;
address internal immutable _wstEthAmmStorage;
address internal immutable _wstEthAmmTreasury;
address internal immutable _wstEthSpread;
address public immutable iporOracle;
address public immutable messageSigner;
constructor(SwapLensPoolConfiguration memory wstEthCfg, address iporOracleInput, address messageSignerInput) {
_wstEthAsset = wstEthCfg.asset.checkAddress();
_wstEthAmmStorage = wstEthCfg.ammStorage.checkAddress();
_wstEthAmmTreasury = wstEthCfg.ammTreasury.checkAddress();
_wstEthSpread = wstEthCfg.spread.checkAddress();
iporOracle = iporOracleInput.checkAddress();
messageSigner = messageSignerInput.checkAddress();
}
function getSwapLensPoolConfiguration(
address asset
) external view override returns (SwapLensPoolConfiguration memory) {
return _getSwapLensPoolConfiguration(asset);
}
function getSwaps(
address asset,
address account,
uint256 offset,
uint256 chunkSize
) external view returns (uint256 totalCount, IAmmSwapsLens.IporSwap[] memory swaps) {
return AmmSwapsLensLibBaseV1.getSwaps(iporOracle, _wstEthAmmStorage, asset, account, offset, chunkSize);
}
function getPnlPayFixed(address asset, uint256 swapId) external view override returns (int256) {
return AmmSwapsLensLibBaseV1.getPnlPayFixed(iporOracle, _wstEthAmmStorage, _wstEthAsset, swapId);
}
function getPnlReceiveFixed(address asset, uint256 swapId) external view override returns (int256) {
return AmmSwapsLensLibBaseV1.getPnlReceiveFixed(iporOracle, _wstEthAmmStorage, _wstEthAsset, swapId);
}
function getSoap(
address asset
) external view override returns (int256 soapPayFixed, int256 soapReceiveFixed, int256 soap) {
AmmTypes.AmmPoolCoreModel memory ammCoreModel;
ammCoreModel.asset = asset;
ammCoreModel.ammStorage = _wstEthAmmStorage;
ammCoreModel.iporOracle = iporOracle;
(soapPayFixed, soapReceiveFixed, soap) = ammCoreModel.getSoap();
}
function getOfferedRate(
address asset,
IporTypes.SwapTenor tenor,
uint256 notional,
AmmTypes.RiskIndicatorsInputs calldata payFixedRiskIndicatorsInputs,
AmmTypes.RiskIndicatorsInputs calldata receiveFixedRiskIndicatorsInputs
) external view override returns (uint256 offeredRatePayFixed, uint256 offeredRateReceiveFixed) {
require(notional > 0, AmmErrors.INVALID_NOTIONAL);
SwapLensPoolConfiguration memory poolCfg = _getSwapLensPoolConfiguration(asset);
(uint256 indexValue, , ) = IIporOracle(iporOracle).getIndex(asset);
AmmTypes.OpenSwapRiskIndicators memory swapRiskIndicatorsPayFixed = payFixedRiskIndicatorsInputs.verify(
asset,
uint256(tenor),
uint256(AmmTypes.SwapDirection.PAY_FIXED_RECEIVE_FLOATING),
messageSigner
);
AmmTypes.OpenSwapRiskIndicators memory swapRiskIndicatorsReceiveFixed = receiveFixedRiskIndicatorsInputs.verify(
asset,
uint256(tenor),
uint256(AmmTypes.SwapDirection.PAY_FLOATING_RECEIVE_FIXED),
messageSigner
);
(offeredRatePayFixed, offeredRateReceiveFixed) = AmmSwapsLensLibBaseV1.getOfferedRate(
poolCfg,
indexValue,
tenor,
notional,
messageSigner,
swapRiskIndicatorsPayFixed,
swapRiskIndicatorsReceiveFixed
);
}
function getBalancesForOpenSwap(address) external view returns (IporTypes.AmmBalancesForOpenSwapMemory memory) {
return AmmSwapsLensLibBaseV1.getBalancesForOpenSwap(_wstEthAmmStorage, _wstEthAmmTreasury);
}
function _getSwapLensPoolConfiguration(address asset) internal view returns (SwapLensPoolConfiguration memory) {
if (asset == _wstEthAsset) {
return
SwapLensPoolConfiguration({
asset: _wstEthAsset,
ammStorage: _wstEthAmmStorage,
ammTreasury: _wstEthAmmTreasury,
spread: _wstEthSpread
});
} else {
revert(IporErrors.ASSET_NOT_SUPPORTED);
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"ammStorage","type":"address"},{"internalType":"address","name":"ammTreasury","type":"address"},{"internalType":"address","name":"spread","type":"address"}],"internalType":"struct IAmmSwapsLens.SwapLensPoolConfiguration","name":"wstEthCfg","type":"tuple"},{"internalType":"address","name":"iporOracleInput","type":"address"},{"internalType":"address","name":"messageSignerInput","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getBalancesForOpenSwap","outputs":[{"components":[{"internalType":"uint256","name":"totalCollateralPayFixed","type":"uint256"},{"internalType":"uint256","name":"totalNotionalPayFixed","type":"uint256"},{"internalType":"uint256","name":"totalCollateralReceiveFixed","type":"uint256"},{"internalType":"uint256","name":"totalNotionalReceiveFixed","type":"uint256"},{"internalType":"uint256","name":"liquidityPool","type":"uint256"}],"internalType":"struct IporTypes.AmmBalancesForOpenSwapMemory","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"enum IporTypes.SwapTenor","name":"tenor","type":"uint8"},{"internalType":"uint256","name":"notional","type":"uint256"},{"components":[{"internalType":"uint256","name":"maxCollateralRatio","type":"uint256"},{"internalType":"uint256","name":"maxCollateralRatioPerLeg","type":"uint256"},{"internalType":"uint256","name":"maxLeveragePerLeg","type":"uint256"},{"internalType":"int256","name":"baseSpreadPerLeg","type":"int256"},{"internalType":"uint256","name":"fixedRateCapPerLeg","type":"uint256"},{"internalType":"uint256","name":"demandSpreadFactor","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct AmmTypes.RiskIndicatorsInputs","name":"payFixedRiskIndicatorsInputs","type":"tuple"},{"components":[{"internalType":"uint256","name":"maxCollateralRatio","type":"uint256"},{"internalType":"uint256","name":"maxCollateralRatioPerLeg","type":"uint256"},{"internalType":"uint256","name":"maxLeveragePerLeg","type":"uint256"},{"internalType":"int256","name":"baseSpreadPerLeg","type":"int256"},{"internalType":"uint256","name":"fixedRateCapPerLeg","type":"uint256"},{"internalType":"uint256","name":"demandSpreadFactor","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct AmmTypes.RiskIndicatorsInputs","name":"receiveFixedRiskIndicatorsInputs","type":"tuple"}],"name":"getOfferedRate","outputs":[{"internalType":"uint256","name":"offeredRatePayFixed","type":"uint256"},{"internalType":"uint256","name":"offeredRateReceiveFixed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"swapId","type":"uint256"}],"name":"getPnlPayFixed","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"swapId","type":"uint256"}],"name":"getPnlReceiveFixed","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getSoap","outputs":[{"internalType":"int256","name":"soapPayFixed","type":"int256"},{"internalType":"int256","name":"soapReceiveFixed","type":"int256"},{"internalType":"int256","name":"soap","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getSwapLensPoolConfiguration","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"ammStorage","type":"address"},{"internalType":"address","name":"ammTreasury","type":"address"},{"internalType":"address","name":"spread","type":"address"}],"internalType":"struct IAmmSwapsLens.SwapLensPoolConfiguration","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"chunkSize","type":"uint256"}],"name":"getSwaps","outputs":[{"internalType":"uint256","name":"totalCount","type":"uint256"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"buyer","type":"address"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"notional","type":"uint256"},{"internalType":"uint256","name":"leverage","type":"uint256"},{"internalType":"uint256","name":"direction","type":"uint256"},{"internalType":"uint256","name":"ibtQuantity","type":"uint256"},{"internalType":"uint256","name":"fixedInterestRate","type":"uint256"},{"internalType":"int256","name":"pnlValue","type":"int256"},{"internalType":"uint256","name":"openTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"liquidationDepositAmount","type":"uint256"},{"internalType":"uint256","name":"state","type":"uint256"}],"internalType":"struct IAmmSwapsLens.IporSwap[]","name":"swaps","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"iporOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101406040523480156200001257600080fd5b50604051620043f3380380620043f383398101604081905262000035916200016f565b82516200004b906001600160a01b0316620000f6565b6001600160a01b0390811660805260208401516200006a9116620000f6565b6001600160a01b0390811660a0526040840151620000899116620000f6565b6001600160a01b0390811660c0526060840151620000a89116620000f6565b6001600160a01b0390811660e052620000c3908316620000f6565b6001600160a01b0390811661010052620000df908216620000f6565b6001600160a01b0316610120525062000289915050565b604080518082019091526008815267049504f525f3030360c41b60208201526000906001600160a01b0383166200014b5760405162461bcd60e51b815260040162000142919062000239565b60405180910390fd5b5090919050565b80516001600160a01b03811681146200016a57600080fd5b919050565b600080600083850360c08112156200018657600080fd5b60808112156200019557600080fd5b50604051608081016001600160401b0381118282101715620001c757634e487b7160e01b600052604160045260246000fd5b604052620001d58562000152565b8152620001e56020860162000152565b6020820152620001f86040860162000152565b60408201526200020b6060860162000152565b60608201529250620002206080850162000152565b91506200023060a0850162000152565b90509250925092565b600060208083528351808285015260005b8181101562000268578581018301518582016040015282016200024a565b506000604082860101526040601f19601f8301168501019250505092915050565b60805160a05160c05160e05161010051610120516140ab620003486000396000818160da015281816103a3015261040001526000818161018f0152818161031701528181610468015281816105d4015281816106cd0152610714015260006108720152600081816105a3015261084301526000818161049001528181610582015281816105f5015281816106a501528181610735015261081401526000818161061601528181610756015281816107a101526107e501526140ab6000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80637761022f1161007657806399fcfbfc1161005b57806399fcfbfc146101d2578063c34605c914610228578063d83eb8ba1461025657600080fd5b80637761022f1461018a5780637eea00a8146101b157600080fd5b8063046df835146100a8578063080387b4146100d55780631188de6214610114578063635411b014610135575b600080fd5b6100bb6100b6366004613717565b610269565b604080519283526020830191909152015b60405180910390f35b6100fc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100cc565b6101276101223660046137aa565b610438565b6040516100cc9291906137f0565b6101486101433660046138d4565b61054b565b6040516100cc9190600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b6100fc7f000000000000000000000000000000000000000000000000000000000000000081565b6101c46101bf3660046138f1565b6105cd565b6040519081526020016100cc565b6101e56101e03660046138d4565b610642565b6040516100cc919081516001600160a01b039081168252602080840151821690830152604080840151821690830152606092830151169181019190915260800190565b61023b6102363660046138d4565b61066f565b604080519384526020840192909252908201526060016100cc565b6101c46102643660046138f1565b61070d565b600080600085116040518060400160405280600881526020017f49504f525f333335000000000000000000000000000000000000000000000000815250906102cd5760405162461bcd60e51b81526004016102c4919061391d565b60405180910390fd5b5060006102d98861077b565b6040517fb31610db0000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063b31610db90602401606060405180830381865afa15801561035e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610382919061396b565b5050905060006103d48a8a600281111561039e5761039e613999565b60005b7f00000000000000000000000000000000000000000000000000000000000000006103cb8c613ad8565b939291906108f4565b905060006103f58b8b60028111156103ee576103ee613999565b60016103a1565b905061042684848c8c7f00000000000000000000000000000000000000000000000000000000000000008787610a6a565b909c909b509950505050505050505050565b6040517f6be212480000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f0000000000000000000000000000000000000000000000000000000000000000811660248301528086166044830152841660648201526084810183905260a4810182905260009060609073aab8f1f70ac5d10804f459ca04159eb61d6646f790636be212489060c401600060405180830381865af4158015610515573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261053d9190810190613b70565b915091505b94509492505050565b61057d6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6105c77f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000610d23565b92915050565b600061063b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000085610e5a565b9392505050565b6040805160808101825260008082526020820181905291810182905260608101919091526105c78261077b565b6040805160e0810182526000602082018190529181018290526080810182905260a081018290526001600160a01b0383811682527f0000000000000000000000000000000000000000000000000000000000000000811660608301527f00000000000000000000000000000000000000000000000000000000000000001660c0820152819081906106ff81610fb6565b919790965090945092505050565b600061063b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000856110dc565b6040805160808101825260008082526020820181905291810182905260608101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036108a45760405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152509050919050565b604080518082018252600881527f49504f525f3031370000000000000000000000000000000000000000000000006020820152905162461bcd60e51b81526102c4919060040161391d565b919050565b61092d6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b600061093b8787878761122d565b9050826001600160a01b031661095e8860e00151836112dc90919063ffffffff16565b6001600160a01b0316146040518060400160405280600881526020017f49504f525f303230000000000000000000000000000000000000000000000000815250906109bc5760405162461bcd60e51b81526004016102c4919061391d565b50428760c00151116040518060400160405280600881526020017f49504f525f30313900000000000000000000000000000000000000000000000081525090610a185760405162461bcd60e51b81526004016102c4919061391d565b506040518060c0016040528088600001518152602001886020015181526020018860400151815260200188606001518152602001886080015181526020018860a0015181525091505095945050505050565b600080600089602001516001600160a01b0316636c2c986e6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610ab1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad59190613cd3565b905060008a604001516001600160a01b0316634fcf9f716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3f9190613d39565b90508a606001516001600160a01b031663259f0bf86040518061014001604052808e600001516001600160a01b031681526020018b81526020018960a0015181526020018960600151815260200185600001518152602001856040015181526020018481526020018d8152602001896080015181526020018c6002811115610bc957610bc9613999565b8152506040518263ffffffff1660e01b8152600401610be89190613d66565b602060405180830381865afa158015610c05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c299190613d39565b93508a606001516001600160a01b03166376ee4c846040518061014001604052808e600001516001600160a01b031681526020018b81526020018860a0015181526020018860600151815260200185600001518152602001856040015181526020018481526020018d8152602001886080015181526020018c6002811115610cb357610cb3613999565b8152506040518263ffffffff1660e01b8152600401610cd29190613d66565b602060405180830381865afa158015610cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d139190613d39565b9250505097509795505050505050565b610d556040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6000836001600160a01b0316636c2c986e6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610d95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db99190613cd3565b90506040518060a0016040528082600001518152602001826020015181526020018260400151815260200182606001518152602001846001600160a01b0316634fcf9f716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e509190613d39565b9052949350505050565b604051630e5c712960e01b81526001600160a01b0383811660048301524260248301526000918291871690630e5c712990604401602060405180830381865afa158015610eab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecf9190613d39565b90506000856001600160a01b031663f1a3c63a6000866040518363ffffffff1660e01b8152600401610f02929190613ddd565b61018060405180830381865afa158015610f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f449190613e15565b805160408051808201909152600881526724a827a92f99981b60c11b6020820152919250610f855760405162461bcd60e51b81526004016102c4919061391d565b50610fab81604001518260c001518360e001518461012001518561010001514288611300565b979650505050505050565b60008060008042905060008086606001516001600160a01b031663cab418206040518163ffffffff1660e01b815260040161014060405180830381865afa158015611005573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110299190613f3c565b60c08901518951604051630e5c712960e01b81526001600160a01b03918216600482015260248101889052939550919350600092911690630e5c712990604401602060405180830381865afa158015611086573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110aa9190613d39565b90506110b783858361134a565b96506110c48285836113a3565b95506110d08688613f88565b96989597505050505050565b604051630e5c712960e01b81526001600160a01b0383811660048301524260248301526000918291871690630e5c712990604401602060405180830381865afa15801561112d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111519190613d39565b90506000856001600160a01b031663f1a3c63a6001866040518363ffffffff1660e01b8152600401611184929190613ddd565b61018060405180830381865afa1580156111a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c69190613e15565b805160408051808201909152600881526724a827a92f99981b60c11b60208201529192506112075760405162461bcd60e51b81526004016102c4919061391d565b50610fab81604001518260c001518360e0015184610120015185610100015142886113d7565b8351602080860151604080880151606089015160808a015160a08b015160c08c015194516000986112bc98909796918d918d918d9101998a5260208a01989098526040890196909652606080890195909552608088019390935260a087019190915260c0860152901b6bffffffffffffffffffffffff191660e084015260f48301526101148201526101340190565b604051602081830303815290604052805190602001209050949350505050565b60008060006112eb8585611404565b915091506112f881611449565b509392505050565b60008060006113138a89898989896115b1565b9150915061133c896113248461163a565b61132d8461163a565b6113379190613fa8565b6116d6565b9a9950505050505050505050565b600061136d6113598585611736565b85602001516113689190613fc8565b61163a565b6113916113688487604001516113839190613fdb565b670de0b6b3a764000061176b565b61139b9190613fa8565b949350505050565b60006113bb6113688386604001516113839190613fdb565b6113916113c88686611736565b86602001516113689190613fc8565b60008060006113ea8a89898989896115b1565b9150915061133c896113fb8361163a565b61132d8561163a565b600080825160410361143a5760208301516040840151606085015160001a61142e8782858561178d565b94509450505050611442565b506000905060025b9250929050565b600081600481111561145d5761145d613999565b036114655750565b600181600481111561147957611479613999565b036114c65760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016102c4565b60028160048111156114da576114da613999565b036115275760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016102c4565b600381600481111561153b5761153b613999565b036115ae5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016102c4565b50565b600080878410156040518060400160405280600881526020017f49504f525f3331390000000000000000000000000000000000000000000000008152509061160c5760405162461bcd60e51b81526004016102c4919061391d565b50611621878761161c8b88613ff2565b61184e565b915061162d8584611864565b9050965096945050505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8211156116d25760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e7432353600000000000000000000000000000000000000000000000060648201526084016102c4565b5090565b6000806116e28461163a565b9050600083131561170557808312156116fe57829150506105c7565b90506105c7565b61170e81614005565b8312156117265761171e81614005565b9150506105c7565b829150506105c7565b5092915050565b600061175f828460800151856000015186602001516117559190613fc8565b8660600151611873565b835161063b9190613fc8565b600081611779600282614037565b6117839085613fc8565b61063b9190614037565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156117c45750600090506003610542565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611818573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661184157600060019250925050610542565b9660009650945050505050565b600061139b61185d8385613fdb565b85906118f5565b600061063b6113838385613fdb565b6000838510156040518060400160405280600881526020017f49504f525f333137000000000000000000000000000000000000000000000000815250906118cd5760405162461bcd60e51b81526004016102c4919061391d565b506118ec6118db8587613ff2565b6118e59084613fdb565b8490611953565b95945050505050565b600080611906836301e1338061176b565b9050600061191c85670de0b6b3a764000061196a565b9050600061193283670de0b6b3a764000061196a565b9050600061194883611943846119bb565b6119ef565b9050610fab81611ce1565b60008261196084846118f5565b61063b9190613ff2565b600080611977838561404b565b111561198b57611988600184613fc8565b92505b600061199684611d0e565b905060006119a384611d0e565b905060006119b18383611d75565b9695505050505050565b60006105c76119ea837f3fff71547652b82fe1777d0ffda0d23a000000000000000000000000000000006119ef565b61206d565b6000617fff60f084811c8216919084901c811690829003611aba5780617fff03611a7c576fffffffffffffffffffffffffffffffff1980851690861603611a4157505050600160ff1b811682186105c7565b6fffffffffffffffffffffffffffffffff1985851816600160ff1b03611a6c575050508181176105c7565b5061ffff60ef1b91506105c79050565b6f7fffffffffffffffffffffffffffffff60801b8416600003611aa9575061ffff60ef1b91506105c79050565b505050600160ff1b811682186105c7565b80617fff03611b01576f7fffffffffffffffffffffffffffffff60801b8516600003611af0575061ffff60ef1b91506105c79050565b505050600160ff1b821681186105c7565b6001600160701b03608086901c166000839003611b215760019250611b28565b600160701b175b6001600160701b03608086901c166000839003611b485760019250611b4f565b600160701b175b808202915081600003611b8157600160ff1b87871816611b70576000611b76565b600160ff1b5b9450505050506105c7565b9282019260007c0200000000000000000000000000000000000000000000000000000000831015611be6577c0100000000000000000000000000000000000000000000000000000000831015611bdf57611bda836135a9565b611be9565b60e0611be9565b60e15b90506140708186011015611c04576000945060009250611ca1565b6140e08186011015611c4757614070851015611c2957846140700383901c9250611c3e565b614070851115611c3e57614070850383901b92505b60009450611ca1565b61c0dd8186011115611c6157617fff945060009250611ca1565b6070811115611c78576070810383901c9250611c8b565b6070811015611c8b578060700383901b92505b6001600160701b03831692506140df8186010394505b82607086901b888a186001607f1b60801b1660801c6fffffffffffffffffffffffffffffffff16171760801b955050505050506105c7565b505092915050565b600080611cf5670de0b6b3a7640000611d0e565b90506000611d0384836119ef565b905061139b81613659565b600081600003611d2057506000919050565b816000611d2c826135a9565b90506070811015611d45578060700382901b9150611d58565b6070811115611d58576070810382901c91505b613fff0160701b6001600160701b03919091161760801b92915050565b6000617fff60f084811c8216919084901c811690829003611da95780617fff03611aa9575061ffff60ef1b91506105c79050565b80617fff03611df9577dffffffffffffffffffffffffffff00000000000000000000000000000000841615611de8575061ffff60ef1b91506105c79050565b505050808218600160ff1b166105c7565b6f7fffffffffffffffffffffffffffffff60801b8416600003611e5b576f7fffffffffffffffffffffffffffffff60801b8516600003611e43575061ffff60ef1b91506105c79050565b505050808218600160ff1b16617fff60f01b176105c7565b6001600160701b03608085901c166000829003611e7b5760019150611e82565b600160701b175b6001600160701b03608087901c166000849003611ec5578015611ec0576000611eaa826135a9565b6001955060e20393840160711901939190911b90505b611ecf565b600160701b1760721b5b818181611ede57611ede614021565b04905080600003611efd57600160ff1b87871816611b70576000611b76565b6d1000000000000000000000000000811015611f1b57611f1b61405f565b60006e080000000000000000000000000000821015611f7b576e040000000000000000000000000000821015611f70576e020000000000000000000000000000821015611f69576070611f73565b6071611f73565b60725b60ff16611f84565b611f84826135a9565b905083614071018186011115611fa257617fff945060009150612035565b83818601613ffc011015611fbd576000945060009150612035565b83818601613f8c01101561200a578385613ffc011115611fe8578385613ffc010382901b9150612001565b8385613ffc01101561200157613ffc8585030382901c91505b60009450612035565b607081111561201d576070810382901c91505b6001600160701b038216915083818601613f8d010394505b81607086901b888a186001607f1b60801b1660801c6fffffffffffffffffffffffffffffffff16171760801b955050505050506105c7565b60006001607f1b608083901c90811190617fff60f085901c8116916001600160701b0316908214801561209f57508015155b156120b3575061ffff60ef1b949350505050565b61400d8211156120d857826120cd57617fff60f01b6118ec565b600095945050505050565b613f7f82101561210c57507f3fff000000000000000000000000000000000000000000000000000000000000949350505050565b8160000361211d5760019150612124565b600160701b175b613fef82111561213a57613fee1982011b61214c565b613fef82101561214c57613fef8290031c5b82801561216a575071406e0000000000000000000000000000000081115b1561217a57506000949350505050565b821580156121995750713fffffffffffffffffffffffffffffffffff81115b156121ad5750617fff60f01b949350505050565b6fffffffffffffffffffffffffffffffff81169060801c8380156121d057508115155b156121dc579019906001015b6001607f1b828116156122005770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6f4000000000000000000000000000000083161561222f577001306fe0a31b7152de8d5a46305c85edec0260801c5b6f2000000000000000000000000000000083161561225e577001172b83c7d517adcdf7c8c50eb14a791f0260801c5b6f1000000000000000000000000000000083161561228d5770010b5586cf9890f6298b92b71842a983630260801c5b6f080000000000000000000000000000008316156122bc577001059b0d31585743ae7c548eb68ca417fd0260801c5b6f040000000000000000000000000000008316156122eb57700102c9a3e778060ee6f7caca4f7a29bde80260801c5b6f0200000000000000000000000000000083161561231a5770010163da9fb33356d84a66ae336dcdfa3f0260801c5b6f0100000000000000000000000000000083161561234957700100b1afa5abcbed6129ab13ec11dc95430260801c5b6e8000000000000000000000000000008316156123775770010058c86da1c09ea1ff19d294cf2f679b0260801c5b6e4000000000000000000000000000008316156123a5577001002c605e2e8cec506d21bfc89a23a00f0260801c5b6e2000000000000000000000000000008316156123d357700100162f3904051fa128bca9c55c31e5df0260801c5b6e100000000000000000000000000000831615612401577001000b175effdc76ba38e31671ca9397250260801c5b6e08000000000000000000000000000083161561242f57700100058ba01fb9f96d6cacd4b180917c3d0260801c5b6e04000000000000000000000000000083161561245d5770010002c5cc37da9491d0985c348c68e7b30260801c5b6e02000000000000000000000000000083161561248b577001000162e525ee054754457d59952920260260801c5b600160701b8316156124ae5770010000b17255775c040618bf4a4ade83fc0260801c5b6d80000000000000000000000000008316156124db577001000058b91b5bc9ae2eed81e9b7d4cfab0260801c5b6d400000000000000000000000000083161561250857700100002c5c89d5ec6ca4d7c8acc017b7c90260801c5b6d20000000000000000000000000008316156125355770010000162e43f4f831060e02d839a9d16d0260801c5b6d100000000000000000000000000083161561256257700100000b1721bcfc99d9f890ea069117630260801c5b6d080000000000000000000000000083161561258f5770010000058b90cf1e6d97f9ca14dbcc16280260801c5b6d04000000000000000000000000008316156125bc577001000002c5c863b73f016468f6bac5ca2b0260801c5b6d02000000000000000000000000008316156125e957700100000162e430e5a18f6119e3c02282a50260801c5b6d0100000000000000000000000000831615612616577001000000b1721835514b86e6d96efd1bfe0260801c5b6c8000000000000000000000000083161561264257700100000058b90c0b48c6be5df846c5b2ef0260801c5b6c4000000000000000000000000083161561266e5770010000002c5c8601cc6b9e94213c72737a0260801c5b6c2000000000000000000000000083161561269a577001000000162e42fff037df38aa2b219f060260801c5b6c100000000000000000000000008316156126c65770010000000b17217fba9c739aa5819f44f90260801c5b6c080000000000000000000000008316156126f2577001000000058b90bfcdee5acd3c1cedc8230260801c5b6c0400000000000000000000000083161561271e57700100000002c5c85fe31f35a6a30da1be500260801c5b6c0200000000000000000000000083161561274a5770010000000162e42ff0999ce3541b9fffcf0260801c5b6c0100000000000000000000000083161561277657700100000000b17217f80f4ef5aadda455540260801c5b6b8000000000000000000000008316156127a15770010000000058b90bfbf8479bd5a81b51ad0260801c5b6b4000000000000000000000008316156127cc577001000000002c5c85fdf84bd62ae30a74cc0260801c5b6b2000000000000000000000008316156127f757700100000000162e42fefb2fed257559bdaa0260801c5b6b100000000000000000000000831615612822577001000000000b17217f7d5a7716bba4a9ae0260801c5b6b08000000000000000000000083161561284d57700100000000058b90bfbe9ddbac5e109cce0260801c5b6b0400000000000000000000008316156128785770010000000002c5c85fdf4b15de6f17eb0d0260801c5b6b0200000000000000000000008316156128a3577001000000000162e42fefa494f1478fde050260801c5b6b0100000000000000000000008316156128ce5770010000000000b17217f7d20cf927c8e94c0260801c5b6a80000000000000000000008316156128f8577001000000000058b90bfbe8f71cb4e4b33d0260801c5b6a400000000000000000000083161561292257700100000000002c5c85fdf477b662b269450260801c5b6a200000000000000000000083161561294c5770010000000000162e42fefa3ae53369388c0260801c5b6a100000000000000000000083161561297657700100000000000b17217f7d1d351a389d400260801c5b6a08000000000000000000008316156129a05770010000000000058b90bfbe8e8b2d3d4ede0260801c5b6a04000000000000000000008316156129ca577001000000000002c5c85fdf4741bea6e77e0260801c5b6a02000000000000000000008316156129f457700100000000000162e42fefa39fe95583c20260801c5b6a0100000000000000000000831615612a1e577001000000000000b17217f7d1cfb72b45e10260801c5b6980000000000000000000831615612a4757700100000000000058b90bfbe8e7cc35c3f00260801c5b6940000000000000000000831615612a705770010000000000002c5c85fdf473e242ea380260801c5b6920000000000000000000831615612a99577001000000000000162e42fefa39f02b772c0260801c5b6910000000000000000000831615612ac25770010000000000000b17217f7d1cf7d83c1a0260801c5b6908000000000000000000831615612aeb577001000000000000058b90bfbe8e7bdcbe2e0260801c5b6904000000000000000000831615612b1457700100000000000002c5c85fdf473dea871f0260801c5b6902000000000000000000831615612b3d5770010000000000000162e42fefa39ef44d910260801c5b6901000000000000000000831615612b6657700100000000000000b17217f7d1cf79e9490260801c5b68800000000000000000831615612b8e5770010000000000000058b90bfbe8e7bce5440260801c5b68400000000000000000831615612bb6577001000000000000002c5c85fdf473de6eca0260801c5b68200000000000000000831615612bde57700100000000000000162e42fefa39ef366f0260801c5b68100000000000000000831615612c06577001000000000000000b17217f7d1cf79afa0260801c5b68080000000000000000831615612c2e57700100000000000000058b90bfbe8e7bcd6d0260801c5b68040000000000000000831615612c565770010000000000000002c5c85fdf473de6b20260801c5b68020000000000000000831615612c7e577001000000000000000162e42fefa39ef3580260801c5b68010000000000000000831615612ca65770010000000000000000b17217f7d1cf79ab0260801c5b678000000000000000831615612ccd577001000000000000000058b90bfbe8e7bcd50260801c5b674000000000000000831615612cf457700100000000000000002c5c85fdf473de6a0260801c5b672000000000000000831615612d1b5770010000000000000000162e42fefa39ef340260801c5b671000000000000000831615612d4257700100000000000000000b17217f7d1cf7990260801c5b670800000000000000831615612d695770010000000000000000058b90bfbe8e7bcc0260801c5b670400000000000000831615612d90577001000000000000000002c5c85fdf473de50260801c5b670200000000000000831615612db757700100000000000000000162e42fefa39ef20260801c5b670100000000000000831615612dde577001000000000000000000b17217f7d1cf780260801c5b6680000000000000831615612e0457700100000000000000000058b90bfbe8e7bb0260801c5b6640000000000000831615612e2a5770010000000000000000002c5c85fdf473dd0260801c5b6620000000000000831615612e50577001000000000000000000162e42fefa39ee0260801c5b6610000000000000831615612e765770010000000000000000000b17217f7d1cf60260801c5b6608000000000000831615612e9c577001000000000000000000058b90bfbe8e7a0260801c5b6604000000000000831615612ec257700100000000000000000002c5c85fdf473c0260801c5b6602000000000000831615612ee85770010000000000000000000162e42fefa39d0260801c5b6601000000000000831615612f0e57700100000000000000000000b17217f7d1ce0260801c5b65800000000000831615612f335770010000000000000000000058b90bfbe8e60260801c5b65400000000000831615612f58577001000000000000000000002c5c85fdf4720260801c5b65200000000000831615612f7d57700100000000000000000000162e42fefa380260801c5b65100000000000831615612fa2577001000000000000000000000b17217f7d1b0260801c5b65080000000000831615612fc757700100000000000000000000058b90bfbe8d0260801c5b65040000000000831615612fec5770010000000000000000000002c5c85fdf460260801c5b65020000000000831615613011577001000000000000000000000162e42fefa20260801c5b650100000000008316156130365770010000000000000000000000b17217f7d00260801c5b64800000000083161561305a577001000000000000000000000058b90bfbe70260801c5b64400000000083161561307e57700100000000000000000000002c5c85fdf30260801c5b6420000000008316156130a25770010000000000000000000000162e42fef90260801c5b6410000000008316156130c657700100000000000000000000000b17217f7c0260801c5b6408000000008316156130ea5770010000000000000000000000058b90bfbd0260801c5b64040000000083161561310e577001000000000000000000000002c5c85fde0260801c5b64020000000083161561313257700100000000000000000000000162e42fee0260801c5b640100000000831615613156577001000000000000000000000000b17217f60260801c5b638000000083161561317957700100000000000000000000000058b90bfa0260801c5b634000000083161561319c5770010000000000000000000000002c5c85fc0260801c5b63200000008316156131bf577001000000000000000000000000162e42fd0260801c5b63100000008316156131e25770010000000000000000000000000b17217e0260801c5b6308000000831615613205577001000000000000000000000000058b90be0260801c5b630400000083161561322857700100000000000000000000000002c5c85e0260801c5b630200000083161561324b5770010000000000000000000000000162e42e0260801c5b630100000083161561326e57700100000000000000000000000000b172160260801c5b628000008316156132905770010000000000000000000000000058b90a0260801c5b624000008316156132b2577001000000000000000000000000002c5c840260801c5b622000008316156132d457700100000000000000000000000000162e410260801c5b621000008316156132f6577001000000000000000000000000000b17200260801c5b6208000083161561331857700100000000000000000000000000058b8f0260801c5b6204000083161561333a5770010000000000000000000000000002c5c70260801c5b6202000083161561335c577001000000000000000000000000000162e30260801c5b6201000083161561337e5770010000000000000000000000000000b1710260801c5b61800083161561339f577001000000000000000000000000000058b80260801c5b6140008316156133c057700100000000000000000000000000002c5b0260801c5b6120008316156133e15770010000000000000000000000000000162d0260801c5b61100083161561340257700100000000000000000000000000000b160260801c5b6108008316156134235770010000000000000000000000000000058a0260801c5b610400831615613444577001000000000000000000000000000002c40260801c5b610200831615613465577001000000000000000000000000000001610260801c5b610100831615613486577001000000000000000000000000000000b00260801c5b60808316156134a6577001000000000000000000000000000000570260801c5b60408316156134c65770010000000000000000000000000000002b0260801c5b60208316156134e6577001000000000000000000000000000000150260801c5b60108316156135065770010000000000000000000000000000000a0260801c5b6008831615613526577001000000000000000000000000000000040260801c5b6004831615613546577001000000000000000000000000000000010260801c5b8461356757600f81901c6001600160701b03169050613fff82019150613596565b613ffe821161358c57600f81901c6001600160701b0316905081613fff039150613596565b600091613fee19011c5b60709190911b1760801b95945050505050565b60008082116135b757600080fd5b600070010000000000000000000000000000000083106135d957608092831c92015b6801000000000000000083106135f157604092831c92015b640100000000831061360557602092831c92015b62010000831061361757601092831c92015b610100831061362857600892831c92015b6010831061363857600492831c92015b6004831061364857600292831c92015b600283106105c75760010192915050565b6000617fff60f083901c16613fff8110156136775750600092915050565b6001607f1b608084901c1061368b57600080fd5b6140fe81111561369a57600080fd5b600160701b6001600160701b03608085901c161761406f8210156136c45761406f8290031c61063b565b61406f82111561063b5761406e1982011b9392505050565b6001600160a01b03811681146115ae57600080fd5b600381106115ae57600080fd5b6000610100828403121561371157600080fd5b50919050565b600080600080600060a0868803121561372f57600080fd5b853561373a816136dc565b9450602086013561374a816136f1565b935060408601359250606086013567ffffffffffffffff8082111561376e57600080fd5b61377a89838a016136fe565b9350608088013591508082111561379057600080fd5b5061379d888289016136fe565b9150509295509295909350565b600080600080608085870312156137c057600080fd5b84356137cb816136dc565b935060208501356137db816136dc565b93969395505050506040820135916060013590565b600060408083018584526020828186015281865180845260609350838701915082880160005b828110156138c557815180518552858101516001600160a01b039081168787015288820151168886015286810151878601526080808201519086015260a0808201519086015260c0808201519086015260e08082015190860152610100808201519086015261012080820151908601526101408082015190860152610160808201519086015261018080820151908601526101a090810151908501526101c09093019290840190600101613816565b50919998505050505050505050565b6000602082840312156138e657600080fd5b813561063b816136dc565b6000806040838503121561390457600080fd5b823561390f816136dc565b946020939093013593505050565b600060208083528351808285015260005b8181101561394a5785810183015185820160400152820161392e565b506000604082860101526040601f19601f8301168501019250505092915050565b60008060006060848603121561398057600080fd5b8351925060208401519150604084015190509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b604051610100810167ffffffffffffffff811182821017156139e9576139e96139af565b60405290565b6040516101c0810167ffffffffffffffff811182821017156139e9576139e96139af565b604051610180810167ffffffffffffffff811182821017156139e9576139e96139af565b604051601f8201601f1916810167ffffffffffffffff81118282101715613a6057613a606139af565b604052919050565b600082601f830112613a7957600080fd5b813567ffffffffffffffff811115613a9357613a936139af565b613aa6601f8201601f1916602001613a37565b818152846020838601011115613abb57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101008236031215613aeb57600080fd5b613af36139c5565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013567ffffffffffffffff811115613b4d57600080fd5b613b5936828601613a68565b60e08301525092915050565b80516108ef816136dc565b6000806040808486031215613b8457600080fd5b8351925060208085015167ffffffffffffffff80821115613ba457600080fd5b818701915087601f830112613bb857600080fd5b815181811115613bca57613bca6139af565b613bd8848260051b01613a37565b81815284810192506101c091820284018501918a831115613bf857600080fd5b938501935b82851015613cc25780858c031215613c155760008081fd5b613c1d6139ef565b85518152613c2c878701613b65565b87820152613c3b888701613b65565b81890152606086810151908201526080808701519082015260a0808701519082015260c0808701519082015260e08087015190820152610100808701519082015261012080870151908201526101408087015190820152610160808701519082015261018080870151908201526101a0808701519082015284529384019392850192613bfd565b508096505050505050509250929050565b600060808284031215613ce557600080fd5b6040516080810181811067ffffffffffffffff82111715613d0857613d086139af565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b600060208284031215613d4b57600080fd5b5051919050565b60038110613d6257613d62613999565b9052565b81516001600160a01b0316815261014081016020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151611cd982850182613d52565b6040810160028410613df157613df1613999565b9281526020015290565b80516108ef816136f1565b8051600281106108ef57600080fd5b60006101808284031215613e2857600080fd5b613e30613a13565b82518152613e4060208401613b65565b602082015260408301516040820152613e5b60608401613dfb565b6060820152613e6c60808401613e06565b608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120808401518183015250610140808401518183015250610160613ec1818501613e06565b908201529392505050565b600060a08284031215613ede57600080fd5b60405160a0810181811067ffffffffffffffff82111715613f0157613f016139af565b806040525080915082518152602083015160208201526040830151604082015260608301516060820152608083015160808201525092915050565b6000806101408385031215613f5057600080fd5b613f5a8484613ecc565b9150613f698460a08501613ecc565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8082018281126000831280158216821582161715611cd957611cd9613f72565b818103600083128015838313168383128216171561172f5761172f613f72565b808201808211156105c7576105c7613f72565b80820281158282048414176105c7576105c7613f72565b818103818111156105c7576105c7613f72565b6000600160ff1b820161401a5761401a613f72565b5060000390565b634e487b7160e01b600052601260045260246000fd5b60008261404657614046614021565b500490565b60008261405a5761405a614021565b500690565b634e487b7160e01b600052600160045260246000fdfea26469706673582212202e1acbc7ff8c92bcbd4a74625bf5a4cd65d86b23f8f5adaea42c0d7a5e477c0c64736f6c634300081400330000000000000000000000005979d7b546e38e414f7e9822514be443a4800529000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c28000000000000000000000000bd013ea2e01c2ab3462dd67e9c83aa3834882a5d00000000000000000000000042444c388beac2d1685ebfafaed1e86b9e7a1b3d00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d000000000000000000000000005e275e063fe89d9abcb62c3a91205e8bf7c4052
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a35760003560e01c80637761022f1161007657806399fcfbfc1161005b57806399fcfbfc146101d2578063c34605c914610228578063d83eb8ba1461025657600080fd5b80637761022f1461018a5780637eea00a8146101b157600080fd5b8063046df835146100a8578063080387b4146100d55780631188de6214610114578063635411b014610135575b600080fd5b6100bb6100b6366004613717565b610269565b604080519283526020830191909152015b60405180910390f35b6100fc7f00000000000000000000000005e275e063fe89d9abcb62c3a91205e8bf7c405281565b6040516001600160a01b0390911681526020016100cc565b6101276101223660046137aa565b610438565b6040516100cc9291906137f0565b6101486101433660046138d4565b61054b565b6040516100cc9190600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b6100fc7f00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d081565b6101c46101bf3660046138f1565b6105cd565b6040519081526020016100cc565b6101e56101e03660046138d4565b610642565b6040516100cc919081516001600160a01b039081168252602080840151821690830152604080840151821690830152606092830151169181019190915260800190565b61023b6102363660046138d4565b61066f565b604080519384526020840192909252908201526060016100cc565b6101c46102643660046138f1565b61070d565b600080600085116040518060400160405280600881526020017f49504f525f333335000000000000000000000000000000000000000000000000815250906102cd5760405162461bcd60e51b81526004016102c4919061391d565b60405180910390fd5b5060006102d98861077b565b6040517fb31610db0000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301529192506000917f00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d0169063b31610db90602401606060405180830381865afa15801561035e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610382919061396b565b5050905060006103d48a8a600281111561039e5761039e613999565b60005b7f00000000000000000000000005e275e063fe89d9abcb62c3a91205e8bf7c40526103cb8c613ad8565b939291906108f4565b905060006103f58b8b60028111156103ee576103ee613999565b60016103a1565b905061042684848c8c7f00000000000000000000000005e275e063fe89d9abcb62c3a91205e8bf7c40528787610a6a565b909c909b509950505050505050505050565b6040517f6be212480000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d0811660048301527f000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c28811660248301528086166044830152841660648201526084810183905260a4810182905260009060609073aab8f1f70ac5d10804f459ca04159eb61d6646f790636be212489060c401600060405180830381865af4158015610515573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261053d9190810190613b70565b915091505b94509492505050565b61057d6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6105c77f000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c287f000000000000000000000000bd013ea2e01c2ab3462dd67e9c83aa3834882a5d610d23565b92915050565b600061063b7f00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d07f000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c287f0000000000000000000000005979d7b546e38e414f7e9822514be443a480052985610e5a565b9392505050565b6040805160808101825260008082526020820181905291810182905260608101919091526105c78261077b565b6040805160e0810182526000602082018190529181018290526080810182905260a081018290526001600160a01b0383811682527f000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c28811660608301527f00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d01660c0820152819081906106ff81610fb6565b919790965090945092505050565b600061063b7f00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d07f000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c287f0000000000000000000000005979d7b546e38e414f7e9822514be443a4800529856110dc565b6040805160808101825260008082526020820181905291810182905260608101919091527f0000000000000000000000005979d7b546e38e414f7e9822514be443a48005296001600160a01b0316826001600160a01b0316036108a45760405180608001604052807f0000000000000000000000005979d7b546e38e414f7e9822514be443a48005296001600160a01b031681526020017f000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c286001600160a01b031681526020017f000000000000000000000000bd013ea2e01c2ab3462dd67e9c83aa3834882a5d6001600160a01b031681526020017f00000000000000000000000042444c388beac2d1685ebfafaed1e86b9e7a1b3d6001600160a01b03168152509050919050565b604080518082018252600881527f49504f525f3031370000000000000000000000000000000000000000000000006020820152905162461bcd60e51b81526102c4919060040161391d565b919050565b61092d6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b600061093b8787878761122d565b9050826001600160a01b031661095e8860e00151836112dc90919063ffffffff16565b6001600160a01b0316146040518060400160405280600881526020017f49504f525f303230000000000000000000000000000000000000000000000000815250906109bc5760405162461bcd60e51b81526004016102c4919061391d565b50428760c00151116040518060400160405280600881526020017f49504f525f30313900000000000000000000000000000000000000000000000081525090610a185760405162461bcd60e51b81526004016102c4919061391d565b506040518060c0016040528088600001518152602001886020015181526020018860400151815260200188606001518152602001886080015181526020018860a0015181525091505095945050505050565b600080600089602001516001600160a01b0316636c2c986e6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610ab1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad59190613cd3565b905060008a604001516001600160a01b0316634fcf9f716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3f9190613d39565b90508a606001516001600160a01b031663259f0bf86040518061014001604052808e600001516001600160a01b031681526020018b81526020018960a0015181526020018960600151815260200185600001518152602001856040015181526020018481526020018d8152602001896080015181526020018c6002811115610bc957610bc9613999565b8152506040518263ffffffff1660e01b8152600401610be89190613d66565b602060405180830381865afa158015610c05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c299190613d39565b93508a606001516001600160a01b03166376ee4c846040518061014001604052808e600001516001600160a01b031681526020018b81526020018860a0015181526020018860600151815260200185600001518152602001856040015181526020018481526020018d8152602001886080015181526020018c6002811115610cb357610cb3613999565b8152506040518263ffffffff1660e01b8152600401610cd29190613d66565b602060405180830381865afa158015610cef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d139190613d39565b9250505097509795505050505050565b610d556040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6000836001600160a01b0316636c2c986e6040518163ffffffff1660e01b8152600401608060405180830381865afa158015610d95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db99190613cd3565b90506040518060a0016040528082600001518152602001826020015181526020018260400151815260200182606001518152602001846001600160a01b0316634fcf9f716040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e509190613d39565b9052949350505050565b604051630e5c712960e01b81526001600160a01b0383811660048301524260248301526000918291871690630e5c712990604401602060405180830381865afa158015610eab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecf9190613d39565b90506000856001600160a01b031663f1a3c63a6000866040518363ffffffff1660e01b8152600401610f02929190613ddd565b61018060405180830381865afa158015610f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f449190613e15565b805160408051808201909152600881526724a827a92f99981b60c11b6020820152919250610f855760405162461bcd60e51b81526004016102c4919061391d565b50610fab81604001518260c001518360e001518461012001518561010001514288611300565b979650505050505050565b60008060008042905060008086606001516001600160a01b031663cab418206040518163ffffffff1660e01b815260040161014060405180830381865afa158015611005573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110299190613f3c565b60c08901518951604051630e5c712960e01b81526001600160a01b03918216600482015260248101889052939550919350600092911690630e5c712990604401602060405180830381865afa158015611086573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110aa9190613d39565b90506110b783858361134a565b96506110c48285836113a3565b95506110d08688613f88565b96989597505050505050565b604051630e5c712960e01b81526001600160a01b0383811660048301524260248301526000918291871690630e5c712990604401602060405180830381865afa15801561112d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111519190613d39565b90506000856001600160a01b031663f1a3c63a6001866040518363ffffffff1660e01b8152600401611184929190613ddd565b61018060405180830381865afa1580156111a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c69190613e15565b805160408051808201909152600881526724a827a92f99981b60c11b60208201529192506112075760405162461bcd60e51b81526004016102c4919061391d565b50610fab81604001518260c001518360e0015184610120015185610100015142886113d7565b8351602080860151604080880151606089015160808a015160a08b015160c08c015194516000986112bc98909796918d918d918d9101998a5260208a01989098526040890196909652606080890195909552608088019390935260a087019190915260c0860152901b6bffffffffffffffffffffffff191660e084015260f48301526101148201526101340190565b604051602081830303815290604052805190602001209050949350505050565b60008060006112eb8585611404565b915091506112f881611449565b509392505050565b60008060006113138a89898989896115b1565b9150915061133c896113248461163a565b61132d8461163a565b6113379190613fa8565b6116d6565b9a9950505050505050505050565b600061136d6113598585611736565b85602001516113689190613fc8565b61163a565b6113916113688487604001516113839190613fdb565b670de0b6b3a764000061176b565b61139b9190613fa8565b949350505050565b60006113bb6113688386604001516113839190613fdb565b6113916113c88686611736565b86602001516113689190613fc8565b60008060006113ea8a89898989896115b1565b9150915061133c896113fb8361163a565b61132d8561163a565b600080825160410361143a5760208301516040840151606085015160001a61142e8782858561178d565b94509450505050611442565b506000905060025b9250929050565b600081600481111561145d5761145d613999565b036114655750565b600181600481111561147957611479613999565b036114c65760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016102c4565b60028160048111156114da576114da613999565b036115275760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016102c4565b600381600481111561153b5761153b613999565b036115ae5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016102c4565b50565b600080878410156040518060400160405280600881526020017f49504f525f3331390000000000000000000000000000000000000000000000008152509061160c5760405162461bcd60e51b81526004016102c4919061391d565b50611621878761161c8b88613ff2565b61184e565b915061162d8584611864565b9050965096945050505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8211156116d25760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e7432353600000000000000000000000000000000000000000000000060648201526084016102c4565b5090565b6000806116e28461163a565b9050600083131561170557808312156116fe57829150506105c7565b90506105c7565b61170e81614005565b8312156117265761171e81614005565b9150506105c7565b829150506105c7565b5092915050565b600061175f828460800151856000015186602001516117559190613fc8565b8660600151611873565b835161063b9190613fc8565b600081611779600282614037565b6117839085613fc8565b61063b9190614037565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156117c45750600090506003610542565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611818573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661184157600060019250925050610542565b9660009650945050505050565b600061139b61185d8385613fdb565b85906118f5565b600061063b6113838385613fdb565b6000838510156040518060400160405280600881526020017f49504f525f333137000000000000000000000000000000000000000000000000815250906118cd5760405162461bcd60e51b81526004016102c4919061391d565b506118ec6118db8587613ff2565b6118e59084613fdb565b8490611953565b95945050505050565b600080611906836301e1338061176b565b9050600061191c85670de0b6b3a764000061196a565b9050600061193283670de0b6b3a764000061196a565b9050600061194883611943846119bb565b6119ef565b9050610fab81611ce1565b60008261196084846118f5565b61063b9190613ff2565b600080611977838561404b565b111561198b57611988600184613fc8565b92505b600061199684611d0e565b905060006119a384611d0e565b905060006119b18383611d75565b9695505050505050565b60006105c76119ea837f3fff71547652b82fe1777d0ffda0d23a000000000000000000000000000000006119ef565b61206d565b6000617fff60f084811c8216919084901c811690829003611aba5780617fff03611a7c576fffffffffffffffffffffffffffffffff1980851690861603611a4157505050600160ff1b811682186105c7565b6fffffffffffffffffffffffffffffffff1985851816600160ff1b03611a6c575050508181176105c7565b5061ffff60ef1b91506105c79050565b6f7fffffffffffffffffffffffffffffff60801b8416600003611aa9575061ffff60ef1b91506105c79050565b505050600160ff1b811682186105c7565b80617fff03611b01576f7fffffffffffffffffffffffffffffff60801b8516600003611af0575061ffff60ef1b91506105c79050565b505050600160ff1b821681186105c7565b6001600160701b03608086901c166000839003611b215760019250611b28565b600160701b175b6001600160701b03608086901c166000839003611b485760019250611b4f565b600160701b175b808202915081600003611b8157600160ff1b87871816611b70576000611b76565b600160ff1b5b9450505050506105c7565b9282019260007c0200000000000000000000000000000000000000000000000000000000831015611be6577c0100000000000000000000000000000000000000000000000000000000831015611bdf57611bda836135a9565b611be9565b60e0611be9565b60e15b90506140708186011015611c04576000945060009250611ca1565b6140e08186011015611c4757614070851015611c2957846140700383901c9250611c3e565b614070851115611c3e57614070850383901b92505b60009450611ca1565b61c0dd8186011115611c6157617fff945060009250611ca1565b6070811115611c78576070810383901c9250611c8b565b6070811015611c8b578060700383901b92505b6001600160701b03831692506140df8186010394505b82607086901b888a186001607f1b60801b1660801c6fffffffffffffffffffffffffffffffff16171760801b955050505050506105c7565b505092915050565b600080611cf5670de0b6b3a7640000611d0e565b90506000611d0384836119ef565b905061139b81613659565b600081600003611d2057506000919050565b816000611d2c826135a9565b90506070811015611d45578060700382901b9150611d58565b6070811115611d58576070810382901c91505b613fff0160701b6001600160701b03919091161760801b92915050565b6000617fff60f084811c8216919084901c811690829003611da95780617fff03611aa9575061ffff60ef1b91506105c79050565b80617fff03611df9577dffffffffffffffffffffffffffff00000000000000000000000000000000841615611de8575061ffff60ef1b91506105c79050565b505050808218600160ff1b166105c7565b6f7fffffffffffffffffffffffffffffff60801b8416600003611e5b576f7fffffffffffffffffffffffffffffff60801b8516600003611e43575061ffff60ef1b91506105c79050565b505050808218600160ff1b16617fff60f01b176105c7565b6001600160701b03608085901c166000829003611e7b5760019150611e82565b600160701b175b6001600160701b03608087901c166000849003611ec5578015611ec0576000611eaa826135a9565b6001955060e20393840160711901939190911b90505b611ecf565b600160701b1760721b5b818181611ede57611ede614021565b04905080600003611efd57600160ff1b87871816611b70576000611b76565b6d1000000000000000000000000000811015611f1b57611f1b61405f565b60006e080000000000000000000000000000821015611f7b576e040000000000000000000000000000821015611f70576e020000000000000000000000000000821015611f69576070611f73565b6071611f73565b60725b60ff16611f84565b611f84826135a9565b905083614071018186011115611fa257617fff945060009150612035565b83818601613ffc011015611fbd576000945060009150612035565b83818601613f8c01101561200a578385613ffc011115611fe8578385613ffc010382901b9150612001565b8385613ffc01101561200157613ffc8585030382901c91505b60009450612035565b607081111561201d576070810382901c91505b6001600160701b038216915083818601613f8d010394505b81607086901b888a186001607f1b60801b1660801c6fffffffffffffffffffffffffffffffff16171760801b955050505050506105c7565b60006001607f1b608083901c90811190617fff60f085901c8116916001600160701b0316908214801561209f57508015155b156120b3575061ffff60ef1b949350505050565b61400d8211156120d857826120cd57617fff60f01b6118ec565b600095945050505050565b613f7f82101561210c57507f3fff000000000000000000000000000000000000000000000000000000000000949350505050565b8160000361211d5760019150612124565b600160701b175b613fef82111561213a57613fee1982011b61214c565b613fef82101561214c57613fef8290031c5b82801561216a575071406e0000000000000000000000000000000081115b1561217a57506000949350505050565b821580156121995750713fffffffffffffffffffffffffffffffffff81115b156121ad5750617fff60f01b949350505050565b6fffffffffffffffffffffffffffffffff81169060801c8380156121d057508115155b156121dc579019906001015b6001607f1b828116156122005770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b6f4000000000000000000000000000000083161561222f577001306fe0a31b7152de8d5a46305c85edec0260801c5b6f2000000000000000000000000000000083161561225e577001172b83c7d517adcdf7c8c50eb14a791f0260801c5b6f1000000000000000000000000000000083161561228d5770010b5586cf9890f6298b92b71842a983630260801c5b6f080000000000000000000000000000008316156122bc577001059b0d31585743ae7c548eb68ca417fd0260801c5b6f040000000000000000000000000000008316156122eb57700102c9a3e778060ee6f7caca4f7a29bde80260801c5b6f0200000000000000000000000000000083161561231a5770010163da9fb33356d84a66ae336dcdfa3f0260801c5b6f0100000000000000000000000000000083161561234957700100b1afa5abcbed6129ab13ec11dc95430260801c5b6e8000000000000000000000000000008316156123775770010058c86da1c09ea1ff19d294cf2f679b0260801c5b6e4000000000000000000000000000008316156123a5577001002c605e2e8cec506d21bfc89a23a00f0260801c5b6e2000000000000000000000000000008316156123d357700100162f3904051fa128bca9c55c31e5df0260801c5b6e100000000000000000000000000000831615612401577001000b175effdc76ba38e31671ca9397250260801c5b6e08000000000000000000000000000083161561242f57700100058ba01fb9f96d6cacd4b180917c3d0260801c5b6e04000000000000000000000000000083161561245d5770010002c5cc37da9491d0985c348c68e7b30260801c5b6e02000000000000000000000000000083161561248b577001000162e525ee054754457d59952920260260801c5b600160701b8316156124ae5770010000b17255775c040618bf4a4ade83fc0260801c5b6d80000000000000000000000000008316156124db577001000058b91b5bc9ae2eed81e9b7d4cfab0260801c5b6d400000000000000000000000000083161561250857700100002c5c89d5ec6ca4d7c8acc017b7c90260801c5b6d20000000000000000000000000008316156125355770010000162e43f4f831060e02d839a9d16d0260801c5b6d100000000000000000000000000083161561256257700100000b1721bcfc99d9f890ea069117630260801c5b6d080000000000000000000000000083161561258f5770010000058b90cf1e6d97f9ca14dbcc16280260801c5b6d04000000000000000000000000008316156125bc577001000002c5c863b73f016468f6bac5ca2b0260801c5b6d02000000000000000000000000008316156125e957700100000162e430e5a18f6119e3c02282a50260801c5b6d0100000000000000000000000000831615612616577001000000b1721835514b86e6d96efd1bfe0260801c5b6c8000000000000000000000000083161561264257700100000058b90c0b48c6be5df846c5b2ef0260801c5b6c4000000000000000000000000083161561266e5770010000002c5c8601cc6b9e94213c72737a0260801c5b6c2000000000000000000000000083161561269a577001000000162e42fff037df38aa2b219f060260801c5b6c100000000000000000000000008316156126c65770010000000b17217fba9c739aa5819f44f90260801c5b6c080000000000000000000000008316156126f2577001000000058b90bfcdee5acd3c1cedc8230260801c5b6c0400000000000000000000000083161561271e57700100000002c5c85fe31f35a6a30da1be500260801c5b6c0200000000000000000000000083161561274a5770010000000162e42ff0999ce3541b9fffcf0260801c5b6c0100000000000000000000000083161561277657700100000000b17217f80f4ef5aadda455540260801c5b6b8000000000000000000000008316156127a15770010000000058b90bfbf8479bd5a81b51ad0260801c5b6b4000000000000000000000008316156127cc577001000000002c5c85fdf84bd62ae30a74cc0260801c5b6b2000000000000000000000008316156127f757700100000000162e42fefb2fed257559bdaa0260801c5b6b100000000000000000000000831615612822577001000000000b17217f7d5a7716bba4a9ae0260801c5b6b08000000000000000000000083161561284d57700100000000058b90bfbe9ddbac5e109cce0260801c5b6b0400000000000000000000008316156128785770010000000002c5c85fdf4b15de6f17eb0d0260801c5b6b0200000000000000000000008316156128a3577001000000000162e42fefa494f1478fde050260801c5b6b0100000000000000000000008316156128ce5770010000000000b17217f7d20cf927c8e94c0260801c5b6a80000000000000000000008316156128f8577001000000000058b90bfbe8f71cb4e4b33d0260801c5b6a400000000000000000000083161561292257700100000000002c5c85fdf477b662b269450260801c5b6a200000000000000000000083161561294c5770010000000000162e42fefa3ae53369388c0260801c5b6a100000000000000000000083161561297657700100000000000b17217f7d1d351a389d400260801c5b6a08000000000000000000008316156129a05770010000000000058b90bfbe8e8b2d3d4ede0260801c5b6a04000000000000000000008316156129ca577001000000000002c5c85fdf4741bea6e77e0260801c5b6a02000000000000000000008316156129f457700100000000000162e42fefa39fe95583c20260801c5b6a0100000000000000000000831615612a1e577001000000000000b17217f7d1cfb72b45e10260801c5b6980000000000000000000831615612a4757700100000000000058b90bfbe8e7cc35c3f00260801c5b6940000000000000000000831615612a705770010000000000002c5c85fdf473e242ea380260801c5b6920000000000000000000831615612a99577001000000000000162e42fefa39f02b772c0260801c5b6910000000000000000000831615612ac25770010000000000000b17217f7d1cf7d83c1a0260801c5b6908000000000000000000831615612aeb577001000000000000058b90bfbe8e7bdcbe2e0260801c5b6904000000000000000000831615612b1457700100000000000002c5c85fdf473dea871f0260801c5b6902000000000000000000831615612b3d5770010000000000000162e42fefa39ef44d910260801c5b6901000000000000000000831615612b6657700100000000000000b17217f7d1cf79e9490260801c5b68800000000000000000831615612b8e5770010000000000000058b90bfbe8e7bce5440260801c5b68400000000000000000831615612bb6577001000000000000002c5c85fdf473de6eca0260801c5b68200000000000000000831615612bde57700100000000000000162e42fefa39ef366f0260801c5b68100000000000000000831615612c06577001000000000000000b17217f7d1cf79afa0260801c5b68080000000000000000831615612c2e57700100000000000000058b90bfbe8e7bcd6d0260801c5b68040000000000000000831615612c565770010000000000000002c5c85fdf473de6b20260801c5b68020000000000000000831615612c7e577001000000000000000162e42fefa39ef3580260801c5b68010000000000000000831615612ca65770010000000000000000b17217f7d1cf79ab0260801c5b678000000000000000831615612ccd577001000000000000000058b90bfbe8e7bcd50260801c5b674000000000000000831615612cf457700100000000000000002c5c85fdf473de6a0260801c5b672000000000000000831615612d1b5770010000000000000000162e42fefa39ef340260801c5b671000000000000000831615612d4257700100000000000000000b17217f7d1cf7990260801c5b670800000000000000831615612d695770010000000000000000058b90bfbe8e7bcc0260801c5b670400000000000000831615612d90577001000000000000000002c5c85fdf473de50260801c5b670200000000000000831615612db757700100000000000000000162e42fefa39ef20260801c5b670100000000000000831615612dde577001000000000000000000b17217f7d1cf780260801c5b6680000000000000831615612e0457700100000000000000000058b90bfbe8e7bb0260801c5b6640000000000000831615612e2a5770010000000000000000002c5c85fdf473dd0260801c5b6620000000000000831615612e50577001000000000000000000162e42fefa39ee0260801c5b6610000000000000831615612e765770010000000000000000000b17217f7d1cf60260801c5b6608000000000000831615612e9c577001000000000000000000058b90bfbe8e7a0260801c5b6604000000000000831615612ec257700100000000000000000002c5c85fdf473c0260801c5b6602000000000000831615612ee85770010000000000000000000162e42fefa39d0260801c5b6601000000000000831615612f0e57700100000000000000000000b17217f7d1ce0260801c5b65800000000000831615612f335770010000000000000000000058b90bfbe8e60260801c5b65400000000000831615612f58577001000000000000000000002c5c85fdf4720260801c5b65200000000000831615612f7d57700100000000000000000000162e42fefa380260801c5b65100000000000831615612fa2577001000000000000000000000b17217f7d1b0260801c5b65080000000000831615612fc757700100000000000000000000058b90bfbe8d0260801c5b65040000000000831615612fec5770010000000000000000000002c5c85fdf460260801c5b65020000000000831615613011577001000000000000000000000162e42fefa20260801c5b650100000000008316156130365770010000000000000000000000b17217f7d00260801c5b64800000000083161561305a577001000000000000000000000058b90bfbe70260801c5b64400000000083161561307e57700100000000000000000000002c5c85fdf30260801c5b6420000000008316156130a25770010000000000000000000000162e42fef90260801c5b6410000000008316156130c657700100000000000000000000000b17217f7c0260801c5b6408000000008316156130ea5770010000000000000000000000058b90bfbd0260801c5b64040000000083161561310e577001000000000000000000000002c5c85fde0260801c5b64020000000083161561313257700100000000000000000000000162e42fee0260801c5b640100000000831615613156577001000000000000000000000000b17217f60260801c5b638000000083161561317957700100000000000000000000000058b90bfa0260801c5b634000000083161561319c5770010000000000000000000000002c5c85fc0260801c5b63200000008316156131bf577001000000000000000000000000162e42fd0260801c5b63100000008316156131e25770010000000000000000000000000b17217e0260801c5b6308000000831615613205577001000000000000000000000000058b90be0260801c5b630400000083161561322857700100000000000000000000000002c5c85e0260801c5b630200000083161561324b5770010000000000000000000000000162e42e0260801c5b630100000083161561326e57700100000000000000000000000000b172160260801c5b628000008316156132905770010000000000000000000000000058b90a0260801c5b624000008316156132b2577001000000000000000000000000002c5c840260801c5b622000008316156132d457700100000000000000000000000000162e410260801c5b621000008316156132f6577001000000000000000000000000000b17200260801c5b6208000083161561331857700100000000000000000000000000058b8f0260801c5b6204000083161561333a5770010000000000000000000000000002c5c70260801c5b6202000083161561335c577001000000000000000000000000000162e30260801c5b6201000083161561337e5770010000000000000000000000000000b1710260801c5b61800083161561339f577001000000000000000000000000000058b80260801c5b6140008316156133c057700100000000000000000000000000002c5b0260801c5b6120008316156133e15770010000000000000000000000000000162d0260801c5b61100083161561340257700100000000000000000000000000000b160260801c5b6108008316156134235770010000000000000000000000000000058a0260801c5b610400831615613444577001000000000000000000000000000002c40260801c5b610200831615613465577001000000000000000000000000000001610260801c5b610100831615613486577001000000000000000000000000000000b00260801c5b60808316156134a6577001000000000000000000000000000000570260801c5b60408316156134c65770010000000000000000000000000000002b0260801c5b60208316156134e6577001000000000000000000000000000000150260801c5b60108316156135065770010000000000000000000000000000000a0260801c5b6008831615613526577001000000000000000000000000000000040260801c5b6004831615613546577001000000000000000000000000000000010260801c5b8461356757600f81901c6001600160701b03169050613fff82019150613596565b613ffe821161358c57600f81901c6001600160701b0316905081613fff039150613596565b600091613fee19011c5b60709190911b1760801b95945050505050565b60008082116135b757600080fd5b600070010000000000000000000000000000000083106135d957608092831c92015b6801000000000000000083106135f157604092831c92015b640100000000831061360557602092831c92015b62010000831061361757601092831c92015b610100831061362857600892831c92015b6010831061363857600492831c92015b6004831061364857600292831c92015b600283106105c75760010192915050565b6000617fff60f083901c16613fff8110156136775750600092915050565b6001607f1b608084901c1061368b57600080fd5b6140fe81111561369a57600080fd5b600160701b6001600160701b03608085901c161761406f8210156136c45761406f8290031c61063b565b61406f82111561063b5761406e1982011b9392505050565b6001600160a01b03811681146115ae57600080fd5b600381106115ae57600080fd5b6000610100828403121561371157600080fd5b50919050565b600080600080600060a0868803121561372f57600080fd5b853561373a816136dc565b9450602086013561374a816136f1565b935060408601359250606086013567ffffffffffffffff8082111561376e57600080fd5b61377a89838a016136fe565b9350608088013591508082111561379057600080fd5b5061379d888289016136fe565b9150509295509295909350565b600080600080608085870312156137c057600080fd5b84356137cb816136dc565b935060208501356137db816136dc565b93969395505050506040820135916060013590565b600060408083018584526020828186015281865180845260609350838701915082880160005b828110156138c557815180518552858101516001600160a01b039081168787015288820151168886015286810151878601526080808201519086015260a0808201519086015260c0808201519086015260e08082015190860152610100808201519086015261012080820151908601526101408082015190860152610160808201519086015261018080820151908601526101a090810151908501526101c09093019290840190600101613816565b50919998505050505050505050565b6000602082840312156138e657600080fd5b813561063b816136dc565b6000806040838503121561390457600080fd5b823561390f816136dc565b946020939093013593505050565b600060208083528351808285015260005b8181101561394a5785810183015185820160400152820161392e565b506000604082860101526040601f19601f8301168501019250505092915050565b60008060006060848603121561398057600080fd5b8351925060208401519150604084015190509250925092565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b604051610100810167ffffffffffffffff811182821017156139e9576139e96139af565b60405290565b6040516101c0810167ffffffffffffffff811182821017156139e9576139e96139af565b604051610180810167ffffffffffffffff811182821017156139e9576139e96139af565b604051601f8201601f1916810167ffffffffffffffff81118282101715613a6057613a606139af565b604052919050565b600082601f830112613a7957600080fd5b813567ffffffffffffffff811115613a9357613a936139af565b613aa6601f8201601f1916602001613a37565b818152846020838601011115613abb57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101008236031215613aeb57600080fd5b613af36139c5565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013567ffffffffffffffff811115613b4d57600080fd5b613b5936828601613a68565b60e08301525092915050565b80516108ef816136dc565b6000806040808486031215613b8457600080fd5b8351925060208085015167ffffffffffffffff80821115613ba457600080fd5b818701915087601f830112613bb857600080fd5b815181811115613bca57613bca6139af565b613bd8848260051b01613a37565b81815284810192506101c091820284018501918a831115613bf857600080fd5b938501935b82851015613cc25780858c031215613c155760008081fd5b613c1d6139ef565b85518152613c2c878701613b65565b87820152613c3b888701613b65565b81890152606086810151908201526080808701519082015260a0808701519082015260c0808701519082015260e08087015190820152610100808701519082015261012080870151908201526101408087015190820152610160808701519082015261018080870151908201526101a0808701519082015284529384019392850192613bfd565b508096505050505050509250929050565b600060808284031215613ce557600080fd5b6040516080810181811067ffffffffffffffff82111715613d0857613d086139af565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b600060208284031215613d4b57600080fd5b5051919050565b60038110613d6257613d62613999565b9052565b81516001600160a01b0316815261014081016020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151611cd982850182613d52565b6040810160028410613df157613df1613999565b9281526020015290565b80516108ef816136f1565b8051600281106108ef57600080fd5b60006101808284031215613e2857600080fd5b613e30613a13565b82518152613e4060208401613b65565b602082015260408301516040820152613e5b60608401613dfb565b6060820152613e6c60808401613e06565b608082015260a083015160a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120808401518183015250610140808401518183015250610160613ec1818501613e06565b908201529392505050565b600060a08284031215613ede57600080fd5b60405160a0810181811067ffffffffffffffff82111715613f0157613f016139af565b806040525080915082518152602083015160208201526040830151604082015260608301516060820152608083015160808201525092915050565b6000806101408385031215613f5057600080fd5b613f5a8484613ecc565b9150613f698460a08501613ecc565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8082018281126000831280158216821582161715611cd957611cd9613f72565b818103600083128015838313168383128216171561172f5761172f613f72565b808201808211156105c7576105c7613f72565b80820281158282048414176105c7576105c7613f72565b818103818111156105c7576105c7613f72565b6000600160ff1b820161401a5761401a613f72565b5060000390565b634e487b7160e01b600052601260045260246000fd5b60008261404657614046614021565b500490565b60008261405a5761405a614021565b500690565b634e487b7160e01b600052600160045260246000fdfea26469706673582212202e1acbc7ff8c92bcbd4a74625bf5a4cd65d86b23f8f5adaea42c0d7a5e477c0c64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005979d7b546e38e414f7e9822514be443a4800529000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c28000000000000000000000000bd013ea2e01c2ab3462dd67e9c83aa3834882a5d00000000000000000000000042444c388beac2d1685ebfafaed1e86b9e7a1b3d00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d000000000000000000000000005e275e063fe89d9abcb62c3a91205e8bf7c4052
-----Decoded View---------------
Arg [0] : wstEthCfg (tuple):
Arg [1] : asset (address): 0x5979D7b546E38E414F7E9822514be443A4800529
Arg [2] : ammStorage (address): 0x326804339eC2a210e5f9246F4959aE50961c5C28
Arg [3] : ammTreasury (address): 0xBd013Ea2E01C2Ab3462dd67e9C83aa3834882A5D
Arg [4] : spread (address): 0x42444C388BEAC2D1685eBfaFaED1e86B9e7A1b3d
Arg [1] : iporOracleInput (address): 0x70DdDE503edf4816B5991Ca5E2f9DE79e295F2D0
Arg [2] : messageSignerInput (address): 0x05e275e063fe89D9abcB62C3A91205e8bF7c4052
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000005979d7b546e38e414f7e9822514be443a4800529
Arg [1] : 000000000000000000000000326804339ec2a210e5f9246f4959ae50961c5c28
Arg [2] : 000000000000000000000000bd013ea2e01c2ab3462dd67e9c83aa3834882a5d
Arg [3] : 00000000000000000000000042444c388beac2d1685ebfafaed1e86b9e7a1b3d
Arg [4] : 00000000000000000000000070ddde503edf4816b5991ca5e2f9de79e295f2d0
Arg [5] : 00000000000000000000000005e275e063fe89d9abcb62c3a91205e8bf7c4052
Deployed Bytecode Sourcemap
320840:4685:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;323284:1486;;;;;;:::i;:::-;;:::i;:::-;;;;1668:25:1;;;1724:2;1709:18;;1702:34;;;;1641:18;323284:1486:0;;;;;;;;321336:38;;;;;;;;-1:-1:-1;;;;;2043:55:1;;;2025:74;;2013:2;1998:18;321336:38:0;1879:226:1;322077:332:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;324778:220::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;5018:4:1;5060:3;5049:9;5045:19;5037:27;;5097:6;5091:13;5080:9;5073:32;5161:4;5153:6;5149:17;5143:24;5136:4;5125:9;5121:20;5114:54;5224:4;5216:6;5212:17;5206:24;5199:4;5188:9;5184:20;5177:54;5287:4;5279:6;5275:17;5269:24;5262:4;5251:9;5247:20;5240:54;5350:4;5342:6;5338:17;5332:24;5325:4;5314:9;5310:20;5303:54;4836:527;;;;;321294:35:0;;;;;322417:210;;;;;;:::i;:::-;;:::i;:::-;;;5832:25:1;;;5820:2;5805:18;322417:210:0;5688:175:1;321872:197:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;6186:13:1;;-1:-1:-1;;;;;6182:22:1;;;6164:41;;6265:4;6253:17;;;6247:24;6243:33;;6221:20;;;6214:63;6337:4;6325:17;;;6319:24;6315:33;;6293:20;;;6286:63;6409:4;6397:17;;;6391:24;6387:33;6365:20;;;6358:63;;;;6090:3;6075:19;;5868:559;322861:415:0;;;;;;:::i;:::-;;:::i;:::-;;;;6628:25:1;;;6684:2;6669:18;;6662:34;;;;6712:18;;;6705:34;6616:2;6601:18;322861:415:0;6432:313:1;322635:218:0;;;;;;:::i;:::-;;:::i;323284:1486::-;323594:27;323623:31;323686:1;323675:8;:12;323689:26;;;;;;;;;;;;;;;;;323667:49;;;;;-1:-1:-1;;;323667:49:0;;;;;;;;:::i;:::-;;;;;;;;;;323729:40;323772:36;323802:5;323772:29;:36::i;:::-;323848:39;;;;;-1:-1:-1;;;;;2043:55:1;;;323848:39:0;;;2025:74:1;323729:79:0;;-1:-1:-1;323822:18:0;;323860:10;323848:32;;;;1998:18:1;;323848:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;323821:66;;;;323900:65;323968:196;324018:5;324046;324038:14;;;;;;;;:::i;:::-;324075:49;324067:58;324140:13;323968:35;:28;:35;:::i;:::-;;:196;;;:35;:196::i;:::-;323900:264;;324177:69;324249:200;324303:5;324331;324323:14;;;;;;;;:::i;:::-;324360:49;324352:58;;324249:200;324177:272;;324511:251;324562:7;324584:10;324609:5;324629:8;324652:13;324680:26;324721:30;324511:36;:251::i;:::-;324462:300;;;;-1:-1:-1;323284:1486:0;-1:-1:-1;;;;;;;;;;323284:1486:0:o;322077:332::-;322305:96;;;;;-1:-1:-1;;;;;322336:10:0;10883:15:1;;322305:96:0;;;10865:34:1;322348:17:0;10935:15:1;;10915:18;;;10908:43;10987:15;;;10967:18;;;10960:43;11039:15;;11019:18;;;11012:43;11071:19;;;11064:35;;;11115:19;;;11108:35;;;322228:18:0;;322248:37;;322305:21;;:30;;10776:19:1;;322305:96:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;322305:96:0;;;;;;;;;;;;:::i;:::-;322298:103;;;;322077:332;;;;;;;;:::o;324778:220::-;324842:45;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;324842:45:0;324907:83;324952:17;324971:18;324907:44;:83::i;:::-;324900:90;324778:220;-1:-1:-1;;324778:220:0:o;322417:210::-;322504:6;322530:89;322567:10;322579:17;322598:12;322612:6;322530:36;:89::i;:::-;322523:96;322417:210;-1:-1:-1;;;322417:210:0:o;321872:197::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;322025:36:0;322055:5;322025:29;:36::i;322861:415::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;323067:26:0;;;;;323130:17;323104:43;;-1:-1:-1;;;323104:43:0;323184:10;323158:36;-1:-1:-1;;;323158:36:0;-1:-1:-1;;;;323246:22:0;-1:-1:-1;323246:20:0;:22::i;:::-;323205:63;;;;-1:-1:-1;323205:63:0;;-1:-1:-1;322861:415:0;-1:-1:-1;;;322861:415:0:o;322635:218::-;322726:6;322752:93;322793:10;322805:17;322824:12;322838:6;322752:40;:93::i;325006:516::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;325141:12:0;-1:-1:-1;;;;;325132:21:0;:5;-1:-1:-1;;;;;325132:21:0;;325128:387;;325194:238;;;;;;;;325250:12;-1:-1:-1;;;;;325194:238:0;;;;;325297:17;-1:-1:-1;;;;;325194:238:0;;;;;325350:18;-1:-1:-1;;;;;325194:238:0;;;;;325399:13;-1:-1:-1;;;;;325194:238:0;;;;325170:262;;325006:516;;;:::o;325128:387::-;325472:30;;;;;;;;;;;;;;;;325465:38;;-1:-1:-1;;;325465:38:0;;;;325472:30;325465:38;;;:::i;325128:387::-;325006:516;;;:::o;274130:888::-;274338:53;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;274338:53:0;274404:12;274419:57;274444:6;274452:5;274459;274466:9;274419:24;:57::i;:::-;274404:72;;274543:13;-1:-1:-1;;;;;274509:47:0;:30;274522:6;:16;;;274509:4;:12;;:30;;;;:::i;:::-;-1:-1:-1;;;;;274509:47:0;;274571:44;;;;;;;;;;;;;;;;;274487:139;;;;;-1:-1:-1;;;274487:139:0;;;;;;;;:::i;:::-;;274665:15;274645:6;:17;;;:35;274682:34;;;;;;;;;;;;;;;;;274637:80;;;;;-1:-1:-1;;;274637:80:0;;;;;;;;:::i;:::-;;274735:275;;;;;;;;274781:6;:25;;;274735:275;;;;274821:6;:31;;;274735:275;;;;274867:6;:24;;;274735:275;;;;274906:6;:23;;;274735:275;;;;274944:6;:25;;;274735:275;;;;274984:6;:25;;;274735:275;;;274728:282;;;274130:888;;;;;;;:::o;312990:2319::-;313393:27;313422:31;313466:51;313538:7;:18;;;-1:-1:-1;;;;;313520:74:0;;:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;313466:130;;313607:28;313657:7;:19;;;-1:-1:-1;;;;;313638:63:0;;:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;313607:96;;313752:7;:14;;;-1:-1:-1;;;;;313738:58:0;;313811:670;;;;;;;;313864:7;:13;;;-1:-1:-1;;;;;313811:670:0;;;;;313910:12;313811:670;;;;313961:26;:45;;;313811:670;;;;314043:26;:43;;;313811:670;;;;314130:7;:31;;;313811:670;;;;314209:7;:35;;;313811:670;;;;314285:20;313811:670;;;;314340:10;313811:670;;;;314389:26;:45;;;313811:670;;;;314460:5;313811:670;;;;;;;;:::i;:::-;;;;313738:754;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;313716:776;;314545:7;:14;;;-1:-1:-1;;;;;314531:62:0;;314608:682;;;;;;;;314661:7;:13;;;-1:-1:-1;;;;;314608:682:0;;;;;314707:12;314608:682;;;;314758:30;:49;;;314608:682;;;;314844:30;:47;;;314608:682;;;;314935:7;:31;;;314608:682;;;;315014:7;:35;;;314608:682;;;;315090:20;314608:682;;;;315145:10;314608:682;;;;315194:30;:49;;;314608:682;;;;315269:5;314608:682;;;;;;;;:::i;:::-;;;;314531:770;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;314505:796;;313455:1854;;312990:2319;;;;;;;;;;:::o;312202:780::-;312323:45;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;312323:45:0;312381:51;312453:10;-1:-1:-1;;;;;312435:52:0;;:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;312381:108;;312520:454;;;;;;;;312603:7;:31;;;312520:454;;;;312676:7;:29;;;312520:454;;;;312753:7;:35;;;312520:454;;;;312834:7;:33;;;312520:454;;;;312920:11;-1:-1:-1;;;;;312901:55:0;;:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;312520:454;;312500:474;312202:780;-1:-1:-1;;;;312202:780:0:o;315939:901::-;316145:72;;-1:-1:-1;;;316145:72:0;;-1:-1:-1;;;;;15758:55:1;;;316145:72:0;;;15740:74:1;316201:15:0;15830:18:1;;;15823:34;316100:6:0;;;;316145:48;;;;;15713:18:1;;316145:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;316119:98;;316230:37;316288:10;-1:-1:-1;;;;;316270:37:0;;316322:49;316386:6;316270:133;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;316424:13;;316443:27;;;;;;;;;;;;-1:-1:-1;;;316443:27:0;;;;316230:173;;-1:-1:-1;316416:55:0;;;;-1:-1:-1;;;316416:55:0;;;;;;;;:::i;:::-;;316504:328;316559:10;:24;;;316602:10;:21;;;316642:10;:19;;;316680:10;:28;;;316727:10;:22;;;316768:15;316802;316504:36;:328::i;:::-;316484:348;315939:901;-1:-1:-1;;;;;;;315939:901:0:o;281128:774::-;281224:19;281245:23;281270:11;281294:17;281314:15;281294:35;;281355:56;281426:60;281512:5;:16;;;-1:-1:-1;;;;;281500:47:0;;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;281593:16;;;;281636:11;;281581:78;;-1:-1:-1;;;281581:78:0;;-1:-1:-1;;;;;15758:55:1;;;281581:78:0;;;15740:74:1;15830:18;;;15823:34;;;281340:209:0;;-1:-1:-1;281340:209:0;;-1:-1:-1;281562:16:0;;281581:54;;;;;15713:18:1;;281581:78:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;281562:97;-1:-1:-1;281685:61:0;:18;281726:9;281562:97;281685:40;:61::i;:::-;281670:76;-1:-1:-1;281776:69:0;:22;281825:9;281836:8;281776:48;:69::i;:::-;281757:88;-1:-1:-1;281863:31:0;281757:88;281863:12;:31;:::i;:::-;281128:774;;;;-1:-1:-1;;;;;;281128:774:0:o;316848:909::-;317058:72;;-1:-1:-1;;;317058:72:0;;-1:-1:-1;;;;;15758:55:1;;;317058:72:0;;;15740:74:1;317114:15:0;15830:18:1;;;15823:34;317013:6:0;;;;317058:48;;;;;15713:18:1;;317058:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;317032:98;;317143:37;317201:10;-1:-1:-1;;;;;317183:37:0;;317235:49;317299:6;317183:133;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;317337:13;;317356:27;;;;;;;;;;;;-1:-1:-1;;;317356:27:0;;;;317143:173;;-1:-1:-1;317329:55:0;;;;-1:-1:-1;;;317329:55:0;;;;;;;;:::i;:::-;;317417:332;317476:10;:24;;;317519:10;:21;;;317559:10;:19;;;317597:10;:28;;;317644:10;:22;;;317685:15;317719;317417:40;:332::i;275026:738::-;275326:25;;275374:31;;;;;275428:24;;;;;275475:23;;;;275521:25;;;;275569;;;;275617:17;;;;275287:454;;275219:7;;275287:454;;275326:25;;275374:31;275617:17;275657:5;;275685;;275713:9;;275287:454;19515:19:1;;;19559:2;19550:12;;19543:28;;;;19596:2;19587:12;;19580:28;;;;19633:2;19624:12;;;19617:28;;;;19670:3;19661:13;;19654:29;;;;19708:3;19699:13;;19692:29;;;;19746:3;19737:13;;19730:29;19794:15;;-1:-1:-1;;19790:53:1;19784:3;19775:13;;19768:76;19869:3;19860:13;;19853:29;19907:3;19898:13;;19891:29;19945:3;19936:13;;19136:819;275287:454:0;;;;;;;;;;;;;275259:497;;;;;;275239:517;;275026:738;;;;;;:::o;227034:231::-;227112:7;227133:17;227152:18;227174:27;227185:4;227191:9;227174:10;:27::i;:::-;227132:69;;;;227212:18;227224:5;227212:11;:18::i;:::-;-1:-1:-1;227248:9:0;227034:231;-1:-1:-1;;;227034:231:0:o;287117:708::-;287415:15;287444:21;287467:24;287495:209;287527:17;287559:12;287586:21;287622:15;287652:16;287683:10;287495:17;:209::i;:::-;287443:261;;;;287728:89;287746:14;287792:24;:13;:22;:24::i;:::-;287762:27;:16;:25;:27::i;:::-;:54;;;;:::i;:::-;287728:17;:89::i;:::-;287717:100;287117:708;-1:-1:-1;;;;;;;;;;287117:708:0:o;259768:395::-;259944:6;260065:90;260085:58;260120:2;260124:18;260085:34;:58::i;:::-;260066:2;:16;;;:77;;;;:::i;:::-;260065:88;:90::i;:::-;259983:66;:55;260023:8;260001:2;:19;;;:30;;;;:::i;:::-;260033:4;259983:17;:55::i;:66::-;:172;;;;:::i;:::-;259963:192;259768:395;-1:-1:-1;;;;259768:395:0:o;260410:399::-;260590:6;260735:66;:55;260775:8;260753:2;:19;;;:30;;;;:::i;260735:66::-;260629:90;260649:58;260684:2;260688:18;260649:34;:58::i;:::-;260630:2;:16;;;:77;;;;:::i;288694:712::-;288996:15;289025:21;289048:24;289076:209;289108:17;289140:12;289167:21;289203:15;289233:16;289264:10;289076:17;:209::i;:::-;289024:261;;;;289309:89;289327:14;289370:27;:16;:25;:27::i;:::-;289343:24;:13;:22;:24::i;225485:747::-;225566:7;225575:12;225604:9;:16;225624:2;225604:22;225600:625;;225948:4;225933:20;;225927:27;225998:4;225983:20;;225977:27;226056:4;226041:20;;226035:27;225643:9;226027:36;226099:25;226110:4;226027:36;225927:27;225977;226099:10;:25::i;:::-;226092:32;;;;;;;;;225600:625;-1:-1:-1;226173:1:0;;-1:-1:-1;226177:35:0;225600:625;225485:747;;;;;:::o;223878:521::-;223956:20;223947:5;:29;;;;;;;;:::i;:::-;;223943:449;;223878:521;:::o;223943:449::-;224054:29;224045:5;:38;;;;;;;;:::i;:::-;;224041:351;;224100:34;;-1:-1:-1;;;224100:34:0;;20670:2:1;224100:34:0;;;20652:21:1;20709:2;20689:18;;;20682:30;20748:26;20728:18;;;20721:54;20792:18;;224100:34:0;20468:348:1;224041:351:0;224165:35;224156:5;:44;;;;;;;;:::i;:::-;;224152:240;;224217:41;;-1:-1:-1;;;224217:41:0;;21023:2:1;224217:41:0;;;21005:21:1;21062:2;21042:18;;;21035:30;21101:33;21081:18;;;21074:61;21152:18;;224217:41:0;20821:355:1;224152:240:0;224289:30;224280:5;:39;;;;;;;;:::i;:::-;;224276:116;;224336:44;;-1:-1:-1;;;224336:44:0;;21383:2:1;224336:44:0;;;21365:21:1;21422:2;21402:18;;;21395:30;21461:34;21441:18;;;21434:62;21532:4;21512:18;;;21505:32;21554:19;;224336:44:0;21181:398:1;224276:116:0;223878:521;:::o;290250:698::-;290512:21;290535:24;290600:17;290580:16;:37;;290619:58;;;;;;;;;;;;;;;;;290572:106;;;;;-1:-1:-1;;;290572:106:0;;;;;;;;:::i;:::-;-1:-1:-1;290707:147:0;290744:12;290771:21;290807:36;290826:17;290807:16;:36;:::i;:::-;290707:22;:147::i;:::-;290691:163;;290886:54;290912:15;290929:10;290886:25;:54::i;:::-;290867:73;;290250:698;;;;;;;;;:::o;97779:301::-;97835:6;97979:16;97962:5;:34;;97954:87;;;;-1:-1:-1;;;97954:87:0;;21919:2:1;97954:87:0;;;21901:21:1;21958:2;21938:18;;;21931:30;21997:34;21977:18;;;21970:62;22068:10;22048:18;;;22041:38;22096:19;;97954:87:0;21717:404:1;97954:87:0;-1:-1:-1;98066:5:0;97779:301::o;294137:530::-;294224:6;294243:20;294266:21;:10;:19;:21::i;:::-;294243:44;;294315:1;294304:8;:12;294300:360;;;294348:13;294337:8;:24;294333:141;;;294389:8;294382:15;;;;;294333:141;294445:13;-1:-1:-1;294438:20:0;;294300:360;294521:14;294522:13;294521:14;:::i;:::-;294510:8;:25;294506:143;;;294563:14;294564:13;294563:14;:::i;:::-;294556:21;;;;;294506:143;294625:8;294618:15;;;;;294506:143;294232:435;294137:530;;;;:::o;261062:497::-;261224:7;261313:238;261366:18;261403:2;:21;;;261462:2;:33;;;261443:2;:16;;;:52;;;;:::i;:::-;261514:2;:22;;;261313:34;:238::i;:::-;261264:33;;:287;;;;:::i;31829:114::-;31892:9;31934:1;31924:5;31928:1;31934;31924:5;:::i;:::-;31919:11;;:1;:11;:::i;:::-;31918:17;;;;:::i;228418:1477::-;228506:7;;229440:66;229427:79;;229423:163;;;-1:-1:-1;229539:1:0;;-1:-1:-1;229543:30:0;229523:51;;229423:163;229700:24;;;229683:14;229700:24;;;;;;;;;22808:25:1;;;22881:4;22869:17;;22849:18;;;22842:45;;;;22903:18;;;22896:34;;;22946:18;;;22939:34;;;229700:24:0;;22780:19:1;;229700:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;229700:24:0;;-1:-1:-1;;229700:24:0;;;-1:-1:-1;;;;;;;229739:20:0;;229735:103;;229792:1;229796:29;229776:50;;;;;;;229735:103;229858:6;229866:20;;-1:-1:-1;228418:1477:0;-1:-1:-1;;;;;228418:1477:0:o;291410:359::-;291577:7;291617:144;291703:43;291727:19;291703:21;:43;:::i;:::-;291617:8;;:67;:144::i;292117:286::-;292221:7;292341:54;292359:29;292373:15;292359:11;:29;:::i;261944:612::-;262166:7;262230:22;262208:18;:44;;262267:60;;;;;;;;;;;;;;;;;262186:152;;;;;-1:-1:-1;;;262186:152:0;;;;;;;;:::i;:::-;-1:-1:-1;262369:179:0;262489:43;262510:22;262489:18;:43;:::i;:::-;262466:67;;:19;:67;:::i;:::-;262369:13;;:78;:179::i;:::-;262349:199;261944:612;-1:-1:-1;;;;;261944:612:0:o;233098:656::-;233271:7;233291:39;233333:115;233365:32;12151:8;233333:17;:115::i;:::-;233291:157;;233459:18;233480:34;233502:5;233509:4;233480:21;:34::i;:::-;233459:55;;233525:16;233544:60;233566:31;233599:4;233544:21;:60::i;:::-;233525:79;;233615:25;233643:56;233660:10;233672:26;233689:8;233672:16;:26::i;:::-;233643:16;:56::i;:::-;233615:84;;233717:29;233728:17;233717:10;:29::i;235235:334::-;235414:7;235556:5;235454:99;235513:5;235520:32;235454:58;:99::i;:::-;:107;;;;:::i;236372:477::-;236459:7;;236483:17;236492:8;236483:6;:17;:::i;:::-;:21;236479:143;;;236599:11;236609:1;236599:11;;:::i;:::-;;;236479:143;236632:17;236652:29;236674:6;236652:21;:29::i;:::-;236632:49;;236692:19;236714:31;236736:8;236714:21;:31::i;:::-;236692:53;;236756:16;236775:40;236792:9;236803:11;236775:16;:40::i;:::-;236756:59;236372:477;-1:-1:-1;;;;;;236372:477:0:o;152186:154::-;152234:7;152276:51;152283:43;152288:1;152283:43;:3;:43::i;:::-;152276:5;:51::i;121423:2550::-;121482:7;121558:6;121537:18;;;;:27;;;121593:18;;;;:27;;;121635:19;;;121631:2330;;121671:9;121684:6;121671:19;121667:375;;-1:-1:-1;;121709:6:0;;;;;;;121705:168;;-1:-1:-1;;;;;;121728:38:0;;121724:42;;121717:49;;121705:168;-1:-1:-1;;121788:5:0;;;:43;-1:-1:-1;;;121788:43:0;121784:89;;-1:-1:-1;;;121840:5:0;;;121833:12;;121784:89;-1:-1:-1;;;;121870:3:0;-1:-1:-1;121863:10:0;;-1:-1:-1;121863:10:0;121667:375;-1:-1:-1;;;121908:38:0;;121950:1;121908:43;121904:126;;-1:-1:-1;;;;121960:3:0;-1:-1:-1;121953:10:0;;-1:-1:-1;121953:10:0;121904:126;-1:-1:-1;;;;;;121992:38:0;;121988:42;;121981:49;;121631:2330;122061:9;122074:6;122061:19;122057:1904;;-1:-1:-1;;;122099:38:0;;122141:1;122099:43;122095:126;;-1:-1:-1;;;;122151:3:0;-1:-1:-1;122144:10:0;;-1:-1:-1;122144:10:0;122095:126;-1:-1:-1;;;;;;122183:38:0;;122179:42;;122172:49;;122057:1904;-1:-1:-1;;;;;122269:11:0;;;;:44;122248:18;122328:14;;;122324:94;;122356:1;122344:13;;122324:94;;;-1:-1:-1;;;122373:45:0;122324:94;-1:-1:-1;;;;;122452:11:0;;;;:44;122431:18;122511:14;;;122507:94;;122539:1;122527:13;;122507:94;;;-1:-1:-1;;;122556:45:0;122507:94;122628:10;122614:24;;;;122653:10;122667:1;122653:15;122649:134;;-1:-1:-1;;;122689:5:0;;;122688:44;:95;;99856:34;122688:95;;;-1:-1:-1;;;122688:95:0;122681:102;;;;;;;;122649:134;122796:22;;;;122831:11;122870:59;122856:73;;;:217;;122963:59;122949:10;:73;;:124;;123042:31;123062:10;123042:18;:31::i;:::-;122856:217;;122949:124;123025:3;122856:217;;;122932:3;122856:217;122831:242;;123108:5;123102:3;123090:9;:15;:23;123086:727;;;123153:1;123141:13;;123180:1;123167:14;;123086:727;;;123221:5;123215:3;123203:9;:15;:23;123199:614;;;123270:5;123258:9;:17;123254:154;;;123313:9;123305:5;:17;123290:32;;;;;123254:154;;;123356:5;123344:9;:17;123340:68;;;123403:5;123391:9;:17;123376:32;;;;;123340:68;123433:1;123421:13;;123199:614;;;123474:5;123468:3;123456:9;:15;:23;123452:361;;;123506:6;123494:18;;123538:1;123525:14;;123452:361;;;123580:3;123574;:9;123570:122;;;123619:3;123613;:9;123598:24;;;;;123570:122;;;123650:3;123644;:9;123640:52;;;123689:3;123683;:9;123668:24;;;;;123640:52;-1:-1:-1;;;;;123707:44:0;;;;123796:5;123790:3;123778:9;:15;:23;123766:35;;123452:361;123939:10;123933:3;123920:9;:16;;123864:1;123860;:5;-1:-1:-1;;;123859:44:0;;;123850:54;;:86;;;:99;123832:119;;123825:126;;;;;;;;;122057:1904;121498:2470;;121423:2550;;;;:::o;237385:243::-;237442:7;237462:16;237481:27;237503:4;237481:21;:27::i;:::-;237462:46;;237519:17;237539:33;237556:5;237563:8;237539:16;:33::i;:::-;237519:53;;237590:30;237610:9;237590:19;:30::i;102449:462::-;102502:7;102541:1;102546;102541:6;102537:362;;-1:-1:-1;102565:1:0;;102449:462;-1:-1:-1;102449:462:0:o;102537:362::-;102609:1;102592:14;102637:27;102609:1;102637:18;:27::i;:::-;102623:41;;102685:3;102679;:9;102675:86;;;102707:3;102701;:9;102690:20;;;;;102675:86;;;102736:3;102730;:9;102726:35;;;102758:3;102752;:9;102741:20;;;;;102726:35;102825:5;:11;102840:3;102825:18;-1:-1:-1;;;;;102783:39:0;;;;:60;102863:26;;;;-1:-1:-1;;102449:462:0:o;125266:2866::-;125325:7;125401:6;125380:18;;;;:27;;;125436:18;;;;:27;;;125478:19;;;125474:2646;;125514:9;125527:6;125514:19;125510:100;;-1:-1:-1;;;;125542:3:0;-1:-1:-1;125535:10:0;;-1:-1:-1;125535:10:0;125474:2646;125630:9;125643:6;125630:19;125626:2494;;125666:38;;;:43;125662:142;;-1:-1:-1;;;;125718:3:0;-1:-1:-1;125711:10:0;;-1:-1:-1;125711:10:0;125662:142;-1:-1:-1;;;125761:5:0;;;-1:-1:-1;;;125760:44:0;125737:67;;125626:2494;-1:-1:-1;;;125824:38:0;;125866:1;125824:43;125820:2300;;-1:-1:-1;;;125884:38:0;;125926:1;125884:43;125880:146;;-1:-1:-1;;;;125936:3:0;-1:-1:-1;125929:10:0;;-1:-1:-1;125929:10:0;125880:146;-1:-1:-1;;;125983:5:0;;;-1:-1:-1;;;125982:44:0;-1:-1:-1;;;125962:64:0;125955:71;;125820:2300;-1:-1:-1;;;;;126074:11:0;;;;:44;126053:18;126133:14;;;126129:94;;126161:1;126149:13;;126129:94;;;-1:-1:-1;;;126178:45:0;126129:94;-1:-1:-1;;;;;126257:11:0;;;;:44;126236:18;126316:14;;;126312:356;;126349:15;;126345:206;;126381:10;126400:31;126420:10;126400:18;:31::i;:::-;126497:1;;-1:-1:-1;126394:3:0;:37;126513:24;;;-1:-1:-1;;126513:24:0;;126448:20;;;;;-1:-1:-1;126345:206:0;126312:356;;;-1:-1:-1;;;126604:44:0;126653:3;126603:53;126312:356;126706:10;126693;:23;;;;;:::i;:::-;;126680:36;;126731:10;126745:1;126731:15;126727:134;;-1:-1:-1;;;126767:5:0;;;126766:44;:95;;99856:34;126766:95;;126727:134;126896:30;126882:10;:44;;126874:53;;;;:::i;:::-;126940:11;126979:31;126965:10;:45;;:215;;127072:31;127058:10;:45;;:122;;127137:31;127123:10;:45;;:57;;127177:3;127058:122;;127123:57;127171:3;127058:122;;;127106:3;127058:122;126965:215;;;;;127013:31;127033:10;127013:18;:31::i;:::-;126940:240;;127215:9;127227:5;127215:17;127209:3;127197:9;:15;:35;127193:779;;;127271:6;127259:18;;127303:1;127290:14;;127193:779;;;127353:9;127338:3;127326:9;:15;127344:5;127326:23;:36;127322:650;;;127402:1;127390:13;;127429:1;127416:14;;127322:650;;;127479:9;127464:3;127452:9;:15;127470:5;127452:23;:36;127448:524;;;127540:9;127520;127532:5;127520:17;:29;127516:202;;;127599:9;127579;127591:5;127579:17;:29;127564:44;;;;;127516:202;;;127650:9;127630;127642:5;127630:17;:29;127626:92;;;127713:5;127701:9;127689;:21;:29;127674:44;;;;;127626:92;127745:1;127733:13;;127448:524;;;127797:3;127791;:9;127787:52;;;127836:3;127830;:9;127815:24;;;;;127787:52;-1:-1:-1;;;;;127854:44:0;;;;127951:9;127937:3;127925:9;:15;127943:5;127925:23;:35;127913:47;;127448:524;128098:10;128092:3;128079:9;:16;;128023:1;128019;:5;-1:-1:-1;;;128018:44:0;;;128009:54;;:86;;;:99;127991:119;;127984:126;;;;;;;;;133657:18399;133707:7;-1:-1:-1;;;133759:11:0;;;;:48;;;;133857:6;133836:18;;;;:27;;;-1:-1:-1;;;;;133893:44:0;;133952:19;;:38;;;;-1:-1:-1;133975:15:0;;;133952:38;133948:18096;;;-1:-1:-1;;;;133999:3:0;133657:18399;-1:-1:-1;;;;133657:18399:0:o;133948:18096::-;134032:5;134020:9;:17;134016:18028;;;134055:9;:45;;-1:-1:-1;;;134055:45:0;;;99856:34;134048:52;133657:18399;-1:-1:-1;;;;;133657:18399:0:o;134016:18028::-;134130:5;134118:9;:17;134114:17930;;;-1:-1:-1;134146:41:0;;133657:18399;-1:-1:-1;;;;133657:18399:0:o;134114:17930::-;134216:9;134229:1;134216:14;134212:94;;134244:1;134232:13;;134212:94;;;-1:-1:-1;;;134261:45:0;134212:94;134335:5;134323:9;:17;134319:148;;;-1:-1:-1;;134368:17:0;;134353:32;134319:148;;;134417:5;134405:9;:17;134401:66;;;134450:5;:17;;;134435:32;134401:66;134484:9;:64;;;;;134510:38;134497:10;:51;134484:64;134480:101;;;-1:-1:-1;99856:34:0;;133657:18399;-1:-1:-1;;;;133657:18399:0:o;134480:101::-;134599:9;134598:10;:65;;;;;134625:38;134612:10;:51;134598:65;134594:106;;;-1:-1:-1;;;;134683:17:0;133657:18399;-1:-1:-1;;;;133657:18399:0:o;134594:106::-;134780:34;134766:48;;;134752:3;134738:17;134829:9;:28;;;;-1:-1:-1;134842:15:0;;;134829:28;134825:115;;;134885:11;;;134927:1;134909:19;134825:115;-1:-1:-1;;;135027:47:0;;;:51;135023:135;;135116:35;135098:53;135155:3;135098:60;135023:135;135186:34;135173:47;;:51;135169:135;;135262:35;135244:53;135301:3;135244:60;135169:135;135332:34;135319:47;;:51;135315:135;;135408:35;135390:53;135447:3;135390:60;135315:135;135478:34;135465:47;;:51;135461:135;;135554:35;135536:53;135593:3;135536:60;135461:135;135624:33;135611:46;;:50;135607:134;;135699:35;135681:53;135738:3;135681:60;135607:134;135769:33;135756:46;;:50;135752:134;;135844:35;135826:53;135883:3;135826:60;135752:134;135914:33;135901:46;;:50;135897:134;;135989:35;135971:53;136028:3;135971:60;135897:134;136059:33;136046:46;;:50;136042:134;;136134:35;136116:53;136173:3;136116:60;136042:134;136204:32;136191:45;;:49;136187:133;;136278:35;136260:53;136317:3;136260:60;136187:133;136348:32;136335:45;;:49;136331:133;;136422:35;136404:53;136461:3;136404:60;136331:133;136492:32;136479:45;;:49;136475:133;;136566:35;136548:53;136605:3;136548:60;136475:133;136636:32;136623:45;;:49;136619:133;;136710:35;136692:53;136749:3;136692:60;136619:133;136780:31;136767:44;;:48;136763:132;;136853:35;136835:53;136892:3;136835:60;136763:132;136923:31;136910:44;;:48;136906:132;;136996:35;136978:53;137035:3;136978:60;136906:132;137066:31;137053:44;;:48;137049:132;;137139:35;137121:53;137178:3;137121:60;137049:132;-1:-1:-1;;;137196:44:0;;:48;137192:132;;137282:35;137264:53;137321:3;137264:60;137192:132;137352:30;137339:43;;:47;137335:131;;137424:35;137406:53;137463:3;137406:60;137335:131;137494:30;137481:43;;:47;137477:131;;137566:35;137548:53;137605:3;137548:60;137477:131;137636:30;137623:43;;:47;137619:131;;137708:35;137690:53;137747:3;137690:60;137619:131;137778:30;137765:43;;:47;137761:131;;137850:35;137832:53;137889:3;137832:60;137761:131;137920:29;137907:42;;:46;137903:130;;137991:35;137973:53;138030:3;137973:60;137903:130;138061:29;138048:42;;:46;138044:130;;138132:35;138114:53;138171:3;138114:60;138044:130;138202:29;138189:42;;:46;138185:130;;138273:35;138255:53;138312:3;138255:60;138185:130;138343:29;138330:42;;:46;138326:130;;138414:35;138396:53;138453:3;138396:60;138326:130;138484:28;138471:41;;:45;138467:129;;138554:35;138536:53;138593:3;138536:60;138467:129;138624:28;138611:41;;:45;138607:129;;138694:35;138676:53;138733:3;138676:60;138607:129;138764:28;138751:41;;:45;138747:129;;138834:35;138816:53;138873:3;138816:60;138747:129;138904:28;138891:41;;:45;138887:129;;138974:35;138956:53;139013:3;138956:60;138887:129;139044:27;139031:40;;:44;139027:128;;139113:35;139095:53;139152:3;139095:60;139027:128;139183:27;139170:40;;:44;139166:128;;139252:35;139234:53;139291:3;139234:60;139166:128;139322:27;139309:40;;:44;139305:128;;139391:35;139373:53;139430:3;139373:60;139305:128;139461:27;139448:40;;:44;139444:128;;139530:35;139512:53;139569:3;139512:60;139444:128;139600:26;139587:39;;:43;139583:127;;139668:35;139650:53;139707:3;139650:60;139583:127;139738:26;139725:39;;:43;139721:127;;139806:35;139788:53;139845:3;139788:60;139721:127;139876:26;139863:39;;:43;139859:127;;139944:35;139926:53;139983:3;139926:60;139859:127;140014:26;140001:39;;:43;139997:127;;140082:35;140064:53;140121:3;140064:60;139997:127;140152:25;140139:38;;:42;140135:126;;140219:35;140201:53;140258:3;140201:60;140135:126;140289:25;140276:38;;:42;140272:126;;140356:35;140338:53;140395:3;140338:60;140272:126;140426:25;140413:38;;:42;140409:126;;140493:35;140475:53;140532:3;140475:60;140409:126;140563:25;140550:38;;:42;140546:126;;140630:35;140612:53;140669:3;140612:60;140546:126;140700:24;140687:37;;:41;140683:125;;140766:35;140748:53;140805:3;140748:60;140683:125;140836:24;140823:37;;:41;140819:125;;140902:35;140884:53;140941:3;140884:60;140819:125;140972:24;140959:37;;:41;140955:125;;141038:35;141020:53;141077:3;141020:60;140955:125;141108:24;141095:37;;:41;141091:125;;141174:35;141156:53;141213:3;141156:60;141091:125;141244:23;141231:36;;:40;141227:124;;141309:35;141291:53;141348:3;141291:60;141227:124;141379:23;141366:36;;:40;141362:124;;141444:35;141426:53;141483:3;141426:60;141362:124;141514:23;141501:36;;:40;141497:124;;141579:35;141561:53;141618:3;141561:60;141497:124;141649:23;141636:36;;:40;141632:124;;141714:35;141696:53;141753:3;141696:60;141632:124;141784:22;141771:35;;:39;141767:123;;141848:35;141830:53;141887:3;141830:60;141767:123;141918:22;141905:35;;:39;141901:123;;141982:35;141964:53;142021:3;141964:60;141901:123;142052:22;142039:35;;:39;142035:123;;142116:35;142098:53;142155:3;142098:60;142035:123;142186:22;142173:35;;:39;142169:123;;142250:35;142232:53;142289:3;142232:60;142169:123;142320:21;142307:34;;:38;142303:122;;142383:35;142365:53;142422:3;142365:60;142303:122;142453:21;142440:34;;:38;142436:122;;142516:35;142498:53;142555:3;142498:60;142436:122;142586:21;142573:34;;:38;142569:122;;142649:35;142631:53;142688:3;142631:60;142569:122;142719:21;142706:34;;:38;142702:122;;142782:35;142764:53;142821:3;142764:60;142702:122;142852:20;142839:33;;:37;142835:121;;142914:35;142896:53;142953:3;142896:60;142835:121;142984:20;142971:33;;:37;142967:121;;143046:35;143028:53;143085:3;143028:60;142967:121;143116:20;143103:33;;:37;143099:121;;143178:35;143160:53;143217:3;143160:60;143099:121;143248:20;143235:33;;:37;143231:121;;143310:35;143292:53;143349:3;143292:60;143231:121;143380:19;143367:32;;:36;143363:120;;143441:35;143423:53;143480:3;143423:60;143363:120;143511:19;143498:32;;:36;143494:120;;143572:35;143554:53;143611:3;143554:60;143494:120;143642:19;143629:32;;:36;143625:120;;143703:35;143685:53;143742:3;143685:60;143625:120;143773:19;143760:32;;:36;143756:120;;143834:35;143816:53;143873:3;143816:60;143756:120;143904:18;143891:31;;:35;143887:119;;143964:35;143946:53;144003:3;143946:60;143887:119;144034:18;144021:31;;:35;144017:119;;144094:35;144076:53;144133:3;144076:60;144017:119;144164:18;144151:31;;:35;144147:119;;144224:35;144206:53;144263:3;144206:60;144147:119;144294:18;144281:31;;:35;144277:119;;144354:35;144336:53;144393:3;144336:60;144277:119;144424:17;144411:30;;:34;144407:118;;144483:35;144465:53;144522:3;144465:60;144407:118;144553:17;144540:30;;:34;144536:118;;144612:35;144594:53;144651:3;144594:60;144536:118;144682:17;144669:30;;:34;144665:118;;144741:35;144723:53;144780:3;144723:60;144665:118;144811:17;144798:30;;:34;144794:118;;144870:35;144852:53;144909:3;144852:60;144794:118;144940:16;144927:29;;:33;144923:117;;144998:35;144980:53;145037:3;144980:60;144923:117;145068:16;145055:29;;:33;145051:117;;145126:35;145108:53;145165:3;145108:60;145051:117;145196:16;145183:29;;:33;145179:117;;145254:35;145236:53;145293:3;145236:60;145179:117;145324:16;145311:29;;:33;145307:117;;145382:35;145364:53;145421:3;145364:60;145307:117;145452:15;145439:28;;:32;145435:116;;145509:35;145491:53;145548:3;145491:60;145435:116;145579:15;145566:28;;:32;145562:116;;145636:35;145618:53;145675:3;145618:60;145562:116;145706:15;145693:28;;:32;145689:116;;145763:35;145745:53;145802:3;145745:60;145689:116;145833:15;145820:28;;:32;145816:116;;145890:35;145872:53;145929:3;145872:60;145816:116;145960:14;145947:27;;:31;145943:115;;146016:35;145998:53;146055:3;145998:60;145943:115;146086:14;146073:27;;:31;146069:115;;146142:35;146124:53;146181:3;146124:60;146069:115;146212:14;146199:27;;:31;146195:115;;146268:35;146250:53;146307:3;146250:60;146195:115;146338:14;146325:27;;:31;146321:115;;146394:35;146376:53;146433:3;146376:60;146321:115;146464:13;146451:26;;:30;146447:114;;146519:35;146501:53;146558:3;146501:60;146447:114;146589:13;146576:26;;:30;146572:114;;146644:35;146626:53;146683:3;146626:60;146572:114;146714:13;146701:26;;:30;146697:114;;146769:35;146751:53;146808:3;146751:60;146697:114;146839:13;146826:26;;:30;146822:114;;146894:35;146876:53;146933:3;146876:60;146822:114;146964:12;146951:25;;:29;146947:113;;147018:35;147000:53;147057:3;147000:60;146947:113;147088:12;147075:25;;:29;147071:113;;147142:35;147124:53;147181:3;147124:60;147071:113;147212:12;147199:25;;:29;147195:113;;147266:35;147248:53;147305:3;147248:60;147195:113;147336:12;147323:25;;:29;147319:113;;147390:35;147372:53;147429:3;147372:60;147319:113;147460:11;147447:24;;:28;147443:112;;147513:35;147495:53;147552:3;147495:60;147443:112;147583:11;147570:24;;:28;147566:112;;147636:35;147618:53;147675:3;147618:60;147566:112;147706:11;147693:24;;:28;147689:112;;147759:35;147741:53;147798:3;147741:60;147689:112;147829:11;147816:24;;:28;147812:112;;147882:35;147864:53;147921:3;147864:60;147812:112;147952:10;147939:23;;:27;147935:111;;148004:35;147986:53;148043:3;147986:60;147935:111;148074:10;148061:23;;:27;148057:111;;148126:35;148108:53;148165:3;148108:60;148057:111;148196:10;148183:23;;:27;148179:111;;148248:35;148230:53;148287:3;148230:60;148179:111;148318:10;148305:23;;:27;148301:111;;148370:35;148352:53;148409:3;148352:60;148301:111;148440:9;148427:22;;:26;148423:110;;148491:35;148473:53;148530:3;148473:60;148423:110;148561:9;148548:22;;:26;148544:110;;148612:35;148594:53;148651:3;148594:60;148544:110;148682:9;148669:22;;:26;148665:110;;148733:35;148715:53;148772:3;148715:60;148665:110;148803:9;148790:22;;:26;148786:110;;148854:35;148836:53;148893:3;148836:60;148786:110;148924:8;148911:21;;:25;148907:109;;148974:35;148956:53;149013:3;148956:60;148907:109;149044:8;149031:21;;:25;149027:109;;149094:35;149076:53;149133:3;149076:60;149027:109;149164:8;149151:21;;:25;149147:109;;149214:35;149196:53;149253:3;149196:60;149147:109;149284:8;149271:21;;:25;149267:109;;149334:35;149316:53;149373:3;149316:60;149267:109;149404:7;149391:20;;:24;149387:108;;149453:35;149435:53;149492:3;149435:60;149387:108;149523:7;149510:20;;:24;149506:108;;149572:35;149554:53;149611:3;149554:60;149506:108;149642:7;149629:20;;:24;149625:108;;149691:35;149673:53;149730:3;149673:60;149625:108;149761:7;149748:20;;:24;149744:108;;149810:35;149792:53;149849:3;149792:60;149744:108;149880:6;149867:19;;:23;149863:107;;149928:35;149910:53;149967:3;149910:60;149863:107;149998:6;149985:19;;:23;149981:107;;150046:35;150028:53;150085:3;150028:60;149981:107;150116:6;150103:19;;:23;150099:107;;150164:35;150146:53;150203:3;150146:60;150099:107;150234:6;150221:19;;:23;150217:107;;150282:35;150264:53;150321:3;150264:60;150217:107;150352:5;150339:18;;:22;150335:106;;150399:35;150381:53;150438:3;150381:60;150335:106;150469:5;150456:18;;:22;150452:106;;150516:35;150498:53;150555:3;150498:60;150452:106;150586:5;150573:18;;:22;150569:106;;150633:35;150615:53;150672:3;150615:60;150569:106;150703:5;150690:18;;:22;150686:106;;150750:35;150732:53;150789:3;150732:60;150686:106;150820:4;150807:17;;:21;150803:105;;150866:35;150848:53;150905:3;150848:60;150803:105;150936:4;150923:17;;:21;150919:105;;150982:35;150964:53;151021:3;150964:60;150919:105;151052:4;151039:17;;:21;151035:105;;151098:35;151080:53;151137:3;151080:60;151035:105;151168:4;151155:17;;:21;151151:105;;151214:35;151196:53;151253:3;151196:60;151151:105;151284:3;151271:16;;:20;151267:104;;151329:35;151311:53;151368:3;151311:60;151267:104;151399:3;151386:16;;:20;151382:104;;151444:35;151426:53;151483:3;151426:60;151382:104;151504:9;151499:457;;151565:2;151546:15;:21;;-1:-1:-1;;;;;151546:54:0;151528:72;;151631:6;151613:24;;;;151499:457;;;151677:6;151659:14;:24;151655:301;;151735:2;151716:15;:21;;-1:-1:-1;;;;;151716:54:0;151698:72;;151809:14;151800:6;:23;151783:40;;151655:301;;;151943:1;;-1:-1:-1;;151891:22:0;151872:41;151655:301;152011:3;151993:21;;;;:39;151975:59;;;133657:18399;-1:-1:-1;;;;;133657:18399:0:o;152580:646::-;152642:7;152690:1;152686;:5;152677:15;;;;;;152703:14;152741:35;152736:1;:40;152732:75;;152786:3;152780:9;;;;152791:13;152732:75;152824:19;152819:1;:24;152815:57;;152853:2;152847:8;;;;152857:12;152815:57;152889:11;152884:1;:16;152880:49;;152910:2;152904:8;;;;152914:12;152880:49;152946:7;152941:1;:12;152937:45;;152963:2;152957:8;;;;152967:12;152937:45;152999:5;152994:1;:10;152990:41;;153014:1;153008:7;;;;153017:11;152990:41;153048:4;153043:1;:9;153039:40;;153062:1;153056:7;;;;153065:11;153039:40;153096:3;153091:1;:8;153087:39;;153109:1;153103:7;;;;153112:11;153087:39;153143:3;153138:1;:8;153134:25;;153158:1;153148:11;153207:6;152580:646;-1:-1:-1;;152580:646:0:o;103319:600::-;103370:7;103445:6;103424:18;;;;:27;103477:5;103466:16;;103462:30;;;-1:-1:-1;103491:1:0;;103319:600;-1:-1:-1;;103319:600:0:o;103462:30::-;-1:-1:-1;;;103525:11:0;;;;:48;103516:58;;;;;;103618:5;103606:8;:17;;103597:27;;;;;;-1:-1:-1;;;;;;;;103671:11:0;;;;103662:54;:97;103785:5;103774:16;;103770:112;;;103803:5;:16;;;103792:27;103770:112;;;103848:5;103837:8;:16;103833:49;;;-1:-1:-1;;103866:16:0;;103855:27;103900:6;103319:600;-1:-1:-1;;;103319:600:0:o;14:154:1:-;-1:-1:-1;;;;;93:5:1;89:54;82:5;79:65;69:93;;158:1;155;148:12;173:108;255:1;248:5;245:12;235:40;;271:1;268;261:12;286:169;359:5;404:3;395:6;390:3;386:16;382:26;379:46;;;421:1;418;411:12;379:46;-1:-1:-1;443:6:1;286:169;-1:-1:-1;286:169:1:o;460:1029::-;648:6;656;664;672;680;733:3;721:9;712:7;708:23;704:33;701:53;;;750:1;747;740:12;701:53;789:9;776:23;808:31;833:5;808:31;:::i;:::-;858:5;-1:-1:-1;915:2:1;900:18;;887:32;928:40;887:32;928:40;:::i;:::-;987:7;-1:-1:-1;1041:2:1;1026:18;;1013:32;;-1:-1:-1;1096:2:1;1081:18;;1068:32;1119:18;1149:14;;;1146:34;;;1176:1;1173;1166:12;1146:34;1199:80;1271:7;1262:6;1251:9;1247:22;1199:80;:::i;:::-;1189:90;;1332:3;1321:9;1317:19;1304:33;1288:49;;1362:2;1352:8;1349:16;1346:36;;;1378:1;1375;1368:12;1346:36;;1401:82;1475:7;1464:8;1453:9;1449:24;1401:82;:::i;:::-;1391:92;;;460:1029;;;;;;;;:::o;2110:525::-;2196:6;2204;2212;2220;2273:3;2261:9;2252:7;2248:23;2244:33;2241:53;;;2290:1;2287;2280:12;2241:53;2329:9;2316:23;2348:31;2373:5;2348:31;:::i;:::-;2398:5;-1:-1:-1;2455:2:1;2440:18;;2427:32;2468:33;2427:32;2468:33;:::i;:::-;2110:525;;2520:7;;-1:-1:-1;;;;2574:2:1;2559:18;;2546:32;;2625:2;2610:18;2597:32;;2110:525::o;2640:1939::-;2864:4;2893:2;2933;2922:9;2918:18;2963:6;2952:9;2945:25;2989:2;3027;3022;3011:9;3007:18;3000:30;3050:6;3085;3079:13;3116:6;3108;3101:22;3142:2;3132:12;;3175:2;3164:9;3160:18;3153:25;;3213:2;3205:6;3201:15;3234:1;3244:1309;3258:6;3255:1;3252:13;3244:1309;;;3317:13;;3355:9;;3343:22;;3404:11;;;3398:18;-1:-1:-1;;;;;1813:54:1;;;3462:12;;;1801:67;3516:11;;;3510:18;1813:54;3576:12;;;1801:67;3629:11;;;3623:18;3609:12;;;3602:40;3665:4;3709:11;;;3703:18;3689:12;;;3682:40;3745:4;3789:11;;;3783:18;3769:12;;;3762:40;3825:4;3869:11;;;3863:18;3849:12;;;3842:40;3905:4;3949:11;;;3943:18;3929:12;;;3922:40;3985:6;4031:11;;;4025:18;4011:12;;;4004:40;4068:6;4115:12;;;4109:19;4094:13;;;4087:42;4153:6;4200:12;;;4194:19;4179:13;;;4172:42;4238:6;4285:12;;;4279:19;4264:13;;;4257:42;4323:6;4370:12;;;4364:19;4349:13;;;4342:42;4408:6;4455:12;;;4449:19;4434:13;;;4427:42;4498:6;4489:16;;;;4528:15;;;;3280:1;3273:9;3244:1309;;;-1:-1:-1;4570:3:1;;2640:1939;-1:-1:-1;;;;;;;;;2640:1939:1:o;4584:247::-;4643:6;4696:2;4684:9;4675:7;4671:23;4667:32;4664:52;;;4712:1;4709;4702:12;4664:52;4751:9;4738:23;4770:31;4795:5;4770:31;:::i;5368:315::-;5436:6;5444;5497:2;5485:9;5476:7;5472:23;5468:32;5465:52;;;5513:1;5510;5503:12;5465:52;5552:9;5539:23;5571:31;5596:5;5571:31;:::i;:::-;5621:5;5673:2;5658:18;;;;5645:32;;-1:-1:-1;;;5368:315:1:o;6750:548::-;6862:4;6891:2;6920;6909:9;6902:21;6952:6;6946:13;6995:6;6990:2;6979:9;6975:18;6968:34;7020:1;7030:140;7044:6;7041:1;7038:13;7030:140;;;7139:14;;;7135:23;;7129:30;7105:17;;;7124:2;7101:26;7094:66;7059:10;;7030:140;;;7034:3;7219:1;7214:2;7205:6;7194:9;7190:22;7186:31;7179:42;7289:2;7282;7278:7;7273:2;7265:6;7261:15;7257:29;7246:9;7242:45;7238:54;7230:62;;;;6750:548;;;;:::o;7303:306::-;7391:6;7399;7407;7460:2;7448:9;7439:7;7435:23;7431:32;7428:52;;;7476:1;7473;7466:12;7428:52;7505:9;7499:16;7489:26;;7555:2;7544:9;7540:18;7534:25;7524:35;;7599:2;7588:9;7584:18;7578:25;7568:35;;7303:306;;;;;:::o;7614:184::-;-1:-1:-1;;;7663:1:1;7656:88;7763:4;7760:1;7753:15;7787:4;7784:1;7777:15;7803:184;-1:-1:-1;;;7852:1:1;7845:88;7952:4;7949:1;7942:15;7976:4;7973:1;7966:15;7992:255;8064:2;8058:9;8106:6;8094:19;;8143:18;8128:34;;8164:22;;;8125:62;8122:88;;;8190:18;;:::i;:::-;8226:2;8219:22;7992:255;:::o;8252:::-;8324:2;8318:9;8366:6;8354:19;;8403:18;8388:34;;8424:22;;;8385:62;8382:88;;;8450:18;;:::i;8512:252::-;8584:2;8578:9;8626:3;8614:16;;8660:18;8645:34;;8681:22;;;8642:62;8639:88;;;8707:18;;:::i;8769:275::-;8840:2;8834:9;8905:2;8886:13;;-1:-1:-1;;8882:27:1;8870:40;;8940:18;8925:34;;8961:22;;;8922:62;8919:88;;;8987:18;;:::i;:::-;9023:2;9016:22;8769:275;;-1:-1:-1;8769:275:1:o;9049:530::-;9091:5;9144:3;9137:4;9129:6;9125:17;9121:27;9111:55;;9162:1;9159;9152:12;9111:55;9198:6;9185:20;9224:18;9220:2;9217:26;9214:52;;;9246:18;;:::i;:::-;9290:55;9333:2;9314:13;;-1:-1:-1;;9310:27:1;9339:4;9306:38;9290:55;:::i;:::-;9370:2;9361:7;9354:19;9416:3;9409:4;9404:2;9396:6;9392:15;9388:26;9385:35;9382:55;;;9433:1;9430;9423:12;9382:55;9498:2;9491:4;9483:6;9479:17;9472:4;9463:7;9459:18;9446:55;9546:1;9521:16;;;9539:4;9517:27;9510:38;;;;9525:7;9049:530;-1:-1:-1;;;9049:530:1:o;9584:920::-;9712:9;9771:6;9763:5;9747:14;9743:26;9739:39;9736:59;;;9791:1;9788;9781:12;9736:59;9819:22;;:::i;:::-;9879:5;9866:19;9857:7;9850:36;9944:2;9937:5;9933:14;9920:28;9915:2;9906:7;9902:16;9895:54;10007:2;10000:5;9996:14;9983:28;9978:2;9969:7;9965:16;9958:54;10070:2;10063:5;10059:14;10046:28;10041:2;10032:7;10028:16;10021:54;10134:3;10127:5;10123:15;10110:29;10104:3;10095:7;10091:17;10084:56;10199:3;10192:5;10188:15;10175:29;10169:3;10160:7;10156:17;10149:56;10264:3;10257:5;10253:15;10240:29;10234:3;10225:7;10221:17;10214:56;10317:3;10310:5;10306:15;10293:29;10345:18;10337:6;10334:30;10331:50;;;10377:1;10374;10367:12;10331:50;10416:52;10453:14;10444:6;10437:5;10433:18;10416:52;:::i;:::-;10410:3;10397:17;;10390:79;-1:-1:-1;10401:7:1;9584:920;-1:-1:-1;;9584:920:1:o;11154:138::-;11233:13;;11255:31;11233:13;11255:31;:::i;11297:2356::-;11428:6;11436;11467:2;11510;11498:9;11489:7;11485:23;11481:32;11478:52;;;11526:1;11523;11516:12;11478:52;11555:9;11549:16;11539:26;;11584:2;11630;11619:9;11615:18;11609:25;11653:18;11694:2;11686:6;11683:14;11680:34;;;11710:1;11707;11700:12;11680:34;11748:6;11737:9;11733:22;11723:32;;11793:7;11786:4;11782:2;11778:13;11774:27;11764:55;;11815:1;11812;11805:12;11764:55;11844:2;11838:9;11866:2;11862;11859:10;11856:36;;;11872:18;;:::i;:::-;11912:36;11944:2;11939;11936:1;11932:10;11928:19;11912:36;:::i;:::-;11982:15;;;12013:12;;;;-1:-1:-1;12044:6:1;12085:11;;;12077:20;;12073:29;;;12114:19;;;12111:39;;;12146:1;12143;12136:12;12111:39;12170:11;;;;12190:1433;12206:6;12201:3;12198:15;12190:1433;;;12286:2;12280:3;12271:7;12267:17;12263:26;12260:116;;;12330:1;12359:2;12355;12348:14;12260:116;12402:22;;:::i;:::-;12457:3;12451:10;12444:5;12437:25;12498:43;12537:2;12532:3;12528:12;12498:43;:::i;:::-;12493:2;12486:5;12482:14;12475:67;12578:43;12617:2;12612:3;12608:12;12578:43;:::i;:::-;12562:14;;;12555:67;12645:2;12689:12;;;12683:19;12667:14;;;12660:43;12726:3;12771:12;;;12765:19;12749:14;;;12742:43;12809:3;12855:13;;;12849:20;12832:15;;;12825:45;12894:3;12940:13;;;12934:20;12917:15;;;12910:45;12979:3;13025:13;;;13019:20;13002:15;;;12995:45;13064:3;13110:13;;;13104:20;13087:15;;;13080:45;13149:3;13195:13;;;13189:20;13172:15;;;13165:45;13234:3;13280:13;;;13274:20;13257:15;;;13250:45;13319:3;13365:13;;;13359:20;13342:15;;;13335:45;13404:3;13450:13;;;13444:20;13427:15;;;13420:45;13489:3;13535:13;;;13529:20;13512:15;;;13505:45;13563:18;;12223:12;;;;13601;;;;12190:1433;;;12194:3;13642:5;13632:15;;;;;;;;11297:2356;;;;;:::o;13658:636::-;13768:6;13821:3;13809:9;13800:7;13796:23;13792:33;13789:53;;;13838:1;13835;13828:12;13789:53;13871:2;13865:9;13913:3;13905:6;13901:16;13983:6;13971:10;13968:22;13947:18;13935:10;13932:34;13929:62;13926:88;;;13994:18;;:::i;:::-;14034:10;14030:2;14023:22;;14075:9;14069:16;14061:6;14054:32;14140:2;14129:9;14125:18;14119:25;14114:2;14106:6;14102:15;14095:50;14199:2;14188:9;14184:18;14178:25;14173:2;14165:6;14161:15;14154:50;14258:2;14247:9;14243:18;14237:25;14232:2;14224:6;14220:15;14213:50;14282:6;14272:16;;;13658:636;;;;:::o;14299:184::-;14369:6;14422:2;14410:9;14401:7;14397:23;14393:32;14390:52;;;14438:1;14435;14428:12;14390:52;-1:-1:-1;14461:16:1;;14299:184;-1:-1:-1;14299:184:1:o;14488:140::-;14569:1;14562:5;14559:12;14549:46;;14575:18;;:::i;:::-;14604;;14488:140::o;14633:928::-;14861:13;;-1:-1:-1;;;;;1813:54:1;1801:67;;14829:3;14814:19;;14942:4;14934:6;14930:17;14924:24;14917:4;14906:9;14902:20;14895:54;15005:4;14997:6;14993:17;14987:24;14980:4;14969:9;14965:20;14958:54;15068:4;15060:6;15056:17;15050:24;15043:4;15032:9;15028:20;15021:54;15131:4;15123:6;15119:17;15113:24;15106:4;15095:9;15091:20;15084:54;15194:4;15186:6;15182:17;15176:24;15169:4;15158:9;15154:20;15147:54;15257:4;15249:6;15245:17;15239:24;15232:4;15221:9;15217:20;15210:54;15320:4;15312:6;15308:17;15302:24;15295:4;15284:9;15280:20;15273:54;15346:6;15406:2;15398:6;15394:15;15388:22;15383:2;15372:9;15368:18;15361:50;;15430:6;15483:2;15475:6;15471:15;15465:22;15496:59;15551:2;15540:9;15536:18;15522:12;15496:59;:::i;15868:320::-;16046:2;16031:18;;16079:1;16068:13;;16058:47;;16085:18;;:::i;:::-;16114:25;;;16170:2;16155:18;16148:34;15868:320;:::o;16193:152::-;16279:13;;16301:38;16279:13;16301:38;:::i;16350:158::-;16440:13;;16482:1;16472:12;;16462:40;;16498:1;16495;16488:12;16513:1140;16606:6;16659:3;16647:9;16638:7;16634:23;16630:33;16627:53;;;16676:1;16673;16666:12;16627:53;16702:22;;:::i;:::-;16753:9;16747:16;16740:5;16733:31;16796:49;16841:2;16830:9;16826:18;16796:49;:::i;:::-;16791:2;16784:5;16780:14;16773:73;16899:2;16888:9;16884:18;16878:25;16873:2;16866:5;16862:14;16855:49;16936:56;16988:2;16977:9;16973:18;16936:56;:::i;:::-;16931:2;16924:5;16920:14;16913:80;17026:61;17082:3;17071:9;17067:19;17026:61;:::i;:::-;17020:3;17013:5;17009:15;17002:86;17142:3;17131:9;17127:19;17121:26;17115:3;17108:5;17104:15;17097:51;17202:3;17191:9;17187:19;17181:26;17175:3;17168:5;17164:15;17157:51;17262:3;17251:9;17247:19;17241:26;17235:3;17228:5;17224:15;17217:51;17287:3;17343:2;17332:9;17328:18;17322:25;17317:2;17310:5;17306:14;17299:49;;17367:3;17423:2;17412:9;17408:18;17402:25;17397:2;17390:5;17386:14;17379:49;;17447:3;17503:2;17492:9;17488:18;17482:25;17477:2;17470:5;17466:14;17459:49;;17527:3;17562:60;17618:2;17607:9;17603:18;17562:60;:::i;:::-;17546:14;;;17539:84;17550:5;16513:1140;-1:-1:-1;;;16513:1140:1:o;17658:655::-;17730:5;17778:4;17766:9;17761:3;17757:19;17753:30;17750:50;;;17796:1;17793;17786:12;17750:50;17829:2;17823:9;17871:4;17863:6;17859:17;17942:6;17930:10;17927:22;17906:18;17894:10;17891:34;17888:62;17885:88;;;17953:18;;:::i;:::-;17993:10;17989:2;17982:22;;18022:6;18013:15;;18058:9;18052:16;18044:6;18037:32;18123:2;18112:9;18108:18;18102:25;18097:2;18089:6;18085:15;18078:50;18182:2;18171:9;18167:18;18161:25;18156:2;18148:6;18144:15;18137:50;18241:2;18230:9;18226:18;18220:25;18215:2;18207:6;18203:15;18196:50;18301:3;18290:9;18286:19;18280:26;18274:3;18266:6;18262:16;18255:52;;17658:655;;;;:::o;18318:403::-;18459:6;18467;18520:3;18508:9;18499:7;18495:23;18491:33;18488:53;;;18537:1;18534;18527:12;18488:53;18560:63;18615:7;18604:9;18560:63;:::i;:::-;18550:73;;18642;18707:7;18701:3;18690:9;18686:19;18642:73;:::i;:::-;18632:83;;18318:403;;;;;:::o;18726:184::-;-1:-1:-1;;;18775:1:1;18768:88;18875:4;18872:1;18865:15;18899:4;18896:1;18889:15;18915:216;18979:9;;;19007:11;;;18954:3;19037:9;;19065:10;;19061:19;;19090:10;;19082:19;;19058:44;19055:70;;;19105:18;;:::i;19960:200::-;20026:9;;;19999:4;20054:9;;20082:10;;20094:12;;;20078:29;20117:12;;;20109:21;;20075:56;20072:82;;;20134:18;;:::i;20165:125::-;20230:9;;;20251:10;;;20248:36;;;20264:18;;:::i;20295:168::-;20368:9;;;20399;;20416:15;;;20410:22;;20396:37;20386:71;;20437:18;;:::i;21584:128::-;21651:9;;;21672:11;;;21669:37;;;21686:18;;:::i;22126:136::-;22161:3;-1:-1:-1;;;22182:22:1;;22179:48;;22207:18;;:::i;:::-;-1:-1:-1;22247:1:1;22243:13;;22126:136::o;22267:184::-;-1:-1:-1;;;22316:1:1;22309:88;22416:4;22413:1;22406:15;22440:4;22437:1;22430:15;22456:120;22496:1;22522;22512:35;;22527:18;;:::i;:::-;-1:-1:-1;22561:9:1;;22456:120::o;22984:112::-;23016:1;23042;23032:35;;23047:18;;:::i;:::-;-1:-1:-1;23081:9:1;;22984:112::o;23101:184::-;-1:-1:-1;;;23150:1:1;23143:88;23250:4;23247:1;23240:15;23274:4;23271:1;23264:15
Swarm Source
ipfs://2e1acbc7ff8c92bcbd4a74625bf5a4cd65d86b23f8f5adaea42c0d7a5e477c0c
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.