Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60a06040 | 23144432 | 191 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
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:
NAVCalculator
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@chainlink/src/interfaces/feeds/AggregatorV3Interface.sol";
import {IPrices, Prices} from "src/prices/Prices.sol";
import {IBalances, Balances} from "src/balances/Balances.sol";
import {INAVCalculator} from "./INAVCalculator.sol";
import {BridgeAware} from "./BridgeAware.sol";
import {RecoverFunds} from "../RecoverFunds.sol";
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import "src/errors.sol";
import "src/constants.sol";
/// @title NAV Calculator
/// @notice Calculates NAV based on on-chain balances and price oracles.
/// @author kpk
contract NAVCalculator is
Initializable,
UUPSUpgradeable,
AccessControlUpgradeable,
INAVCalculator,
Prices,
Balances,
BridgeAware,
RecoverFunds
{
//
// Libraries
//
using EnumerableMap for EnumerableMap.AddressToUintMap;
//
// State
//
/// @notice Set of known assets to track
EnumerableMap.AddressToUintMap private _assetDecimals;
/// @notice Asset recoverer. useful solely for recovery of wrongly sent funds to this contract.
/// @dev This is the recipient address that will receive the assets recovered by a call to the `recoverAssets`
/// function.
address public assetRecoverer;
//
// Constructor
//
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/// @notice Initializer for UUPS proxy
/// @param admin_ The initial admin
/// @param assetRecoverer_ Asset recoverer. useful solely for recovery of wrongly sent funds
/// @param chainlinkL2SequencerUptimeFeed_ The address of the chainlink feed for the sequencer uptime
function initialize(address admin_, address assetRecoverer_, address chainlinkL2SequencerUptimeFeed_)
public
initializer
{
__UUPSUpgradeable_init();
__AccessControl_init();
__Prices_init(chainlinkL2SequencerUptimeFeed_);
__Balances_init();
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
assetRecoverer = assetRecoverer_;
}
//
// INAVCalculator
//
/// @inheritdoc INAVCalculator
function addPrice(address underlyingAsset, address oracle, IPrices.PriceType priceType, uint256 chainlinkHeartbeat)
external
{
if (!hasRole(MANAGER, msg.sender)) revert NotAuthorized();
// TODO: are all native _assets 18 decimals?
uint8 decimals = underlyingAsset == NATIVE_ADDRESS ? 18 : IERC20Metadata(underlyingAsset).decimals();
_assetDecimals.set(underlyingAsset, decimals);
_setPriceOracle(underlyingAsset, oracle, chainlinkHeartbeat, priceType);
}
/// @inheritdoc INAVCalculator
function addBalance(address underlyingAsset, address oracle, IBalances.BalanceType balanceType) external {
if (!hasRole(MANAGER, msg.sender)) revert NotAuthorized();
if (!_assetDecimals.contains(underlyingAsset)) {
revert AssetNotFound();
}
_addBalanceOracle(underlyingAsset, oracle, balanceType);
}
/// @inheritdoc INAVCalculator
function removePrice(address underlyingAsset) external {
if (!hasRole(MANAGER, msg.sender)) revert NotAuthorized();
if (balanceOracleCountFor(underlyingAsset) > 0) {
revert InvalidArguments();
}
bool success = _assetDecimals.remove(underlyingAsset);
if (!success) {
revert AssetNotFound();
}
_removePriceOracle(underlyingAsset);
}
/// @inheritdoc INAVCalculator
function removeBalance(address underlyingAsset, address oracle) external {
if (!hasRole(MANAGER, msg.sender)) revert NotAuthorized();
if (!_assetDecimals.contains(underlyingAsset)) {
revert AssetNotFound();
}
_removeBalanceOracle(underlyingAsset, oracle);
}
/// @inheritdoc INAVCalculator
function setNativeTokenSymbol(string memory nativeTokenSymbol) external {
if (!hasRole(MANAGER, msg.sender)) revert NotAuthorized();
_nativeTokenSymbol = nativeTokenSymbol;
}
/// @inheritdoc INAVCalculator
function setAssetRecoverer(address newAssetRecoverer) external onlyRole(DEFAULT_ADMIN_ROLE) {
address oldAssetRecoverer = assetRecoverer;
assetRecoverer = newAssetRecoverer;
emit AssetRecovererUpdated(oldAssetRecoverer, newAssetRecoverer);
}
/// @inheritdoc INAVCalculator
function setChainlinkL2SequencerUptimeFeed(address newChainlinkL2SequencerUptimeFeed) external {
if (!hasRole(MANAGER, msg.sender)) revert NotAuthorized();
address oldChainlinkL2SequencerUptimeFeed = address(chainlinkL2SequencerUptimeFeed);
chainlinkL2SequencerUptimeFeed = AggregatorV3Interface(newChainlinkL2SequencerUptimeFeed);
emit ChainlinkUptimeFeedUpdated(oldChainlinkL2SequencerUptimeFeed, newChainlinkL2SequencerUptimeFeed);
}
/// @inheritdoc INAVCalculator
function setChainlinkL2SequencerGracePeriod(uint256 newSequencerGracePeriod) external {
if (!hasRole(MANAGER, msg.sender)) revert NotAuthorized();
if (address(chainlinkL2SequencerUptimeFeed) == address(0)) {
revert UptimeFeedNotSet();
}
if (newSequencerGracePeriod == 0) {
revert InvalidArguments();
}
uint256 oldSequencerGracePeriod = chainlinkL2SequencerGracePeriod;
chainlinkL2SequencerGracePeriod = newSequencerGracePeriod;
emit L2SequencerGracePeriodUpdated(oldSequencerGracePeriod, newSequencerGracePeriod);
}
/// @inheritdoc INAVCalculator
function assetCount() external view returns (uint256) {
return _assetDecimals.length();
}
/// @inheritdoc INAVCalculator
function read(address account) external view returns (INAVCalculator.NAV memory nav) {
nav.block = uint64(block.number);
nav.timestamp = uint64(block.timestamp);
uint256 length = _assetDecimals.length();
if (length != 0) {
// read all of the account's positions
// NOTE: this can exceed gas limit
(nav.usd, nav.issues) = readPositionsRange(account, 0, length - 1);
}
}
/// @inheritdoc INAVCalculator
function readPositionsRange(address account, uint256 from, uint256 to)
public
view
returns (int256 usd, uint16 issues)
{
if (from > to || to >= _assetDecimals.length()) {
revert InvalidArguments();
}
if (checkL2SequencerUptime()) {
issues++;
}
// iterate over every known asset
for (uint256 i = from; i <= to; i++) {
(address assetAddr,) = _assetDecimals.at(i);
if (priceOracles[assetAddr].oracle == address(0)) {
revert PriceOracleNotSet();
}
bool bridging = isAssetBridging(assetAddr);
if (bridging) {
issues++;
}
// fetches the current price for this asset
(uint256 usdRate, uint256 usdRateDecimals, bool stale) = _latestPrice(assetAddr);
if (stale) {
issues++;
}
// for each asset, iterate over its known balance oracles
uint256 balanceOracleCount = balanceOracleCountFor(assetAddr);
for (uint256 balanceIdx = 0; balanceIdx < balanceOracleCount; ++balanceIdx) {
usd += _calculatePositionUsdValue(account, assetAddr, balanceIdx, usdRate, usdRateDecimals);
}
}
}
/// @inheritdoc INAVCalculator
function readPosition(address account, address underlyingAsset, uint256 idxBalanceOracle)
external
view
returns (INAVCalculator.Position memory p)
{
if (!_assetDecimals.contains(underlyingAsset)) {
revert AssetNotFound();
}
if (priceOracles[underlyingAsset].oracle == address(0)) {
revert PriceOracleNotSet();
}
bool bridging = isAssetBridging(underlyingAsset);
(uint256 usdRate, uint256 usdRateDecimals, bool stale) = _latestPrice(underlyingAsset);
if (checkL2SequencerUptime()) {
stale = true;
}
return _readPositionWithPrice(
account, underlyingAsset, idxBalanceOracle, usdRate, usdRateDecimals, bridging, stale
);
}
/// @inheritdoc INAVCalculator
function readPositionWithMetadata(address account, address underlyingAsset, uint256 idx)
external
view
returns (INAVCalculator.PositionWithMetadata memory p)
{
(bool contains, uint256 decimals) = _assetDecimals.tryGet(underlyingAsset);
if (!contains) {
revert AssetNotFound();
}
BalanceOracleWithMetadata memory oracleWithMetadata = _balanceOracleWithMetadata(underlyingAsset, idx);
(uint256 usdRate, uint256 usdRateDecimals, bool stale) = _latestPrice(underlyingAsset);
string memory symbol;
if (underlyingAsset == NATIVE_ADDRESS) {
symbol = _nativeTokenSymbol;
} else {
try IERC20Metadata(underlyingAsset).symbol() returns (string memory symbol_) {
symbol = symbol_;
} catch {
symbol = "";
}
}
p.protocol = oracleWithMetadata.protocol;
p.position = oracleWithMetadata.position;
p.positionType = oracleWithMetadata.positionType;
p.underlyingAsset = underlyingAsset;
p.underlyingAssetSymbol = symbol;
p.underlyingAssetDecimals = uint8(decimals);
p.usdRate = usdRate;
p.usdRateDecimals = usdRateDecimals;
p.stale = stale;
p.balance = balanceOf(underlyingAsset, idx, account);
p.usd = _toUsd(p.balance, uint8(decimals), usdRate, usdRateDecimals);
p.bridging = isAssetBridging(underlyingAsset);
return p;
}
/// @inheritdoc INAVCalculator
function usdDecimals() external pure returns (uint8) {
return NAV_DECIMALS;
}
/// @inheritdoc INAVCalculator
function assetAt(uint256 idx) external view returns (INAVCalculator.Asset memory a) {
(address asset, uint256 decimals) = _assetDecimals.at(idx);
a.addr = asset;
a.decimals = uint8(decimals);
}
/// @inheritdoc INAVCalculator
function assets() external view returns (address[] memory) {
return _assetDecimals.keys();
}
//
// BridgeAware
//
/// @inheritdoc BridgeAware
//solhint-disable-next-line func-name-mixedcase, no-empty-blocks
function _bridgeAware_ensureCanCall(bytes4 /* selector */ ) internal view override(BridgeAware) {
// TODO: test this
if (!hasRole(OPERATOR, msg.sender)) revert NotAuthorized();
}
//
// RecoverFunds
//
/// @inheritdoc RecoverFunds
function _assetRecoverer() internal view override(RecoverFunds) returns (address) {
return assetRecoverer;
}
//
// UUPSUpgradeable
//
/// @inheritdoc UUPSUpgradeable
function _authorizeUpgrade(address /* newImpl */ ) internal view override(UUPSUpgradeable) {
if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert NotAuthorized();
}
//
// Internal API
//
/// @notice Computes the full position data, along with the USD vale based on the already-provided exchange rate
/// info
/// @param account The address of the account
/// @param underlyingAsset The address of the asset
/// @param idxBalanceOracle The index of the balance oracle
/// @param usdRate The USD rate of the asset
/// @param usdRateDecimals The number of decimals of the USD rate
/// @param bridging If the asset is bridging
/// @param stale If the price is stale
/// @return p The computed position
function _readPositionWithPrice(
address account,
address underlyingAsset,
uint256 idxBalanceOracle,
uint256 usdRate,
uint256 usdRateDecimals,
bool bridging,
bool stale
) internal view returns (INAVCalculator.Position memory p) {
(bool contains, uint256 decimals) = _assetDecimals.tryGet(underlyingAsset);
if (!contains) {
revert AssetNotFound();
}
p.underlyingAsset = underlyingAsset;
p.balance = balanceOf(underlyingAsset, idxBalanceOracle, account);
p.stale = stale;
p.usdRate = usdRate;
p.usdRateDecimals = usdRateDecimals;
p.bridging = bridging;
p.usd = _toUsd(p.balance, uint8(decimals), usdRate, usdRateDecimals);
}
/// @notice Calculates the USD value of a given position
/// @param account The address of the account
/// @param underlyingAsset The address of the asset
/// @param idxBalanceOracle The index of the balance oracle
/// @param usdRate The USD rate of the asset
/// @param usdRateDecimals The number of decimals of the USD rate
/// @return usd The computed USD value of the position
function _calculatePositionUsdValue(
address account,
address underlyingAsset,
uint256 idxBalanceOracle,
uint256 usdRate,
uint256 usdRateDecimals
) internal view returns (int256 usd) {
(bool contains, uint256 decimals) = _assetDecimals.tryGet(underlyingAsset);
if (!contains) {
revert AssetNotFound();
}
int256 balance = balanceOf(underlyingAsset, idxBalanceOracle, account);
return _toUsd(balance, uint8(decimals), usdRate, usdRateDecimals);
}
/// @notice Converts an asset's balance to USD
/// @param balance The balance of the asset
/// @param decimals The number of decimals of the asset
/// @param usdRate The USD rate of the asset
/// @param usdRateDecimals The number of decimals of the USD rate
/// @return usd The computed balance in USD
function _toUsd(int256 balance, uint16 decimals, uint256 usdRate, uint256 usdRateDecimals)
internal
pure
returns (int256 usd)
{
usd = (balance * int256(usdRate)) / int256(10 ** (decimals + usdRateDecimals - NAV_DECIMALS));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
bytes32 previousAdminRole = getRoleAdmin(role);
$._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId) external view returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData() external view returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import "@chainlink/src/interfaces/feeds/AggregatorV3Interface.sol";
import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IPrices} from "./IPrices.sol";
import {IPriceOracleCustom} from "./IPriceOracleCustom.sol";
import "src/errors.sol";
/// @title Prices
/// @notice This contract manages the price oracles for different tokens.
/// @author kpk
abstract contract Prices is IPrices, Initializable {
//
// Libraries
//
using ERC165Checker for address;
/// @notice Grace period for L2 sequencer downtime
uint256 public chainlinkL2SequencerGracePeriod;
/// @notice Uptime feed for L2 sequencer
AggregatorV3Interface public chainlinkL2SequencerUptimeFeed;
/// @notice Price oracles by address
mapping(address asset => PriceOracle oracle) public priceOracles;
/// @notice Initializer for UUPS proxy
/// @param chainlinkL2SequencerUptimeFeed_ The address of the Chainlink feed for the L2 sequencer
/// uptime. If this is run on a chain without the need of an uptime feed (e.g. L1), this parameter
/// should be set to 0.
// solhint-disable-next-line func-name-mixedcase
function __Prices_init(address chainlinkL2SequencerUptimeFeed_) internal onlyInitializing {
chainlinkL2SequencerUptimeFeed = AggregatorV3Interface(chainlinkL2SequencerUptimeFeed_);
chainlinkL2SequencerGracePeriod = 1 hours; // This is initialised with 1 hour by default.
}
/// @inheritdoc IPrices
function latestPrice(address token) external view returns (uint256 price, uint8 decimals, bool stale) {
(price, decimals, stale) = _latestPrice(token);
stale = checkL2SequencerUptime() || stale;
}
/// @notice Returns the latest price for a given token without checking the uptime of the sequencer.
/// @param token The address of the token.
/// @return price The latest price of the token.
/// @return decimals The amount of decimal places the price is represented with
/// @return stale COMPLETE ME
function _latestPrice(address token) internal view returns (uint256 price, uint8 decimals, bool stale) {
PriceOracle storage oracle = priceOracles[token];
stale = false;
if (oracle.oracle == address(0)) {
revert PriceOracleNotSet();
}
if (oracle.priceType == PriceType.Chainlink) {
AggregatorV3Interface chainlinkOracle = AggregatorV3Interface(oracle.oracle);
(, int256 chainlinkPrice,, uint256 updatedAt,) = chainlinkOracle.latestRoundData();
if (chainlinkPrice <= 0) {
return (0, oracle.decimals, true);
}
if (block.timestamp - updatedAt > oracle.chainlinkHeartbeat) stale = true;
price = uint256(chainlinkPrice);
} else {
bool customStale = false;
(price, customStale) = IPriceOracleCustom(oracle.oracle).getLatestPrice();
stale = stale || customStale;
}
decimals = oracle.decimals;
}
/// @inheritdoc IPrices
function checkL2SequencerUptime() public view returns (bool stale) {
stale = false;
if (address(chainlinkL2SequencerUptimeFeed) != address(0)) {
(, int256 answer, uint256 startedAt,,) = chainlinkL2SequencerUptimeFeed.latestRoundData();
if (answer != 0) {
stale = true;
} else {
// Make sure the grace period has passed after the
// sequencer is back up.
uint256 timeSinceUp = block.timestamp - startedAt;
if (timeSinceUp <= chainlinkL2SequencerGracePeriod) stale = true;
}
}
}
/// @inheritdoc IPrices
function checkPriceOracleSupport(address token, address oracle, PriceType priceType) public view {
if (oracle == address(0) || token == address(0)) {
revert InvalidPriceOracle();
}
if (priceType == PriceType.Custom) {
if (!oracle.supportsInterface(type(IPriceOracleCustom).interfaceId)) {
revert InvalidPriceOracle();
}
} else if (priceType == PriceType.Chainlink) {
AggregatorV3Interface(oracle).latestRoundData();
} else {
revert InvalidPriceOracleType();
}
if (priceOracles[token].oracle != address(0)) {
revert PriceOracleAlreadySet();
}
}
/// @notice Sets the oracle for a given token.
/// @param token The address of the token.
/// @param oracle The address of the oracle.
/// @param chainlinkHeartbeat The heartbeat interval for the Chainlink oracle. This parameter is ignored for
/// non-Chainlink oracles.
/// @param priceType The type of the oracle.
function _setPriceOracle(address token, address oracle, uint256 chainlinkHeartbeat, PriceType priceType) internal {
checkPriceOracleSupport(token, oracle, priceType);
uint8 decimals;
if (priceType == PriceType.Chainlink) {
if (chainlinkHeartbeat == 0) revert InvalidPriceOracle();
decimals = AggregatorV3Interface(oracle).decimals();
} else {
decimals = IPriceOracleCustom(oracle).decimals();
}
priceOracles[token] = PriceOracle({
oracle: oracle,
priceType: priceType,
decimals: decimals,
chainlinkHeartbeat: chainlinkHeartbeat
});
emit PriceOracleSet(token, oracle, chainlinkHeartbeat, priceType);
}
/// @notice Removes the oracle for a given token.
/// @param token The address of the token.
function _removePriceOracle(address token) internal {
delete priceOracles[token];
emit PriceOracleRemoved(token);
}
/// @notice Gap for upgradeability
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IBalances} from "./IBalances.sol";
import {IBalanceOracleCustom} from "./IBalanceOracleCustom.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import "src/errors.sol";
/// @title Balances
/// @author kpk
/// @notice Manages the balance oracles for different tokens and their latest balances.
abstract contract Balances is IBalances, Initializable {
//
// Libraries
//
using ERC165Checker for address;
using SafeCast for uint256;
using EnumerableMap for EnumerableMap.AddressToUintMap;
//
// Constants
//
/// @notice ERC-7528 convention for ETH address representation
address public constant NATIVE_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
/// @notice The symbol of the chain's native token, used for display purposes
string internal _nativeTokenSymbol;
//
// Storage
//
/// @notice Mapping from token address to balance oracles.
mapping(address token => EnumerableMap.AddressToUintMap oracles) private _balanceOracles;
/// @notice Total count of balance oracles.
uint256 public balanceOracleTotalCount;
//
// Constructor
//
/// @notice Initializer for UUPS proxy
// solhint-disable-next-line func-name-mixedcase
function __Balances_init() internal onlyInitializing {
// This is equal everywhere, so we add it right away. The same does noy apply for the adding of the price
// oracle. The native token will not be added to the _assetDecimals mapping unless the proper price oracle is
// set.
_balanceOracles[NATIVE_ADDRESS].set(NATIVE_ADDRESS, uint256(BalanceType.Native));
balanceOracleTotalCount = 1;
_nativeTokenSymbol = "ETH"; // Default value, can be overridden by derived contracts
}
//
// IBalances
//
/// @inheritdoc IBalances
function balanceOf(address underlyingAsset, uint256 idx, address account) public view returns (int256) {
if (idx >= _balanceOracles[underlyingAsset].length()) {
revert BalanceOracleNotSet();
}
(address oracleAddress, uint256 balanceTypeUInt) = _balanceOracles[underlyingAsset].at(idx);
BalanceType balanceType = BalanceType(balanceTypeUInt);
if (oracleAddress == address(0)) {
revert BalanceOracleNotSet();
}
int256 balance;
if (balanceType == BalanceType.ERC20) {
balance = ERC20(oracleAddress).balanceOf(account).toInt256();
} else if (balanceType == BalanceType.Native) {
balance = address(account).balance.toInt256();
} else {
balance = IBalanceOracleCustom(oracleAddress).balanceOf(underlyingAsset, account);
}
return balance;
}
/// @inheritdoc IBalances
function balanceOracleCountFor(address underlyingAsset) public view override returns (uint256) {
return _balanceOracles[underlyingAsset].length();
}
/// @inheritdoc IBalances
function balanceOracleAt(address underlyingAsset, uint256 idx)
public
view
override
returns (address, BalanceType)
{
(address oracleAddress, uint256 balanceTypeUInt) = _balanceOracles[underlyingAsset].at(idx);
return (oracleAddress, BalanceType(balanceTypeUInt));
}
/// @inheritdoc IBalances
function balanceOracles(address underlyingAsset) public view override returns (address[] memory) {
return _balanceOracles[underlyingAsset].keys();
}
/// @inheritdoc IBalances
function balanceOraclesWithMetadata(address underlyingAsset)
public
view
override
returns (BalanceOracleWithMetadata[] memory)
{
uint256 len = _balanceOracles[underlyingAsset].length();
BalanceOracleWithMetadata[] memory list = new BalanceOracleWithMetadata[](len);
for (uint256 idx = 0; idx < len; idx++) {
list[idx] = _balanceOracleWithMetadata(underlyingAsset, idx);
}
return list;
}
/// @inheritdoc IBalances
function checkBalanceOracleSupport(address underlyingAsset, address oracle, BalanceType balanceType) public view {
if (oracle == address(0) || underlyingAsset == address(0)) revert InvalidArguments();
if (balanceType == BalanceType.Custom) {
if (!oracle.supportsInterface(type(IBalanceOracleCustom).interfaceId)) {
revert InvalidBalanceOracle();
}
} else if (balanceType == BalanceType.ERC20) {
ERC20(oracle).balanceOf(address(this));
} else if (balanceType == BalanceType.Native) {
// Native balance oracles are always supported, added in the constructor
revert DuplicateBalanceOracle();
} else {
revert InvalidBalanceOracleType();
}
if (_balanceOracles[underlyingAsset].contains(oracle)) {
revert DuplicateBalanceOracle();
}
}
//
// Internal API
//
/// @notice Sets the oracle for a given underlying asset.
/// @param underlyingAsset The address of the token.
/// @param oracle The address of the oracle.
/// @param balanceType The type of the oracle.
function _addBalanceOracle(address underlyingAsset, address oracle, BalanceType balanceType) internal {
checkBalanceOracleSupport(underlyingAsset, oracle, balanceType);
_balanceOracles[underlyingAsset].set(oracle, uint256(balanceType));
balanceOracleTotalCount++;
emit BalanceOracleAdd(underlyingAsset, oracle, balanceType);
}
/// @notice Removes the oracle for a given underlying asset.
/// @param underlyingAsset The address of the token.
/// @param oracle The address of the oracle.
function _removeBalanceOracle(address underlyingAsset, address oracle) internal {
if (underlyingAsset == NATIVE_ADDRESS && oracle == NATIVE_ADDRESS) revert InvalidArguments();
bool removed = _balanceOracles[underlyingAsset].remove(oracle);
if (!removed) {
revert InvalidBalanceOracle();
}
balanceOracleTotalCount--;
emit BalanceOracleRemoved(underlyingAsset, oracle);
}
/// @notice Fetches metadata for the oracle at a specific index for an asset
/// @dev Constructs a `BalanceOracleWithMetadata` by:
/// 1. If `Custom`, calling `positionMetadata()` on the custom oracle
/// 2. If `Native`, using `_nativeTokenSymbol` and type "Native"
/// 3. Otherwise (`ERC20`), attempting `symbol()` or falling back to empty string
/// @param underlyingAsset The asset whose oracle metadata is fetched
/// @param idx The index of the balance oracle.
/// @return balanceOracleWithMetadata A struct with `oracle`, `protocol`, `position`, and `positionType` fields
function _balanceOracleWithMetadata(address underlyingAsset, uint256 idx)
internal
view
returns (BalanceOracleWithMetadata memory balanceOracleWithMetadata)
{
(address oracle, uint256 balanceTypeUInt) = _balanceOracles[underlyingAsset].at(idx);
BalanceType balanceType = BalanceType(balanceTypeUInt);
IBalanceOracleCustom.PositionMetadata memory metadata;
if (balanceType == BalanceType.Custom) {
metadata = IBalanceOracleCustom(oracle).positionMetadata();
} else if (balanceType == BalanceType.Native) {
metadata = IBalanceOracleCustom.PositionMetadata({
protocol: "Portfolio balance",
position: _nativeTokenSymbol,
positionType: "Native"
});
} else {
string memory symbol;
try ERC20(oracle).symbol() returns (string memory symbol_) {
symbol = symbol_;
} catch {
symbol = "";
}
metadata = IBalanceOracleCustom.PositionMetadata({
protocol: "Portfolio balance",
position: symbol,
positionType: "ERC20"
});
}
return BalanceOracleWithMetadata({
oracle: oracle,
protocol: metadata.protocol,
position: metadata.position,
positionType: metadata.positionType
});
}
/// @notice Gap for upgradeability
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {IPrices} from "src/prices/Prices.sol";
import {IBalances} from "src/balances/Balances.sol";
/// @title INAVCalculator Interface
/// @notice Interface for NAVCalculator contract
/// @author kpk
interface INAVCalculator {
/// @notice A holding a specific asset, and its corresponding usd equivalent
/// This can represent a direct ERC20 balance, or a position deposited in a 3rd party contract
/// @param underlyingAsset Address of the token
/// @param balance The amount of the asset
/// @param usd Amount of USD equivalent represented with NAV_DECIMALS decimals
/// @param usdRate The usd rate used, i.e. the USD price per one full token unit, scaled by `usdRateDecimals`
/// @param usdRateDecimals The decimals with which usdRate is represented
/// @param bridging Whether this asset is undergoing a bridge operation
/// @param stale Whether this asset's USD price is currently considered stale
struct Position {
address underlyingAsset;
int256 balance;
int256 usd;
uint256 usdRate;
uint256 usdRateDecimals;
bool bridging;
bool stale;
}
/// @notice An enriched position record including on‑chain amounts plus human‑readable metadata
/// @param protocol The protocol name for the position (e.g. "Portfolio balance", "Aave", etc.)
/// @param position The specified position within the protocol
/// @param positionType The type of the position (e.g., "Supplied", "Borrowed", "Native", "ERC20", etc.).
/// @param underlyingAsset The address of the underlying token
/// @param underlyingAssetSymbol The symbol of the underlying asset (e.g. "USDC", "ETH")
/// @param underlyingAssetDecimals Number of decimals of the underlying asset
/// @param usdRate The usd rate used, i.e. the USD price per one full token unit, scaled by `usdRateDecimals`
/// @param usdRateDecimals The decimals with which usdRate is represented
/// @param stale Whether this asset's USD price is currently considered stale
/// @param balance The equivalent balance of this underlyng asset (signed to allow negative/debt positions)
/// @param usd Amount of USD equivalent represented with NAV_DECIMALS decimals
/// @param bridging Whether this asset is undergoing a bridge operation
struct PositionWithMetadata {
string protocol;
string position;
string positionType;
address underlyingAsset;
string underlyingAssetSymbol;
uint8 underlyingAssetDecimals;
uint256 usdRate;
uint256 usdRateDecimals;
bool stale;
int256 balance;
int256 usd;
bool bridging;
}
/// @notice The complete NAV snapshot
/// @param block Block number this reading refers to
/// @param timestamp Block timestamp this reading refers to
/// @param usd Total USD calculated
/// @param issues Counter of issues found (bridging & stale operations).
/// @notice Anything other than 0 means this reading should not be used to compute deposits/withdrawals,
/// @notice but may still be kept for notifications & historical purposes
struct NAV {
uint64 block;
uint64 timestamp;
int256 usd;
uint16 issues;
}
/// @notice A known ERC20 asset
/// @param addr The address of the asset
/// @param decimals The number of decimals the asset uses
struct Asset {
address addr;
uint8 decimals;
}
//
// Events
//
/// @notice Event emitted when the string for the native token symbol is set
/// @param nativeTokenSymbol The symbol of the chain's native token
event NativeTokenSymbolSet(string indexed nativeTokenSymbol);
/// @notice Event emitted when the asset recoverer is updated by a call to `setAssetRecoverer`
/// @param oldAssetRecoverer The address of the old asset recoverer
/// @param newAssetRecoverer The address of the new asset recoverer
event AssetRecovererUpdated(address indexed oldAssetRecoverer, address indexed newAssetRecoverer);
/// @notice Event emitted when the Chainlink uptime feed is updated by a call to `setChainlinkUptimeFeed`
/// @param oldChainlinkUptimeFeed The address of the old Chainlink uptime feed
/// @param newChainlinkUptimeFeed The address of the new Chainlink uptime feed
event ChainlinkUptimeFeedUpdated(address indexed oldChainlinkUptimeFeed, address indexed newChainlinkUptimeFeed);
/// @notice Event emitted when the L2 sequencer grace period is updated by a call to `setSequencerGracePeriod`
/// @param oldSequencerGracePeriod The old sequencer grace period in seconds
/// @param newSequencerGracePeriod The new sequencer grace period in seconds
event L2SequencerGracePeriodUpdated(uint256 oldSequencerGracePeriod, uint256 newSequencerGracePeriod);
//
// Errors
//
/// @notice Emitted when an asset is not found
error AssetNotFound();
/// @notice Emitted when 'setSequencerGracePeriod' is called and 'chainlinkUptimeFeed' is the zero address
error UptimeFeedNotSet();
/// @notice Adds a new asset to the calculator along with its price oracle
/// @param asset The address of the asset to add
/// @param oracle The address of the price oracle to use
/// @param priceType The type of the price oracle
/// @param chainlinkHeartbeat The heartbeat interval for the Chainlink oracle. This is relevant only for Chainlink
/// oracles.
function addPrice(address asset, address oracle, IPrices.PriceType priceType, uint256 chainlinkHeartbeat)
external;
/// @notice Adds a new balance source to an existing underlying asset.
/// @param underlyingAsset The address of the token to add a balance oracle to.
/// @param oracle The address of the balance oracle to use.
/// @param balanceType The type of the balance.
function addBalance(address underlyingAsset, address oracle, IBalances.BalanceType balanceType) external;
/// @notice Removes the oracle for a given token.
/// @param underlyingAsset The address of the token.
function removePrice(address underlyingAsset) external;
/// @notice Removes the oracle for a given token.
/// @param underlyingAsset The address of the token.
/// @param oracle The address of the oracle.
function removeBalance(address underlyingAsset, address oracle) external;
/// @notice Sets the symbol of the native token used for display purposes (e.g. "xDAI")
/// @dev This function can only be called by the manager role
/// @param nativeTokenSymbol The symbol of the native token
function setNativeTokenSymbol(string memory nativeTokenSymbol) external;
/// @notice Update The asset recoverer address
/// @param addr The new asset recoverer
function setAssetRecoverer(address addr) external;
/// @notice Update the Chainlink L2 sequencer uptime feed address
/// @param newChainlinkL2UptimeFeed The new Chainlink L2 sequencer uptime feed address
function setChainlinkL2SequencerUptimeFeed(address newChainlinkL2UptimeFeed) external;
/// @notice Sets the Chainlink L2 sequencer grace period
/// @param newSequencerGracePeriod The new Chainlink L2 sequencer grace period in seconds
function setChainlinkL2SequencerGracePeriod(uint256 newSequencerGracePeriod) external;
/// @notice Counts the number of assets known by this calculator.
/// @return the number of assets known by this calculator.
function assetCount() external view returns (uint256);
/// @notice Reads the current NAV of a given account.
/// @param account The address of the account to calculate for.
/// @dev This function reads all known assets, and might exhaust gas if there are too many
/// assets known by the calculator contract at the time of calling.
/// It is recommended to use the readPositionsRange function instead, with an appropriate range of assets and call
/// it multiple times if necessary.
/// @return The NAV of the account.
function read(address account) external view returns (NAV memory);
/// @notice Reads the holdings of a given account, for a limited range of assets
/// Also includes the corresponding usd total, and the amount of issues found long the way
///
/// Important :
/// - The ordering of oracles in the underlying data structure is not guaranteed. Entries may change order as
/// oracles are added or removed . It is not safe to assume a fixed order or that the same
/// query will yield a consistent oracle order.
///
/// - Ensure that any external integrations using
/// the oracle data accounts for potential reordering, and calls `balanceOracleAt` directly for
/// verification if needed.
///
/// @param account The address to calculate for
/// @param underlyingAsset The address of the token to calculate
/// @param idx The index of the balance oracle
/// @return p A `Position` struct containing:
/// • `underlyingAsset` – the token address
/// • `balance` – the on‑chain asset amount (signed to allow negative/debt)
/// • `usdRate` – USD price per full token unit (scaled by `usdRateDecimals`)
/// • `usdRateDecimals` – decimals used in `usdRate`
/// • `usd` – amount of USD equivalent represented with NAV_DECIMALS decimals
/// • `bridging` – whether this asset is undergoing a bridge operation
/// • `stale` – whether this asset's USD price is currently considered stale
function readPosition(address account, address underlyingAsset, uint256 idx)
external
view
returns (Position memory p);
/// @notice Reads a single enriched position record—including human‑readable metadata for a given account and
/// balance oracle.
/// @param account The address to calculate for
/// @param underlyingAsset The address of the token to calculate
/// @param idx The index of the balance oracle
/// @return p A `PositionWithMetadata` struct containing:
/// • `protocol` — The protocol name for the position (e.g. "Portfolio balance", "Aave", etc.)
/// • `position` — The specified position within the protocol
/// • `positionType` — The type of the position (e.g., "Supplied", "Borrowed", "ERC20", etc.)
/// • `underlyingAsset`— The address of the underlying token
/// • `underlyingAssetSymbol` — The symbol of the underlying asset (e.g. "USDC", "ETH")
/// • `underlyingAssetDecimals` — Number of decimals of the underlying asset
/// • `usdRate` — The USD price per one full token unit, scaled by `usdRateDecimals`
/// • `usdRateDecimals` — How many decimals are used in `usdRate`
/// • `stale` — Whether this asset’s USD price is currently considered stale
/// • `balance` — The equivalent balance of this underlying asset (signed to allow negative/debt
/// positions)
/// • `usd` — Amount of USD equivalent represented with `NAV_DECIMALS` decimals
/// • `bridging` — Whether this asset is undergoing a bridge operation
function readPositionWithMetadata(address account, address underlyingAsset, uint256 idx)
external
view
returns (PositionWithMetadata memory p);
/// @notice Reads the holdings of a given account, for a limited range of assets.
/// Also includes the corresponding usd total, and the amount of issues found long the way.
///
/// Important:
/// - The ordering of balances in the returned array is not guaranteed. Entries may change order as oracles
/// are added or removed from the nav calculator. It is not safe to assume a fixed order or that the same
/// query will yield a consistent oracle order.
///
/// - To ensure complete and consistent data, it is recommended to retrieve the full range in a single query.
///
/// - If a caller splits their query range into smaller parts (e.g., retrieving assets 0 to 20 in two
/// separate calls: 0-10 and 11-20), there is a risk of duplicating or missing assets if a oracle for that asset
/// was added or removed. Ensure that any external integrations using
/// the oracle data account for potential reordering, and calls `balanceOracleAt` directly for
/// verification if needed.
///
/// @param account The address to calculate for
/// @param from The index of the first balance oracle
/// @param to The index of the last balance oracle
/// @return usd The total USD value of the positions
/// @return issues The amount of issues found
function readPositionsRange(address account, uint256 from, uint256 to)
external
view
returns (int256 usd, uint16 issues);
/// @notice The amount of decimals returned with each USD value
/// @return The amount of decimals
function usdDecimals() external view returns (uint8);
/// @notice Returns the asset at a given index
/// @param idx The index of the asset
/// @return The asset at the given index
function assetAt(uint256 idx) external view returns (Asset memory);
/// @notice Returns the assets for this calculator
/// @return The assets known by this calculator
function assets() external view returns (address[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import "src/errors.sol";
/// @title BridgeAware
/// @author kpk
/// @notice A contract to be called alongside briding operations, and notifying listener contracts when such operations
/// are started/finalized
///
/// @notice The end goal for this feature is to tag bridged funds in the NAV Calculator logic, so that historical data
/// can be used instead while funds are in transit, in order to prevent undercounting or double-counting funds.
/// @notice Through Zodiac Pilot, it should be enforced that all bridge operations must also include a call to this
/// contract, thereby ensuring the NAVCalculator correctly accounts for the operation.
///
/// @notice Bridging operations are then expected to be manually marked as finished by an operator (which can be human
/// or automated), once it is verified that the funds have reached the destination chain, and accounting can proceed
/// normally
abstract contract BridgeAware {
//
// Type definitions
//
/// @notice Record of a pending bridge operation
/// @param id Unique identifier for the operation
/// @param asset ERC20 Asset to bridge
/// @param blockNumber Block number where operation started
struct BridgeOperation {
bytes32 id;
address asset;
uint96 blockNumber;
}
//
// Storage
//
/// @notice Mapping of bridge operations
mapping(bytes32 id => BridgeOperation operation) public bridgeOperations;
/// @notice How many bridge operations currently taking place for a given token
mapping(address token => uint256 bridgingCount) public assetBridgingCounts;
//
// Events
//
/// @notice Emitted when a bridge operation is requested
/// @param id The unique identifier of the operation
/// @param asset ERC20 Asset to bridge
event BridgeOperationStarted(bytes32 id, address asset);
/// @notice Emitted when a bridge operation is manually finalized
/// @param id The unique identifier of the
event BridgeOperationFinalized(bytes32 id);
//
// External API
//
/// @notice Start a bridge operation
/// @param underlyingAsset ERC20 Asset to bridge
/// @return id Unique identifier for the operation
function bridgeStart(address underlyingAsset) external returns (bytes32 id) {
_bridgeAware_ensureCanCall(this.bridgeStart.selector);
id = keccak256(abi.encodePacked(uint96(block.number), underlyingAsset));
BridgeOperation memory op = BridgeOperation({id: id, asset: underlyingAsset, blockNumber: uint96(block.number)});
// prevent duplicate operations (in the same block)
BridgeOperation memory existing = bridgeOperations[id];
if (existing.id != 0 || existing.blockNumber != 0 || existing.asset != address(0)) {
revert DuplicateBridgeOperation();
}
// updates state
bridgeOperations[id] = op;
unchecked {
assetBridgingCounts[op.asset]++;
}
emit BridgeOperationStarted(id, underlyingAsset);
return id;
}
/// @notice Indicates a bridge operation has been completed
/// This voluntarily unfreezes the asset count for that token (unless other operations with the same token are
/// also pending), causing the NAV calculator to start updating the value once again
/// @param id The unique identifier of the operation
function bridgeFinalize(bytes32 id) external {
_bridgeAware_ensureCanCall(this.bridgeFinalize.selector);
BridgeOperation memory op = bridgeOperations[id];
if (op.id == 0 && op.blockNumber == 0 && op.asset == address(0)) {
revert BridgeOperationNotFound();
}
if (op.blockNumber == block.number) {
revert CantFinalizeOnSameBlock();
}
// update state
assetBridgingCounts[op.asset]--;
delete bridgeOperations[id];
emit BridgeOperationFinalized(id);
}
/// @notice Check if a given asset is currently undergoing a bridge operation
/// @param underlyingAsset The asset to check
/// @return true if the asset is currently undergoing a bridge operation
function isAssetBridging(address underlyingAsset) public view returns (bool) {
return assetBridgingCounts[underlyingAsset] > 0;
}
/// @notice Overridable function to include permissions specifying permissions for calling `bridgeStart` and
/// `bridgeFinalize`
/// @notice By default, the function allows all calls
///
/// @param selector The selector of the function being called
//solhint-disable-next-line func-name-mixedcase, no-empty-blocks
function _bridgeAware_ensureCanCall(bytes4 selector) internal virtual {}
/// @notice Gap for upgradeability
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
abstract contract RecoverFunds {
using SafeERC20 for IERC20;
/// @notice Recover assets to the asset recoverer
/// @param assets The address of the assets to recover
function recoverAssets(address[] calldata assets) external {
uint256 length = assets.length;
for (uint256 i; i < length; ++i) {
IERC20(assets[i]).safeTransfer(_assetRecoverer(), _assetRecoverableAmount(assets[i]));
}
}
/// @notice The address who will receive locked funds
/// @return The address to which the recovered assets will be sent
function _assetRecoverer() internal virtual returns (address);
/// @notice Overridable function to check whether an asset can be safely recovered without breaking other contract's
/// invariants
/// @param token The address of the token to recover
/// @return true if the token can be recovered, false otherwise
function _assetRecoverableAmount(address token) internal view virtual returns (uint256) {
return IERC20(token).balanceOf(address(this));
}
/// @notice Gap for upgradeability
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.20;
import {EnumerableSet} from "./EnumerableSet.sol";
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code repetition as possible, we write it in
// terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,
// and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit in bytes32.
/**
* @dev Query for a nonexistent map key.
*/
error EnumerableMapNonexistentKey(bytes32 key);
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 key => bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
bytes32 value = map._values[key];
if (value == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
if (value == 0 && !contains(map, key)) {
revert EnumerableMapNonexistentKey(key);
}
return value;
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
return map._keys.values();
}
// UintToUintMap
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintToAddressMap
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressToUintMap
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// Bytes32ToUintMap
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8; error InvalidArguments(); error DuplicateBridgeOperation(); error BridgeOperationNotFound(); error CantFinalizeOnSameBlock(); error NoPendingDepositRequest(); error NoPendingRedeemRequest(); error InsufficientShares(); error NotAuthorized(); error NotChainlinkOracle();
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
uint8 constant NAV_DECIMALS = 8;
// Define the Shares contract INVESTOR role ID
bytes32 constant INVESTOR = keccak256("INVESTOR"); // 0x5614e11ca6d7673c9c8dcec913465d676494aad1151bb2c1cf40b9d99be4d935
// Define the NAVCalculator contract MANAGER role ID
bytes32 constant MANAGER = keccak256("MANAGER"); // 0xaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c
// Define the OPERATOR role ID, used for the Shares contract and for the bridging operations in the NAVCalculator
// contract
bytes32 constant OPERATOR = keccak256("OPERATOR"); // 0x523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c
bytes32 constant DEFAULT_ADMIN_ROLE = 0x00;
uint256 constant ONE_HUNDRED_PERCENT = 100e18;
uint256 constant TEN_PERCENT = 10e18;// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/// @title IOracleManager
/// @notice Interface for managing price oracles for different tokens.
/// @author kpk
interface IPrices {
/// @notice Enum representing the type of oracle.
enum PriceType {
Chainlink,
Custom
}
/// @notice Struct representing an oracle and its type.
/// @param oracle The address of the oracle contract.
/// @param decimals The number of decimal places the oracle uses.
/// @param chainlinkHeartbeat The heartbeat interval for the Chainlink oracle. This is relevant only for Chainlink
/// oracles.
/// @param priceType The type of the oracle (Chainlink or Custom).
struct PriceOracle {
address oracle;
uint8 decimals;
uint256 chainlinkHeartbeat;
PriceType priceType;
}
/// @notice Emitted when an oracle is set for a token.
/// @param underlyingAsset The address of the token.
/// @param oracle The address of the oracle.
/// @param chainlinkHeartbeat The heartbeat interval for the Chainlink oracle. This is relevant only for Chainlink
/// oracles.
/// @param priceType The type of the oracle.
event PriceOracleSet(
address indexed underlyingAsset, address indexed oracle, uint256 chainlinkHeartbeat, PriceType priceType
);
/// @notice Emitted when an oracle is removed for a token.
/// @param underlyingAsset The address of the token.
event PriceOracleRemoved(address indexed underlyingAsset);
//
// Errors
//
/// @notice Error when the price oracle is
error PriceOracleNotSet();
/// @notice Error when the price oracle is invalid
error InvalidPriceOracle();
/// @notice Error when the price oracle type is not valid
error InvalidPriceOracleType();
/// @notice Error when the price oracle is already set
error PriceOracleAlreadySet();
/// @notice Returns the latest price for a given token while checking if the price is stale.
/// @param underlyingAsset The address of the token.
/// @return price The latest price of the token.
/// @return decimals The amount of decimal places the price is represented with.
/// @return stale If the price returned is stale, be it by heartbeat, L2 sequencer down or L2 sequencer's feed
/// within grace period.
function latestPrice(address underlyingAsset) external view returns (uint256 price, uint8 decimals, bool stale);
/// @notice Checks if the L2 sequencer is up and running. If 'chainlinkL2SequencerUptimeFeed' is the zero address
/// (e.g. on an L1) it returns false.
/// @return stale If the L2 sequencer is down or if it's within the grace period.
function checkL2SequencerUptime() external view returns (bool stale);
/// @notice Checks if the oracle supports the given oracle type.
/// @param underlyingAsset The address of the token.
/// @param oracle The address of the oracle.
/// @param priceType The type of the oracle.
function checkPriceOracleSupport(address underlyingAsset, address oracle, PriceType priceType) external view;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/// @title IPriceOracleCustom
/// @notice This interface defines the standard functions for a custom price oracle.
/// @author kpk
interface IPriceOracleCustom is IERC165 {
/// @notice Returns the latest price for for the underlying asset, and whether the price is stale
/// (only relevant when this custom oracle makes use of an external oracle)
/// @return price The latest price of the underlying asset.
/// @return stale If the price returned is stale.
function getLatestPrice() external view returns (uint256 price, bool stale);
/// @notice Returns the number of decimals the oracle uses.
/// @return decimals the number of decimals the oracle uses.
function decimals() external view returns (uint8 decimals);
/// @notice Returns the address of the underlying asset supported by this oracle.
/// @return underlyingAsset The address of the underlying asset supported by this oracle.
function underlyingAssetSupported() external view returns (address underlyingAsset);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
interface IBalances {
//
// Type definitions
//
/// @notice Enum representing the types of balance oracles.
/// @param ERC20 The oracle is an ERC20 token.
/// @param Native The native token of the underlying chain.
/// @param Custom The balance oracle is a custom oracle.
enum BalanceType {
ERC20,
Native,
Custom
}
/// @notice Struct representing a balance oracle.
/// @param oracle The address of the oracle.
/// @param balanceType The type of the oracle (ERC20, Native or Custom).
struct BalanceOracle {
address oracle;
BalanceType balanceType;
}
/// @notice Struct representing a balance oracle with metadata.
/// @param oracle The address of the oracle.
/// @param protocol The protocol name.
/// @param position The specified position within the protocol.
/// @param positionType The type of the position (e.g., "Supplied", "Borrowed", "Staked").
struct BalanceOracleWithMetadata {
address oracle;
string protocol;
string position;
string positionType;
}
//
// Events
//
/// @notice Event emitted when a balance oracle is added for an underlying asset.
/// @param underlyingAsset The address of the token for which the oracle is set.
/// @param oracle The address of the oracle being set.
/// @param oracleType The type of the oracle (ERC20 or Custom).
event BalanceOracleAdd(address indexed underlyingAsset, address indexed oracle, BalanceType oracleType);
/// @notice Event emitted when a balance oracle is removed for an underlying asset.
/// @param underlyingAsset The address of the token for which the oracle is removed.
/// @param oracle The address of the balance oracles to remove from the token oracle set.
event BalanceOracleRemoved(address indexed underlyingAsset, address oracle);
//
// Errors
//
/// @notice Error when the balance oracle is not set.
error BalanceOracleNotSet();
/// @notice Error when the balance oracle is not valid
error InvalidBalanceOracle();
/// @notice Error when the balance oracle type is not valid
error InvalidBalanceOracleType();
/// @notice Error when the same balance oracle is already set.
error DuplicateBalanceOracle();
/// @notice Returns the latest balance for the given underlying asset and account.
///
/// Important :
/// - The ordering of assets in the underlying data structure is not guaranteed. Entries may change order as
/// oracles are added or removed . It is not safe to assume a fixed order or that the same
/// query will yield a consistent oracle order.
///
/// - Ensure that any external integrations using
/// the oracle data accounts for potential reordering, and calls `balanceOracleAt` directly for
/// verification if needed.
///
/// @param underlyingAsset The address of the token.
/// @param idx The index of the balance oracle.
/// @param account The address of the account.
/// @return balance The latest balance of the account for the token.
function balanceOf(address underlyingAsset, uint256 idx, address account) external view returns (int256 balance);
/// @notice Returns the amount of balance oracles defined for a given underlying asset
/// @param underlyingAsset The address of the token.
/// @return count The amount of balance oracles defined for the token.
function balanceOracleCountFor(address underlyingAsset) external view returns (uint256 count);
/// @notice Returns the balance oracle and type for a given underlying asset
/// @param underlyingAsset The address of the token.
/// @param idx The index of the balance oracle.
/// @return oracle The address of the balance oracle.
/// @return balanceType The type of the balance oracle.
function balanceOracleAt(address underlyingAsset, uint256 idx) external view returns (address, BalanceType);
/// @notice Returns all the balance oracles addresses for a given underlying asset
/// @param underlyingAsset The address of the token.
/// @return oracles The address of the balance oracle.
function balanceOracles(address underlyingAsset) external view returns (address[] memory oracles);
/// @notice Retrieve all configured balance oracles for a given underlying asset, including human‑readable metadata.
/// @dev
/// - Custom oracles (BalanceType.Custom) provide metadata via their own `positionMetadata()` hook.
/// - Native oracles (BalanceType.Native) return a default metadata struct with:
/// protocol = "Portfolio balance",
/// position = _nativeTokenSymbol,
/// positionType = "Native"
/// - ERC20 oracles (BalanceType.ERC20) attempt to read the underlying asset token’s `symbol()`. On failure,
/// the `position` field is left empty.
/// - The returned array order corresponds to the internal oracle set’s iteration; callers should not
/// assume any particular order across invocations.
/// @param underlyingAsset The token address whose oracles you wish to query.
/// @return list An array of `BalanceOracleWithMetadata` structs, each containing:
/// - oracle The oracle contract’s address.
/// - protocol The name of the protocol or system supplying the balance.
/// - position A position identifier (e.g. token symbol or custom string).
/// - positionType A tag describing the position (“Native”, “ERC20”, or custom type).
function balanceOraclesWithMetadata(address underlyingAsset)
external
view
returns (BalanceOracleWithMetadata[] memory);
/// @notice Checks if the oracle supports the given oracle type.
/// @param underlyingAsset The address of the token.
/// @param oracle The address of the oracle.
/// @param oracleType The type of the oracle.
function checkBalanceOracleSupport(address underlyingAsset, address oracle, BalanceType oracleType) external view;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
/// @title IBalanceOracleCustom
/// @author kpk
/// @notice A standard interface for custom balance oracles that map a user’s DeFi position
/// (vault shares, receipt tokens, LP tokens, etc.) back into an amount of an underlying token asset.
/// @dev Extends ERC165 to allow on‐chain discovery with `supportsInterface`.
interface IBalanceOracleCustom is IERC165 {
/// @notice Metadata tags describing the DeFi position this oracle is associated to.
/// @param protocol The protocol name.
/// @param position The specified position within the protocol.
/// @param positionType The type of the position (e.g., "Supplied", "Borrowed", "Staked").
struct PositionMetadata {
string protocol;
string position;
string positionType;
}
/// @notice Calculates the current value of a user’s holdings in this DeFi position,
/// expressed in the underlying asset.
/// @param underlyingAsset The token address in which the position’s value is denominated.
/// @param account The address whose position balance is being queried.
/// @return balance The amount of `underlyingAsset` that `account`’s position is worth, as a signed integer.
function balanceOf(address underlyingAsset, address account) external view returns (int256 balance);
/// @notice Returns the list of all the underlying assets supported by this oracle.
/// @dev The returned list may be empty if the oracle cannot determine or provide the supported assets.
/// @return underlyingAssets The list of underlying asset addresses supported by this oracle (may be empty).
function underlyingAssetsSupported() external view returns (address[] memory underlyingAssets);
/// @notice Metadata tags describing the DeFi position this oracle is associated to.
/// @return positionMetadata The position metadata associated with this oracle.
function positionMetadata() external view returns (PositionMetadata memory positionMetadata);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @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.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @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
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
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
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
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
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
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
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
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
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
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
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
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
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
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
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
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
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
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
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
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
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
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
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
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
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
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
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
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
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
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
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
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
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
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
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
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
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
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
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
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
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
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
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
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
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
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
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
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
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
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
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
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
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
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
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
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
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
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
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
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
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
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
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @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
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @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
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @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
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @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
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @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
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @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
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @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
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @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
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @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
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @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
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @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
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @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
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @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
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @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
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @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
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @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
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @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
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @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
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @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
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @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
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @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
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @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
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @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
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @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
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @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
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @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
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @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
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @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
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @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
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @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
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 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 Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(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.
*/
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.
*/
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 Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
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 silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* 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[EIP 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}{
"remappings": [
"src/=src/",
"@chainlink/=lib/foundry-chainlink-toolkit/",
"forge-std/=lib/forge-std/src/",
"foundry-chainlink-toolkit/=lib/foundry-chainlink-toolkit/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"morpho-blue/=lib/morpho-blue/",
"chainlink-brownie-contracts/=lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/",
"ds-test/=lib/foundry-chainlink-toolkit/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/foundry-chainlink-toolkit/lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AssetNotFound","type":"error"},{"inputs":[],"name":"BalanceOracleNotSet","type":"error"},{"inputs":[],"name":"BridgeOperationNotFound","type":"error"},{"inputs":[],"name":"CantFinalizeOnSameBlock","type":"error"},{"inputs":[],"name":"DuplicateBalanceOracle","type":"error"},{"inputs":[],"name":"DuplicateBridgeOperation","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidArguments","type":"error"},{"inputs":[],"name":"InvalidBalanceOracle","type":"error"},{"inputs":[],"name":"InvalidBalanceOracleType","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidPriceOracle","type":"error"},{"inputs":[],"name":"InvalidPriceOracleType","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"PriceOracleAlreadySet","type":"error"},{"inputs":[],"name":"PriceOracleNotSet","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintToInt","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"inputs":[],"name":"UptimeFeedNotSet","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAssetRecoverer","type":"address"},{"indexed":true,"internalType":"address","name":"newAssetRecoverer","type":"address"}],"name":"AssetRecovererUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":false,"internalType":"enum IBalances.BalanceType","name":"oracleType","type":"uint8"}],"name":"BalanceOracleAdd","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":false,"internalType":"address","name":"oracle","type":"address"}],"name":"BalanceOracleRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"BridgeOperationFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"address","name":"asset","type":"address"}],"name":"BridgeOperationStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldChainlinkUptimeFeed","type":"address"},{"indexed":true,"internalType":"address","name":"newChainlinkUptimeFeed","type":"address"}],"name":"ChainlinkUptimeFeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldSequencerGracePeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSequencerGracePeriod","type":"uint256"}],"name":"L2SequencerGracePeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"nativeTokenSymbol","type":"string"}],"name":"NativeTokenSymbolSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"}],"name":"PriceOracleRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":false,"internalType":"uint256","name":"chainlinkHeartbeat","type":"uint256"},{"indexed":false,"internalType":"enum IPrices.PriceType","name":"priceType","type":"uint8"}],"name":"PriceOracleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"enum IBalances.BalanceType","name":"balanceType","type":"uint8"}],"name":"addBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"enum IPrices.PriceType","name":"priceType","type":"uint8"},{"internalType":"uint256","name":"chainlinkHeartbeat","type":"uint256"}],"name":"addPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"assetAt","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"internalType":"struct INAVCalculator.Asset","name":"a","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"assetBridgingCounts","outputs":[{"internalType":"uint256","name":"bridgingCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetRecoverer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"uint256","name":"idx","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"balanceOracleAt","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"enum IBalances.BalanceType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"}],"name":"balanceOracleCountFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOracleTotalCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"}],"name":"balanceOracles","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"}],"name":"balanceOraclesWithMetadata","outputs":[{"components":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"string","name":"protocol","type":"string"},{"internalType":"string","name":"position","type":"string"},{"internalType":"string","name":"positionType","type":"string"}],"internalType":"struct IBalances.BalanceOracleWithMetadata[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"bridgeFinalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"bridgeOperations","outputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint96","name":"blockNumber","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"}],"name":"bridgeStart","outputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainlinkL2SequencerGracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainlinkL2SequencerUptimeFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"enum IBalances.BalanceType","name":"balanceType","type":"uint8"}],"name":"checkBalanceOracleSupport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkL2SequencerUptime","outputs":[{"internalType":"bool","name":"stale","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"enum IPrices.PriceType","name":"priceType","type":"uint8"}],"name":"checkPriceOracleSupport","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin_","type":"address"},{"internalType":"address","name":"assetRecoverer_","type":"address"},{"internalType":"address","name":"chainlinkL2SequencerUptimeFeed_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"}],"name":"isAssetBridging","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"latestPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bool","name":"stale","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"priceOracles","outputs":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"chainlinkHeartbeat","type":"uint256"},{"internalType":"enum IPrices.PriceType","name":"priceType","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"read","outputs":[{"components":[{"internalType":"uint64","name":"block","type":"uint64"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"int256","name":"usd","type":"int256"},{"internalType":"uint16","name":"issues","type":"uint16"}],"internalType":"struct INAVCalculator.NAV","name":"nav","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"uint256","name":"idxBalanceOracle","type":"uint256"}],"name":"readPosition","outputs":[{"components":[{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"int256","name":"balance","type":"int256"},{"internalType":"int256","name":"usd","type":"int256"},{"internalType":"uint256","name":"usdRate","type":"uint256"},{"internalType":"uint256","name":"usdRateDecimals","type":"uint256"},{"internalType":"bool","name":"bridging","type":"bool"},{"internalType":"bool","name":"stale","type":"bool"}],"internalType":"struct INAVCalculator.Position","name":"p","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"readPositionWithMetadata","outputs":[{"components":[{"internalType":"string","name":"protocol","type":"string"},{"internalType":"string","name":"position","type":"string"},{"internalType":"string","name":"positionType","type":"string"},{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"string","name":"underlyingAssetSymbol","type":"string"},{"internalType":"uint8","name":"underlyingAssetDecimals","type":"uint8"},{"internalType":"uint256","name":"usdRate","type":"uint256"},{"internalType":"uint256","name":"usdRateDecimals","type":"uint256"},{"internalType":"bool","name":"stale","type":"bool"},{"internalType":"int256","name":"balance","type":"int256"},{"internalType":"int256","name":"usd","type":"int256"},{"internalType":"bool","name":"bridging","type":"bool"}],"internalType":"struct INAVCalculator.PositionWithMetadata","name":"p","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"}],"name":"readPositionsRange","outputs":[{"internalType":"int256","name":"usd","type":"int256"},{"internalType":"uint16","name":"issues","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"}],"name":"recoverAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"},{"internalType":"address","name":"oracle","type":"address"}],"name":"removeBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAsset","type":"address"}],"name":"removePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAssetRecoverer","type":"address"}],"name":"setAssetRecoverer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newSequencerGracePeriod","type":"uint256"}],"name":"setChainlinkL2SequencerGracePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newChainlinkL2SequencerUptimeFeed","type":"address"}],"name":"setChainlinkL2SequencerUptimeFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"nativeTokenSymbol","type":"string"}],"name":"setNativeTokenSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"usdDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
60a060405230608052348015610013575f5ffd5b5061001c610021565b6100d3565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100715760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100d05780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6080516145806100f95f395f81816123ff01528181612428015261258801526145805ff3fe60806040526004361061028b575f3560e01c80638cf0f4a911610155578063d572e445116100be578063eafe7a7411610078578063eafe7a74146109c4578063ece11414146109d8578063efab40e8146109f7578063f4961fa314610a16578063fe0c258614610a35578063ffa9274d14610a54575f5ffd5b8063d572e44514610896578063d5bcb61014610913578063e0caf62d1461093a578063e0f71fbe14610959578063e2832ac41461096d578063e3109cdd14610998575f5ffd5b8063ad3cb1cc1161010f578063ad3cb1cc146107be578063b1c2d7fe146107fb578063b6240bc01461081a578063c0c53b8b14610839578063cc8e1a4a14610858578063d547741f14610877575f5ffd5b80638cf0f4a9146106845780638deefa67146106a357806391d14854146106da578063a087a87e146106f9578063a217fddf14610765578063aa9239f514610778575f5ffd5b8063467f4cb9116101f757806366a4b6c0116101b157806366a4b6c0146105bf5780636c5b180d146105da57806371a9730514610606578063725e30071461061a578063821f5e2c14610639578063842c6b9d1461064e575f5ffd5b8063467f4cb9146104fd5780634f1ef2861461051c57806352d1902d1461052f57806353084eff1461054357806356aa9cae146105815780635aa2b300146105a0575f5ffd5b806315ff34ba1161024857806315ff34ba146104105780631650d4bf1461042f578063248a9ca31461045b5780632f2ff15d1461048857806335834599146104a757806336568abe146104de575f5ffd5b80630127c6981461028f57806301374518146102b057806301ffc9a71461031c5780630603dbf21461034b57806306f319fa1461036a5780631387380f14610397575b5f5ffd5b34801561029a575f5ffd5b506102ae6102a9366004613811565b610a68565b005b3480156102bb575f5ffd5b506103036102ca366004613811565b600260208190525f91825260409091208054600182015491909201546001600160a01b0383169260ff600160a01b909104811692911684565b6040516103139493929190613852565b60405180910390f35b348015610327575f5ffd5b5061033b61033636600461387f565b610ac4565b6040519015158152602001610313565b348015610356575f5ffd5b506102ae610365366004613811565b610afa565b348015610375575f5ffd5b506103896103843660046138a6565b610b7f565b6040516103139291906138de565b3480156103a2575f5ffd5b506103e46103b13660046138fb565b606a6020525f9081526040902080546001909101546001600160a01b03811690600160a01b90046001600160601b031683565b604080519384526001600160a01b0390921660208401526001600160601b031690820152606001610313565b34801561041b575f5ffd5b506102ae61042a366004613912565b610bcb565b34801561043a575f5ffd5b5061044e610449366004613811565b610c35565b6040516103139190613943565b348015610466575f5ffd5b5061047a6104753660046138fb565b610c58565b604051908152602001610313565b348015610493575f5ffd5b506102ae6104a236600461398e565b610c78565b3480156104b2575f5ffd5b506001546104c6906001600160a01b031681565b6040516001600160a01b039091168152602001610313565b3480156104e9575f5ffd5b506102ae6104f836600461398e565b610c9a565b348015610508575f5ffd5b5061047a6105173660046139af565b610cd2565b6102ae61052a366004613ab5565b610eb2565b34801561053a575f5ffd5b5061047a610ecd565b34801561054e575f5ffd5b5061056261055d366004613811565b610ee9565b6040805193845260ff9092166020840152151590820152606001610313565b34801561058c575f5ffd5b5061047a61059b366004613811565b610f14565b3480156105ab575f5ffd5b506102ae6105ba366004613b20565b6110bf565b3480156105ca575f5ffd5b5060405160088152602001610313565b3480156105e5575f5ffd5b506105f96105f4366004613811565b611222565b6040516103139190613b85565b348015610611575f5ffd5b5061044e611309565b348015610625575f5ffd5b5061047a610634366004613811565b61131a565b348015610644575f5ffd5b5061047a60375481565b348015610659575f5ffd5b5061033b610668366004613811565b6001600160a01b03165f908152606b6020526040902054151590565b34801561068f575f5ffd5b506102ae61069e366004613c3e565b61133a565b3480156106ae575f5ffd5b506106c26106bd366004613c85565b6113a1565b6040805192835261ffff909116602083015201610313565b3480156106e5575f5ffd5b5061033b6106f436600461398e565b6114f4565b348015610704575f5ffd5b50610718610713366004613811565b61152a565b60405161031391905f6080820190506001600160401b0383511682526001600160401b0360208401511660208301526040830151604083015261ffff606084015116606083015292915050565b348015610770575f5ffd5b5061047a5f81565b348015610783575f5ffd5b506107976107923660046138fb565b61158e565b6040805182516001600160a01b0316815260209283015160ff169281019290925201610313565b3480156107c9575f5ffd5b506107ee604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516103139190613cb5565b348015610806575f5ffd5b506102ae6108153660046138fb565b6115cb565b348015610825575f5ffd5b506102ae610834366004613cc7565b611724565b348015610844575f5ffd5b506102ae610853366004613d0b565b611764565b348015610863575f5ffd5b506102ae610872366004613c3e565b6118b0565b348015610882575f5ffd5b506102ae61089136600461398e565b611a4e565b3480156108a1575f5ffd5b506108b56108b0366004613d42565b611a6a565b604051610313919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a08281015115159082015260c09182015115159181019190915260e00190565b34801561091e575f5ffd5b506104c673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b348015610945575f5ffd5b506102ae610954366004613d7c565b611b2c565b348015610964575f5ffd5b5061033b611bba565b348015610978575f5ffd5b5061047a610987366004613811565b606b6020525f908152604090205481565b3480156109a3575f5ffd5b506109b76109b2366004613d42565b611c7a565b6040516103139190613deb565b3480156109cf575f5ffd5b5061047a611f16565b3480156109e3575f5ffd5b5060d3546104c6906001600160a01b031681565b348015610a02575f5ffd5b506102ae610a11366004613eec565b611f21565b348015610a21575f5ffd5b506102ae610a30366004613811565b612007565b348015610a40575f5ffd5b506102ae610a4f3660046138fb565b612099565b348015610a5f575f5ffd5b5061047a5f5481565b5f610a7281612153565b60d380546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f61a7c68b6abb604f0ed53b0e3bb073fe5e86ea8197ed15d9fd58bc05eefde240905f90a3505050565b5f6001600160e01b03198216637965db0b60e01b1480610af457506301ffc9a760e01b6001600160e01b03198316145b92915050565b610b115f5160206144eb5f395f51905f52336114f4565b610b2e5760405163ea8e4eb560e01b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f2a59683570cc5c432ceb0946923d7692d85f972004dacdcb650e52bbb9ad0358905f90a35050565b6001600160a01b0382165f908152603660205260408120819081908190610ba69086612160565b9150915081816002811115610bbd57610bbd61382a565b9350935050505b9250929050565b610be25f5160206144eb5f395f51905f52336114f4565b610bff5760405163ea8e4eb560e01b815260040160405180910390fd5b610c0a60d08361217b565b610c275760405163470cbf4760e01b815260040160405180910390fd5b610c31828261218f565b5050565b6001600160a01b0381165f908152603660205260409020606090610af49061228f565b5f9081525f51602061452b5f395f51905f52602052604090206001015490565b610c8182610c58565b610c8a81612153565b610c94838361229b565b50505050565b6001600160a01b0381163314610cc35760405163334bd91960e11b815260040160405180910390fd5b610ccd828261233c565b505050565b6001600160a01b0383165f908152603660205260408120610cf2906123b5565b8310610d11576040516349a023a960e01b815260040160405180910390fd5b6001600160a01b0384165f9081526036602052604081208190610d349086612160565b915091505f816002811115610d4b57610d4b61382a565b90506001600160a01b038316610d74576040516349a023a960e01b815260040160405180910390fd5b5f80826002811115610d8857610d8861382a565b03610e06576040516370a0823160e01b81526001600160a01b038781166004830152610dff91908616906370a0823190602401602060405180830381865afa158015610dd6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dfa9190613f34565b6123bf565b9050610ea5565b6001826002811115610e1a57610e1a61382a565b03610e3257610dff866001600160a01b0316316123bf565b604051633de222bb60e21b81526001600160a01b038981166004830152878116602483015285169063f7888aec90604401602060405180830381865afa158015610e7e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ea29190613f34565b90505b93505050505b9392505050565b610eba6123f4565b610ec38261249a565b610c3182826124c1565b5f610ed661257d565b505f51602061450b5f395f51905f525b90565b5f5f5f610ef5846125c6565b91945092509050610f04611bba565b80610f0c5750805b929491935050565b5f610f25632b554e5760e11b612771565b604080516001600160a01b03194360a01b1660208201526bffffffffffffffffffffffff19606085901b16602c8201520160408051601f198184030181528282528051602091820120606080850184528185526001600160a01b03808816868501526001600160601b03438116878701525f848152606a865286902086519384018752805480855260019091015492831695840195909552600160a01b90910416938101939093529350151580610fe8575060408101516001600160601b031615155b80610fff575060208101516001600160a01b031615155b1561101d576040516349b7f6b560e11b815260040160405180910390fd5b5f838152606a602090815260408083208551815582860151828701516001600160601b0316600160a01b026001600160a01b039091169081176001928301558452606b9092529182902080549091019055517fa5eb2bc0ce6c8ac8a4410b5f80002e5a2e46f94fb054d0b6c7ed400d4f782536906110b090859087909182526001600160a01b0316602082015260400190565b60405180910390a15050919050565b6001600160a01b03821615806110dc57506001600160a01b038316155b156110fa57604051636077d21b60e01b815260040160405180910390fd5b600181600181111561110e5761110e61382a565b0361114f5761112d6001600160a01b038316635841c1eb60e01b61279b565b61114a57604051636077d21b60e01b815260040160405180910390fd5b6111ea565b5f8160018111156111625761116261382a565b036111d157816001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156111a3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111c79190613f64565b50505050506111ea565b6040516384014a8160e01b815260040160405180910390fd5b6001600160a01b038381165f908152600260205260409020541615610ccd57604051634e133d4760e01b815260040160405180910390fd5b6001600160a01b0381165f90815260366020526040812060609190611246906123b5565b90505f816001600160401b03811115611261576112616139e8565b6040519080825280602002602001820160405280156112c557816020015b6112b260405180608001604052805f6001600160a01b031681526020016060815260200160608152602001606081525090565b81526020019060019003908161127f5790505b5090505f5b82811015611301576112dc85826127b6565b8282815181106112ee576112ee613fb2565b60209081029190910101526001016112ca565b509392505050565b606061131560d061228f565b905090565b6001600160a01b0381165f908152603660205260408120610af4906123b5565b6113515f5160206144eb5f395f51905f52336114f4565b61136e5760405163ea8e4eb560e01b815260040160405180910390fd5b61137960d08461217b565b6113965760405163470cbf4760e01b815260040160405180910390fd5b610ccd838383612aeb565b5f5f828411806113ba57506113b660d06123b5565b8310155b156113d8576040516317dbc4cb60e21b815260040160405180910390fd5b6113e0611bba565b156113f357806113ef81613fda565b9150505b835b8381116114eb575f61140860d083612160565b506001600160a01b038082165f908152600260205260409020549192501661144357604051633e6d0a1d60e21b815260040160405180910390fd5b6001600160a01b0381165f908152606b602052604090205415801590611471578361146d81613fda565b9450505b5f5f5f61147d856125c6565b925060ff1692509250801561149a578661149681613fda565b9750505b5f6114a48661131a565b90505f5b818110156114d1576114bd8d88838888612b8f565b6114c7908b613ffa565b99506001016114a8565b5050505050505080806114e390614021565b9150506113f5565b50935093915050565b5f9182525f51602061452b5f395f51905f52602090815260408084206001600160a01b0393909316845291905290205460ff1690565b604080516080810182525f918101829052606081018290526001600160401b034381168252421660208201529061156160d06123b5565b9050801561158857611579835f6106bd600185614039565b61ffff16606084015260408301525b50919050565b604080518082019091525f80825260208201525f806115ae60d085612160565b6001600160a01b03909116845260ff166020840152509092915050565b6115db6358e16bff60e11b612771565b5f818152606a6020908152604091829020825160608101845281548082526001909201546001600160a01b03811693820193909352600160a01b9092046001600160601b03169282019290925290158015611641575060408101516001600160601b0316155b8015611658575060208101516001600160a01b0316155b15611676576040516379eb2a3d60e01b815260040160405180910390fd5b4381604001516001600160601b0316036116a3576040516318f3e12f60e11b815260040160405180910390fd5b6020808201516001600160a01b03165f908152606b909152604081208054916116cb8361404c565b90915550505f828152606a602052604080822082815560010191909155517f4a6b5dc9057d1036f88e7ce9bbd1471d08f3f9617d47d7891daeacdad81be8e4906117189084815260200190565b60405180910390a15050565b61173b5f5160206144eb5f395f51905f52336114f4565b6117585760405163ea8e4eb560e01b815260040160405180910390fd5b6035610c3182826140d7565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f811580156117a85750825b90505f826001600160401b031660011480156117c35750303b155b9050811580156117d1575080155b156117ef5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561181957845460ff60401b1916600160401b1785555b611821612beb565b611829612beb565b61183286612bf3565b61183a612c22565b6118445f8961229b565b5060d380546001600160a01b0319166001600160a01b03891617905583156118a657845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6001600160a01b03821615806118cd57506001600160a01b038316155b156118eb576040516317dbc4cb60e21b815260040160405180910390fd5b60028160028111156118ff576118ff61382a565b036119405761191e6001600160a01b038316632409bd1760e11b61279b565b61193b576040516308b3cf3960e31b815260040160405180910390fd5b611a0f565b5f8160028111156119535761195361382a565b036119c4576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561199a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119be9190613f34565b50611a0f565b60018160028111156119d8576119d861382a565b036119f65760405163bdd791f760e01b815260040160405180910390fd5b604051632201de1960e21b815260040160405180910390fd5b6001600160a01b0383165f908152603660205260409020611a30908361217b565b15610ccd5760405163bdd791f760e01b815260040160405180910390fd5b611a5782610c58565b611a6081612153565b610c94838361233c565b611a726137b3565b611a7d60d08461217b565b611a9a5760405163470cbf4760e01b815260040160405180910390fd5b6001600160a01b038381165f9081526002602052604090205416611ad157604051633e6d0a1d60e21b815260040160405180910390fd5b6001600160a01b0383165f908152606b60205260408120541515908080611af7876125c6565b925060ff1692509250611b08611bba565b15611b11575060015b611b2088888886868987612cb5565b98975050505050505050565b805f5b81811015610c9457611bb2611b4c60d3546001600160a01b031690565b611b7b868685818110611b6157611b61613fb2565b9050602002016020810190611b769190613811565b612d4a565b868685818110611b8d57611b8d613fb2565b9050602002016020810190611ba29190613811565b6001600160a01b03169190612db2565b600101611b2f565b6001545f906001600160a01b031615610ee6575f5f60015f9054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611c1f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c439190613f64565b50509250925050815f14611c5a5760019250505090565b5f611c658242614039565b90505f548111611c7457600193505b50505090565b611ce66040518061018001604052806060815260200160608152602001606081526020015f6001600160a01b03168152602001606081526020015f60ff1681526020015f81526020015f81526020015f151581526020015f81526020015f81526020015f151581525090565b5f80611cf360d086612e04565b9150915081611d155760405163470cbf4760e01b815260040160405180910390fd5b5f611d2086866127b6565b90505f5f5f611d2e896125c6565b91945060ff1692509050606073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038b1601611def5760358054611d6c90614061565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9890614061565b8015611de35780601f10611dba57610100808354040283529160200191611de3565b820191905f5260205f20905b815481529060010190602001808311611dc657829003601f168201915b50505050509050611e67565b896001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa925050508015611e4c57506040513d5f823e601f3d908101601f19168201604052611e4991908101906141de565b60015b611e64575060408051602081019091525f8152611e67565b90505b6020808601518952604080870151918a0191909152606080870151918a01919091526001600160a01b038b16908901526080880181905260ff861660a089015260c0880184905260e08801839052811515610100890152611ec98a8a8d610cd2565b6101208901819052611ee09060ff88168686612e1b565b6101408901526001600160a01b038a165f908152606b602052604090205415151515610160890152505050505050509392505050565b5f61131560d06123b5565b611f385f5160206144eb5f395f51905f52336114f4565b611f555760405163ea8e4eb560e01b815260040160405180910390fd5b5f6001600160a01b03851673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611fdf57846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fda919061420f565b611fe2565b60125b9050611ff360d08660ff8416612e55565b5061200085858486612e72565b5050505050565b61201e5f5160206144eb5f395f51905f52336114f4565b61203b5760405163ea8e4eb560e01b815260040160405180910390fd5b5f6120458261131a565b1115612064576040516317dbc4cb60e21b815260040160405180910390fd5b5f61207060d08361308c565b9050806120905760405163470cbf4760e01b815260040160405180910390fd5b610c31826130a0565b6120b05f5160206144eb5f395f51905f52336114f4565b6120cd5760405163ea8e4eb560e01b815260040160405180910390fd5b6001546001600160a01b03166120f657604051636c9e815560e01b815260040160405180910390fd5b805f03612116576040516317dbc4cb60e21b815260040160405180910390fd5b5f80549082905560408051828152602081018490527f8517713fa4ff1f4d78f1a611f588f5200338514d49a4e224d5de5ff73020b9c09101611718565b61215d8133613102565b50565b5f80808061216e868661313b565b9097909650945050505050565b5f610eab836001600160a01b038416613164565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156121d757506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156121f5576040516317dbc4cb60e21b815260040160405180910390fd5b6001600160a01b0382165f908152603660205260408120612216908361308c565b905080612236576040516308b3cf3960e31b815260040160405180910390fd5b60378054905f6122458361404c565b90915550506040516001600160a01b0383811682528416907fa76503e54196bc4ca156f2a7e4295faeae83dad92c4928c4b8d0b1fd7a09b2129060200160405180910390a2505050565b60605f610eab8361316f565b5f5f51602061452b5f395f51905f526122b484846114f4565b612333575f848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556122e93390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610af4565b5f915050610af4565b5f5f51602061452b5f395f51905f5261235584846114f4565b15612333575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610af4565b5f610af48261317a565b5f6001600160ff1b038211156123f05760405163123baf0360e11b8152600481018390526024015b60405180910390fd5b5090565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061247a57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661246e5f51602061450b5f395f51905f52546001600160a01b031690565b6001600160a01b031614155b156124985760405163703e46dd60e11b815260040160405180910390fd5b565b6124a45f336114f4565b61215d5760405163ea8e4eb560e01b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561251b575060408051601f3d908101601f1916820190925261251891810190613f34565b60015b61254357604051634c9c8ce360e01b81526001600160a01b03831660048201526024016123e7565b5f51602061450b5f395f51905f52811461257357604051632a87526960e21b8152600481018290526024016123e7565b610ccd8383613184565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146124985760405163703e46dd60e11b815260040160405180910390fd5b6001600160a01b038082165f9081526002602052604081208054919283928392911661260557604051633e6d0a1d60e21b815260040160405180910390fd5b5f600282015460ff16600181111561261f5761261f61382a565b036126e457805460408051633fabe5a360e21b815290516001600160a01b03909216915f918291849163feaf968c9160048083019260a09291908290030181865afa158015612670573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126949190613f64565b509350509250505f82136126c057505090545f9450600160a01b900460ff1692506001915061276a9050565b60018401546126cf8242614039565b11156126da57600194505b50945061275c9050565b805460408051638e15f47360e01b815281515f936001600160a01b031692638e15f47392600480820193918290030181865afa158015612726573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061274a919061423e565b909550905082806127585750805b9250505b54600160a01b900460ff1691505b9193909250565b6124a47f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c336114f4565b5f6127a5836131d9565b8015610eab5750610eab838361320b565b6127e960405180608001604052805f6001600160a01b031681526020016060815260200160608152602001606081525090565b6001600160a01b0383165f908152603660205260408120819061280c9085612160565b915091505f8160028111156128235761282361382a565b905061284960405180606001604052806060815260200160608152602001606081525090565b600282600281111561285d5761285d61382a565b036128cb57836001600160a01b0316639d7c4ee16040518163ffffffff1660e01b81526004015f60405180830381865afa15801561289d573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526128c4919081019061425f565b9050612ab0565b60018260028111156128df576128df61382a565b036129d1576040805160a0810190915260116060820190815270506f7274666f6c696f2062616c616e636560781b608083015281526035805460208301919061292790614061565b80601f016020809104026020016040519081016040528092919081815260200182805461295390614061565b801561299e5780601f106129755761010080835404028352916020019161299e565b820191905f5260205f20905b81548152906001019060200180831161298157829003601f168201915b50505050508152602001604051806040016040528060068152602001654e617469766560d01b8152508152509050612ab0565b6060846001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa925050508015612a3057506040513d5f823e601f3d908101601f19168201604052612a2d91908101906141de565b60015b612a48575060408051602081019091525f8152612a4b565b90505b604051806060016040528060405180604001604052806011815260200170506f7274666f6c696f2062616c616e636560781b815250815260200182815260200160405180604001604052806005815260200164045524332360dc1b8152508152509150505b604080516080810182526001600160a01b03909516855281516020808701919091528201518582015201516060840152509091505092915050565b612af68383836118b0565b612b2a82826002811115612b0c57612b0c61382a565b6001600160a01b0386165f9081526036602052604090209190612e55565b5060378054905f612b3a83614021565b9190505550816001600160a01b0316836001600160a01b03167f4acc8c77664751f0229cdecd20b537d6a486ccecb3f77d26bdb3ee51a7cf0b4583604051612b82919061431d565b60405180910390a3505050565b5f8080612b9d60d088612e04565b9150915081612bbf5760405163470cbf4760e01b815260040160405180910390fd5b5f612bcb88888b610cd2565b9050612bdc818360ff168888612e1b565b93505050505b95945050505050565b612498613291565b612bfb613291565b600180546001600160a01b0319166001600160a01b0392909216919091179055610e105f55565b612c2a613291565b612c8873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee600173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f5260366020527f4c3ec90a8c757a3f8ecca3252cd089d9560a01e7389ee2625bef52796e9ebd2b9190612e55565b50600160375560408051808201909152600381526208aa8960eb1b602082015260359061215d90826140d7565b612cbd6137b3565b5f80612cca60d08a612e04565b9150915081612cec5760405163470cbf4760e01b815260040160405180910390fd5b6001600160a01b0389168352612d0389898c610cd2565b6020840181905284151560c0850152606084018890526080840187905285151560a0850152612d379060ff83168989612e1b565b6040840152509098975050505050505050565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa158015612d8e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610af49190613f34565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610ccd9084906132da565b5f80808061216e866001600160a01b03871661333b565b5f6008612e2c8361ffff871661432b565b612e369190614039565b612e4190600a614421565b612e4b848761442c565b612be2919061445b565b5f612e6a846001600160a01b03851684613373565b949350505050565b612e7d8484836110bf565b5f80826001811115612e9157612e9161382a565b03612f1d57825f03612eb657604051636077d21b60e01b815260040160405180910390fd5b836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f16919061420f565b9050612f80565b836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f59573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f7d919061420f565b90505b6040518060800160405280856001600160a01b031681526020018260ff168152602001848152602001836001811115612fbb57612fbb61382a565b90526001600160a01b038087165f90815260026020818152604092839020855181549287015160ff16600160a01b026001600160a81b03199093169516949094171783559083015160018084019190915560608401519183018054909160ff199091169083818111156130305761303061382a565b0217905550905050836001600160a01b0316856001600160a01b03167fa49194f841578adf42e4abe85004e75cdf662d7c6f75608ddeb76ad3251d185a858560405161307d929190614493565b60405180910390a35050505050565b5f610eab836001600160a01b03841661338f565b6001600160a01b0381165f81815260026020819052604080832080546001600160a81b031916815560018101849055909101805460ff19169055517f1ab93c820592302b2bef0070dd03654585b6942bfde155498ddd3d69190bf0429190a250565b61310c82826114f4565b610c315760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044016123e7565b5f808061314885856133ab565b5f81815260029690960160205260409095205494959350505050565b5f610eab83836133b6565b6060610af4826133cd565b5f610af4826133d9565b61318d826133e2565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156131d157610ccd8282613445565b610c316134ae565b5f6131eb826301ffc9a760e01b61320b565b8015610af45750613204826001600160e01b031961320b565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f51905082801561327b575060208210155b801561328657505f81115b979650505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661249857604051631afcd79f60e31b815260040160405180910390fd5b5f6132ee6001600160a01b038416836134cd565b905080515f1415801561331257508080602001905181019061331091906144a7565b155b15610ccd57604051635274afe760e01b81526001600160a01b03841660048201526024016123e7565b5f8181526002830160205260408120548190806133685761335c8585613164565b92505f9150610bc49050565b600192509050610bc4565b5f8281526002840160205260408120829055612e6a84846134da565b5f8181526002830160205260408120819055610eab83836134e5565b5f610eab83836134f0565b5f8181526001830160205260408120541515610eab565b60605f610eab83613516565b5f610af4825490565b806001600160a01b03163b5f0361341757604051634c9c8ce360e01b81526001600160a01b03821660048201526024016123e7565b5f51602061450b5f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b03168460405161346191906144c0565b5f60405180830381855af49150503d805f8114613499576040519150601f19603f3d011682016040523d82523d5f602084013e61349e565b606091505b5091509150612be285838361356f565b34156124985760405163b398979f60e01b815260040160405180910390fd5b6060610eab83835f6135cb565b5f610eab8383613664565b5f610eab83836136b0565b5f825f01828154811061350557613505613fb2565b905f5260205f200154905092915050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561356357602002820191905f5260205f20905b81548152602001906001019080831161354f575b50505050509050919050565b6060826135845761357f8261378a565b610eab565b815115801561359b57506001600160a01b0384163b155b156135c457604051639996b31560e01b81526001600160a01b03851660048201526024016123e7565b5080610eab565b6060814710156135f05760405163cd78605960e01b81523060048201526024016123e7565b5f5f856001600160a01b0316848660405161360b91906144c0565b5f6040518083038185875af1925050503d805f8114613645576040519150601f19603f3d011682016040523d82523d5f602084013e61364a565b606091505b509150915061365a86838361356f565b9695505050505050565b5f8181526001830160205260408120546136a957508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610af4565b505f610af4565b5f8181526001830160205260408120548015612333575f6136d2600183614039565b85549091505f906136e590600190614039565b9050808214613744575f865f01828154811061370357613703613fb2565b905f5260205f200154905080875f01848154811061372357613723613fb2565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080613755576137556144d6565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610af4565b80511561379a5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040518060e001604052805f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f151581526020015f151581525090565b80356001600160a01b038116811461380c575f5ffd5b919050565b5f60208284031215613821575f5ffd5b610eab826137f6565b634e487b7160e01b5f52602160045260245ffd5b6002811061384e5761384e61382a565b9052565b6001600160a01b038516815260ff841660208201526040810183905260808101612be2606083018461383e565b5f6020828403121561388f575f5ffd5b81356001600160e01b031981168114610eab575f5ffd5b5f5f604083850312156138b7575f5ffd5b6138c0836137f6565b946020939093013593505050565b6003811061384e5761384e61382a565b6001600160a01b038316815260408101610eab60208301846138ce565b5f6020828403121561390b575f5ffd5b5035919050565b5f5f60408385031215613923575f5ffd5b61392c836137f6565b915061393a602084016137f6565b90509250929050565b602080825282518282018190525f918401906040840190835b818110156139835783516001600160a01b031683526020938401939092019160010161395c565b509095945050505050565b5f5f6040838503121561399f575f5ffd5b8235915061393a602084016137f6565b5f5f5f606084860312156139c1575f5ffd5b6139ca846137f6565b9250602084013591506139df604085016137f6565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b604051606081016001600160401b0381118282101715613a1e57613a1e6139e8565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613a4c57613a4c6139e8565b604052919050565b5f6001600160401b03821115613a6c57613a6c6139e8565b50601f01601f191660200190565b5f613a8c613a8784613a54565b613a24565b9050828152838383011115613a9f575f5ffd5b828260208301375f602084830101529392505050565b5f5f60408385031215613ac6575f5ffd5b613acf836137f6565b915060208301356001600160401b03811115613ae9575f5ffd5b8301601f81018513613af9575f5ffd5b613b0885823560208401613a7a565b9150509250929050565b80356002811061380c575f5ffd5b5f5f5f60608486031215613b32575f5ffd5b613b3b846137f6565b9250613b49602085016137f6565b91506139df60408501613b12565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015613c3257868503603f19018452815180516001600160a01b03168652602080820151608091880182905290613be690880182613b57565b905060408201518782036040890152613bff8282613b57565b915050606082015191508681036060880152613c1b8183613b57565b965050506020938401939190910190600101613bab565b50929695505050505050565b5f5f5f60608486031215613c50575f5ffd5b613c59846137f6565b9250613c67602085016137f6565b9150604084013560038110613c7a575f5ffd5b809150509250925092565b5f5f5f60608486031215613c97575f5ffd5b613ca0846137f6565b95602085013595506040909401359392505050565b602081525f610eab6020830184613b57565b5f60208284031215613cd7575f5ffd5b81356001600160401b03811115613cec575f5ffd5b8201601f81018413613cfc575f5ffd5b612e6a84823560208401613a7a565b5f5f5f60608486031215613d1d575f5ffd5b613d26846137f6565b9250613d34602085016137f6565b91506139df604085016137f6565b5f5f5f60608486031215613d54575f5ffd5b613d5d846137f6565b9250613d6b602085016137f6565b929592945050506040919091013590565b5f5f60208385031215613d8d575f5ffd5b82356001600160401b03811115613da2575f5ffd5b8301601f81018513613db2575f5ffd5b80356001600160401b03811115613dc7575f5ffd5b8560208260051b8401011115613ddb575f5ffd5b6020919091019590945092505050565b602081525f82516101806020840152613e086101a0840182613b57565b90506020840151601f19848303016040850152613e258282613b57565b9150506040840151601f19848303016060850152613e438282613b57565b9150506060840151613e6060808501826001600160a01b03169052565b506080840151838203601f190160a0850152613e7c8282613b57565b91505060a0840151613e9360c085018260ff169052565b5060c084015160e084015260e0840151610100840152610100840151613ebe61012085018215159052565b5061012084015161014084015261014084015161016084015261016084015161130161018085018215159052565b5f5f5f5f60808587031215613eff575f5ffd5b613f08856137f6565b9350613f16602086016137f6565b9250613f2460408601613b12565b9396929550929360600135925050565b5f60208284031215613f44575f5ffd5b5051919050565b805169ffffffffffffffffffff8116811461380c575f5ffd5b5f5f5f5f5f60a08688031215613f78575f5ffd5b613f8186613f4b565b60208701516040880151606089015192975090955093509150613fa660808701613f4b565b90509295509295909350565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f61ffff821661ffff8103613ff157613ff1613fc6565b60010192915050565b8082018281125f83128015821682158216171561401957614019613fc6565b505092915050565b5f6001820161403257614032613fc6565b5060010190565b81810381811115610af457610af4613fc6565b5f8161405a5761405a613fc6565b505f190190565b600181811c9082168061407557607f821691505b60208210810361158857634e487b7160e01b5f52602260045260245ffd5b601f821115610ccd57805f5260205f20601f840160051c810160208510156140b85750805b601f840160051c820191505b81811015612000575f81556001016140c4565b81516001600160401b038111156140f0576140f06139e8565b614104816140fe8454614061565b84614093565b6020601f821160018114614136575f831561411f5750848201515b5f19600385901b1c1916600184901b178455612000565b5f84815260208120601f198516915b828110156141655787850151825560209485019460019092019101614145565b508482101561418257868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f82601f8301126141a0575f5ffd5b81516141ae613a8782613a54565b8181528460208386010111156141c2575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f602082840312156141ee575f5ffd5b81516001600160401b03811115614203575f5ffd5b612e6a84828501614191565b5f6020828403121561421f575f5ffd5b815160ff81168114610eab575f5ffd5b8051801515811461380c575f5ffd5b5f5f6040838503121561424f575f5ffd5b8251915061393a6020840161422f565b5f6020828403121561426f575f5ffd5b81516001600160401b03811115614284575f5ffd5b820160608185031215614295575f5ffd5b61429d6139fc565b81516001600160401b038111156142b2575f5ffd5b6142be86828501614191565b82525060208201516001600160401b038111156142d9575f5ffd5b6142e586828501614191565b60208301525060408201516001600160401b03811115614303575f5ffd5b61430f86828501614191565b604083015250949350505050565b60208101610af482846138ce565b80820180821115610af457610af4613fc6565b6001815b60018411156143795780850481111561435d5761435d613fc6565b600184161561436b57908102905b60019390931c928002614342565b935093915050565b5f8261438f57506001610af4565b8161439b57505f610af4565b81600181146143b157600281146143bb576143d7565b6001915050610af4565b60ff8411156143cc576143cc613fc6565b50506001821b610af4565b5060208310610133831016604e8410600b84101617156143fa575081810a610af4565b6144065f19848461433e565b805f190482111561441957614419613fc6565b029392505050565b5f610eab8383614381565b8082025f8212600160ff1b8414161561444757614447613fc6565b8181058314821517610af457610af4613fc6565b5f8261447557634e487b7160e01b5f52601260045260245ffd5b600160ff1b82145f198414161561448e5761448e613fc6565b500590565b82815260408101610eab602083018461383e565b5f602082840312156144b7575f5ffd5b610eab8261422f565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603160045260245ffdfeaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a264697066735822122092d2b04c170d97d9ffa43ce97d53a373db5600e78a16afa20cb6b356ae18f12b64736f6c634300081b0033
Deployed Bytecode
0x60806040526004361061028b575f3560e01c80638cf0f4a911610155578063d572e445116100be578063eafe7a7411610078578063eafe7a74146109c4578063ece11414146109d8578063efab40e8146109f7578063f4961fa314610a16578063fe0c258614610a35578063ffa9274d14610a54575f5ffd5b8063d572e44514610896578063d5bcb61014610913578063e0caf62d1461093a578063e0f71fbe14610959578063e2832ac41461096d578063e3109cdd14610998575f5ffd5b8063ad3cb1cc1161010f578063ad3cb1cc146107be578063b1c2d7fe146107fb578063b6240bc01461081a578063c0c53b8b14610839578063cc8e1a4a14610858578063d547741f14610877575f5ffd5b80638cf0f4a9146106845780638deefa67146106a357806391d14854146106da578063a087a87e146106f9578063a217fddf14610765578063aa9239f514610778575f5ffd5b8063467f4cb9116101f757806366a4b6c0116101b157806366a4b6c0146105bf5780636c5b180d146105da57806371a9730514610606578063725e30071461061a578063821f5e2c14610639578063842c6b9d1461064e575f5ffd5b8063467f4cb9146104fd5780634f1ef2861461051c57806352d1902d1461052f57806353084eff1461054357806356aa9cae146105815780635aa2b300146105a0575f5ffd5b806315ff34ba1161024857806315ff34ba146104105780631650d4bf1461042f578063248a9ca31461045b5780632f2ff15d1461048857806335834599146104a757806336568abe146104de575f5ffd5b80630127c6981461028f57806301374518146102b057806301ffc9a71461031c5780630603dbf21461034b57806306f319fa1461036a5780631387380f14610397575b5f5ffd5b34801561029a575f5ffd5b506102ae6102a9366004613811565b610a68565b005b3480156102bb575f5ffd5b506103036102ca366004613811565b600260208190525f91825260409091208054600182015491909201546001600160a01b0383169260ff600160a01b909104811692911684565b6040516103139493929190613852565b60405180910390f35b348015610327575f5ffd5b5061033b61033636600461387f565b610ac4565b6040519015158152602001610313565b348015610356575f5ffd5b506102ae610365366004613811565b610afa565b348015610375575f5ffd5b506103896103843660046138a6565b610b7f565b6040516103139291906138de565b3480156103a2575f5ffd5b506103e46103b13660046138fb565b606a6020525f9081526040902080546001909101546001600160a01b03811690600160a01b90046001600160601b031683565b604080519384526001600160a01b0390921660208401526001600160601b031690820152606001610313565b34801561041b575f5ffd5b506102ae61042a366004613912565b610bcb565b34801561043a575f5ffd5b5061044e610449366004613811565b610c35565b6040516103139190613943565b348015610466575f5ffd5b5061047a6104753660046138fb565b610c58565b604051908152602001610313565b348015610493575f5ffd5b506102ae6104a236600461398e565b610c78565b3480156104b2575f5ffd5b506001546104c6906001600160a01b031681565b6040516001600160a01b039091168152602001610313565b3480156104e9575f5ffd5b506102ae6104f836600461398e565b610c9a565b348015610508575f5ffd5b5061047a6105173660046139af565b610cd2565b6102ae61052a366004613ab5565b610eb2565b34801561053a575f5ffd5b5061047a610ecd565b34801561054e575f5ffd5b5061056261055d366004613811565b610ee9565b6040805193845260ff9092166020840152151590820152606001610313565b34801561058c575f5ffd5b5061047a61059b366004613811565b610f14565b3480156105ab575f5ffd5b506102ae6105ba366004613b20565b6110bf565b3480156105ca575f5ffd5b5060405160088152602001610313565b3480156105e5575f5ffd5b506105f96105f4366004613811565b611222565b6040516103139190613b85565b348015610611575f5ffd5b5061044e611309565b348015610625575f5ffd5b5061047a610634366004613811565b61131a565b348015610644575f5ffd5b5061047a60375481565b348015610659575f5ffd5b5061033b610668366004613811565b6001600160a01b03165f908152606b6020526040902054151590565b34801561068f575f5ffd5b506102ae61069e366004613c3e565b61133a565b3480156106ae575f5ffd5b506106c26106bd366004613c85565b6113a1565b6040805192835261ffff909116602083015201610313565b3480156106e5575f5ffd5b5061033b6106f436600461398e565b6114f4565b348015610704575f5ffd5b50610718610713366004613811565b61152a565b60405161031391905f6080820190506001600160401b0383511682526001600160401b0360208401511660208301526040830151604083015261ffff606084015116606083015292915050565b348015610770575f5ffd5b5061047a5f81565b348015610783575f5ffd5b506107976107923660046138fb565b61158e565b6040805182516001600160a01b0316815260209283015160ff169281019290925201610313565b3480156107c9575f5ffd5b506107ee604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516103139190613cb5565b348015610806575f5ffd5b506102ae6108153660046138fb565b6115cb565b348015610825575f5ffd5b506102ae610834366004613cc7565b611724565b348015610844575f5ffd5b506102ae610853366004613d0b565b611764565b348015610863575f5ffd5b506102ae610872366004613c3e565b6118b0565b348015610882575f5ffd5b506102ae61089136600461398e565b611a4e565b3480156108a1575f5ffd5b506108b56108b0366004613d42565b611a6a565b604051610313919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a08281015115159082015260c09182015115159181019190915260e00190565b34801561091e575f5ffd5b506104c673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b348015610945575f5ffd5b506102ae610954366004613d7c565b611b2c565b348015610964575f5ffd5b5061033b611bba565b348015610978575f5ffd5b5061047a610987366004613811565b606b6020525f908152604090205481565b3480156109a3575f5ffd5b506109b76109b2366004613d42565b611c7a565b6040516103139190613deb565b3480156109cf575f5ffd5b5061047a611f16565b3480156109e3575f5ffd5b5060d3546104c6906001600160a01b031681565b348015610a02575f5ffd5b506102ae610a11366004613eec565b611f21565b348015610a21575f5ffd5b506102ae610a30366004613811565b612007565b348015610a40575f5ffd5b506102ae610a4f3660046138fb565b612099565b348015610a5f575f5ffd5b5061047a5f5481565b5f610a7281612153565b60d380546001600160a01b038481166001600160a01b0319831681179093556040519116919082907f61a7c68b6abb604f0ed53b0e3bb073fe5e86ea8197ed15d9fd58bc05eefde240905f90a3505050565b5f6001600160e01b03198216637965db0b60e01b1480610af457506301ffc9a760e01b6001600160e01b03198316145b92915050565b610b115f5160206144eb5f395f51905f52336114f4565b610b2e5760405163ea8e4eb560e01b815260040160405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f2a59683570cc5c432ceb0946923d7692d85f972004dacdcb650e52bbb9ad0358905f90a35050565b6001600160a01b0382165f908152603660205260408120819081908190610ba69086612160565b9150915081816002811115610bbd57610bbd61382a565b9350935050505b9250929050565b610be25f5160206144eb5f395f51905f52336114f4565b610bff5760405163ea8e4eb560e01b815260040160405180910390fd5b610c0a60d08361217b565b610c275760405163470cbf4760e01b815260040160405180910390fd5b610c31828261218f565b5050565b6001600160a01b0381165f908152603660205260409020606090610af49061228f565b5f9081525f51602061452b5f395f51905f52602052604090206001015490565b610c8182610c58565b610c8a81612153565b610c94838361229b565b50505050565b6001600160a01b0381163314610cc35760405163334bd91960e11b815260040160405180910390fd5b610ccd828261233c565b505050565b6001600160a01b0383165f908152603660205260408120610cf2906123b5565b8310610d11576040516349a023a960e01b815260040160405180910390fd5b6001600160a01b0384165f9081526036602052604081208190610d349086612160565b915091505f816002811115610d4b57610d4b61382a565b90506001600160a01b038316610d74576040516349a023a960e01b815260040160405180910390fd5b5f80826002811115610d8857610d8861382a565b03610e06576040516370a0823160e01b81526001600160a01b038781166004830152610dff91908616906370a0823190602401602060405180830381865afa158015610dd6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dfa9190613f34565b6123bf565b9050610ea5565b6001826002811115610e1a57610e1a61382a565b03610e3257610dff866001600160a01b0316316123bf565b604051633de222bb60e21b81526001600160a01b038981166004830152878116602483015285169063f7888aec90604401602060405180830381865afa158015610e7e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ea29190613f34565b90505b93505050505b9392505050565b610eba6123f4565b610ec38261249a565b610c3182826124c1565b5f610ed661257d565b505f51602061450b5f395f51905f525b90565b5f5f5f610ef5846125c6565b91945092509050610f04611bba565b80610f0c5750805b929491935050565b5f610f25632b554e5760e11b612771565b604080516001600160a01b03194360a01b1660208201526bffffffffffffffffffffffff19606085901b16602c8201520160408051601f198184030181528282528051602091820120606080850184528185526001600160a01b03808816868501526001600160601b03438116878701525f848152606a865286902086519384018752805480855260019091015492831695840195909552600160a01b90910416938101939093529350151580610fe8575060408101516001600160601b031615155b80610fff575060208101516001600160a01b031615155b1561101d576040516349b7f6b560e11b815260040160405180910390fd5b5f838152606a602090815260408083208551815582860151828701516001600160601b0316600160a01b026001600160a01b039091169081176001928301558452606b9092529182902080549091019055517fa5eb2bc0ce6c8ac8a4410b5f80002e5a2e46f94fb054d0b6c7ed400d4f782536906110b090859087909182526001600160a01b0316602082015260400190565b60405180910390a15050919050565b6001600160a01b03821615806110dc57506001600160a01b038316155b156110fa57604051636077d21b60e01b815260040160405180910390fd5b600181600181111561110e5761110e61382a565b0361114f5761112d6001600160a01b038316635841c1eb60e01b61279b565b61114a57604051636077d21b60e01b815260040160405180910390fd5b6111ea565b5f8160018111156111625761116261382a565b036111d157816001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156111a3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111c79190613f64565b50505050506111ea565b6040516384014a8160e01b815260040160405180910390fd5b6001600160a01b038381165f908152600260205260409020541615610ccd57604051634e133d4760e01b815260040160405180910390fd5b6001600160a01b0381165f90815260366020526040812060609190611246906123b5565b90505f816001600160401b03811115611261576112616139e8565b6040519080825280602002602001820160405280156112c557816020015b6112b260405180608001604052805f6001600160a01b031681526020016060815260200160608152602001606081525090565b81526020019060019003908161127f5790505b5090505f5b82811015611301576112dc85826127b6565b8282815181106112ee576112ee613fb2565b60209081029190910101526001016112ca565b509392505050565b606061131560d061228f565b905090565b6001600160a01b0381165f908152603660205260408120610af4906123b5565b6113515f5160206144eb5f395f51905f52336114f4565b61136e5760405163ea8e4eb560e01b815260040160405180910390fd5b61137960d08461217b565b6113965760405163470cbf4760e01b815260040160405180910390fd5b610ccd838383612aeb565b5f5f828411806113ba57506113b660d06123b5565b8310155b156113d8576040516317dbc4cb60e21b815260040160405180910390fd5b6113e0611bba565b156113f357806113ef81613fda565b9150505b835b8381116114eb575f61140860d083612160565b506001600160a01b038082165f908152600260205260409020549192501661144357604051633e6d0a1d60e21b815260040160405180910390fd5b6001600160a01b0381165f908152606b602052604090205415801590611471578361146d81613fda565b9450505b5f5f5f61147d856125c6565b925060ff1692509250801561149a578661149681613fda565b9750505b5f6114a48661131a565b90505f5b818110156114d1576114bd8d88838888612b8f565b6114c7908b613ffa565b99506001016114a8565b5050505050505080806114e390614021565b9150506113f5565b50935093915050565b5f9182525f51602061452b5f395f51905f52602090815260408084206001600160a01b0393909316845291905290205460ff1690565b604080516080810182525f918101829052606081018290526001600160401b034381168252421660208201529061156160d06123b5565b9050801561158857611579835f6106bd600185614039565b61ffff16606084015260408301525b50919050565b604080518082019091525f80825260208201525f806115ae60d085612160565b6001600160a01b03909116845260ff166020840152509092915050565b6115db6358e16bff60e11b612771565b5f818152606a6020908152604091829020825160608101845281548082526001909201546001600160a01b03811693820193909352600160a01b9092046001600160601b03169282019290925290158015611641575060408101516001600160601b0316155b8015611658575060208101516001600160a01b0316155b15611676576040516379eb2a3d60e01b815260040160405180910390fd5b4381604001516001600160601b0316036116a3576040516318f3e12f60e11b815260040160405180910390fd5b6020808201516001600160a01b03165f908152606b909152604081208054916116cb8361404c565b90915550505f828152606a602052604080822082815560010191909155517f4a6b5dc9057d1036f88e7ce9bbd1471d08f3f9617d47d7891daeacdad81be8e4906117189084815260200190565b60405180910390a15050565b61173b5f5160206144eb5f395f51905f52336114f4565b6117585760405163ea8e4eb560e01b815260040160405180910390fd5b6035610c3182826140d7565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f811580156117a85750825b90505f826001600160401b031660011480156117c35750303b155b9050811580156117d1575080155b156117ef5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561181957845460ff60401b1916600160401b1785555b611821612beb565b611829612beb565b61183286612bf3565b61183a612c22565b6118445f8961229b565b5060d380546001600160a01b0319166001600160a01b03891617905583156118a657845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b6001600160a01b03821615806118cd57506001600160a01b038316155b156118eb576040516317dbc4cb60e21b815260040160405180910390fd5b60028160028111156118ff576118ff61382a565b036119405761191e6001600160a01b038316632409bd1760e11b61279b565b61193b576040516308b3cf3960e31b815260040160405180910390fd5b611a0f565b5f8160028111156119535761195361382a565b036119c4576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561199a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119be9190613f34565b50611a0f565b60018160028111156119d8576119d861382a565b036119f65760405163bdd791f760e01b815260040160405180910390fd5b604051632201de1960e21b815260040160405180910390fd5b6001600160a01b0383165f908152603660205260409020611a30908361217b565b15610ccd5760405163bdd791f760e01b815260040160405180910390fd5b611a5782610c58565b611a6081612153565b610c94838361233c565b611a726137b3565b611a7d60d08461217b565b611a9a5760405163470cbf4760e01b815260040160405180910390fd5b6001600160a01b038381165f9081526002602052604090205416611ad157604051633e6d0a1d60e21b815260040160405180910390fd5b6001600160a01b0383165f908152606b60205260408120541515908080611af7876125c6565b925060ff1692509250611b08611bba565b15611b11575060015b611b2088888886868987612cb5565b98975050505050505050565b805f5b81811015610c9457611bb2611b4c60d3546001600160a01b031690565b611b7b868685818110611b6157611b61613fb2565b9050602002016020810190611b769190613811565b612d4a565b868685818110611b8d57611b8d613fb2565b9050602002016020810190611ba29190613811565b6001600160a01b03169190612db2565b600101611b2f565b6001545f906001600160a01b031615610ee6575f5f60015f9054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611c1f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c439190613f64565b50509250925050815f14611c5a5760019250505090565b5f611c658242614039565b90505f548111611c7457600193505b50505090565b611ce66040518061018001604052806060815260200160608152602001606081526020015f6001600160a01b03168152602001606081526020015f60ff1681526020015f81526020015f81526020015f151581526020015f81526020015f81526020015f151581525090565b5f80611cf360d086612e04565b9150915081611d155760405163470cbf4760e01b815260040160405180910390fd5b5f611d2086866127b6565b90505f5f5f611d2e896125c6565b91945060ff1692509050606073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038b1601611def5760358054611d6c90614061565b80601f0160208091040260200160405190810160405280929190818152602001828054611d9890614061565b8015611de35780601f10611dba57610100808354040283529160200191611de3565b820191905f5260205f20905b815481529060010190602001808311611dc657829003601f168201915b50505050509050611e67565b896001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa925050508015611e4c57506040513d5f823e601f3d908101601f19168201604052611e4991908101906141de565b60015b611e64575060408051602081019091525f8152611e67565b90505b6020808601518952604080870151918a0191909152606080870151918a01919091526001600160a01b038b16908901526080880181905260ff861660a089015260c0880184905260e08801839052811515610100890152611ec98a8a8d610cd2565b6101208901819052611ee09060ff88168686612e1b565b6101408901526001600160a01b038a165f908152606b602052604090205415151515610160890152505050505050509392505050565b5f61131560d06123b5565b611f385f5160206144eb5f395f51905f52336114f4565b611f555760405163ea8e4eb560e01b815260040160405180910390fd5b5f6001600160a01b03851673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611fdf57846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fda919061420f565b611fe2565b60125b9050611ff360d08660ff8416612e55565b5061200085858486612e72565b5050505050565b61201e5f5160206144eb5f395f51905f52336114f4565b61203b5760405163ea8e4eb560e01b815260040160405180910390fd5b5f6120458261131a565b1115612064576040516317dbc4cb60e21b815260040160405180910390fd5b5f61207060d08361308c565b9050806120905760405163470cbf4760e01b815260040160405180910390fd5b610c31826130a0565b6120b05f5160206144eb5f395f51905f52336114f4565b6120cd5760405163ea8e4eb560e01b815260040160405180910390fd5b6001546001600160a01b03166120f657604051636c9e815560e01b815260040160405180910390fd5b805f03612116576040516317dbc4cb60e21b815260040160405180910390fd5b5f80549082905560408051828152602081018490527f8517713fa4ff1f4d78f1a611f588f5200338514d49a4e224d5de5ff73020b9c09101611718565b61215d8133613102565b50565b5f80808061216e868661313b565b9097909650945050505050565b5f610eab836001600160a01b038416613164565b6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480156121d757506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156121f5576040516317dbc4cb60e21b815260040160405180910390fd5b6001600160a01b0382165f908152603660205260408120612216908361308c565b905080612236576040516308b3cf3960e31b815260040160405180910390fd5b60378054905f6122458361404c565b90915550506040516001600160a01b0383811682528416907fa76503e54196bc4ca156f2a7e4295faeae83dad92c4928c4b8d0b1fd7a09b2129060200160405180910390a2505050565b60605f610eab8361316f565b5f5f51602061452b5f395f51905f526122b484846114f4565b612333575f848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556122e93390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610af4565b5f915050610af4565b5f5f51602061452b5f395f51905f5261235584846114f4565b15612333575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610af4565b5f610af48261317a565b5f6001600160ff1b038211156123f05760405163123baf0360e11b8152600481018390526024015b60405180910390fd5b5090565b306001600160a01b037f00000000000000000000000001fadd5cd79ed3e33f5a438b1e00e502bca68bdf16148061247a57507f00000000000000000000000001fadd5cd79ed3e33f5a438b1e00e502bca68bdf6001600160a01b031661246e5f51602061450b5f395f51905f52546001600160a01b031690565b6001600160a01b031614155b156124985760405163703e46dd60e11b815260040160405180910390fd5b565b6124a45f336114f4565b61215d5760405163ea8e4eb560e01b815260040160405180910390fd5b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561251b575060408051601f3d908101601f1916820190925261251891810190613f34565b60015b61254357604051634c9c8ce360e01b81526001600160a01b03831660048201526024016123e7565b5f51602061450b5f395f51905f52811461257357604051632a87526960e21b8152600481018290526024016123e7565b610ccd8383613184565b306001600160a01b037f00000000000000000000000001fadd5cd79ed3e33f5a438b1e00e502bca68bdf16146124985760405163703e46dd60e11b815260040160405180910390fd5b6001600160a01b038082165f9081526002602052604081208054919283928392911661260557604051633e6d0a1d60e21b815260040160405180910390fd5b5f600282015460ff16600181111561261f5761261f61382a565b036126e457805460408051633fabe5a360e21b815290516001600160a01b03909216915f918291849163feaf968c9160048083019260a09291908290030181865afa158015612670573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126949190613f64565b509350509250505f82136126c057505090545f9450600160a01b900460ff1692506001915061276a9050565b60018401546126cf8242614039565b11156126da57600194505b50945061275c9050565b805460408051638e15f47360e01b815281515f936001600160a01b031692638e15f47392600480820193918290030181865afa158015612726573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061274a919061423e565b909550905082806127585750805b9250505b54600160a01b900460ff1691505b9193909250565b6124a47f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c336114f4565b5f6127a5836131d9565b8015610eab5750610eab838361320b565b6127e960405180608001604052805f6001600160a01b031681526020016060815260200160608152602001606081525090565b6001600160a01b0383165f908152603660205260408120819061280c9085612160565b915091505f8160028111156128235761282361382a565b905061284960405180606001604052806060815260200160608152602001606081525090565b600282600281111561285d5761285d61382a565b036128cb57836001600160a01b0316639d7c4ee16040518163ffffffff1660e01b81526004015f60405180830381865afa15801561289d573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526128c4919081019061425f565b9050612ab0565b60018260028111156128df576128df61382a565b036129d1576040805160a0810190915260116060820190815270506f7274666f6c696f2062616c616e636560781b608083015281526035805460208301919061292790614061565b80601f016020809104026020016040519081016040528092919081815260200182805461295390614061565b801561299e5780601f106129755761010080835404028352916020019161299e565b820191905f5260205f20905b81548152906001019060200180831161298157829003601f168201915b50505050508152602001604051806040016040528060068152602001654e617469766560d01b8152508152509050612ab0565b6060846001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa925050508015612a3057506040513d5f823e601f3d908101601f19168201604052612a2d91908101906141de565b60015b612a48575060408051602081019091525f8152612a4b565b90505b604051806060016040528060405180604001604052806011815260200170506f7274666f6c696f2062616c616e636560781b815250815260200182815260200160405180604001604052806005815260200164045524332360dc1b8152508152509150505b604080516080810182526001600160a01b03909516855281516020808701919091528201518582015201516060840152509091505092915050565b612af68383836118b0565b612b2a82826002811115612b0c57612b0c61382a565b6001600160a01b0386165f9081526036602052604090209190612e55565b5060378054905f612b3a83614021565b9190505550816001600160a01b0316836001600160a01b03167f4acc8c77664751f0229cdecd20b537d6a486ccecb3f77d26bdb3ee51a7cf0b4583604051612b82919061431d565b60405180910390a3505050565b5f8080612b9d60d088612e04565b9150915081612bbf5760405163470cbf4760e01b815260040160405180910390fd5b5f612bcb88888b610cd2565b9050612bdc818360ff168888612e1b565b93505050505b95945050505050565b612498613291565b612bfb613291565b600180546001600160a01b0319166001600160a01b0392909216919091179055610e105f55565b612c2a613291565b612c8873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee600173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5f5260366020527f4c3ec90a8c757a3f8ecca3252cd089d9560a01e7389ee2625bef52796e9ebd2b9190612e55565b50600160375560408051808201909152600381526208aa8960eb1b602082015260359061215d90826140d7565b612cbd6137b3565b5f80612cca60d08a612e04565b9150915081612cec5760405163470cbf4760e01b815260040160405180910390fd5b6001600160a01b0389168352612d0389898c610cd2565b6020840181905284151560c0850152606084018890526080840187905285151560a0850152612d379060ff83168989612e1b565b6040840152509098975050505050505050565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa158015612d8e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610af49190613f34565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610ccd9084906132da565b5f80808061216e866001600160a01b03871661333b565b5f6008612e2c8361ffff871661432b565b612e369190614039565b612e4190600a614421565b612e4b848761442c565b612be2919061445b565b5f612e6a846001600160a01b03851684613373565b949350505050565b612e7d8484836110bf565b5f80826001811115612e9157612e9161382a565b03612f1d57825f03612eb657604051636077d21b60e01b815260040160405180910390fd5b836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f16919061420f565b9050612f80565b836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f59573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f7d919061420f565b90505b6040518060800160405280856001600160a01b031681526020018260ff168152602001848152602001836001811115612fbb57612fbb61382a565b90526001600160a01b038087165f90815260026020818152604092839020855181549287015160ff16600160a01b026001600160a81b03199093169516949094171783559083015160018084019190915560608401519183018054909160ff199091169083818111156130305761303061382a565b0217905550905050836001600160a01b0316856001600160a01b03167fa49194f841578adf42e4abe85004e75cdf662d7c6f75608ddeb76ad3251d185a858560405161307d929190614493565b60405180910390a35050505050565b5f610eab836001600160a01b03841661338f565b6001600160a01b0381165f81815260026020819052604080832080546001600160a81b031916815560018101849055909101805460ff19169055517f1ab93c820592302b2bef0070dd03654585b6942bfde155498ddd3d69190bf0429190a250565b61310c82826114f4565b610c315760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044016123e7565b5f808061314885856133ab565b5f81815260029690960160205260409095205494959350505050565b5f610eab83836133b6565b6060610af4826133cd565b5f610af4826133d9565b61318d826133e2565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156131d157610ccd8282613445565b610c316134ae565b5f6131eb826301ffc9a760e01b61320b565b8015610af45750613204826001600160e01b031961320b565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f51905082801561327b575060208210155b801561328657505f81115b979650505050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661249857604051631afcd79f60e31b815260040160405180910390fd5b5f6132ee6001600160a01b038416836134cd565b905080515f1415801561331257508080602001905181019061331091906144a7565b155b15610ccd57604051635274afe760e01b81526001600160a01b03841660048201526024016123e7565b5f8181526002830160205260408120548190806133685761335c8585613164565b92505f9150610bc49050565b600192509050610bc4565b5f8281526002840160205260408120829055612e6a84846134da565b5f8181526002830160205260408120819055610eab83836134e5565b5f610eab83836134f0565b5f8181526001830160205260408120541515610eab565b60605f610eab83613516565b5f610af4825490565b806001600160a01b03163b5f0361341757604051634c9c8ce360e01b81526001600160a01b03821660048201526024016123e7565b5f51602061450b5f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b03168460405161346191906144c0565b5f60405180830381855af49150503d805f8114613499576040519150601f19603f3d011682016040523d82523d5f602084013e61349e565b606091505b5091509150612be285838361356f565b34156124985760405163b398979f60e01b815260040160405180910390fd5b6060610eab83835f6135cb565b5f610eab8383613664565b5f610eab83836136b0565b5f825f01828154811061350557613505613fb2565b905f5260205f200154905092915050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561356357602002820191905f5260205f20905b81548152602001906001019080831161354f575b50505050509050919050565b6060826135845761357f8261378a565b610eab565b815115801561359b57506001600160a01b0384163b155b156135c457604051639996b31560e01b81526001600160a01b03851660048201526024016123e7565b5080610eab565b6060814710156135f05760405163cd78605960e01b81523060048201526024016123e7565b5f5f856001600160a01b0316848660405161360b91906144c0565b5f6040518083038185875af1925050503d805f8114613645576040519150601f19603f3d011682016040523d82523d5f602084013e61364a565b606091505b509150915061365a86838361356f565b9695505050505050565b5f8181526001830160205260408120546136a957508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610af4565b505f610af4565b5f8181526001830160205260408120548015612333575f6136d2600183614039565b85549091505f906136e590600190614039565b9050808214613744575f865f01828154811061370357613703613fb2565b905f5260205f200154905080875f01848154811061372357613723613fb2565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080613755576137556144d6565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610af4565b80511561379a5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040518060e001604052805f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f151581526020015f151581525090565b80356001600160a01b038116811461380c575f5ffd5b919050565b5f60208284031215613821575f5ffd5b610eab826137f6565b634e487b7160e01b5f52602160045260245ffd5b6002811061384e5761384e61382a565b9052565b6001600160a01b038516815260ff841660208201526040810183905260808101612be2606083018461383e565b5f6020828403121561388f575f5ffd5b81356001600160e01b031981168114610eab575f5ffd5b5f5f604083850312156138b7575f5ffd5b6138c0836137f6565b946020939093013593505050565b6003811061384e5761384e61382a565b6001600160a01b038316815260408101610eab60208301846138ce565b5f6020828403121561390b575f5ffd5b5035919050565b5f5f60408385031215613923575f5ffd5b61392c836137f6565b915061393a602084016137f6565b90509250929050565b602080825282518282018190525f918401906040840190835b818110156139835783516001600160a01b031683526020938401939092019160010161395c565b509095945050505050565b5f5f6040838503121561399f575f5ffd5b8235915061393a602084016137f6565b5f5f5f606084860312156139c1575f5ffd5b6139ca846137f6565b9250602084013591506139df604085016137f6565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b604051606081016001600160401b0381118282101715613a1e57613a1e6139e8565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613a4c57613a4c6139e8565b604052919050565b5f6001600160401b03821115613a6c57613a6c6139e8565b50601f01601f191660200190565b5f613a8c613a8784613a54565b613a24565b9050828152838383011115613a9f575f5ffd5b828260208301375f602084830101529392505050565b5f5f60408385031215613ac6575f5ffd5b613acf836137f6565b915060208301356001600160401b03811115613ae9575f5ffd5b8301601f81018513613af9575f5ffd5b613b0885823560208401613a7a565b9150509250929050565b80356002811061380c575f5ffd5b5f5f5f60608486031215613b32575f5ffd5b613b3b846137f6565b9250613b49602085016137f6565b91506139df60408501613b12565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015613c3257868503603f19018452815180516001600160a01b03168652602080820151608091880182905290613be690880182613b57565b905060408201518782036040890152613bff8282613b57565b915050606082015191508681036060880152613c1b8183613b57565b965050506020938401939190910190600101613bab565b50929695505050505050565b5f5f5f60608486031215613c50575f5ffd5b613c59846137f6565b9250613c67602085016137f6565b9150604084013560038110613c7a575f5ffd5b809150509250925092565b5f5f5f60608486031215613c97575f5ffd5b613ca0846137f6565b95602085013595506040909401359392505050565b602081525f610eab6020830184613b57565b5f60208284031215613cd7575f5ffd5b81356001600160401b03811115613cec575f5ffd5b8201601f81018413613cfc575f5ffd5b612e6a84823560208401613a7a565b5f5f5f60608486031215613d1d575f5ffd5b613d26846137f6565b9250613d34602085016137f6565b91506139df604085016137f6565b5f5f5f60608486031215613d54575f5ffd5b613d5d846137f6565b9250613d6b602085016137f6565b929592945050506040919091013590565b5f5f60208385031215613d8d575f5ffd5b82356001600160401b03811115613da2575f5ffd5b8301601f81018513613db2575f5ffd5b80356001600160401b03811115613dc7575f5ffd5b8560208260051b8401011115613ddb575f5ffd5b6020919091019590945092505050565b602081525f82516101806020840152613e086101a0840182613b57565b90506020840151601f19848303016040850152613e258282613b57565b9150506040840151601f19848303016060850152613e438282613b57565b9150506060840151613e6060808501826001600160a01b03169052565b506080840151838203601f190160a0850152613e7c8282613b57565b91505060a0840151613e9360c085018260ff169052565b5060c084015160e084015260e0840151610100840152610100840151613ebe61012085018215159052565b5061012084015161014084015261014084015161016084015261016084015161130161018085018215159052565b5f5f5f5f60808587031215613eff575f5ffd5b613f08856137f6565b9350613f16602086016137f6565b9250613f2460408601613b12565b9396929550929360600135925050565b5f60208284031215613f44575f5ffd5b5051919050565b805169ffffffffffffffffffff8116811461380c575f5ffd5b5f5f5f5f5f60a08688031215613f78575f5ffd5b613f8186613f4b565b60208701516040880151606089015192975090955093509150613fa660808701613f4b565b90509295509295909350565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f61ffff821661ffff8103613ff157613ff1613fc6565b60010192915050565b8082018281125f83128015821682158216171561401957614019613fc6565b505092915050565b5f6001820161403257614032613fc6565b5060010190565b81810381811115610af457610af4613fc6565b5f8161405a5761405a613fc6565b505f190190565b600181811c9082168061407557607f821691505b60208210810361158857634e487b7160e01b5f52602260045260245ffd5b601f821115610ccd57805f5260205f20601f840160051c810160208510156140b85750805b601f840160051c820191505b81811015612000575f81556001016140c4565b81516001600160401b038111156140f0576140f06139e8565b614104816140fe8454614061565b84614093565b6020601f821160018114614136575f831561411f5750848201515b5f19600385901b1c1916600184901b178455612000565b5f84815260208120601f198516915b828110156141655787850151825560209485019460019092019101614145565b508482101561418257868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f82601f8301126141a0575f5ffd5b81516141ae613a8782613a54565b8181528460208386010111156141c2575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f602082840312156141ee575f5ffd5b81516001600160401b03811115614203575f5ffd5b612e6a84828501614191565b5f6020828403121561421f575f5ffd5b815160ff81168114610eab575f5ffd5b8051801515811461380c575f5ffd5b5f5f6040838503121561424f575f5ffd5b8251915061393a6020840161422f565b5f6020828403121561426f575f5ffd5b81516001600160401b03811115614284575f5ffd5b820160608185031215614295575f5ffd5b61429d6139fc565b81516001600160401b038111156142b2575f5ffd5b6142be86828501614191565b82525060208201516001600160401b038111156142d9575f5ffd5b6142e586828501614191565b60208301525060408201516001600160401b03811115614303575f5ffd5b61430f86828501614191565b604083015250949350505050565b60208101610af482846138ce565b80820180821115610af457610af4613fc6565b6001815b60018411156143795780850481111561435d5761435d613fc6565b600184161561436b57908102905b60019390931c928002614342565b935093915050565b5f8261438f57506001610af4565b8161439b57505f610af4565b81600181146143b157600281146143bb576143d7565b6001915050610af4565b60ff8411156143cc576143cc613fc6565b50506001821b610af4565b5060208310610133831016604e8410600b84101617156143fa575081810a610af4565b6144065f19848461433e565b805f190482111561441957614419613fc6565b029392505050565b5f610eab8383614381565b8082025f8212600160ff1b8414161561444757614447613fc6565b8181058314821517610af457610af4613fc6565b5f8261447557634e487b7160e01b5f52601260045260245ffd5b600160ff1b82145f198414161561448e5761448e613fc6565b500590565b82815260408101610eab602083018461383e565b5f602082840312156144b7575f5ffd5b610eab8261422f565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603160045260245ffdfeaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800a264697066735822122092d2b04c170d97d9ffa43ce97d53a373db5600e78a16afa20cb6b356ae18f12b64736f6c634300081b0033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.