Source Code
Overview
S Balance
S Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
IdleModule
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 100000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
import {IAaveV3Pool} from "../interfaces/IAaveV3Pool.sol";
import {IAccountValuesLens} from "../interfaces/IAccountValuesLens.sol";
import {PMStorage} from "../storage/PMStorage.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IConfigRegistry} from "../interfaces/IConfigRegistry.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract IdleModule is PMStorage {
function harvestIdle(address asset, bool strict) external {
if (address(config) == address(0)) revert("IDLE_CONFIG_ZERO");
IConfigRegistry.IdleCfg memory icfg = config.getIdleCfg(asset);
if (!icfg.aaveEnabled) return;
if (icfg.aavePool == address(0) || icfg.aToken == address(0)) {
if (strict) {
if (icfg.aavePool == address(0)) revert("IDLE_POOL_ZERO");
if (icfg.aToken == address(0)) revert("IDLE_ATOKEN_ZERO");
}
return;
}
AssetState storage s = astate[asset];
uint256 u = IERC20(icfg.aToken).balanceOf(address(this));
uint256 p = s.idlePrincipal;
if (u == p) return;
if (u > p) {
uint256 delta = u - p;
IConfigRegistry.AssetCfg memory c = config.getAssetCfg(asset);
uint256 reserveAdd = (delta * c.reserveFactorBps) / BPS;
if (reserveAdd > 0) s.reserves += reserveAdd;
uint256 toSuppliers = delta - reserveAdd;
if (toSuppliers > 0) {
uint256 ts = s.totalSupplied;
if (ts > 0) {
uint256 dIdx = (toSuppliers * WAD) / ts;
s.supplyIndexWad += dIdx;
s.supplierInterestAccrued += toSuppliers;
} else {
s.reserves += toSuppliers;
}
}
s.idlePrincipal = u;
emit IdleHarvested(asset, delta, 0, s.supplyIndexWad);
} else {
uint256 loss = p - u;
if (strict) {
if (s.reserves < loss) revert("IDLE_LOSS_GT_RES");
s.reserves -= loss;
s.idlePrincipal = u;
emit IdleHarvested(asset, 0, loss, s.supplyIndexWad);
} else {
return;
}
}
}
function rebalanceIdle(address asset) external {
if (address(config) == address(0)) revert("IDLE_CONFIG_ZERO");
IConfigRegistry.IdleCfg memory icfg = config.getIdleCfg(asset);
if (!icfg.aaveEnabled) revert("IDLE_NOT_ENABLED");
if (icfg.aavePool == address(0)) revert("IDLE_POOL_ZERO");
if (icfg.aToken == address(0)) revert("IDLE_ATOKEN_ZERO");
AssetState storage s = astate[asset];
uint256 cash = s.cash;
uint256 buffer = icfg.cashBuffer;
if (cash > buffer) {
uint256 excess = cash - buffer;
uint16 bpsCap = icfg.maxDepositBps == 0 ? uint16(BPS) : icfg.maxDepositBps;
uint256 capAmt = (excess * bpsCap) / BPS;
uint256 toDeposit = capAmt > 0 ? (capAmt > excess ? excess : capAmt) : 0;
if (toDeposit == 0 || toDeposit < icfg.minRebalance) revert("IDLE_MIN_REBAL");
IERC20(asset).approve(icfg.aavePool, 0);
IERC20(asset).approve(icfg.aavePool, toDeposit);
IAaveV3Pool(icfg.aavePool).supply(asset, toDeposit, address(this), 0);
IERC20(asset).approve(icfg.aavePool, 0);
s.cash = cash - toDeposit;
s.idlePrincipal += toDeposit;
emit IdleRebalanced(asset, toDeposit, 0, s.idlePrincipal, s.cash);
return;
}
if (cash < buffer) {
uint256 need = buffer - cash;
uint256 withdrawn = IAaveV3Pool(icfg.aavePool).withdraw(asset, need, address(this));
if (withdrawn == 0 || withdrawn < icfg.minRebalance) revert("IDLE_MIN_REBAL");
s.cash = cash + withdrawn;
uint256 p = s.idlePrincipal;
s.idlePrincipal = p > withdrawn ? (p - withdrawn) : 0;
emit IdleRebalanced(asset, 0, withdrawn, s.idlePrincipal, s.cash);
return;
}
revert("IDLE_NOTHING");
}
function pullFromIdleIfNeeded(address asset, uint256 minCash)
external
returns (uint256 pulled)
{
if (address(config) == address(0)) revert("IDLE_CONFIG_ZERO");
AssetState storage s = astate[asset];
if (s.cash >= minCash) return 0;
IConfigRegistry.IdleCfg memory icfg = config.getIdleCfg(asset);
if (!icfg.aaveEnabled || icfg.aavePool == address(0) || icfg.aToken == address(0)) {
return 0;
}
// realize positive yield
{
IConfigRegistry.IdleCfg memory icfg2 = config.getIdleCfg(asset);
if (icfg2.aaveEnabled && icfg2.aToken != address(0)) {
AssetState storage s2 = astate[asset];
uint256 u = IERC20(icfg2.aToken).balanceOf(address(this));
uint256 p2 = s2.idlePrincipal;
if (u > p2) {
uint256 delta = u - p2;
IConfigRegistry.AssetCfg memory c2 = config.getAssetCfg(asset);
uint256 reserveAdd2 = (delta * c2.reserveFactorBps) / BPS;
if (reserveAdd2 > 0) s2.reserves += reserveAdd2;
uint256 toSuppliers2 = delta - reserveAdd2;
if (toSuppliers2 > 0) {
uint256 ts2 = s2.totalSupplied;
if (ts2 > 0) {
uint256 dIdx2 = (toSuppliers2 * WAD) / ts2;
s2.supplyIndexWad += dIdx2;
s2.supplierInterestAccrued += toSuppliers2;
} else {
s2.reserves += toSuppliers2;
}
}
s2.idlePrincipal = u;
emit IdleRebalanced(asset, 0, 0, s2.idlePrincipal, s2.cash);
}
}
}
uint256 need = minCash - s.cash;
pulled = IAaveV3Pool(icfg.aavePool).withdraw(asset, need, address(this));
if (pulled > 0) {
s.cash += pulled;
uint256 p = s.idlePrincipal;
s.idlePrincipal = p > pulled ? (p - pulled) : 0;
emit IdleRebalanced(asset, 0, pulled, s.idlePrincipal, s.cash);
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
interface IAaveV3Pool {
/// @notice Supply `amount` of `asset` on behalf of `onBehalfOf`.
/// @param asset underlying ERC20 asset
/// @param amount amount of underlying to supply
/// @param onBehalfOf address that receives the aTokens
/// @param referralCode referral code (0 if none)
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
/// @notice Withdraw `amount` of `asset` to `to`. Returns actually withdrawn amount.
/// @param asset underlying ERC20 asset
/// @param amount amount of underlying to withdraw (type(uint256).max to withdraw all)
/// @param to destination address
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
interface IAccountValuesLens {
function accountValues(address pm, address user)
external
view
returns (uint256 collUSD, uint256 debtUSD, uint256 collUSDNoLTV);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
import {ConfigRegistry} from "../ConfigRegistry.sol";
import {IAccountValuesLens} from "../interfaces/IAccountValuesLens.sol";
import {IPerpPnlView} from "../interfaces/IPerpPnlView.sol";
abstract contract PMStorage {
uint256 internal constant WAD = 1e18;
uint256 internal constant BPS = 1e4;
struct Balance {
uint256 avail;
uint256 hold;
}
struct DebtData {
uint256 principal;
uint256 indexAtOpenWad;
}
struct AssetState {
uint256 borrowIndexWad;
uint256 lastAccrual;
uint256 cash;
uint256 borrows;
uint256 reserves;
// Supplier interest index (additive, WAD) and total supplied principal (token units)
uint256 supplyIndexWad;
uint256 totalSupplied;
// Unclaimable supplier interest bucket (asset units) accrued since last settlement
uint256 supplierInterestAccrued;
// FT rewards index paid per unit of supplier interest (WAD)
uint256 ftPerInterestIndexWad;
// FT index snapshot at epoch open (WAD) to bound prior-epoch settlement
uint256 ftIndexAtEpochOpenWad;
// Snapshot of supply index at last FT settlement (WAD)
uint256 lastSupplyIndexSettledWad;
// Snapshot of supply index at the previous epoch open (WAD) to split multi-epoch catch-ups
uint256 prevSupplyIndexSettledWad;
// Frozen base units for a settlement epoch (asset units) — denominator for FT per-interest index
uint256 settlementBaseUnits;
// Amount of base units already settled in the current epoch (asset units)
uint256 settlementUnitsSettled;
// Monotonic settlement epoch id (increments each epoch start)
uint64 settleEpoch;
// Underlying principal invested into Aave (asset units)
uint256 idlePrincipal;
}
// --- PositionsManager storage (prefix must match exact declaration order) ---
ConfigRegistry public config;
// Skip fields before collateral/debt only if order matches; we include full block necessary
address public admin;
mapping(address => bool) public engines; // PositionsManager, RFQ, ftLP, OrderBook, AMM, etc
// Core ledgers
// user => token => {avail,hold}
mapping(address => mapping(address => Balance)) public collateral;
mapping(address => mapping(address => DebtData)) public debt; // user->asset->debt
mapping(address => AssetState) public astate;
// Per-account active asset sets (separate for clarity & simpler netting)
mapping(address => address[]) internal _userCollAssets; // user -> assets with non-zero collateral
mapping(address => mapping(address => uint256)) internal _collIx; // user->asset->index+1 (0 = absent)
mapping(address => address[]) internal _userDebtAssets; // user -> assets with non-zero debt
mapping(address => mapping(address => uint256)) internal _debtIx; // user->asset->index+1 (0 = absent)
// ===== Perp PnL (view-only, liquidation/HF only) =====
IPerpPnlView public perpPnlView; // single engine
uint32 public perpPnlMaxAge = 60; // seconds; 0 = no staleness check
// Externalized account valuation lens (upgradeable)
IAccountValuesLens public valuesLens;
// Emergency per-asset borrow pause (deposits/withdraws still governed by asset enabled flag)
mapping(address => bool) public borrowPaused;
// Emergency per-asset deposit/withdraw pause (orthogonal to `enabled` and borrowPaused)
mapping(address => bool) public depositPaused;
mapping(address => bool) public withdrawPaused;
// ========== Supplier interest accounting (Aave-like) ==========
// Per-user last synchronized index for an asset
mapping(address => mapping(address => uint256)) public userSupplyIndexWad; // user->asset->index
// Note: supplier interest is not claimable in-kind; FT settlement uses userInterestSettledUnits.
// Historical per-user interest is derived on-the-fly via indices; no storage bucket needed.
// System token used to settle supplier interest into FT collateral
address public systemTokenFT;
// FT sweep guardrails
uint256 public ftDustThreshold; // max FT amount sweepable per call
uint256 public ftRequiredCashBuffer; // min FT cash to retain after sweep
// Per-user FT reward index snapshots per source asset (per interest unit)
mapping(address => mapping(address => uint256)) public userFtPerInterestIndexWad; // user->asset->idx
// Per-user eligible supplier interest units realized up to last settlement boundary
mapping(address => mapping(address => uint256)) public userInterestSettledUnits; // user->asset->interestUnits
// Per-user supply index snapshot at last FT settlement boundary applied to the user
mapping(address => mapping(address => uint256)) public userSupplyIdxAtSettleWad; // user->asset->idx
// Per-user last observed settlement epoch for srcAsset
mapping(address => mapping(address => uint64)) public userSettleEpoch; // user->asset->epoch
bytes32 public DOMAIN_SEPARATOR;
mapping(address => mapping(bytes32 => uint256)) public noncesTyped;
address public ftModule;
address public metaActions;
// Caps in token units (0 = no cap)
mapping(address => uint256) public supplyCap; // asset => max (cash + borrows)
mapping(address => uint256) public borrowCap; // asset => max borrows
// Per-account, per-asset nominal debt cap in token units (0 = no cap)
mapping(address => mapping(address => uint256)) public accountBorrowCap; // user => asset => cap
address public idleModule;
// Events signature (emitted via delegatecall from PM address)
event InterestSettledWithFT(
address indexed asset,
uint256 expectedOutAsset,
uint256 ftAmountIn,
uint256 conversionCoeffWad,
uint256 deltaSupplyIdxPaidWad
);
event IdleHarvested(
address indexed asset, uint256 yieldUnits, uint256 reservesUsed, uint256 newSupplyIndexWad
);
event IdleRebalanced(
address indexed asset,
uint256 deposited,
uint256 withdrawn,
uint256 newIdlePrincipal,
uint256 newCash
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
interface IConfigRegistry {
error Unauthorized();
error NotGuardian();
error OracleTimelock();
error NoTimelock();
error TimelockNotReached();
error LTVTimelock();
error OnlyIncrease();
error HealthFactorMinimum();
error InvalidBps();
struct AssetCfg {
address irm;
uint16 ltvBps; // Loan-to-Value in bps
uint16 reserveFactorBps; // Reserve Factor in bps
bool enabled;
}
// ========== Idle/Aave configuration ==========
struct IdleCfg {
bool aaveEnabled; // enable supply-only strategy on Aave for this asset
address aavePool; // Aave V3 Pool address
address aToken; // corresponding aToken for the underlying asset
uint256 cashBuffer; // keep at least this much underlying liquid in PM
uint256 minRebalance; // min amount to move on a rebalance to avoid dust churn
uint16 maxDepositBps; // cap how much of on-hand cash can be deposited per rebalance (in bps of (cash - buffer))
}
event OwnerChanged(address indexed o);
event GuardianChanged(address indexed g);
event AssetSet(address indexed asset, AssetCfg cfg);
event IdleCfgSet(address indexed asset, IdleCfg cfg);
event OracleSet(address indexed router);
event HFTargetSet(uint16 bps);
event HFSafeSet(uint16 bps);
event DelaySet(uint32 delaySec);
event LtvChangeProposed(address indexed asset, uint16 oldLtv, uint16 newLtv, uint64 eta);
event LtvChangeExecuted(address indexed asset, uint16 newLtv);
event OracleChangeProposed(address indexed next, uint64 eta);
event OracleChangeExecuted(address indexed next);
function getAssetCfg(address asset) external view returns (AssetCfg memory);
function getIdleCfg(address asset) external view returns (IdleCfg memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
import {Initializable} from "./utils/Initializable.sol";
import {IConfigRegistry} from "./interfaces/IConfigRegistry.sol";
contract ConfigRegistry is Initializable, IConfigRegistry {
address public owner;
address public guardian;
mapping(address => AssetCfg) public assetCfg;
mapping(address => IdleCfg) public idleCfg; // asset => cfg
address public oracleRouter;
uint16 public hfTargetBps = 11000; // 110%
uint16 public hfSafeBps = 12000; // 120%
modifier onlyOwner() {
_onlyOwner();
_;
}
modifier onlyGuardianOrOwner() {
_onlyGuardianOrOwner();
_;
}
function _onlyOwner() internal view {
if (msg.sender != owner) revert Unauthorized();
}
function _onlyGuardianOrOwner() internal view {
if (msg.sender != guardian && msg.sender != owner) revert NotGuardian();
}
function initialize(address _owner, address _oracle) external initializer {
owner = _owner;
oracleRouter = _oracle;
guardian = _owner;
// set default risk thresholds to match constructor-era defaults
hfTargetBps = 11000; // 110%
hfSafeBps = 12000; // 120%
// delay remains 0 by default
}
// Timelock delay for sensitive changes (seconds). Default 0 = disabled.
uint32 public delay;
function setDelay(uint32 d) external onlyOwner {
delay = d;
emit DelaySet(d);
}
function setOwner(address o) external onlyOwner {
owner = o;
emit OwnerChanged(o);
}
function setGuardian(address g) external onlyOwner {
guardian = g;
emit GuardianChanged(g);
}
// Immediate oracle update only when delay==0
function setOracle(address o) external onlyOwner {
if (delay != 0) revert OracleTimelock();
oracleRouter = o;
emit OracleSet(o);
}
struct PendingOracle {
address next;
uint64 eta;
}
PendingOracle public pendingOracle;
function proposeOracle(address next) external onlyOwner {
if (delay == 0) revert NoTimelock();
uint64 eta = uint64(block.timestamp + delay);
pendingOracle = PendingOracle({next: next, eta: eta});
emit OracleChangeProposed(next, eta);
}
function executeOracle() external onlyOwner {
if (pendingOracle.eta == 0 || block.timestamp < pendingOracle.eta) {
revert TimelockNotReached();
}
oracleRouter = pendingOracle.next;
emit OracleChangeExecuted(pendingOracle.next);
delete pendingOracle;
}
function setAsset(address asset, AssetCfg calldata c) external onlyOwner {
// Sanity checks: bps fields must be within [0, 10000]
if (c.ltvBps > 10000 || c.reserveFactorBps > 10000) revert InvalidBps();
AssetCfg memory prev = assetCfg[asset];
if (delay > 0) {
if (c.ltvBps > prev.ltvBps) revert LTVTimelock(); // increases must go through timelock
}
assetCfg[asset] = c;
emit AssetSet(asset, c);
}
function setIdleCfg(address asset, IdleCfg calldata c) external onlyOwner {
// No timelock requirement by default; governance can choose to add if needed externally
idleCfg[asset] = c;
emit IdleCfgSet(asset, c);
}
struct PendingLtv {
uint16 ltvBps;
uint64 eta;
}
mapping(address => PendingLtv) public pendingLtv;
function proposeAssetLtv(address asset, uint16 newLtvBps) external onlyOwner {
AssetCfg memory prev = assetCfg[asset];
if (delay == 0) revert NoTimelock();
if (newLtvBps > 10000) revert InvalidBps();
if (newLtvBps < prev.ltvBps) revert OnlyIncrease();
uint64 eta = uint64(block.timestamp + delay);
pendingLtv[asset] = PendingLtv({ltvBps: newLtvBps, eta: eta});
emit LtvChangeProposed(asset, prev.ltvBps, newLtvBps, eta);
}
function executeAssetLtv(address asset) external onlyOwner {
PendingLtv memory p = pendingLtv[asset];
if (p.eta == 0 || block.timestamp < p.eta) revert TimelockNotReached();
AssetCfg storage cfg = assetCfg[asset];
cfg.ltvBps = p.ltvBps;
emit LtvChangeExecuted(asset, p.ltvBps);
delete pendingLtv[asset];
emit AssetSet(asset, cfg);
}
function getAssetCfg(address asset) external view returns (AssetCfg memory) {
return assetCfg[asset];
}
function getIdleCfg(address asset) external view returns (IdleCfg memory) {
return idleCfg[asset];
}
function setHFTarget(uint16 bps) external onlyGuardianOrOwner {
if (bps < 10000) revert HealthFactorMinimum();
hfTargetBps = bps;
emit HFTargetSet(bps);
}
function setHFSafe(uint16 bps) external onlyGuardianOrOwner {
if (bps < hfTargetBps) revert HealthFactorMinimum();
hfSafeBps = bps;
emit HFSafeSet(bps);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
interface IPerpPnlView {
/// @return pnlUSDWad signed USD in 1e18; positive = profit, negative = loss
/// @return updatedAt epoch seconds of the PnL snapshot
function pnlUSD(address user) external view returns (int256 pnlUSDWad, uint64 updatedAt);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
/**
* Minimal initializer guard for proxy-based deployments.
* Mirrors the common pattern: one-time initialize() replacing constructors.
*/
abstract contract Initializable {
bool private _initialized;
modifier initializer() {
_initializer();
_;
}
function _initializer() internal {
require(!_initialized, "Initializable: already initialized");
_initialized = true;
}
function initialized() public view returns (bool) {
return _initialized;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 100000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"yieldUnits","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reservesUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSupplyIndexWad","type":"uint256"}],"name":"IdleHarvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"deposited","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newIdlePrincipal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCash","type":"uint256"}],"name":"IdleRebalanced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"expectedOutAsset","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ftAmountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"conversionCoeffWad","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deltaSupplyIdxPaidWad","type":"uint256"}],"name":"InterestSettledWithFT","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"accountBorrowCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"astate","outputs":[{"internalType":"uint256","name":"borrowIndexWad","type":"uint256"},{"internalType":"uint256","name":"lastAccrual","type":"uint256"},{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"borrows","type":"uint256"},{"internalType":"uint256","name":"reserves","type":"uint256"},{"internalType":"uint256","name":"supplyIndexWad","type":"uint256"},{"internalType":"uint256","name":"totalSupplied","type":"uint256"},{"internalType":"uint256","name":"supplierInterestAccrued","type":"uint256"},{"internalType":"uint256","name":"ftPerInterestIndexWad","type":"uint256"},{"internalType":"uint256","name":"ftIndexAtEpochOpenWad","type":"uint256"},{"internalType":"uint256","name":"lastSupplyIndexSettledWad","type":"uint256"},{"internalType":"uint256","name":"prevSupplyIndexSettledWad","type":"uint256"},{"internalType":"uint256","name":"settlementBaseUnits","type":"uint256"},{"internalType":"uint256","name":"settlementUnitsSettled","type":"uint256"},{"internalType":"uint64","name":"settleEpoch","type":"uint64"},{"internalType":"uint256","name":"idlePrincipal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"collateral","outputs":[{"internalType":"uint256","name":"avail","type":"uint256"},{"internalType":"uint256","name":"hold","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"contract ConfigRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"debt","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"indexAtOpenWad","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"depositPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"engines","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ftDustThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ftModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ftRequiredCashBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"strict","type":"bool"}],"name":"harvestIdle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"idleModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metaActions","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"noncesTyped","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"perpPnlMaxAge","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"perpPnlView","outputs":[{"internalType":"contract IPerpPnlView","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"minCash","type":"uint256"}],"name":"pullFromIdleIfNeeded","outputs":[{"internalType":"uint256","name":"pulled","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"rebalanceIdle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supplyCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"systemTokenFT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userFtPerInterestIndexWad","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userInterestSettledUnits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userSettleEpoch","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userSupplyIdxAtSettleWad","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userSupplyIndexWad","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"valuesLens","outputs":[{"internalType":"contract IAccountValuesLens","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60808060405234602b57600a805463ffffffff60a01b1916600f60a21b1790556123a690816100308239f35b5f80fdfe60a06040526004361015610011575f80fd5b5f3560e01c806304a34e3514610dc957806305d79c1414610d665780630a78447c14610d1a57806314f316b914610c8e578063192c2d2014610c1f5780632850e9e214610bce57806331a42e1b14610a925780633281fbc514610a065780633644e515146109cb57806338ade96d1461097a5780633ec21993146108ee57806340ccf256146108865780634a34a55d1461081e5780635020136b146107e357806379502c55146107935780637b030b33146107075780637dd7442e146106cc5780637fda8adc1461067f578063873642601461063b578063a5cef321146105ea578063bf09f27414610582578063c0fda29214610531578063cb208443146104ce578063cc218ece14610439578063ce855f23146103e8578063d449300d14610353578063d76a6779146102eb578063db84aa59146102aa578063e413cbc614610214578063f6f6f72c146101c35763f851a4401461016e575f80fd5b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b5f80fd5b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff600b5416604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5761024b610e55565b73ffffffffffffffffffffffffffffffffffffffff610268610e78565b91165f52601660205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602067ffffffffffffffff60405f205416604051908152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf576102e96102e4610e55565b611cae565b005b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff610337610e55565b165f52600c602052602060ff60405f2054166040519015158152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5761038a610e55565b73ffffffffffffffffffffffffffffffffffffffff6103a7610e78565b91165f52600460205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f526020526040805f206001815491015482519182526020820152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff600a5416604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610470610e55565b73ffffffffffffffffffffffffffffffffffffffff61048d610e78565b91165f52600360205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f526020526040805f206001815491015482519182526020820152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff61051a610e55565b165f52601c602052602060405f2054604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff60195416604051908152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff6105ce610e55565b165f526002602052602060ff60405f2054166040519015158152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff601e5416604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602063ffffffff600a5460a01c16604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5760206106c46106bb610e55565b60243590611696565b604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf576020601154604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5761073e610e55565b73ffffffffffffffffffffffffffffffffffffffff61075b610e78565b91165f52600f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf576020601254604051908152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff61086a610e55565b165f52600d602052602060ff60405f2054166040519015158152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff6108d2610e55565b165f52600e602052602060ff60405f2054166040519015158152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610925610e55565b73ffffffffffffffffffffffffffffffffffffffff610942610e78565b91165f52601d60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff60105416604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf576020601754604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610a3d610e55565b73ffffffffffffffffffffffffffffffffffffffff610a5a610e78565b91165f52601560205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610ac9610e55565b73ffffffffffffffffffffffffffffffffffffffff165f52600560205260405f2080549080600181015460028201546003830154600484015460058501546006860154600787015490600888015492600989015494600a8a015496600b8b015498600c8c01549a600d8d01549c600e015467ffffffffffffffff169d600f01549e604051608052608051526080516020015260805160400152608051606001526080516080015260805160a0015260805160c0015260805160e00152608051610100015260805161012001526080516101400152608051610160015260805161018001526080516101a001526080516101c001526080516101e0015260805161020090f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff601a5416604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff610c6b610e55565b165f52601860205260405f206024355f52602052602060405f2054604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610cc5610e55565b73ffffffffffffffffffffffffffffffffffffffff610ce2610e78565b91165f52601460205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610d51610e55565b60243580151581036101bf576102e9916110c1565b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff610db2610e55565b165f52601b602052602060405f2054604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610e00610e55565b73ffffffffffffffffffffffffffffffffffffffff610e1d610e78565b91165f52601360205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101bf57565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101bf57565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610edc57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b519081151582036101bf57565b519073ffffffffffffffffffffffffffffffffffffffff821682036101bf57565b519061ffff821682036101bf57565b908160c09103126101bf576040519060c0820182811067ffffffffffffffff821117610edc57610fbd9160a091604052610f7f81610f09565b8452610f8d60208201610f16565b6020850152610f9e60408201610f16565b6040850152606081015160608501526080810151608085015201610f37565b60a082015290565b91908203918211610fd257565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b908160809103126101bf57604051906080820182811067ffffffffffffffff821117610edc576110629160609160405261103881610f16565b845261104660208201610f37565b602085015261105760408201610f37565b604085015201610f09565b606082015290565b81810292918115918404141715610fd257565b8115611087570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b91908201809211610fd257565b73ffffffffffffffffffffffffffffffffffffffff5f54169182156116375760c073ffffffffffffffffffffffffffffffffffffffff926024604051809581937f31ddaa1f00000000000000000000000000000000000000000000000000000000835216968760048301525afa9182156113dc575f92611606575b508151156116015773ffffffffffffffffffffffffffffffffffffffff602083015116158080156115df575b6114f1575090602491835f526005602052602073ffffffffffffffffffffffffffffffffffffffff6040805f2094015116604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9283156113dc575f936114bd575b50600f82019283548082146114b557808211156113e757816111fc929350610fc5565b926024608073ffffffffffffffffffffffffffffffffffffffff5f5416604051928380927ffb20974f0000000000000000000000000000000000000000000000000000000082528a60048301525afa80156113dc5761127261ffff60406127109361127f955f916113ad575b500151168761106a565b0480611397575b85610fc5565b801580156112c7575b50505560050154604080519283525f60208401528201527f3da554118f5a2adbe66b8089472fbb7e6b6c86598448e01b2482b01bb8c569e090606090a2565b939094926006820154928315155f1461135757670de0b6b3a7640000870295878704670de0b6b3a7640000141715610fd2577f3da554118f5a2adbe66b8089472fbb7e6b6c86598448e01b2482b01bb8c569e09661132960059560609861107d565b6113378686019182546110b4565b9055611348600785019182546110b4565b90555b92509294819450611288565b60609550600593507f3da554118f5a2adbe66b8089472fbb7e6b6c86598448e01b2482b01bb8c569e096611390600485019182546110b4565b905561134b565b600485016113a68282546110b4565b9055611279565b6113cf915060803d6080116113d5575b6113c78183610e9b565b810190610fff565b5f611268565b503d6113bd565b6040513d5f823e3d90fd5b816113f191610fc5565b91156114ae576004830192835491838310611450577f3da554118f5a2adbe66b8089472fbb7e6b6c86598448e01b2482b01bb8c569e09560609561143786600596610fc5565b9055550154604051915f835260208301526040820152a2565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f49444c455f4c4f53535f47545f524553000000000000000000000000000000006044820152fd5b5050505050565b505050505050565b9092506020813d6020116114e9575b816114d960209383610e9b565b810103126101bf5751915f6111d9565b3d91506114cc565b9192506114fc575050565b611580576040015173ffffffffffffffffffffffffffffffffffffffff161561152157565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f49444c455f41544f4b454e5f5a45524f000000000000000000000000000000006044820152606490fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f49444c455f504f4f4c5f5a45524f0000000000000000000000000000000000006044820152606490fd5b5073ffffffffffffffffffffffffffffffffffffffff60408401511615611168565b505050565b61162991925060c03d60c011611630575b6116218183610e9b565b810190610f46565b905f61113c565b503d611617565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f49444c455f434f4e4649475f5a45524f000000000000000000000000000000006044820152606490fd5b5f5473ffffffffffffffffffffffffffffffffffffffff16929183156116375773ffffffffffffffffffffffffffffffffffffffff821691825f52600560205260405f209060028201928084541015611ca457604051907f31ddaa1f00000000000000000000000000000000000000000000000000000000825285600483015260c0826024818b5afa9182156113dc575f92611c83575b508151158015611c61575b8015611c3f575b611c34576040517f31ddaa1f00000000000000000000000000000000000000000000000000000000815286600482015260c0816024818c5afa9081156113dc575f91611c15575b508051151580611bf2575b6118f7575b5061182a97509073ffffffffffffffffffffffffffffffffffffffff60206117c2819594885490610fc5565b92015116905f604051809a819582947f69328dec00000000000000000000000000000000000000000000000000000000845230916004850191604091949373ffffffffffffffffffffffffffffffffffffffff91826060860197168552602085015216910152565b03925af19485156113dc575f956118c3575b50848061184a575b50505050565b82600f60809361187c847f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e097546110b4565b809355018054838082115f146118b95761189591610fc5565b80915b55604051925f8452602084015260408301526060820152a25f808080611844565b50505f8091611898565b9094506020813d6020116118ef575b816118df60209383610e9b565b810103126101bf5751935f61183c565b3d91506118d2565b602490875f526005602052602073ffffffffffffffffffffffffffffffffffffffff6040805f2093015116604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9182156113dc575f92611bbe575b50600f8101998a5480841161197a575b505050611796565b6119849084610fc5565b60808a6024604051809581937ffb20974f00000000000000000000000000000000000000000000000000000000835260048301525afa80156113dc576119e161ffff6040612710936119ed965f91611b9f575b500151168361106a565b049081611b8957610fc5565b80158015611a66575b50506117c26020959493897f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e060808661182a9f8b9773ffffffffffffffffffffffffffffffffffffffff99600292550154604051915f83525f8984015260408301526060820152a2939495611972565b6006830154919695949092918015611b2457670de0b6b3a7640000880293888504670de0b6b3a7640000141715610fd2577f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e060808661182a9f6117c2968f959960029260209e8f9b73ffffffffffffffffffffffffffffffffffffffff9d611aed9161107d565b611afc600586019182546110b4565b9055611b0d600785019182546110b4565b90555b9d505097505096505050509394959a6119f6565b506020968793507f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e060808661182a9f868f959960029273ffffffffffffffffffffffffffffffffffffffff9b611b8260046117c29c019182546110b4565b9055611b10565b60048401611b988382546110b4565b9055610fc5565b611bb8915060803d6080116113d5576113c78183610e9b565b5f6119d7565b9091506020813d602011611bea575b81611bda60209383610e9b565b810103126101bf5751905f611962565b3d9150611bcd565b5073ffffffffffffffffffffffffffffffffffffffff6040820151161515611791565b611c2e915060c03d60c011611630576116218183610e9b565b5f611786565b505f96505050505050565b5073ffffffffffffffffffffffffffffffffffffffff6040830151161561173f565b5073ffffffffffffffffffffffffffffffffffffffff60208301511615611738565b611c9d91925060c03d60c011611630576116218183610e9b565b905f61172d565b505f955050505050565b5f9073ffffffffffffffffffffffffffffffffffffffff5f541691821561163757604051907f31ddaa1f00000000000000000000000000000000000000000000000000000000825260c08260248173ffffffffffffffffffffffffffffffffffffffff8716978860048301525afa9182156113dc575f92612385575b5081511561232757602082019173ffffffffffffffffffffffffffffffffffffffff835116156115805773ffffffffffffffffffffffffffffffffffffffff6040820151161561152157845f52600560205260405f20926002840191825495606082015190818811611fc557818810611dfb5760646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f49444c455f4e4f5448494e4700000000000000000000000000000000000000006044820152fd5b611e879373ffffffffffffffffffffffffffffffffffffffff611e208a602095610fc5565b91511690876040518097819582947f69328dec00000000000000000000000000000000000000000000000000000000845230916004850191604091949373ffffffffffffffffffffffffffffffffffffffff91826060860197168552602085015216910152565b03925af1918215611fba578492611f86575b508115908115611f78575b50611f1957600f608094611ed9837f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e0986110b4565b80945501908154818082115f14611f0f57611ef391610fc5565b80925b55604051938452602084015260408301526060820152a2565b5050838092611ef6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f49444c455f4d494e5f524542414c0000000000000000000000000000000000006044820152606490fd5b60809150015181105f611ea4565b9091506020813d602011611fb2575b81611fa260209383610e9b565b810103126101bf5751905f611e99565b3d9150611f95565b6040513d86823e3d90fd5b50611fd69087939297969496610fc5565b60a087015161ffff16806123185750612710611ff761ffff825b168361106a565b04801561230f578181111561230857505b955b86159081156122fa575b50611f195773ffffffffffffffffffffffffffffffffffffffff815116604051907f095ea7b300000000000000000000000000000000000000000000000000000000825260048201525f60248201526020816044815f8c5af180156113dc576122c3575b5073ffffffffffffffffffffffffffffffffffffffff815116604051907f095ea7b300000000000000000000000000000000000000000000000000000000825260048201528660248201526020816044815f8c5af180156113dc5761228c575b5073ffffffffffffffffffffffffffffffffffffffff815116803b156101bf575f80916084604051809481937f617ba0370000000000000000000000000000000000000000000000000000000083528d60048401528c60248401523060448401528160648401525af180156113dc57612263575b5073ffffffffffffffffffffffffffffffffffffffff905116604051907f095ea7b30000000000000000000000000000000000000000000000000000000082526004820152836024820152602081604481878b5af18015611fba576121f0575b5091600f608094926121e0877f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e09896610fc5565b8094550190611ef38483546110b4565b6020813d60201161225b575b8161220960209383610e9b565b8101031261225757608094926121e0877f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e0989694612248600f95610f09565b509496509750509294506121ac565b8380fd5b3d91506121fc565b6122709194505f90610e9b565b5f9273ffffffffffffffffffffffffffffffffffffffff61214c565b6020813d6020116122bb575b816122a560209383610e9b565b810103126101bf576122b690610f09565b6120d8565b3d9150612298565b6020813d6020116122f2575b816122dc60209383610e9b565b810103126101bf576122ed90610f09565b612078565b3d91506122cf565b60809150015186105f612014565b9050612008565b50505f9561200a565b611ff761ffff61271092611ff0565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f49444c455f4e4f545f454e41424c4544000000000000000000000000000000006044820152fd5b61239f91925060c03d60c011611630576116218183610e9b565b905f611d2a56
Deployed Bytecode
0x60a06040526004361015610011575f80fd5b5f3560e01c806304a34e3514610dc957806305d79c1414610d665780630a78447c14610d1a57806314f316b914610c8e578063192c2d2014610c1f5780632850e9e214610bce57806331a42e1b14610a925780633281fbc514610a065780633644e515146109cb57806338ade96d1461097a5780633ec21993146108ee57806340ccf256146108865780634a34a55d1461081e5780635020136b146107e357806379502c55146107935780637b030b33146107075780637dd7442e146106cc5780637fda8adc1461067f578063873642601461063b578063a5cef321146105ea578063bf09f27414610582578063c0fda29214610531578063cb208443146104ce578063cc218ece14610439578063ce855f23146103e8578063d449300d14610353578063d76a6779146102eb578063db84aa59146102aa578063e413cbc614610214578063f6f6f72c146101c35763f851a4401461016e575f80fd5b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b5f80fd5b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff600b5416604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5761024b610e55565b73ffffffffffffffffffffffffffffffffffffffff610268610e78565b91165f52601660205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602067ffffffffffffffff60405f205416604051908152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf576102e96102e4610e55565b611cae565b005b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff610337610e55565b165f52600c602052602060ff60405f2054166040519015158152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5761038a610e55565b73ffffffffffffffffffffffffffffffffffffffff6103a7610e78565b91165f52600460205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f526020526040805f206001815491015482519182526020820152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff600a5416604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610470610e55565b73ffffffffffffffffffffffffffffffffffffffff61048d610e78565b91165f52600360205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f526020526040805f206001815491015482519182526020820152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff61051a610e55565b165f52601c602052602060405f2054604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff60195416604051908152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff6105ce610e55565b165f526002602052602060ff60405f2054166040519015158152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff601e5416604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602063ffffffff600a5460a01c16604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5760206106c46106bb610e55565b60243590611696565b604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf576020601154604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5761073e610e55565b73ffffffffffffffffffffffffffffffffffffffff61075b610e78565b91165f52600f60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf576020601254604051908152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff61086a610e55565b165f52600d602052602060ff60405f2054166040519015158152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff6108d2610e55565b165f52600e602052602060ff60405f2054166040519015158152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610925610e55565b73ffffffffffffffffffffffffffffffffffffffff610942610e78565b91165f52601d60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff60105416604051908152f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf576020601754604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610a3d610e55565b73ffffffffffffffffffffffffffffffffffffffff610a5a610e78565b91165f52601560205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610ac9610e55565b73ffffffffffffffffffffffffffffffffffffffff165f52600560205260405f2080549080600181015460028201546003830154600484015460058501546006860154600787015490600888015492600989015494600a8a015496600b8b015498600c8c01549a600d8d01549c600e015467ffffffffffffffff169d600f01549e604051608052608051526080516020015260805160400152608051606001526080516080015260805160a0015260805160c0015260805160e00152608051610100015260805161012001526080516101400152608051610160015260805161018001526080516101a001526080516101c001526080516101e0015260805161020090f35b346101bf575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57602073ffffffffffffffffffffffffffffffffffffffff601a5416604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff610c6b610e55565b165f52601860205260405f206024355f52602052602060405f2054604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610cc5610e55565b73ffffffffffffffffffffffffffffffffffffffff610ce2610e78565b91165f52601460205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610d51610e55565b60243580151581036101bf576102e9916110c1565b346101bf5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf5773ffffffffffffffffffffffffffffffffffffffff610db2610e55565b165f52601b602052602060405f2054604051908152f35b346101bf5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101bf57610e00610e55565b73ffffffffffffffffffffffffffffffffffffffff610e1d610e78565b91165f52601360205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101bf57565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101bf57565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610edc57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b519081151582036101bf57565b519073ffffffffffffffffffffffffffffffffffffffff821682036101bf57565b519061ffff821682036101bf57565b908160c09103126101bf576040519060c0820182811067ffffffffffffffff821117610edc57610fbd9160a091604052610f7f81610f09565b8452610f8d60208201610f16565b6020850152610f9e60408201610f16565b6040850152606081015160608501526080810151608085015201610f37565b60a082015290565b91908203918211610fd257565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b908160809103126101bf57604051906080820182811067ffffffffffffffff821117610edc576110629160609160405261103881610f16565b845261104660208201610f37565b602085015261105760408201610f37565b604085015201610f09565b606082015290565b81810292918115918404141715610fd257565b8115611087570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b91908201809211610fd257565b73ffffffffffffffffffffffffffffffffffffffff5f54169182156116375760c073ffffffffffffffffffffffffffffffffffffffff926024604051809581937f31ddaa1f00000000000000000000000000000000000000000000000000000000835216968760048301525afa9182156113dc575f92611606575b508151156116015773ffffffffffffffffffffffffffffffffffffffff602083015116158080156115df575b6114f1575090602491835f526005602052602073ffffffffffffffffffffffffffffffffffffffff6040805f2094015116604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9283156113dc575f936114bd575b50600f82019283548082146114b557808211156113e757816111fc929350610fc5565b926024608073ffffffffffffffffffffffffffffffffffffffff5f5416604051928380927ffb20974f0000000000000000000000000000000000000000000000000000000082528a60048301525afa80156113dc5761127261ffff60406127109361127f955f916113ad575b500151168761106a565b0480611397575b85610fc5565b801580156112c7575b50505560050154604080519283525f60208401528201527f3da554118f5a2adbe66b8089472fbb7e6b6c86598448e01b2482b01bb8c569e090606090a2565b939094926006820154928315155f1461135757670de0b6b3a7640000870295878704670de0b6b3a7640000141715610fd2577f3da554118f5a2adbe66b8089472fbb7e6b6c86598448e01b2482b01bb8c569e09661132960059560609861107d565b6113378686019182546110b4565b9055611348600785019182546110b4565b90555b92509294819450611288565b60609550600593507f3da554118f5a2adbe66b8089472fbb7e6b6c86598448e01b2482b01bb8c569e096611390600485019182546110b4565b905561134b565b600485016113a68282546110b4565b9055611279565b6113cf915060803d6080116113d5575b6113c78183610e9b565b810190610fff565b5f611268565b503d6113bd565b6040513d5f823e3d90fd5b816113f191610fc5565b91156114ae576004830192835491838310611450577f3da554118f5a2adbe66b8089472fbb7e6b6c86598448e01b2482b01bb8c569e09560609561143786600596610fc5565b9055550154604051915f835260208301526040820152a2565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f49444c455f4c4f53535f47545f524553000000000000000000000000000000006044820152fd5b5050505050565b505050505050565b9092506020813d6020116114e9575b816114d960209383610e9b565b810103126101bf5751915f6111d9565b3d91506114cc565b9192506114fc575050565b611580576040015173ffffffffffffffffffffffffffffffffffffffff161561152157565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f49444c455f41544f4b454e5f5a45524f000000000000000000000000000000006044820152606490fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f49444c455f504f4f4c5f5a45524f0000000000000000000000000000000000006044820152606490fd5b5073ffffffffffffffffffffffffffffffffffffffff60408401511615611168565b505050565b61162991925060c03d60c011611630575b6116218183610e9b565b810190610f46565b905f61113c565b503d611617565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f49444c455f434f4e4649475f5a45524f000000000000000000000000000000006044820152606490fd5b5f5473ffffffffffffffffffffffffffffffffffffffff16929183156116375773ffffffffffffffffffffffffffffffffffffffff821691825f52600560205260405f209060028201928084541015611ca457604051907f31ddaa1f00000000000000000000000000000000000000000000000000000000825285600483015260c0826024818b5afa9182156113dc575f92611c83575b508151158015611c61575b8015611c3f575b611c34576040517f31ddaa1f00000000000000000000000000000000000000000000000000000000815286600482015260c0816024818c5afa9081156113dc575f91611c15575b508051151580611bf2575b6118f7575b5061182a97509073ffffffffffffffffffffffffffffffffffffffff60206117c2819594885490610fc5565b92015116905f604051809a819582947f69328dec00000000000000000000000000000000000000000000000000000000845230916004850191604091949373ffffffffffffffffffffffffffffffffffffffff91826060860197168552602085015216910152565b03925af19485156113dc575f956118c3575b50848061184a575b50505050565b82600f60809361187c847f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e097546110b4565b809355018054838082115f146118b95761189591610fc5565b80915b55604051925f8452602084015260408301526060820152a25f808080611844565b50505f8091611898565b9094506020813d6020116118ef575b816118df60209383610e9b565b810103126101bf5751935f61183c565b3d91506118d2565b602490875f526005602052602073ffffffffffffffffffffffffffffffffffffffff6040805f2093015116604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9182156113dc575f92611bbe575b50600f8101998a5480841161197a575b505050611796565b6119849084610fc5565b60808a6024604051809581937ffb20974f00000000000000000000000000000000000000000000000000000000835260048301525afa80156113dc576119e161ffff6040612710936119ed965f91611b9f575b500151168361106a565b049081611b8957610fc5565b80158015611a66575b50506117c26020959493897f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e060808661182a9f8b9773ffffffffffffffffffffffffffffffffffffffff99600292550154604051915f83525f8984015260408301526060820152a2939495611972565b6006830154919695949092918015611b2457670de0b6b3a7640000880293888504670de0b6b3a7640000141715610fd2577f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e060808661182a9f6117c2968f959960029260209e8f9b73ffffffffffffffffffffffffffffffffffffffff9d611aed9161107d565b611afc600586019182546110b4565b9055611b0d600785019182546110b4565b90555b9d505097505096505050509394959a6119f6565b506020968793507f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e060808661182a9f868f959960029273ffffffffffffffffffffffffffffffffffffffff9b611b8260046117c29c019182546110b4565b9055611b10565b60048401611b988382546110b4565b9055610fc5565b611bb8915060803d6080116113d5576113c78183610e9b565b5f6119d7565b9091506020813d602011611bea575b81611bda60209383610e9b565b810103126101bf5751905f611962565b3d9150611bcd565b5073ffffffffffffffffffffffffffffffffffffffff6040820151161515611791565b611c2e915060c03d60c011611630576116218183610e9b565b5f611786565b505f96505050505050565b5073ffffffffffffffffffffffffffffffffffffffff6040830151161561173f565b5073ffffffffffffffffffffffffffffffffffffffff60208301511615611738565b611c9d91925060c03d60c011611630576116218183610e9b565b905f61172d565b505f955050505050565b5f9073ffffffffffffffffffffffffffffffffffffffff5f541691821561163757604051907f31ddaa1f00000000000000000000000000000000000000000000000000000000825260c08260248173ffffffffffffffffffffffffffffffffffffffff8716978860048301525afa9182156113dc575f92612385575b5081511561232757602082019173ffffffffffffffffffffffffffffffffffffffff835116156115805773ffffffffffffffffffffffffffffffffffffffff6040820151161561152157845f52600560205260405f20926002840191825495606082015190818811611fc557818810611dfb5760646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f49444c455f4e4f5448494e4700000000000000000000000000000000000000006044820152fd5b611e879373ffffffffffffffffffffffffffffffffffffffff611e208a602095610fc5565b91511690876040518097819582947f69328dec00000000000000000000000000000000000000000000000000000000845230916004850191604091949373ffffffffffffffffffffffffffffffffffffffff91826060860197168552602085015216910152565b03925af1918215611fba578492611f86575b508115908115611f78575b50611f1957600f608094611ed9837f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e0986110b4565b80945501908154818082115f14611f0f57611ef391610fc5565b80925b55604051938452602084015260408301526060820152a2565b5050838092611ef6565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f49444c455f4d494e5f524542414c0000000000000000000000000000000000006044820152606490fd5b60809150015181105f611ea4565b9091506020813d602011611fb2575b81611fa260209383610e9b565b810103126101bf5751905f611e99565b3d9150611f95565b6040513d86823e3d90fd5b50611fd69087939297969496610fc5565b60a087015161ffff16806123185750612710611ff761ffff825b168361106a565b04801561230f578181111561230857505b955b86159081156122fa575b50611f195773ffffffffffffffffffffffffffffffffffffffff815116604051907f095ea7b300000000000000000000000000000000000000000000000000000000825260048201525f60248201526020816044815f8c5af180156113dc576122c3575b5073ffffffffffffffffffffffffffffffffffffffff815116604051907f095ea7b300000000000000000000000000000000000000000000000000000000825260048201528660248201526020816044815f8c5af180156113dc5761228c575b5073ffffffffffffffffffffffffffffffffffffffff815116803b156101bf575f80916084604051809481937f617ba0370000000000000000000000000000000000000000000000000000000083528d60048401528c60248401523060448401528160648401525af180156113dc57612263575b5073ffffffffffffffffffffffffffffffffffffffff905116604051907f095ea7b30000000000000000000000000000000000000000000000000000000082526004820152836024820152602081604481878b5af18015611fba576121f0575b5091600f608094926121e0877f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e09896610fc5565b8094550190611ef38483546110b4565b6020813d60201161225b575b8161220960209383610e9b565b8101031261225757608094926121e0877f3f6c2d888e3655f127387ddbb51a311acc15f36a8d5535bd05b5b9556aaa29e0989694612248600f95610f09565b509496509750509294506121ac565b8380fd5b3d91506121fc565b6122709194505f90610e9b565b5f9273ffffffffffffffffffffffffffffffffffffffff61214c565b6020813d6020116122bb575b816122a560209383610e9b565b810103126101bf576122b690610f09565b6120d8565b3d9150612298565b6020813d6020116122f2575b816122dc60209383610e9b565b810103126101bf576122ed90610f09565b612078565b3d91506122cf565b60809150015186105f612014565b9050612008565b50505f9561200a565b611ff761ffff61271092611ff0565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f49444c455f4e4f545f454e41424c4544000000000000000000000000000000006044820152fd5b61239f91925060c03d60c011611630576116218183610e9b565b905f611d2a56
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
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.