Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 internal transactions (View All)
Advanced mode:
Loading...
Loading
Contract Name:
AeraVaultModulesFactory
Compiler Version
v0.8.21+commit.d9974bed
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "@openzeppelin/IERC20.sol"; import "./AeraVaultAssetRegistry.sol"; import "./AeraVaultHooks.sol"; import "./Sweepable.sol"; import "./interfaces/IAeraV2Factory.sol"; import "./interfaces/IAeraVaultAssetRegistryFactory.sol"; import "./interfaces/IAeraVaultHooksFactory.sol"; /// @title AeraVaultModulesFactory /// @notice Used to create new asset registry and hooks. /// @dev Only one instance of the factory will be required per chain. contract AeraVaultModulesFactory is IAeraVaultAssetRegistryFactory, IAeraVaultHooksFactory, Sweepable { /// @notice The address of the v2 factory. address public immutable v2Factory; /// @notice Wrapped native token. IERC20 public immutable wrappedNativeToken; /// EVENTS /// /// @notice Emitted when the asset registry is created. /// @param assetRegistry Asset registry address. /// @param vault Vault address. /// @param owner Initial owner address. /// @param assets Initial list of registered assets. /// @param numeraireToken Numeraire token address. /// @param feeToken Fee token address. /// @param wrappedNativeToken Wrapped native token address. /// @param sequencer Sequencer Uptime Feed address for L2. event AssetRegistryCreated( address indexed assetRegistry, address indexed vault, address indexed owner, IAssetRegistry.AssetInformation[] assets, IERC20 numeraireToken, IERC20 feeToken, IERC20 wrappedNativeToken, AggregatorV2V3Interface sequencer ); /// @notice Emitted when the hooks is created. /// @param hooks Hooks address. /// @param vault Vault address. /// @param owner Initial owner address. /// @param minDailyValue The minimum fraction of value that the vault has to retain /// during the day in the course of submissions. /// @param targetSighashAllowlist Array of target contract and sighash combinations to allow. event HooksCreated( address indexed hooks, address indexed vault, address indexed owner, uint256 minDailyValue, TargetSighashData[] targetSighashAllowlist ); /// MODIFIERS /// error Aera_CallerIsNeitherOwnerOrV2Factory(); error Aera__V2FactoryIsZeroAddress(); /// MODIFIERS /// /// @dev Throws if called by any account other than the owner or v2 factory. modifier onlyOwnerOrV2Factory() { if (msg.sender != owner() && msg.sender != v2Factory) { revert Aera_CallerIsNeitherOwnerOrV2Factory(); } _; } /// FUNCTIONS /// constructor(address v2Factory_) Ownable() { if (v2Factory_ == address(0)) { revert Aera__V2FactoryIsZeroAddress(); } wrappedNativeToken = IERC20(IAeraV2Factory(v2Factory_).wrappedNativeToken()); v2Factory = v2Factory_; } /// @inheritdoc IAeraVaultAssetRegistryFactory function deployAssetRegistry( bytes32 salt, address owner_, address vault, IAssetRegistry.AssetInformation[] memory assets, IERC20 numeraireToken, IERC20 feeToken, AggregatorV2V3Interface sequencer ) external override onlyOwnerOrV2Factory returns (address deployed) { // Effects: deploy asset registry. deployed = address( new AeraVaultAssetRegistry{salt: salt}( owner_, vault, assets, numeraireToken, feeToken, wrappedNativeToken, sequencer ) ); // Log asset registry creation. emit AssetRegistryCreated( deployed, vault, owner_, assets, numeraireToken, feeToken, wrappedNativeToken, sequencer ); } /// @inheritdoc IAeraVaultHooksFactory function deployHooks( bytes32 salt, address owner_, address vault, uint256 minDailyValue, TargetSighashData[] memory targetSighashAllowlist ) external override onlyOwnerOrV2Factory returns (address deployed) { // Effects: deploy hooks. deployed = address( new AeraVaultHooks{salt:salt}( owner_, vault, minDailyValue, targetSighashAllowlist ) ); // Log hooks creation. emit HooksCreated( deployed, vault, owner_, minDailyValue, targetSighashAllowlist ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "@openzeppelin/ERC165.sol"; import "@openzeppelin/IERC4626.sol"; import "./Sweepable.sol"; import "./interfaces/IAssetRegistry.sol"; import "./interfaces/IVault.sol"; import {ONE} from "./Constants.sol"; /// @title AeraVaultAssetRegistry /// @notice Maintains a list of registered assets and their oracles (when applicable). contract AeraVaultAssetRegistry is IAssetRegistry, Sweepable, ERC165 { /// @notice Maximum number of assets. uint256 public constant MAX_ASSETS = 50; /// @notice Time to pass before accepting answers when sequencer comes back up. uint256 public constant GRACE_PERIOD_TIME = 3600; /// @notice Vault address. address public immutable vault; /// @notice Numeraire token. IERC20 public immutable numeraireToken; /// @notice Fee token. IERC20 public immutable feeToken; /// @notice Wrapped native token. IERC20 public immutable wrappedNativeToken; /// @notice Sequencer Uptime Feed address for L2. AggregatorV2V3Interface public immutable sequencer; /// STORAGE /// /// @notice List of currently registered assets. AssetInformation[] internal _assets; /// @notice Number of ERC4626 assets. Maintained for more efficient calculation of spotPrices. uint256 public numYieldAssets; /// EVENTS /// /// @notice Emitted when a new asset is added. /// @param asset New asset details. event AssetAdded(address indexed asset, AssetInformation assetInfo); /// @notice Emitted when an asset is removed. /// @param asset Address of removed asset. event AssetRemoved(address indexed asset); /// @notice Emitted in constructor. /// @param owner Owner address. /// @param vault Vault address. /// @param assets Initial list of registered assets. /// @param numeraireToken Numeraire token address. /// @param feeToken Fee token address. /// @param wrappedNativeToken Wrapped native token. /// @param sequencer Sequencer Uptime Feed address for L2. event Created( address indexed owner, address indexed vault, AssetInformation[] assets, address indexed numeraireToken, address feeToken, address wrappedNativeToken, address sequencer ); /// ERRORS /// error Aera__NumberOfAssetsExceedsMaximum(uint256 max); error Aera__NumeraireTokenIsNotRegistered(address numeraireToken); error Aera__NumeraireTokenIsERC4626(); error Aera__NumeraireOracleIsNotZeroAddress(); error Aera__FeeTokenIsNotRegistered(address feeToken); error Aera__FeeTokenIsERC4626(address feeToken); error Aera__WrappedNativeTokenIsNotRegistered(address wrappedNativeToken); error Aera__WrappedNativeTokenIsERC4626(address wrappedNativeToken); error Aera__AssetOrderIsIncorrect(uint256 index); error Aera__AssetRegistryInitialOwnerIsZeroAddress(); error Aera__AssetRegistryOwnerIsGuardian(); error Aera__AssetRegistryOwnerIsVault(); error Aera__ERC20OracleIsZeroAddress(address asset); error Aera__ERC4626OracleIsNotZeroAddress(address asset); error Aera__UnderlyingAssetIsNotRegistered( address asset, address underlyingAsset ); error Aera__UnderlyingAssetIsItselfERC4626(); error Aera__AssetIsUnderlyingAssetOfERC4626(address erc4626Asset); error Aera__AssetIsAlreadyRegistered(uint256 index); error Aera__AssetNotRegistered(address asset); error Aera__CannotRemoveNumeraireToken(address asset); error Aera__CannotRemoveFeeToken(address feeToken); error Aera__CannotRemoveWrappedNativeToken(address wrappedNativeToken); error Aera__VaultIsZeroAddress(); error Aera__SequencerIsDown(); error Aera__GracePeriodNotOver(); error Aera__OraclePriceIsInvalid(AssetInformation asset, int256 actual); error Aera__OraclePriceIsTooOld(AssetInformation asset, uint256 updatedAt); /// FUNCTIONS /// /// @param owner_ Initial owner address. /// @param vault_ Vault address. /// @param assets_ Initial list of registered assets. /// @param numeraireToken_ Numeraire token address. /// @param feeToken_ Fee token address. /// @param wrappedNativeToken_ Wrapped native token address. /// @param sequencer_ Sequencer Uptime Feed address for L2. constructor( address owner_, address vault_, AssetInformation[] memory assets_, IERC20 numeraireToken_, IERC20 feeToken_, IERC20 wrappedNativeToken_, AggregatorV2V3Interface sequencer_ ) Ownable() { // Requirements: confirm that owner is not zero address. if (owner_ == address(0)) { revert Aera__AssetRegistryInitialOwnerIsZeroAddress(); } // Requirements: check that an address has been provided. if (vault_ == address(0)) { revert Aera__VaultIsZeroAddress(); } // Requirements: check that asset registry initial owner is not the computed vault address. if (owner_ == vault_) { revert Aera__AssetRegistryOwnerIsVault(); } uint256 numAssets = assets_.length; // Requirements: confirm that number of assets is within bounds. if (numAssets > MAX_ASSETS) { revert Aera__NumberOfAssetsExceedsMaximum(MAX_ASSETS); } // Calculate the Numeraire token index. uint256 numeraireIndex = 0; for (; numeraireIndex < numAssets;) { if (assets_[numeraireIndex].asset == numeraireToken_) { break; } unchecked { numeraireIndex++; // gas savings } } // Calculate the fee token index. uint256 feeTokenIndex = 0; for (; feeTokenIndex < numAssets;) { if (assets_[feeTokenIndex].asset == feeToken_) { break; } unchecked { feeTokenIndex++; // gas savings } } // Calculate the wrapped native token index. uint256 wrappedNativeTokenIndex = 0; for (; wrappedNativeTokenIndex < numAssets;) { if (assets_[wrappedNativeTokenIndex].asset == wrappedNativeToken_) { break; } unchecked { wrappedNativeTokenIndex++; // gas savings } } // Requirements: confirm that Numeraire token is present. if (numeraireIndex >= numAssets) { revert Aera__NumeraireTokenIsNotRegistered( address(numeraireToken_) ); } // Requirements: confirm that numeraire is not an ERC4626 asset. if (assets_[numeraireIndex].isERC4626) { revert Aera__NumeraireTokenIsERC4626(); } // Requirements: confirm that numeraire does not have a specified oracle. if (address(assets_[numeraireIndex].oracle) != address(0)) { revert Aera__NumeraireOracleIsNotZeroAddress(); } // Requirements: confirm that fee token is present. if (feeTokenIndex >= numAssets) { revert Aera__FeeTokenIsNotRegistered(address(feeToken_)); } // Requirements: check that fee token is not an ERC4626. if (assets_[feeTokenIndex].isERC4626) { revert Aera__FeeTokenIsERC4626(address(feeToken_)); } // Requirements: confirm that wrapped native token is present. if (wrappedNativeTokenIndex >= numAssets) { revert Aera__WrappedNativeTokenIsNotRegistered( address(wrappedNativeToken_) ); } // Requirements: check that wrapped native token is not an ERC4626. if (assets_[wrappedNativeTokenIndex].isERC4626) { revert Aera__WrappedNativeTokenIsERC4626( address(wrappedNativeToken_) ); } // Requirements: confirm that assets are sorted by address. for (uint256 i = 1; i < numAssets;) { if (assets_[i - 1].asset >= assets_[i].asset) { revert Aera__AssetOrderIsIncorrect(i); } unchecked { i++; // gas savings } } for (uint256 i = 0; i < numAssets;) { if (i != numeraireIndex) { // Requirements: check asset oracle is correctly specified. _checkAssetOracle(assets_[i]); if (assets_[i].isERC4626) { // Requirements: check that underlying asset is a registered ERC20. _checkUnderlyingAsset(assets_[i], assets_); } } // Effects: add asset to array. _insertAsset(assets_[i], i); unchecked { i++; // gas savings } } // Effects: set vault, numeraire, fee token, wrapped native token // and sequencer uptime feed. vault = vault_; numeraireToken = numeraireToken_; feeToken = feeToken_; wrappedNativeToken = wrappedNativeToken_; sequencer = sequencer_; // Effects: set new owner. _transferOwnership(owner_); // Log asset registry creation. emit Created( owner_, vault_, assets_, address(numeraireToken_), address(feeToken_), address(wrappedNativeToken_), address(sequencer) ); } /// @notice Add a new asset. /// @param asset Asset information for new asset. /// @dev MUST revert if not called by owner. /// @dev MUST revert if asset with the same address exists. function addAsset(AssetInformation calldata asset) external onlyOwner { uint256 numAssets = _assets.length; // Requirements: validate number of assets doesn't exceed bound. if (numAssets >= MAX_ASSETS) { revert Aera__NumberOfAssetsExceedsMaximum(MAX_ASSETS); } // Requirements: validate oracle field for asset struct. _checkAssetOracle(asset); uint256 i = 0; // Find the index to insert the new asset. for (; i < numAssets;) { if (asset.asset < _assets[i].asset) { break; } // Requirements: check that asset is not already present. if (asset.asset == _assets[i].asset) { revert Aera__AssetIsAlreadyRegistered(i); } unchecked { i++; // gas savings } } // Requirements: check that underlying asset is a registered ERC20. if (asset.isERC4626) { _checkUnderlyingAsset(asset, _assets); } // Effects: insert asset at position i. _insertAsset(asset, i); } /// @notice Remove an asset. /// @param asset An asset to remove. /// @dev MUST revert if not called by owner. function removeAsset(address asset) external onlyOwner { // Requirements: confirm that asset to remove is not numeraire. if (asset == address(numeraireToken)) { revert Aera__CannotRemoveNumeraireToken(asset); } // Requirements: check that asset to remove is not fee token. if (asset == address(feeToken)) { revert Aera__CannotRemoveFeeToken(asset); } // Requirements: check that asset to remove is not wrapped native token. if (asset == address(wrappedNativeToken)) { revert Aera__CannotRemoveWrappedNativeToken(asset); } uint256 numAssets = _assets.length; uint256 oldAssetIndex = 0; // Find index of asset. for ( ; oldAssetIndex < numAssets && address(_assets[oldAssetIndex].asset) != asset; ) { unchecked { oldAssetIndex++; // gas savings } } // Requirements: check that asset is registered. if (oldAssetIndex >= numAssets) { revert Aera__AssetNotRegistered(asset); } // Effects: adjust the number of ERC4626 assets. if (_assets[oldAssetIndex].isERC4626) { numYieldAssets--; } else { for (uint256 i = 0; i < numAssets;) { if ( i != oldAssetIndex && _assets[i].isERC4626 && IERC4626(address(_assets[i].asset)).asset() == asset ) { revert Aera__AssetIsUnderlyingAssetOfERC4626( address(_assets[i].asset) ); } unchecked { i++; // gas savings } } } uint256 nextIndex; uint256 lastIndex = numAssets - 1; // Slide all elements after oldAssetIndex left. for (uint256 i = oldAssetIndex; i < lastIndex;) { nextIndex = i + 1; _assets[i] = _assets[nextIndex]; unchecked { i++; // gas savings } } // Effects: remove asset from array. _assets.pop(); // Log removal. emit AssetRemoved(asset); } /// @inheritdoc IAssetRegistry function assets() external view override returns (AssetInformation[] memory) { return _assets; } /// @inheritdoc IAssetRegistry function spotPrices() external view override returns (AssetPriceReading[] memory) { int256 answer; uint256 startedAt; // Requirements: check that sequencer is up. if (address(sequencer) != address(0)) { (, answer, startedAt,,) = sequencer.latestRoundData(); // Answer == 0: Sequencer is up // Requirements: check that the sequencer is up. if (answer != 0) { revert Aera__SequencerIsDown(); } // Requirements: check that the grace period has passed after the // sequencer is back up. if (block.timestamp < startedAt + GRACE_PERIOD_TIME) { revert Aera__GracePeriodNotOver(); } } // Prepare price array. uint256 numAssets = _assets.length; AssetPriceReading[] memory prices = new AssetPriceReading[]( numAssets - numYieldAssets ); uint256 oracleDecimals; uint256 price; uint256 index = 0; for (uint256 i = 0; i < numAssets;) { if (_assets[i].isERC4626) { unchecked { i++; // gas savings } continue; } if (_assets[i].asset == numeraireToken) { // Numeraire has price 1 by definition. prices[index] = AssetPriceReading({ asset: _assets[i].asset, spotPrice: ONE }); } else { price = _checkOraclePrice(_assets[i]); oracleDecimals = _assets[i].oracle.decimals(); if (oracleDecimals < 18) { // slither-disable-next-line divide-before-multiply price = price * (10 ** (18 - oracleDecimals)); } else if (oracleDecimals > 18) { // slither-disable-next-line divide-before-multiply price = price / (10 ** (oracleDecimals - 18)); } prices[index] = AssetPriceReading({ asset: _assets[i].asset, spotPrice: price }); } unchecked { // gas savings index++; i++; } } return prices; } /// @inheritdoc IERC165 function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return interfaceId == type(IAssetRegistry).interfaceId || super.supportsInterface(interfaceId); } /// INTERNAL FUNCTIONS /// /// @notice Ensure non-zero oracle address for ERC20 /// and zero oracle address for ERC4626. /// @param asset Asset details to check function _checkAssetOracle(AssetInformation memory asset) internal view { if (asset.isERC4626) { // ERC4626 asset should not have a specified oracle. if (address(asset.oracle) != address(0)) { revert Aera__ERC4626OracleIsNotZeroAddress( address(asset.asset) ); } } else { // ERC20 asset should have non-zero oracle address. if (address(asset.oracle) == address(0)) { revert Aera__ERC20OracleIsZeroAddress(address(asset.asset)); } // Requirements: validate oracle price. _checkOraclePrice(asset); } } /// @notice Ensure oracle returns valid value and it's up to date. /// @param asset Asset details to check. /// @return price Valid oracle price. function _checkOraclePrice(AssetInformation memory asset) internal view returns (uint256 price) { (, int256 answer,, uint256 updatedAt,) = asset.oracle.latestRoundData(); // Check price staleness if (answer <= 0) { revert Aera__OraclePriceIsInvalid(asset, answer); } if ( asset.heartbeat > 0 && updatedAt + asset.heartbeat + 1 hours < block.timestamp ) { revert Aera__OraclePriceIsTooOld(asset, updatedAt); } price = uint256(answer); } /// @notice Check whether the underlying asset is listed as an ERC20. /// @dev Will revert if underlying asset is an ERC4626. /// @param asset ERC4626 asset to check underlying asset. /// @param assetsToCheck Array of assets. function _checkUnderlyingAsset( AssetInformation memory asset, AssetInformation[] memory assetsToCheck ) internal view { uint256 numAssets = assetsToCheck.length; address underlyingAsset = IERC4626(address(asset.asset)).asset(); uint256 underlyingIndex = 0; for (; underlyingIndex < numAssets;) { if ( underlyingAsset == address(assetsToCheck[underlyingIndex].asset) ) { break; } unchecked { underlyingIndex++; // gas savings } } if (underlyingIndex >= numAssets) { revert Aera__UnderlyingAssetIsNotRegistered( address(asset.asset), underlyingAsset ); } if (assetsToCheck[underlyingIndex].isERC4626) { revert Aera__UnderlyingAssetIsItselfERC4626(); } } /// @notice Insert asset at the given index in an array of assets. /// @param asset New asset details. /// @param index Index of the new asset in the asset array. function _insertAsset( AssetInformation memory asset, uint256 index ) internal { uint256 numAssets = _assets.length; if (index == numAssets) { // Effects: insert new asset at the end. _assets.push(asset); } else { // Effects: push last elements to the right and insert new asset. _assets.push(_assets[numAssets - 1]); uint256 prevIndex; for (uint256 i = numAssets - 1; i > index; i--) { prevIndex = i - 1; _assets[i] = _assets[prevIndex]; } _assets[index] = asset; } // Effects: adjust the number of ERC4626 assets. if (asset.isERC4626) { numYieldAssets++; } // Log asset added. emit AssetAdded(address(asset.asset), asset); } /// @notice Check that owner is not the vault or the guardian. /// @param owner_ Asset registry owner address. /// @param vault_ Vault address. function _checkAssetRegistryOwner( address owner_, address vault_ ) internal view { if (owner_ == vault_) { revert Aera__AssetRegistryOwnerIsVault(); } address guardian = IVault(vault_).guardian(); if (owner_ == guardian) { revert Aera__AssetRegistryOwnerIsGuardian(); } } /// @inheritdoc Ownable2Step function transferOwnership(address newOwner) public override onlyOwner { // Requirements: check that new owner is disaffiliated from existing roles. _checkAssetRegistryOwner(newOwner, vault); // Effects: initiate ownership transfer. super.transferOwnership(newOwner); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "@openzeppelin/IERC20.sol"; import "@openzeppelin/ERC165.sol"; import "@openzeppelin/SafeERC20.sol"; import "@openzeppelin/IERC20IncreaseAllowance.sol"; import "./interfaces/IHooks.sol"; import "./interfaces/IAeraVaultHooksEvents.sol"; import "./interfaces/IVault.sol"; import "./Sweepable.sol"; import "./TargetSighashLib.sol"; import "./Types.sol"; import {ONE} from "./Constants.sol"; /// @title AeraVaultHooks /// @notice Default hooks contract which implements several safeguards. /// @dev Connected vault MUST only call submit with tokens that can increase allowances with approve and increaseAllowance. contract AeraVaultHooks is IHooks, IAeraVaultHooksEvents, Sweepable, ERC165 { using SafeERC20 for IERC20; /// @notice Min bound on minimum fraction of vault value that the vault has to retain /// between submissions during a single day. /// @dev Loose bound to mitigate initialization error. uint256 private constant _LOWEST_MIN_DAILY_VALUE = ONE / 2; /// @notice The minimum fraction of vault value that the vault has to /// retain per day during submit transactions. /// e.g. 0.9 (in 18-decimal form) allows the vault to lose up to /// 10% in value across consecutive submissions. uint256 public immutable minDailyValue; /// STORAGE /// /// @notice The address of the vault. address public vault; /// @notice Current day (UTC). uint256 public currentDay; /// @notice Accumulated value multiplier during submit transactions. uint256 public cumulativeDailyMultiplier; /// @notice Allowed target contract and sighash combinations. mapping(TargetSighash => bool) internal _targetSighashAllowed; /// @notice Total value of assets in vault before submission. /// @dev Assigned in `beforeSubmit` and used in `afterSubmit`. uint256 internal _beforeValue; /// ERRORS /// error Aera__CallerIsNotVault(); error Aera__VaultIsZeroAddress(); error Aera__HooksOwnerIsGuardian(); error Aera__HooksOwnerIsVault(); error Aera__MinDailyValueTooLow(); error Aera__MinDailyValueIsNotLessThanOne(); error Aera__NoCodeAtTarget(address target); error Aera__CallIsNotAllowed(Operation operation); error Aera__VaultValueBelowMinDailyValue(); error Aera__AllowanceIsNotZero(address asset, address spender); error Aera__HooksInitialOwnerIsZeroAddress(); error Aera__RemovingNonexistentTargetSighash(TargetSighash targetSighash); error Aera__AddingDuplicateTargetSighash(TargetSighash targetSighash); /// MODIFIERS /// /// @dev Throws if called by any account other than the vault. modifier onlyVault() { if (msg.sender != vault) { revert Aera__CallerIsNotVault(); } _; } /// FUNCTIONS /// /// @param owner_ Initial owner address. /// @param vault_ Vault address. /// @param minDailyValue_ The minimum fraction of value that the vault has to retain /// during the day in the course of submissions. /// @param targetSighashAllowlist Array of target contract and sighash combinations to allow. constructor( address owner_, address vault_, uint256 minDailyValue_, TargetSighashData[] memory targetSighashAllowlist ) Ownable() { // Requirements: validate vault. if (vault_ == address(0)) { revert Aera__VaultIsZeroAddress(); } if (owner_ == address(0)) { revert Aera__HooksInitialOwnerIsZeroAddress(); } // Requirements: check that hooks initial owner is disaffiliated. if (owner_ == vault_) { revert Aera__HooksOwnerIsVault(); } // Only check vault if it has been deployed already. // This will happen if we are deploying a new Hooks contract for an existing vault. if (vault_.code.length > 0) { address guardian = IVault(vault_).guardian(); if (owner_ == guardian) { revert Aera__HooksOwnerIsGuardian(); } } // Requirements: check that minimum daily value doesn't mandate vault growth. if (minDailyValue_ >= ONE) { revert Aera__MinDailyValueIsNotLessThanOne(); } // Requirements: check that minimum daily value enforces a lower bound. if (minDailyValue_ < _LOWEST_MIN_DAILY_VALUE) { revert Aera__MinDailyValueTooLow(); } uint256 numTargetSighashAllowlist = targetSighashAllowlist.length; // Effects: initialize target sighash allowlist. for (uint256 i = 0; i < numTargetSighashAllowlist;) { _addTargetSighash( targetSighashAllowlist[i].target, targetSighashAllowlist[i].selector ); unchecked { i++; // gas savings } } // Effects: initialize state variables. vault = vault_; minDailyValue = minDailyValue_; currentDay = block.timestamp / 1 days; cumulativeDailyMultiplier = ONE; // Effects: set new owner. _transferOwnership(owner_); } /// @notice Add targetSighash pair to allowlist. /// @param target Address of target. /// @param selector Selector of function. function addTargetSighash( address target, bytes4 selector ) external onlyOwner { _addTargetSighash(target, selector); } /// @notice Remove targetSighash pair from allowlist. /// @param target Address of target. /// @param selector Selector of function. function removeTargetSighash( address target, bytes4 selector ) external onlyOwner { TargetSighash targetSighash = TargetSighashLib.toTargetSighash(target, selector); // Requirements: check that current target sighash is set. if (!_targetSighashAllowed[targetSighash]) { revert Aera__RemovingNonexistentTargetSighash(targetSighash); } // Effects: remove target sighash combination from the allowlist. delete _targetSighashAllowed[targetSighash]; // Log the removal. emit TargetSighashRemoved(target, selector); } /// @inheritdoc IHooks function beforeDeposit(AssetValue[] memory amounts) external override onlyVault {} /// @inheritdoc IHooks function afterDeposit(AssetValue[] memory amounts) external override onlyVault {} /// @inheritdoc IHooks function beforeWithdraw(AssetValue[] memory amounts) external override onlyVault {} /// @inheritdoc IHooks function afterWithdraw(AssetValue[] memory amounts) external override onlyVault {} /// @inheritdoc IHooks function beforeSubmit(Operation[] calldata operations) external override onlyVault { uint256 numOperations = operations.length; bytes4 selector; // Requirements: validate that all operations are allowed. for (uint256 i = 0; i < numOperations;) { selector = bytes4(operations[i].data[0:4]); TargetSighash sigHash = TargetSighashLib.toTargetSighash( operations[i].target, selector ); // Requirements: validate that the target sighash combination is allowed. if (!_targetSighashAllowed[sigHash]) { revert Aera__CallIsNotAllowed(operations[i]); } unchecked { i++; } // gas savings } // Effects: remember current vault value and ETH balance for use in afterSubmit. _beforeValue = IVault(vault).value(); } /// @inheritdoc IHooks function afterSubmit(Operation[] calldata operations) external override onlyVault { uint256 newMultiplier; uint256 currentMultiplier = cumulativeDailyMultiplier; uint256 day = block.timestamp / 1 days; if (_beforeValue > 0) { // Initialize new cumulative multiplier with the current submit multiplier. newMultiplier = currentDay == day ? currentMultiplier : ONE; newMultiplier = (newMultiplier * IVault(vault).value()) / _beforeValue; // Requirements: check that daily execution loss is within bounds. if (newMultiplier < minDailyValue) { revert Aera__VaultValueBelowMinDailyValue(); } // Effects: update the daily multiplier. if (currentMultiplier != newMultiplier) { cumulativeDailyMultiplier = newMultiplier; } } // Effects: reset current day for the next submission. if (currentDay != day) { currentDay = day; } // Effects: reset prior vault value for the next submission. _beforeValue = 0; uint256 numOperations = operations.length; bytes4 selector; address spender; uint256 amount; IERC20 token; // Requirements: check that there are no outgoing allowances that were introduced. for (uint256 i = 0; i < numOperations;) { selector = bytes4(operations[i].data[0:4]); if (_isAllowanceSelector(selector)) { // Extract spender and amount from the allowance transaction. (spender, amount) = abi.decode(operations[i].data[4:], (address, uint256)); // If amount is 0 then allowance hasn't been increased. if (amount == 0) { unchecked { i++; } // gas savings continue; } token = IERC20(operations[i].target); // Requirements: check that the current outgoing allowance for this token is zero. if (token.allowance(vault, spender) > 0) { revert Aera__AllowanceIsNotZero(address(token), spender); } } unchecked { i++; } // gas savings } } /// @inheritdoc IHooks function beforeFinalize() external override onlyVault {} /// @inheritdoc IHooks function afterFinalize() external override onlyVault { // Effects: release storage currentDay = 0; cumulativeDailyMultiplier = 0; } /// @inheritdoc IHooks function decommission() external override onlyVault { // Effects: reset vault address. vault = address(0); // Effects: release storage currentDay = 0; cumulativeDailyMultiplier = 0; // Log decommissioning. emit Decommissioned(); } /// @inheritdoc IERC165 function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return interfaceId == type(IHooks).interfaceId || super.supportsInterface(interfaceId); } /// @notice Check whether target and sighash combination is allowed. /// @param target Address of target. /// @param selector Selector of function. function targetSighashAllowed( address target, bytes4 selector ) external view returns (bool) { return _targetSighashAllowed[TargetSighashLib.toTargetSighash( target, selector )]; } /// INTERNAL FUNCTIONS /// /// @notice Add targetSighash pair to allowlist. /// @param target Address of target. /// @param selector Selector of function. function _addTargetSighash(address target, bytes4 selector) internal { // Requirements: check there is code at target. if (target.code.length == 0) { revert Aera__NoCodeAtTarget(target); } TargetSighash targetSighash = TargetSighashLib.toTargetSighash(target, selector); // Requirements: check that current target sighash is not set. if (_targetSighashAllowed[targetSighash]) { revert Aera__AddingDuplicateTargetSighash(targetSighash); } // Effects: add target sighash combination to the allowlist. _targetSighashAllowed[targetSighash] = true; // Log the addition. emit TargetSighashAdded(target, selector); } /// @notice Check whether selector is allowance related selector or not. /// @param selector Selector of calldata to check. /// @return isAllowanceSelector True if selector is allowance related selector. function _isAllowanceSelector(bytes4 selector) internal pure returns (bool isAllowanceSelector) { return selector == IERC20.approve.selector || selector == IERC20IncreaseAllowance.increaseAllowance.selector; } /// @notice Check that owner is not the vault or the guardian. /// @param owner_ Hooks owner address. /// @param vault_ Vault address. function _checkHooksOwner(address owner_, address vault_) internal view { if (owner_ == vault_) { revert Aera__HooksOwnerIsVault(); } address guardian = IVault(vault_).guardian(); if (owner_ == guardian) { revert Aera__HooksOwnerIsGuardian(); } } /// @inheritdoc Ownable2Step function transferOwnership(address newOwner) public override onlyOwner { // Requirements: check that new owner is disaffiliated from existing roles. _checkHooksOwner(newOwner, vault); // Effects: initiate ownership transfer. super.transferOwnership(newOwner); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "@openzeppelin/Ownable2Step.sol"; import "@openzeppelin/SafeERC20.sol"; import "./interfaces/ISweepable.sol"; /// @title Sweepable. /// @notice Aera Sweepable contract. /// @dev Allows owner of the contract to restore accidentally send tokens // and the chain's native token. contract Sweepable is ISweepable, Ownable2Step { using SafeERC20 for IERC20; /// @inheritdoc ISweepable function sweep(address token, uint256 amount) external onlyOwner { if (token == address(0)) { msg.sender.call{value: amount}(""); } else { IERC20(token).safeTransfer(msg.sender, amount); } emit Sweep(token, amount); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import { AssetRegistryParameters, HooksParameters, VaultParameters } from "../Types.sol"; /// @title IAeraV2Factory /// @notice Interface for the V2 vault factory. interface IAeraV2Factory { /// @notice Create V2 vault. /// @param saltInput The salt input value to generate salt. /// @param description Vault description. /// @param vaultParameters Struct details for vault deployment. /// @param assetRegistryParameters Struct details for asset registry deployment. /// @param hooksParameters Struct details for hooks deployment. /// @return deployedVault The address of deployed vault. /// @return deployedAssetRegistry The address of deployed asset registry. /// @return deployedHooks The address of deployed hooks. function create( bytes32 saltInput, string calldata description, VaultParameters calldata vaultParameters, AssetRegistryParameters memory assetRegistryParameters, HooksParameters memory hooksParameters ) external returns ( address deployedVault, address deployedAssetRegistry, address deployedHooks ); /// @notice Calculate deployment address of V2 vault. /// @param saltInput The salt input value to generate salt. /// @param description Vault description. /// @param vaultParameters Struct details for vault deployment. function computeVaultAddress( bytes32 saltInput, string calldata description, VaultParameters calldata vaultParameters ) external view returns (address); /// @notice Returns the address of wrapped native token. function wrappedNativeToken() external view returns (address); /// @notice Returns vault parameters for vault deployment. /// @return owner Initial owner address. /// @return assetRegistry Asset registry address. /// @return hooks Hooks address. /// @return guardian Guardian address. /// @return feeRecipient Fee recipient address. /// @return fee Fees accrued per second, denoted in 18 decimal fixed point format. function parameters() external view returns ( address owner, address assetRegistry, address hooks, address guardian, address feeRecipient, uint256 fee ); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "./IAssetRegistry.sol"; import "@chainlink/interfaces/AggregatorV2V3Interface.sol"; /// @title IAeraVaultAssetRegistryFactory /// @notice Interface for the asset registry factory. interface IAeraVaultAssetRegistryFactory { /// @notice Deploy asset registry. /// @param salt The salt value to deploy asset registry. /// @param owner Initial owner address. /// @param vault Vault address. /// @param assets Initial list of registered assets. /// @param numeraireToken Numeraire token address. /// @param feeToken Fee token address. /// @param sequencer Sequencer Uptime Feed address for L2. /// @return deployed The address of deployed asset registry. function deployAssetRegistry( bytes32 salt, address owner, address vault, IAssetRegistry.AssetInformation[] memory assets, IERC20 numeraireToken, IERC20 feeToken, AggregatorV2V3Interface sequencer ) external returns (address deployed); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import {TargetSighashData} from "../Types.sol"; /// @title IAeraVaultHooksFactory /// @notice Interface for the hooks factory. interface IAeraVaultHooksFactory { /// @notice Deploy hooks. /// @param salt The salt value to deploy hooks. /// @param owner Initial owner address. /// @param vault Vault address. /// @param minDailyValue The minimum fraction of value that the vault has to retain /// during the day in the course of submissions. /// @param targetSighashAllowlist Array of target contract and sighash combinations to allow. /// @return deployed The address of deployed hooks. function deployHooks( bytes32 salt, address owner, address vault, uint256 minDailyValue, TargetSighashData[] memory targetSighashAllowlist ) external returns (address deployed); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.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); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * _Available since v4.7._ */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "@chainlink/interfaces/AggregatorV2V3Interface.sol"; import "@openzeppelin/IERC20.sol"; /// @title IAssetRegistry /// @notice Asset registry interface. /// @dev Any implementation MUST also implement Ownable2Step and ERC165. interface IAssetRegistry { /// @param asset Asset address. /// @param heartbeat Frequency of oracle price updates. /// @param isERC4626 True if yield-bearing asset, false if just an ERC20 asset. /// @param oracle If applicable, oracle address for asset. struct AssetInformation { IERC20 asset; uint256 heartbeat; bool isERC4626; AggregatorV2V3Interface oracle; } /// @param asset Asset address. /// @param spotPrice Spot price of an asset in Numeraire token terms. struct AssetPriceReading { IERC20 asset; uint256 spotPrice; } /// @notice Get address of vault. /// @return vault Address of vault. function vault() external view returns (address vault); /// @notice Get a list of all registered assets. /// @return assets List of assets. /// @dev MUST return assets in an order sorted by address. function assets() external view returns (AssetInformation[] memory assets); /// @notice Get address of fee token. /// @return feeToken Address of fee token. /// @dev Represented as an address for efficiency reasons. /// @dev MUST be present in assets array. function feeToken() external view returns (IERC20 feeToken); /// @notice Get the index of the Numeraire token in the assets array. /// @return numeraireToken Numeraire token address. /// @dev Represented as an index for efficiency reasons. /// @dev MUST be a number between 0 (inclusive) and the length of assets array (exclusive). function numeraireToken() external view returns (IERC20 numeraireToken); /// @notice Calculate spot prices of non-ERC4626 assets. /// @return spotPrices Spot prices of non-ERC4626 assets in 18 decimals. /// @dev MUST return assets in the same order as in assets but with ERC4626 assets filtered out. /// @dev MUST also include Numeraire token (spot price = 1). /// @dev MAY revert if oracle prices for any asset are unreliable at the time. function spotPrices() external view returns (AssetPriceReading[] memory spotPrices); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "@openzeppelin/IERC20.sol"; import "./IAssetRegistry.sol"; import "./IVaultEvents.sol"; import "./IHooks.sol"; /// @title IVault /// @notice Interface for the vault. /// @dev Any implementation MUST also implement Ownable2Step. interface IVault is IVaultEvents { /// ERRORS /// error Aera__AssetRegistryIsZeroAddress(); error Aera__AssetRegistryIsNotValid(address assetRegistry); error Aera__AssetRegistryHasInvalidVault(); error Aera__HooksIsZeroAddress(); error Aera__HooksIsNotValid(address hooks); error Aera__HooksHasInvalidVault(); error Aera__GuardianIsZeroAddress(); error Aera__GuardianIsOwner(); error Aera__InitialOwnerIsZeroAddress(); error Aera__FeeRecipientIsZeroAddress(); error Aera__ExecuteTargetIsHooksAddress(); error Aera__ExecuteTargetIsVaultAddress(); error Aera__SubmitTransfersAssetFromOwner(); error Aera__SubmitRedeemERC4626AssetFromOwner(); error Aera__SubmitTargetIsVaultAddress(); error Aera__SubmitTargetIsHooksAddress(uint256 index); error Aera__FeeRecipientIsOwner(); error Aera__FeeIsAboveMax(uint256 actual, uint256 max); error Aera__CallerIsNotOwnerAndGuardian(); error Aera__CallerIsNotGuardian(); error Aera__AssetIsNotRegistered(IERC20 asset); error Aera__AmountExceedsAvailable( IERC20 asset, uint256 amount, uint256 available ); error Aera__ExecutionFailed(bytes result); error Aera__VaultIsFinalized(); error Aera__SubmissionFailed(uint256 index, bytes result); error Aera__CannotUseReservedFees(); error Aera__SpotPricesReverted(); error Aera__AmountsOrderIsIncorrect(uint256 index); error Aera__NoAvailableFeesForCaller(address caller); error Aera__NoClaimableFeesForCaller(address caller); error Aera__NotWrappedNativeTokenContract(); error Aera__CannotRenounceOwnership(); /// FUNCTIONS /// /// @notice Deposit assets. /// @param amounts Assets and amounts to deposit. /// @dev MUST revert if not called by owner. function deposit(AssetValue[] memory amounts) external; /// @notice Withdraw assets. /// @param amounts Assets and amounts to withdraw. /// @dev MUST revert if not called by owner. function withdraw(AssetValue[] memory amounts) external; /// @notice Set current guardian and fee recipient. /// @param guardian New guardian address. /// @param feeRecipient New fee recipient address. /// @dev MUST revert if not called by owner. function setGuardianAndFeeRecipient( address guardian, address feeRecipient ) external; /// @notice Sets the current hooks module. /// @param hooks New hooks module address. /// @dev MUST revert if not called by owner. function setHooks(address hooks) external; /// @notice Execute a transaction via the vault. /// @dev Execution still should work when vault is finalized. /// @param operation Struct details for target and calldata to execute. /// @dev MUST revert if not called by owner. function execute(Operation memory operation) external; /// @notice Terminate the vault and return all funds to owner. /// @dev MUST revert if not called by owner. function finalize() external; /// @notice Stops the guardian from submission and halts fee accrual. /// @dev MUST revert if not called by owner or guardian. function pause() external; /// @notice Resume fee accrual and guardian submissions. /// @dev MUST revert if not called by owner. function resume() external; /// @notice Submit a series of transactions for execution via the vault. /// @param operations Sequence of operations to execute. /// @dev MUST revert if not called by guardian. function submit(Operation[] memory operations) external; /// @notice Claim fees on behalf of a current or previous fee recipient. function claim() external; /// @notice Get the current guardian. /// @return guardian Address of guardian. function guardian() external view returns (address guardian); /// @notice Get the current fee recipient. /// @return feeRecipient Address of fee recipient. function feeRecipient() external view returns (address feeRecipient); /// @notice Get the current asset registry. /// @return assetRegistry Address of asset registry. function assetRegistry() external view returns (IAssetRegistry assetRegistry); /// @notice Get the current hooks module address. /// @return hooks Address of hooks module. function hooks() external view returns (IHooks hooks); /// @notice Get fee per second. /// @return fee Fee per second in 18 decimal fixed point format. function fee() external view returns (uint256 fee); /// @notice Get current balances of all assets. /// @return assetAmounts Amounts of registered assets. function holdings() external view returns (AssetValue[] memory assetAmounts); /// @notice Get current total value of assets in vault. /// @return value Current total value. function value() external view returns (uint256 value); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; // Constants.sol // // This file defines the constants used across several contracts in V2. /// @dev Fixed point multiplier. uint256 constant ONE = 1e18;
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./IERC20Permit.sol"; import "./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 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.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to * 0 before setting it to a non-zero value. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(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, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(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.isContract(address(token)); } }
pragma solidity ^0.8.0; /** * @dev ERC20 but not IERC20 defines increaseAllowance */ interface IERC20IncreaseAllowance { /** * Atomically increases the allowance granted to spender by the caller. * This is an alternative to approve that can be used as a mitigation for * problems described in IERC20.approve. * Emits an Approval event indicating the updated allowance. * Requirements: * spender cannot be the zero address. */ function increaseAllowance(address spender, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import {AssetValue, Operation} from "../Types.sol"; /// @title IHooks /// @notice Interface for the hooks module. interface IHooks { /// @notice Get address of vault. /// @return vault Vault address. function vault() external view returns (address vault); /// @notice Hook that runs before deposit. /// @param amounts Struct details for assets and amounts to deposit. /// @dev MUST revert if not called by vault. function beforeDeposit(AssetValue[] memory amounts) external; /// @notice Hook that runs after deposit. /// @param amounts Struct details for assets and amounts to deposit. /// @dev MUST revert if not called by vault. function afterDeposit(AssetValue[] memory amounts) external; /// @notice Hook that runs before withdraw. /// @param amounts Struct details for assets and amounts to withdraw. /// @dev MUST revert if not called by vault. function beforeWithdraw(AssetValue[] memory amounts) external; /// @notice Hook that runs after withdraw. /// @param amounts Struct details for assets and amounts to withdraw. /// @dev MUST revert if not called by vault. function afterWithdraw(AssetValue[] memory amounts) external; /// @notice Hook that runs before submit. /// @param operations Array of struct details for target and calldata to submit. /// @dev MUST revert if not called by vault. function beforeSubmit(Operation[] memory operations) external; /// @notice Hook that runs after submit. /// @param operations Array of struct details for target and calldata to submit. /// @dev MUST revert if not called by vault. function afterSubmit(Operation[] memory operations) external; /// @notice Hook that runs before finalize. /// @dev MUST revert if not called by vault. function beforeFinalize() external; /// @notice Hook that runs after finalize. /// @dev MUST revert if not called by vault. function afterFinalize() external; /// @notice Take hooks out of use. function decommission() external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import {TargetSighash} from "../Types.sol"; /// @title Events emitted by AeraVaultHooks implementation. interface IAeraVaultHooksEvents { /// @notice Emitted when targetSighash is added to allowlist. /// @param target Address of target. /// @param selector Selector of function. event TargetSighashAdded(address indexed target, bytes4 indexed selector); /// @notice Emitted when targetSighash is removed from allowlist. /// @param target Address of target. /// @param selector Selector of function. event TargetSighashRemoved( address indexed target, bytes4 indexed selector ); /// @notice Emitted when hooks contract is decommissioned. event Decommissioned(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import {TargetSighash} from "./Types.sol"; /// @title TargetSighashLib /// @notice Conversion operations for the TargetSighash compound type. library TargetSighashLib { /// @notice Get sighash from target and selector. /// @param target Target contract address. /// @param selector Function selector. /// @return targetSighash Packed value of target and selector. function toTargetSighash( address target, bytes4 selector ) internal pure returns (TargetSighash targetSighash) { targetSighash = TargetSighash.wrap( bytes20(target) | (bytes32(selector) >> (20 * 8)) ); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; import "@openzeppelin/IERC20.sol"; import "./interfaces/IAssetRegistry.sol"; // Types.sol // // This file defines the types used in V2. /// @notice Combination of contract address and sighash to be used in allowlist. /// @dev It's packed as follows: /// [target 160 bits] [selector 32 bits] [<empty> 64 bits] type TargetSighash is bytes32; /// @notice Struct encapulating an asset and an associated value. /// @param asset Asset address. /// @param value The associated value for this asset (e.g., amount or price). struct AssetValue { IERC20 asset; uint256 value; } /// @notice Execution details for a vault operation. /// @param target Target contract address. /// @param value Native token amount. /// @param data Calldata. struct Operation { address target; uint256 value; bytes data; } /// @notice Contract address and sighash struct to be used in the public interface. struct TargetSighashData { address target; bytes4 selector; } /// @notice Parameters for vault deployment. /// @param owner Initial owner address. /// @param assetRegistry Asset registry address. /// @param hooks Hooks address. /// @param guardian Guardian address. /// @param feeRecipient Fee recipient address. /// @param fee Fees accrued per second, denoted in 18 decimal fixed point format. struct Parameters { address owner; address assetRegistry; address hooks; address guardian; address feeRecipient; uint256 fee; } /// @notice Vault parameters for vault deployment. /// @param owner Initial owner address. /// @param guardian Guardian address. /// @param feeRecipient Fee recipient address. /// @param fee Fees accrued per second, denoted in 18 decimal fixed point format. struct VaultParameters { address owner; address guardian; address feeRecipient; uint256 fee; } /// @notice Asset registry parameters for asset registry deployment. /// @param factory Asset registry factory address. /// @param owner Initial owner address. /// @param assets Initial list of registered assets. /// @param numeraireToken Numeraire token address. /// @param feeToken Fee token address. /// @param sequencer Sequencer Uptime Feed address for L2. struct AssetRegistryParameters { address factory; address owner; IAssetRegistry.AssetInformation[] assets; IERC20 numeraireToken; IERC20 feeToken; AggregatorV2V3Interface sequencer; } /// @notice Hooks parameters for hooks deployment. /// @param factory Hooks factory address. /// @param owner Initial owner address. /// @param minDailyValue The fraction of value that the vault has to retain per day /// in the course of submissions. /// @param targetSighashAllowlist Array of target contract and sighash combinations to allow. struct HooksParameters { address factory; address owner; uint256 minDailyValue; TargetSighashData[] targetSighashAllowlist; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol) pragma solidity ^0.8.0; import "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner"); _transferOwnership(sender); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; /// @title Interface for sweepable module. interface ISweepable { /// @notice Emitted when sweep is called. /// @param token Token address or zero address if recovering the chain's native token. /// @param amount Withdrawn amount of token. event Sweep(address token, uint256 amount); /// @notice Withdraw any tokens accidentally sent to contract. /// @param token Token address to withdraw or zero address for the chain's native token. /// @param amount Amount to withdraw. function sweep(address token, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./AggregatorInterface.sol"; import "./AggregatorV3Interface.sol"; interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {}
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @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 v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ 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: BUSL-1.1 pragma solidity 0.8.21; import "@openzeppelin/IERC20.sol"; import {AssetValue, Operation} from "../Types.sol"; /// @title Interface for vault events. interface IVaultEvents { /// @notice Emitted when deposit is called. /// @param owner Owner address. /// @param asset Deposited asset. /// @param amount Deposited asset amount. event Deposit(address indexed owner, IERC20 indexed asset, uint256 amount); /// @notice Emitted when withdraw is called. /// @param owner Owner address. /// @param asset Withdrawn asset. /// @param amount Withdrawn asset amount. event Withdraw( address indexed owner, IERC20 indexed asset, uint256 amount ); /// @notice Emitted when guardian is set. /// @param guardian Address of new guardian. /// @param feeRecipient Address of new fee recipient. event SetGuardianAndFeeRecipient( address indexed guardian, address indexed feeRecipient ); /// @notice Emitted when asset registry is set. /// @param assetRegistry Address of new asset registry. event SetAssetRegistry(address assetRegistry); /// @notice Emitted when hooks is set. /// @param hooks Address of new hooks. event SetHooks(address hooks); /// @notice Emitted when execute is called. /// @param owner Owner address. /// @param operation Struct details for target and calldata. event Executed(address indexed owner, Operation operation); /// @notice Emitted when vault is finalized. /// @param owner Owner address. /// @param withdrawnAmounts Struct details for withdrawn assets and amounts (sent to owner). event Finalized(address indexed owner, AssetValue[] withdrawnAmounts); /// @notice Emitted when submit is called. /// @param guardian Guardian address. /// @param operations Array of struct details for targets and calldatas. event Submitted(address indexed guardian, Operation[] operations); /// @notice Emitted when guardian fees are claimed. /// @param feeRecipient Fee recipient address. /// @param claimedFee Claimed amount of fee token. /// @param unclaimedFee Unclaimed amount of fee token (unclaimed because Vault does not have enough balance of feeToken). /// @param feeTotal New total reserved fee value. event Claimed( address indexed feeRecipient, uint256 claimedFee, uint256 unclaimedFee, uint256 feeTotal ); /// @notice Emitted when new fees are reserved for recipient. /// @param feeRecipient Fee recipient address. /// @param newFee Fee amount reserved. /// @param lastFeeCheckpoint Updated fee checkpoint. /// @param lastValue Last registered vault value. /// @param lastFeeTokenPrice Last registered fee token price. /// @param feeTotal New total reserved fee value. event FeesReserved( address indexed feeRecipient, uint256 newFee, uint256 lastFeeCheckpoint, uint256 lastValue, uint256 lastFeeTokenPrice, uint256 feeTotal ); /// @notice Emitted when no fees are reserved. /// @param lastFeeCheckpoint Updated fee checkpoint. /// @param lastValue Last registered vault value. /// @param feeTotal New total reserved fee value. event NoFeesReserved( uint256 lastFeeCheckpoint, uint256 lastValue, uint256 feeTotal ); /// @notice Emitted when the call to get spot prices from the asset registry reverts. /// @param reason Revert reason. event SpotPricesReverted(bytes reason); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ 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]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "./Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorInterface { function latestAnswer() external view returns (int256); function latestTimestamp() external view returns (uint256); function latestRound() external view returns (uint256); function getAnswer(uint256 roundId) external view returns (int256); function getTimestamp(uint256 roundId) external view returns (uint256); event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. 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 // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } }
{ "remappings": [ "src/=src/", "test/=test/", "@chainlink/=src/v2/dependencies/chainlink/", "@openzeppelin/=src/v2/dependencies/openzeppelin/", "@uniswap/v3-periphery/=lib/v3-periphery/", "@uniswap/v3-core/=lib/v3-core/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "v3-core/=lib/v3-core/", "v3-periphery/=lib/v3-periphery/contracts/" ], "optimizer": { "enabled": true, "runs": 1000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "shanghai", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"v2Factory_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Aera_CallerIsNeitherOwnerOrV2Factory","type":"error"},{"inputs":[],"name":"Aera__V2FactoryIsZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"assetRegistry","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"uint256","name":"heartbeat","type":"uint256"},{"internalType":"bool","name":"isERC4626","type":"bool"},{"internalType":"contract AggregatorV2V3Interface","name":"oracle","type":"address"}],"indexed":false,"internalType":"struct IAssetRegistry.AssetInformation[]","name":"assets","type":"tuple[]"},{"indexed":false,"internalType":"contract IERC20","name":"numeraireToken","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"feeToken","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"wrappedNativeToken","type":"address"},{"indexed":false,"internalType":"contract AggregatorV2V3Interface","name":"sequencer","type":"address"}],"name":"AssetRegistryCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hooks","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"minDailyValue","type":"uint256"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"indexed":false,"internalType":"struct TargetSighashData[]","name":"targetSighashAllowlist","type":"tuple[]"}],"name":"HooksCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Sweep","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"contract IERC20","name":"asset","type":"address"},{"internalType":"uint256","name":"heartbeat","type":"uint256"},{"internalType":"bool","name":"isERC4626","type":"bool"},{"internalType":"contract AggregatorV2V3Interface","name":"oracle","type":"address"}],"internalType":"struct IAssetRegistry.AssetInformation[]","name":"assets","type":"tuple[]"},{"internalType":"contract IERC20","name":"numeraireToken","type":"address"},{"internalType":"contract IERC20","name":"feeToken","type":"address"},{"internalType":"contract AggregatorV2V3Interface","name":"sequencer","type":"address"}],"name":"deployAssetRegistry","outputs":[{"internalType":"address","name":"deployed","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"minDailyValue","type":"uint256"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"internalType":"struct TargetSighashData[]","name":"targetSighashAllowlist","type":"tuple[]"}],"name":"deployHooks","outputs":[{"internalType":"address","name":"deployed","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"v2Factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wrappedNativeToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c080604052346101355761002b906200508480380380916100218285610139565b8339810190610170565b600180546001600160a01b03199081169091555f805433928116831782556040516001600160a01b0393909184167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08480a382841690811561012657506020600491604051928380926317fcb39b60e01b82525afa91821561011a57916100ec575b501660a052608052604051614ef490816200019082396080518181816102d2015281816103a101526109cc015260a0518181816107a401526109050152f35b61010d915060203d8111610113575b6101058183610139565b810190610170565b5f6100ad565b503d6100fb565b604051903d90823e3d90fd5b63a084b37360e01b8152600490fd5b5f80fd5b601f909101601f19168101906001600160401b0382119082101761015c57604052565b634e487b7160e01b5f52604160045260245ffd5b9081602091031261013557516001600160a01b0381168103610135579056fe60406080815260048036101562000014575f80fd5b5f91823560e01c91826308eb137f14620007c857826317fcb39b14620007825782636ea056a9146200054a578263715018a614620004d757826379ba509714620003ed5782638da5cb5b14620003c5578263b4b57c39146200037f578263d881dd34146200014657508163e30c39781462000118575063f2fde38b1462000099575f80fd5b34620001155760203660031901126200011557620000b662000aa8565b620000c062000c35565b6001600160a01b03809116908173ffffffffffffffffffffffffffffffffffffffff1960015416176001558254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b80fd5b90503462000142578160031936011262000142576020906001600160a01b03600154169051908152f35b5080fd5b838234620001425760a036600319011262000142576200016562000a76565b6200016f62000a91565b90606435906084359467ffffffffffffffff80871162000142573660238801121562000142578688013597602490620001a88a62000b0b565b98620001b789519a8b62000ad4565b8a8a5260209a838c8c019160061b830101913683116200037b578401905b828210620002fb575050506001600160a01b03948585541633141580620002ce575b620002bf5788519261184c908185019585871090871117620002ae57506080849388808f9b9a999897956200024c95620036738839169b8c885216809a870152888c8701528160608701523594018b62000b87565b039083f5908115620002a35750907f8426d840103d9ea98b6c3832fcd4c91f66569e96bc2a3f238a295587d0de821991169586926200029a87519283928352888b8401528883019062000b87565b0390a451908152f35b8651903d90823e3d90fd5b86604185634e487b7160e01b835252fd5b5087516371ed832960e01b8152fd5b50857f000000000000000000000000000000000000000000000000000000000000000016331415620001f7565b8a823603126200037b578a518b81018181108882111762000369578c52620003238362000abf565b81528d8301357fffffffff000000000000000000000000000000000000000000000000000000008116810362000365578e8201528152908a01908c01620001d5565b8880fd5b8689604188634e487b7160e01b835252fd5b8680fd5b8382346200014257816003193601126200014257602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b83823462000142578160031936011262000142576001600160a01b0360209254169051908152f35b915034620004d35782600319360112620004d357600154916001600160a01b039133838516036200046a57505073ffffffffffffffffffffffffffffffffffffffff19809216600155825491339083161783553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152fd5b8280fd5b83346200011557806003193601126200011557620004f462000c35565b806001600160a01b0373ffffffffffffffffffffffffffffffffffffffff19806001541660015582549081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b83903462000142578260031936011262000142576200056862000aa8565b602435916200057662000c35565b6001600160a01b03821680620005ea575050620005e483948480807fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779787335af150620005c262000bf2565b505b5192839283602090939291936001600160a01b0360408201951681520152565b0390a180f35b85517fa9059cbb0000000000000000000000000000000000000000000000000000000060208083019182523360248401526044808401889052835292906200063460648462000ad4565b88519289840184811067ffffffffffffffff8211176200076f578a528484527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648585015251620006999392918991829182855af16200069262000bf2565b9162000c8d565b805182811591821562000748575b5050905015620006e0575050620005e47fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779394620005c4565b6084925085519162461bcd60e51b8352820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b83809293500103126200076b5781015180151581036200076b57808289620006a7565b8580fd5b60248a604189634e487b7160e01b835252fd5b8382346200014257816003193601126200014257602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b838234620001425760e03660031901126200014257620007e762000a76565b90620007f262000a91565b67ffffffffffffffff926064358481116200076b57366023820112156200076b578087013595602492620008268862000b0b565b92620008358751948562000ad4565b888452602098858a86019160071b8301019136831162000a72578601905b828210620009f557505050608435916001600160a01b0390818416809403620001155760a43595828716809703620001425760c43593838516809503620004d3578383541633141580620009c8575b620009b95789519161290e90818401809d858210911117620009a85750918c9d85808e9f9c9d9e9594849562000d658639169c8d865216809b8501528c840160e090528960e08501620008f6908b62000b24565b948960608201526080015286867f0000000000000000000000000000000000000000000000000000000000000000169e8f60a082015260c001523592039083f59081156200099d5750916200098193917fec5b40d7c438225388cfe6540237a9a5c4962a253675a65aecc49b101a2eeb15959316998a968a5195869560a0875260a087019062000b24565b938d8601528a850152606084015260808301520390a451908152f35b8951903d90823e3d90fd5b634e487b7160e01b855260418f5284fd5b8c8a516371ed832960e01b8152fd5b50837f000000000000000000000000000000000000000000000000000000000000000016331415620008a2565b608080833603126200076b5789519081018181108c82111762000a5f578a5262000a1f8362000abf565b81528b8301358c8201528983013580151581036200037b578a8201526080918c91606062000a4f86820162000abf565b9082015281520191019062000853565b50878660418f634e487b7160e01b835252fd5b8480fd5b602435906001600160a01b038216820362000a8d57565b5f80fd5b604435906001600160a01b038216820362000a8d57565b600435906001600160a01b038216820362000a8d57565b35906001600160a01b038216820362000a8d57565b90601f8019910116810190811067ffffffffffffffff82111762000af757604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811162000af75760051b60200190565b9081518082526020808093019301915f5b82811062000b44575050505090565b835180516001600160a01b039081168752818401518785015260408083015115159088015260609182015116908601526080909401939281019260010162000b35565b9081518082526020808093019301915f5b82811062000ba7575050505090565b835180516001600160a01b031686528201517fffffffff0000000000000000000000000000000000000000000000000000000016858301526040909401939281019260010162000b98565b3d1562000c30573d9067ffffffffffffffff821162000af7576040519162000c25601f8201601f19166020018462000ad4565b82523d5f602084013e565b606090565b6001600160a01b035f5416330362000c4957565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9192901562000cf1575081511562000ca3575090565b3b1562000cad5790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b82519091501562000d055750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b82851062000d4a575050604492505f838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935062000d2756fe610120806040523462000ad5576200290e803803809162000021828562000aed565b8339810160e08282031262000ad5576200003b8262000b11565b906200004a6020840162000b11565b604084015190936001600160401b039182811162000ad557810183601f8201121562000ad5578051938385116200044857604051936200009160208760051b018662000aed565b85855260208501916020839760071b8501019381851162000ad557602001925b84841062000a62575050505050620000cc6060820162000b11565b90620000db6080820162000b11565b90620000f860c0620000f060a0840162000b11565b920162000b11565b91620001043362000c88565b6001600160a01b0387161562000a50576001600160a01b0388161562000a3e576001600160a01b038781169089161462000a2c5784516032811162000a13575f5b818110620009e3575b5f5b828110620009b3575b5f905b83821062000980575b838310156200095f5760406200017c848b62000b26565b5101516200094d576001600160a01b0360606200019a858c62000b26565b510151166200093b57838110156200091a57620001ba6040918a62000b26565b510151620008f95782811015620008d857620001d96040918962000b26565b510151620008b75760015b8281106200085457505f5b8281106200034457505050876080528360a0528060c0528160e05282610100526200021a8762000c88565b604051946080860190608087525180915260a0860196905f5b818110620002f7575050506001600160a01b039081166020860152908116604085015290811660608401529081169481169316917fdcd068b2c907d464ae5d70938ca193aea2775108a58d5abaa330686223e85acc919081900390a4604051611c3a908162000cd48239608051818181610111015261016b015260a05181818161034301528181610c290152611424015260c051818181610b6c0152610c52015260e051818181610c7b01526114680152610100518181816102cc0152610bb00152f35b9091976020608082620003386001948d516060908160018060a01b039182815116855260208101516020860152604081015115156040860152015116910152565b01990192910162000233565b81810362000500575b62000359818962000b26565b51906002548082145f146200045c575060025468010000000000000000811015620004485782620003958260016200039c940160025562000b64565b9062000c1b565b604082015162000418575b6001917f16d983bc025f9bf2de81704e1b56397e8bab39991b2e9db2b8714a60dcd022b76080848060a01b03835116926200041060405180926060908160018060a01b039182815116855260208101516020860152604081015115156040860152015116910152565ba201620001ef565b600354915f1983146200043457600192909201600355620003a7565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b805f198101116200043457620004755f19820162000b64565b50680100000000000000008210156200044857620004a690600183016002556200049f8362000b64565b9062000b81565b5f19015b818111620004c95750620004c382620003958362000b64565b6200039c565b5f1981018181116200043457620004e4620004f09162000b64565b506200049f8362000b64565b801562000434575f1901620004aa565b6200050c818962000b26565b51604081015115620006a35760608101516001600160a01b03166200068057505b60406200053b828a62000b26565b510151156200034d5762000550818962000b26565b51885181516040516338d52e0f60e01b8152919290602090839060049082906001600160a01b03165afa91821562000675575f926200062e575b505f925b808410620005f5575b831015620005ca575050620005af6040918a62000b26565b510151156200034d57604051636f9158ef60e11b8152600490fd5b516040516302b8ed3f60e01b81526001600160a01b0391821660048201529116602482015260449150fd5b926001600160a01b036200060a828e62000b26565b5151166001600160a01b038416146200062757600101926200058e565b9262000597565b90916020823d6020116200066c575b816200064c6020938362000aed565b81010312620006695750620006619062000b11565b905f6200058a565b80fd5b3d91506200063d565b6040513d5f823e3d90fd5b51604051636e0ec65b60e01b81526001600160a01b039091166004820152602490fd5b60608101516001600160a01b03161562000831576060810151604051633fabe5a360e21b81529060a090829060049082906001600160a01b03165afa90811562000675575f908192620007d4575b505f8113156200078957506020820151801515908162000767575b506200071a5750506200052d565b6040805163bc29ff2b60e01b815283516001600160a01b03908116600483015260208501516024830152918401511515604482015260609093015116606483015260a492505b6084820152fd5b905081018082116200043457610e108101809111620004345742115f6200070c565b604080516325c4b0b560e01b815284516001600160a01b0390811660048301526020860151602483015291850151151560448201526060850151909116606482015260a49162000760565b915060a0823d60a01162000828575b81620007f260a0938362000aed565b81010312620006695750620008078162000b4f565b5060208101516200082060806060840151930162000b4f565b505f620006f1565b3d9150620007e3565b5160405163fe8c11c560e01b81526001600160a01b039091166004820152602490fd5b5f19810181811162000434576001600160a01b039062000875908a62000b26565b5151166001600160a01b036200088c838b62000b26565b51511611156200089f57600101620001e4565b60249060405190631e0076f960e11b82526004820152fd5b6040516337350baf60e11b81526001600160a01b0385166004820152602490fd5b6040516347b6c6d560e01b81526001600160a01b0386166004820152602490fd5b604051630d363d0d60e21b81526001600160a01b0385166004820152602490fd5b60405163f314cd4960e01b81526001600160a01b0386166004820152602490fd5b60405163365dfa4360e11b8152600490fd5b604051631e93c13160e01b8152600490fd5b6040516378fc011760e11b81526001600160a01b0389166004820152602490fd5b906001600160a01b038681169062000999838c62000b26565b51511614620009ac57600101906200015c565b9062000165565b6001600160a01b0384811690620009cb838b62000b26565b51511614620009dd5760010162000150565b62000159565b6001600160a01b0386811690620009fb838a62000b26565b5151161462000a0d5760010162000145565b6200014e565b604051635183e72160e11b815260326004820152602490fd5b60405163687615e560e01b8152600490fd5b6040516318a4224160e11b8152600490fd5b604051630adb389560e01b8152600490fd5b608090818584031262000ad5576040519182018281108582111762000ad95760405262000a8f8562000b11565b825260208501516020830152604085015190811515820362000ad5578260209260406080950152606062000ac581890162000b11565b90820152815201930192620000b1565b5f80fd5b60245f634e487b7160e01b81526041600452fd5b601f909101601f19168101906001600160401b038211908210176200044857604052565b51906001600160a01b038216820362000ad557565b805182101562000b3b5760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b51906001600160501b038216820362000ad557565b60025481101562000b3b5760025f52600360205f20910201905f90565b919062000c085780820362000b94575050565b62000c069160028060018060a01b03928385541660018060a01b03198254161781556001850154600182015501920162000bde60ff825416849060ff801983541691151516179055565b548254610100600160a81b031916600891821c92909216901b610100600160a81b0316179055565b565b634e487b7160e01b5f525f60045260245ffd5b919062000c0857805182546001600160a01b0319166001600160a01b0390911617825560208101516001830155604081015160029092018054606090920151610100600160a81b0360089190911b166001600160a81b031990921660ff9315159390931692909217179055565b60018060a01b03199081600154166001555f5460018060a01b0380921680938216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a356fe6080604081815260049182361015610015575f80fd5b5f92833560e01c91826301ffc9a71461148c5750816317fcb39b146114485781631fb6c52d14611404578163210663d014610f955781634a5e42b114610bf35781634c478a5614610bd45781635c1bba3814610b90578163647846a514610b4c5781636ea056a91461094e578163715018a6146108ec57816371a973051461085a57816376b1d08f1461083e57816379ba5097146107675781638da5cb5b14610741578163e30c397814610719578163ed2f8603146106fc578163edf94acd146102ac578163f2fde38b14610139575063fbfa77cf146100f3575f80fd5b34610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b5080fd5b919050346102a85760203660031901126102a85761015561152a565b9161015e611adc565b6001600160a01b039182807f00000000000000000000000000000000000000000000000000000000000000001694169380851461028157602083918351928380927f452a93200000000000000000000000000000000000000000000000000000000082525afa908115610277579084918791610249575b501684146102235750506101e7611adc565b816001600160a01b031960015416176001558254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b517f54ae5328000000000000000000000000000000000000000000000000000000008152fd5b61026a915060203d8111610270575b6102628183611590565b810190611740565b5f6101d5565b503d610258565b82513d88823e3d90fd5b50517f687615e5000000000000000000000000000000000000000000000000000000008152fd5b8280fd5b839150346101355781600319360112610135576001600160a01b039281847f0000000000000000000000000000000000000000000000000000000000000000168061061b575b505060028054926003548403938085116106085761032b6103168697959497611670565b9561032385519788611590565b808752611670565b60209690601f1901855b8181106105e05750859390507f00000000000000000000000000000000000000000000000000000000000000008916845b8486106103ba5750505050505080519380850191818652845180935281818701950193905b8382106103985786860387f35b845180518916875283015186840152948501949382019360019091019061038b565b8a846103c9889c999a9c611623565b50015460ff9081166105d45783826103e08a611623565b5054160361043b57506103f287611623565b50541688519061040182611544565b8152670de0b6b3a76400008882015261041a828b611889565b52610425818a611889565b505b60018091019501935b939498969598610366565b848961045761045261044c8c611623565b50611688565b61189d565b93886104628c611623565b50015460081c168c51928380927f313ce5670000000000000000000000000000000000000000000000000000000082525afa9081156105ca578d91610590575b506012911681811015610534578103908111610521576104c19061187b565b9081810291818304149015171561050e575b8b6104dd88611623565b505416908951916104ed83611544565b8252888201526104fd828b611889565b52610508818a611889565b50610427565b60248b601186634e487b7160e01b835252fd5b60248c601187634e487b7160e01b835252fd5b818193929311610547575b5090506104d3565b601119810190811161057d5761055c9061187b565b91821561056c575004808d61053f565b634e487b7160e01b8d52855260248cfd5b60248d601188634e487b7160e01b835252fd5b90508981813d83116105c3575b6105a78183611590565b810103126105bf575181811681036105bf578e6104a2565b8c80fd5b503d61059d565b8b513d8f823e3d90fd5b50509460010193610430565b978596988196516105f081611544565b8a81528a8382015282828b0101520197959497610335565b602486601184634e487b7160e01b835252fd5b60a090835192838092633fabe5a360e21b82525afa9081156106f257849085926106be575b5061069757610e10810180911161068457421061065e5781856102f2565b517fa4a7b2a4000000000000000000000000000000000000000000000000000000008152fd5b602484601185634e487b7160e01b835252fd5b50517f73460943000000000000000000000000000000000000000000000000000000008152fd5b90506106e1915060a03d81116106eb575b6106d98183611590565b810190611846565b5050915086610640565b503d6106cf565b82513d86823e3d90fd5b50503461013557816003193601126101355760209051610e108152f35b5050346101355781600319360112610135576020906001600160a01b03600154169051908152f35b5050346101355781600319360112610135576001600160a01b0360209254169051908152f35b919050346102a857826003193601126102a857600154916001600160a01b039133838516036107d55750506001600160a01b0319809216600155825491339083161783553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152fd5b5050346101355781600319360112610135576020905160328152f35b8284346108e957806003193601126108e957906108756116ca565b81519160208080850192818652845180945285019301945b82811061089a5784840385f35b909192826080826108da6001948a51606090816001600160a01b039182815116855260208101516020860152604081015115156040860152015116910152565b0196019101949291909461088d565b80fd5b83346108e957806003193601126108e957610905611adc565b806001600160a01b036001600160a01b0319806001541660015582549081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b8391503461013557826003193601126101355761096961152a565b60243591610975611adc565b6001600160a01b038216806109e55750506109df83948480807fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779787335af1506109bd611a9d565b505b5192839283602090939291936001600160a01b0360408201951681520152565b0390a180f35b85517fa9059cbb0000000000000000000000000000000000000000000000000000000060208083019182523360248401526044808401889052835292610a7d929188908190610a35606486611590565b8b5194610a4186611544565b8786527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656488870152519082855af1610a77611a9d565b91611b33565b8051828115918215610b28575b5050905015610ac05750506109df7fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c7793946109bf565b6084925085519162461bcd60e51b8352820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b8380929350010312610b48578101518015158103610b4857808289610a8a565b8580fd5b505034610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b505034610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b5050346101355781600319360112610135576020906003549051908152f35b919050346102a85760209182600319360112610f9157610c1161152a565b91610c1a611adc565b6001600160a01b0380931692807f0000000000000000000000000000000000000000000000000000000000000000168414610f6257807f0000000000000000000000000000000000000000000000000000000000000000168414610f3357807f0000000000000000000000000000000000000000000000000000000000000000168414610f0457600291825491875b83811080610eee575b15610cbf57600101610ca9565b9394959683851015610ebf5790859291610cd886611623565b5060ff9485910154165f14610ddb5750505050610cf660035461175f565b6003555b5f1991818301918211610dc8575b818110610d8757505081548015610d74570191610d2483611623565b919091610d6257508181868093558260018201550155557f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc8280a280f35b8580602492634e487b7160e01b825252fd5b602486603186634e487b7160e01b835252fd5b6001810190818111610db557610db090610daa610da384611623565b5091611623565b9061177f565b610d08565b602488601188634e487b7160e01b835252fd5b602487601187634e487b7160e01b835252fd5b895b858110610dee575050505050610cfa565b8681141580610eaa575b80610e46575b610e0a57600101610ddd565b888484610e18602494611623565b5054169051917f21d8a3aa000000000000000000000000000000000000000000000000000000008352820152fd5b50888284610e5384611623565b5054168651928380926338d52e0f60e01b82525afa908c8215610e9f578c92869290610e82575b501614610dfe565b610e999150853d8711610270576102628183611590565b5f610e7a565b8651903d90823e3d90fd5b508488610eb683611623565b50015416610df8565b602487898551917f5c753429000000000000000000000000000000000000000000000000000000008352820152fd5b508682610efa83611623565b5054161415610cb2565b509160249251917f999c5225000000000000000000000000000000000000000000000000000000008352820152fd5b509160249251917fb56dc787000000000000000000000000000000000000000000000000000000008352820152fd5b509160249251917fb83266ba000000000000000000000000000000000000000000000000000000008352820152fd5b8380fd5b9050346102a85760803660031901126102a857610fb0611adc565b6002549060328210156113d457610fc6366115b2565b808401511561137d576001600160a01b03908160608201511661134b5750505b835b8281106112ca575b6044358015158103610b48576111ac575b61100a366115b2565b928181036110f7575050600254680100000000000000008110156110e4578261103c8260016110429401600255611623565b90611a0e565b828201516110b7575b506080816110b36001600160a01b037f16d983bc025f9bf2de81704e1b56397e8bab39991b2e9db2b8714a60dcd022b794511694518092606090816001600160a01b039182815116855260208101516020860152604081015115156040860152015116910152565ba280f35b600354905f1982146110d15750600101600355608061104b565b846011602492634e487b7160e01b835252fd5b602485604184634e487b7160e01b835252fd5b5f1990808201908082116111865761110e82611623565b5090680100000000000000008110156111995786939291610daa8260016111389401600255611623565b83811161115257505061103c61114d92611623565b611042565b908092508101818111611186579061117961116f61117e93611623565b50610daa83611623565b61175f565b908491611138565b602488601187634e487b7160e01b835252fd5b602489604188634e487b7160e01b835252fd5b6111b5366115b2565b6111bd6116ca565b805191846001600160a01b03916020838251168a51938480926338d52e0f60e01b82525afa9182156112c0578a926112a0575b5089945b80861061127a575b85101561124157505050859161121191611889565b51015115611001575082517fdf22b1de000000000000000000000000000000000000000000000000000000008152fd5b5188517f02b8ed3f0000000000000000000000000000000000000000000000000000000081529083168188015291166024820152604490fd5b94836112868287611889565b5151168484161461129a57600101946111f4565b946111fc565b6112b991925060203d8111610270576102628183611590565b905f6111f0565b89513d8c823e3d90fd5b6112d261160d565b6112db82611623565b50906001600160a01b038080935416911610611345576112f961160d565b908061130484611623565b50541691161461131657600101610fe8565b602492508351917f3859e924000000000000000000000000000000000000000000000000000000008352820152fd5b50610ff0565b5193517f6e0ec65b00000000000000000000000000000000000000000000000000000000815293169083015250602490fd5b6001600160a01b0380606083015116156113a1575061139b9061189d565b50610fe6565b60249350849151169051917ffe8c11c5000000000000000000000000000000000000000000000000000000008352820152fd5b60249060328451917fa307ce42000000000000000000000000000000000000000000000000000000008352820152fd5b505034610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b505034610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b8491346102a85760203660031901126102a857357fffffffff0000000000000000000000000000000000000000000000000000000081168091036102a857602092507f1c64cd8f000000000000000000000000000000000000000000000000000000008114908115611500575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836114f9565b600435906001600160a01b038216820361154057565b5f80fd5b6040810190811067ffffffffffffffff82111761156057604052565b634e487b7160e01b5f52604160045260245ffd5b6080810190811067ffffffffffffffff82111761156057604052565b90601f8019910116810190811067ffffffffffffffff82111761156057604052565b608090600319011261154057604051906115cb82611574565b6001600160a01b038260043582811681036115405781526024356020820152604435801515810361154057604082015260643591821682036115405760600152565b6004356001600160a01b03811681036115405790565b60025481101561165c5760039060025f52027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace01905f90565b634e487b7160e01b5f52603260045260245ffd5b67ffffffffffffffff81116115605760051b60200190565b9060405161169581611574565b6060819360026001600160a01b039182815416855260018101546020860152015460ff81161515604085015260081c16910152565b600254906116d782611670565b916116e56040519384611590565b80835260025f90815260207f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace8186015b848410611723575050505050565b60038360019261173285611688565b815201920193019290611715565b9081602091031261154057516001600160a01b03811681036115405790565b801561176b575f190190565b634e487b7160e01b5f52601160045260245ffd5b919061181c57808203611790575050565b61181a916002806001600160a01b0392838554166001600160a01b0319825416178155600185015460018201550192016117da60ff825416849060ff801983541691151516179055565b5460081c1674ffffffffffffffffffffffffffffffffffffffff001974ffffffffffffffffffffffffffffffffffffffff0083549260081b169116179055565b565b634e487b7160e01b5f525f60045260245ffd5b519069ffffffffffffffffffff8216820361154057565b908160a09103126115405761185a8161182f565b9160208201519160408101519161187860806060840151930161182f565b90565b604d811161176b57600a0a90565b805182101561165c5760209160051b010190565b60049060a06001600160a01b0360608301511660405193848092633fabe5a360e21b82525afa8015611a03575f9283916119dc575b505f831315611979576020820151801515908161195a575b506118f457505090565b604080517fbc29ff2b00000000000000000000000000000000000000000000000000000000815283516001600160a01b03908116600483015260208501516024830152918401511515604482015260609093015116606483015260a492505b6084820152fd5b9050810180821161176b57610e10810180911161176b5742115f6118ea565b50604080517f25c4b0b500000000000000000000000000000000000000000000000000000000815282516001600160a01b03908116600483015260208401516024830152918301511515604482015260609092015116606482015260a491611953565b90506119f791925060a03d81116106eb576106d98183611590565b5093925050915f6118d2565b6040513d5f823e3d90fd5b919061181c5761181a91606060026001600160a01b0392838551166001600160a01b0319825416178155602085015160018201550192611a6060408201511515859060ff801983541691151516179055565b0151825474ffffffffffffffffffffffffffffffffffffffff001916911660081b74ffffffffffffffffffffffffffffffffffffffff0016179055565b3d15611ad7573d9067ffffffffffffffff82116115605760405191611acc601f8201601f191660200184611590565b82523d5f602084013e565b606090565b6001600160a01b035f54163303611aef57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b91929015611b945750815115611b47575090565b3b15611b505790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015611ba75750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b828510611beb575050604492505f838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350611bc956fea2646970667358221220dcc00f8f3db01542a4c841c7d12c5b86e9fd0ea17ed2c8fbc951a314b8ffe05464736f6c6343000815003360a06040818152346200038f576200184c8038038091620000218286620003bb565b84398201916080818403126200038f576200003c81620003df565b906020906200004d828201620003df565b84820151916060968782015160018060401b03928382116200038f570181601f820112156200038f578051838111620003a757600593895193620000968984881b0186620003bb565b828552888086019360061b850101938185116200038f578901925b84841062000339575050505050620000c9336200041d565b6001600160a01b038381169390929084156200032857838816908115620003175785821462000306573b62000273575b50670de0b6b3a7640000958686101562000262576706f05b59d3b20000861062000251578251935f5b8581106200017957600280546001600160a01b03191688179055608088905262015180420460035560048990558a6200015b8b6200041d565b516113e3908162000469823960805181818161040001526106ef0152f35b620001858186620003f4565b51519082821684620001988389620003f4565b51015192813b1562000239578e1b6001600160601b03191660a084901c6bffffffff000000000000000016175f8181528787528e90205460ff1662000222575f528585528c5f20926001938460ff1982541617905563ffffffff60e01b16907fa10f2fe4b8a71df10b600a159be010c92558175741cec420c971a463470f04ef5f80a30162000122565b6024908e519063027cfe1560e51b82526004820152fd5b8d516369b9f78360e11b815260048101839052602490fd5b8851637c56eb2960e11b8152600490fd5b8851631e76c69d60e11b8152600490fd5b8851630229549960e51b81528781600481895afa908115620002fc579085915f91620002ba575b501614620002a9575f620000f9565b8751630a45718160e11b8152600490fd5b91508882813d8311620002f4575b620002d48183620003bb565b81010312620002f15750620002ea8591620003df565b5f6200029a565b80fd5b503d620002c8565b8a513d5f823e3d90fd5b8951635078aee360e11b8152600490fd5b895163570c35b560e11b8152600490fd5b88516318a4224160e11b8152600490fd5b8b848303126200038f578b51908c82018281108582111762000393578d526200036285620003df565b8252848b0151906001600160e01b0319821682036200038f57828c928f94840152815201930192620000b1565b5f80fd5b60245f634e487b7160e01b81526041600452fd5b634e487b7160e01b5f52604160045260245ffd5b601f909101601f19168101906001600160401b03821190821017620003a757604052565b51906001600160a01b03821682036200038f57565b8051821015620004095760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b60018060a01b03199081600154166001555f5460018060a01b0380921680938216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a356fe6080604081815260049182361015610015575f80fd5b5f92833560e01c91826301871a8314610fb55750816301ffc9a714610f2c578163162146fb146104425781632f40e5b8146104425781633280648e14610d4c57816334d184ae146104425781635c9302c914610d2d57816361e8781114610c07578163683acef014610bc95781636ea056a9146109cf578163715018a61461096057816379ba50971461087c5781637f068c0f146107fd5781638da5cb5b146107d7578163a0e38c811461045a578163b998927514610442578163bfd31dc414610423578163d20fb647146103e8578163e30c3978146103c0578163e87b3abe146102dc578163e8ae44aa146102be578163f2fde38b14610149575063fbfa77cf1461011f575f80fd5b346101455781600319360112610145576020906001600160a01b03600254169051908152f35b5080fd5b919050346102ba5760203660031901126102ba5761016561101a565b9161016e611285565b6001600160a01b039182806002541694169380851461029357602083918351928380927f452a93200000000000000000000000000000000000000000000000000000000082525afa908115610289579084918791610248575b501684146102225750506101d9611285565b8173ffffffffffffffffffffffffffffffffffffffff1960015416176001558254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b517f148ae302000000000000000000000000000000000000000000000000000000008152fd5b9150506020813d8211610281575b816102636020938361107b565b8101031261027d5751838116810361027d5783905f6101c7565b8580fd5b3d9150610256565b82513d88823e3d90fd5b50517fa0f15dc6000000000000000000000000000000000000000000000000000000008152fd5b8280fd5b9050346102ba57826003193601126102ba5760209250549051908152f35b9050346102ba57816003193601126102ba576102f661101a565b916102ff611034565b91610308611285565b606084901b6bffffffffffffffffffffffff191660a084901c6bffffffff0000000000000000161790818652600560205260ff8387205416156103925750845260056020528320805460ff191690556001600160e01b031916906001600160a01b03167f566a9a4fba10e4534371d2ea973f09830a90304a10e2a8fce319764158f9e55c8380a380f35b9060249251917ff0d5987a000000000000000000000000000000000000000000000000000000008352820152fd5b5050346101455781600319360112610145576020906001600160a01b03600154169051908152f35b505034610145578160031936011261014557602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b833461043f578060031936011261043f5761043c6111a4565b80f35b80fd5b833461043f576104513661109d565b5061043c6111a4565b9050346102ba5761046a36611157565b926001600160a01b038060025416908133036107c857845462015180420490600654801580156106a7575b505050806003540361069e575b5086600655865b8681106104b4578780f35b6104cb6104c28289886111c9565b858101906111ff565b8711610670576001600160e01b03199035167f095ea7b3000000000000000000000000000000000000000000000000000000008114908115610674575b50610519575b600101955b956104a9565b6105276104c28289886111c9565b80881161066c57810181900360031901851361067057868101359083821680920361066c5760240135156106625782610569610564848b8a6111c9565b611232565b16908486517fdd62ed3e0000000000000000000000000000000000000000000000000000000081528981806105be86602096879584019060209093929360408301946001600160a01b03809216845216910152565b0381875afa918215610658578c92610626575b50506105de57505061050e565b85517f715879af0000000000000000000000000000000000000000000000000000000081526001600160a01b0392831689820190815291909216602082015281900360400190fd5b90809250813d8311610651575b61063d818361107b565b8101031261064d57515f806105d1565b8a80fd5b503d610633565b88513d8e823e3d90fd5b5060010195610513565b8980fd5b8880fd5b7f39509351000000000000000000000000000000000000000000000000000000009150145f610508565b6003555f6104a2565b60035484036107b95782905b875191633fa4f24560e01b83526020838c818b5afa9283156107af578d93610778575b50828102928184041490151715610765576107525704907f0000000000000000000000000000000000000000000000000000000000000000821061072a578103610722575b8080610495565b86555f61071b565b8786517f47968522000000000000000000000000000000000000000000000000000000008152fd5b60248b60128b634e487b7160e01b835252fd5b60248c60118c634e487b7160e01b835252fd5b9092506020813d82116107a7575b816107936020938361107b565b810103126107a35751915f6106d6565b8c80fd5b3d9150610786565b89513d8f823e3d90fd5b670de0b6b3a7640000906106b3565b84835163152df05f60e11b8152fd5b5050346101455781600319360112610145576001600160a01b0360209254169051908152f35b838334610145578160031936011261014557600254906001600160a01b038216330361086d57509173ffffffffffffffffffffffffffffffffffffffff1982931660025581600355557f4bd04f3440c9bf56a25f7b9e1ac75a9803bd83123a127cf9748129c938630b398180a180f35b83905163152df05f60e11b8152fd5b919050346102ba57826003193601126102ba57600154916001600160a01b039133838516036108f757505073ffffffffffffffffffffffffffffffffffffffff19809216600155825491339083161783553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152fd5b833461043f578060031936011261043f57610979611285565b806001600160a01b0373ffffffffffffffffffffffffffffffffffffffff19806001541660015582549081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b839150346101455782600319360112610145576109ea61101a565b602435916109f6611285565b6001600160a01b03821680610a66575050610a6083948480807fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779787335af150610a3e611246565b505b5192839283602090939291936001600160a01b0360408201951681520152565b0390a180f35b85517fa9059cbb0000000000000000000000000000000000000000000000000000000060208083019182523360248401526044808401889052835292610afe929188908190610ab660648661107b565b8b5194610ac28661104b565b8786527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656488870152519082855af1610af8611246565b916112dc565b8051828115918215610ba9575b5050905015610b41575050610a607fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779394610a40565b6084925085519162461bcd60e51b8352820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b838092935001031261027d57810151801515810361027d57808289610b0b565b8383346101455781600319360112610145576001600160a01b03600254163303610bf857508091816003555580f35b90505163152df05f60e11b8152fd5b9050346102ba57816003193601126102ba57610c2161101a565b91610c2a611034565b91610c33611285565b833b15610cf457606084901b6bffffffffffffffffffffffff191660a084901c6bffffffff0000000000000000161790818652600560205260ff8387205416610cc65750845260056020528320805460ff191660011790556001600160e01b031916906001600160a01b03167fa10f2fe4b8a71df10b600a159be010c92558175741cec420c971a463470f04ef8380a380f35b9060249251917f4f9fc2a0000000000000000000000000000000000000000000000000000000008352820152fd5b83906001600160a01b0360249351927fd373ef060000000000000000000000000000000000000000000000000000000084521690820152fd5b5050346101455781600319360112610145576020906003549051908152f35b9050346102ba57610d5c36611157565b6001600160a01b0391826002541692833303610f1d57865b838110610de45750505050602090835192838092633fa4f24560e01b82525afa918215610ddb57508291610daa575b5060065580f35b90506020813d8211610dd3575b81610dc46020938361107b565b8101031261014557515f610da3565b3d9150610db7565b513d84823e3d90fd5b610dfb610df28286866111c9565b888101906111ff565b8711610670576001600160e01b0319610e48913516610e1e6105648488886111c9565b60601b6bffffffffffffffffffffffff191660a09190911c6bffffffff0000000000000000161790565b885260206005815260ff888a20541615610e655750600101610d74565b869288610e748b9488886111c9565b91838251967fc1c440aa0000000000000000000000000000000000000000000000000000000088528701528235908116809103610f19576024860152828201356044860152810135601e1982360301811215610f15570190813591019167ffffffffffffffff821161043f57813603831361043f57908391606060648401528160848401528160a49485850137828201840152601f01601f19168101030190fd5b8380fd5b8480fd5b84865163152df05f60e11b8152fd5b9050346102ba5760203660031901126102ba5735906001600160e01b031982168092036102ba57602092507f755e7563000000000000000000000000000000000000000000000000000000008214918215610f8b575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491505f610f82565b849084346102ba57806003193601126102ba5760ff9060209361100b610fd961101a565b610fe1611034565b6bffffffff00000000000000009060a01c16906bffffffffffffffffffffffff199060601b161790565b81526005855220541615158152f35b600435906001600160a01b038216820361103057565b5f80fd5b602435906001600160e01b03198216820361103057565b6040810190811067ffffffffffffffff82111761106757604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761106757604052565b6020806003198301126110305760043567ffffffffffffffff918282116110305783602383011215611030578160040135928311611067576040928351946110ea838360051b018761107b565b81865260248387019260061b8501019381851161103057602401915b8483106111165750505050505090565b85838303126110305785519061112b8261104b565b8335906001600160a01b0382168203611030578286928994528286013583820152815201920191611106565b9060206003198301126110305760043567ffffffffffffffff9283821161103057806023830112156110305781600401359384116110305760248460051b83010111611030576024019190565b6001600160a01b036002541633036111b857565b600460405163152df05f60e11b8152fd5b91908110156111eb5760051b81013590605e1981360301821215611030570190565b634e487b7160e01b5f52603260045260245ffd5b903590601e1981360301821215611030570180359067ffffffffffffffff82116110305760200191813603831361103057565b356001600160a01b03811681036110305790565b3d15611280573d9067ffffffffffffffff82116110675760405191611275601f8201601f19166020018461107b565b82523d5f602084013e565b606090565b6001600160a01b035f5416330361129857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9192901561133d57508151156112f0575090565b3b156112f95790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156113505750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b828510611394575050604492505f838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935061137256fea2646970667358221220a6f9c05c46cf1c4c4f1c91f80cd95902f2287cbb8736b0d2e8c1cd8d6980520f64736f6c63430008150033a2646970667358221220379d2c42f74c00aabbbe5385697bf552124f2da702b72b46753d9a3f7ce6eaf864736f6c6343000815003300000000000000000000000038896b4ac8420b8a2b768001da44d11109f1797d
Deployed Bytecode
0x60406080815260048036101562000014575f80fd5b5f91823560e01c91826308eb137f14620007c857826317fcb39b14620007825782636ea056a9146200054a578263715018a614620004d757826379ba509714620003ed5782638da5cb5b14620003c5578263b4b57c39146200037f578263d881dd34146200014657508163e30c39781462000118575063f2fde38b1462000099575f80fd5b34620001155760203660031901126200011557620000b662000aa8565b620000c062000c35565b6001600160a01b03809116908173ffffffffffffffffffffffffffffffffffffffff1960015416176001558254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b80fd5b90503462000142578160031936011262000142576020906001600160a01b03600154169051908152f35b5080fd5b838234620001425760a036600319011262000142576200016562000a76565b6200016f62000a91565b90606435906084359467ffffffffffffffff80871162000142573660238801121562000142578688013597602490620001a88a62000b0b565b98620001b789519a8b62000ad4565b8a8a5260209a838c8c019160061b830101913683116200037b578401905b828210620002fb575050506001600160a01b03948585541633141580620002ce575b620002bf5788519261184c908185019585871090871117620002ae57506080849388808f9b9a999897956200024c95620036738839169b8c885216809a870152888c8701528160608701523594018b62000b87565b039083f5908115620002a35750907f8426d840103d9ea98b6c3832fcd4c91f66569e96bc2a3f238a295587d0de821991169586926200029a87519283928352888b8401528883019062000b87565b0390a451908152f35b8651903d90823e3d90fd5b86604185634e487b7160e01b835252fd5b5087516371ed832960e01b8152fd5b50857f00000000000000000000000038896b4ac8420b8a2b768001da44d11109f1797d16331415620001f7565b8a823603126200037b578a518b81018181108882111762000369578c52620003238362000abf565b81528d8301357fffffffff000000000000000000000000000000000000000000000000000000008116810362000365578e8201528152908a01908c01620001d5565b8880fd5b8689604188634e487b7160e01b835252fd5b8680fd5b8382346200014257816003193601126200014257602090516001600160a01b037f00000000000000000000000038896b4ac8420b8a2b768001da44d11109f1797d168152f35b83823462000142578160031936011262000142576001600160a01b0360209254169051908152f35b915034620004d35782600319360112620004d357600154916001600160a01b039133838516036200046a57505073ffffffffffffffffffffffffffffffffffffffff19809216600155825491339083161783553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152fd5b8280fd5b83346200011557806003193601126200011557620004f462000c35565b806001600160a01b0373ffffffffffffffffffffffffffffffffffffffff19806001541660015582549081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b83903462000142578260031936011262000142576200056862000aa8565b602435916200057662000c35565b6001600160a01b03821680620005ea575050620005e483948480807fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779787335af150620005c262000bf2565b505b5192839283602090939291936001600160a01b0360408201951681520152565b0390a180f35b85517fa9059cbb0000000000000000000000000000000000000000000000000000000060208083019182523360248401526044808401889052835292906200063460648462000ad4565b88519289840184811067ffffffffffffffff8211176200076f578a528484527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648585015251620006999392918991829182855af16200069262000bf2565b9162000c8d565b805182811591821562000748575b5050905015620006e0575050620005e47fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779394620005c4565b6084925085519162461bcd60e51b8352820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b83809293500103126200076b5781015180151581036200076b57808289620006a7565b8580fd5b60248a604189634e487b7160e01b835252fd5b8382346200014257816003193601126200014257602090516001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168152f35b838234620001425760e03660031901126200014257620007e762000a76565b90620007f262000a91565b67ffffffffffffffff926064358481116200076b57366023820112156200076b578087013595602492620008268862000b0b565b92620008358751948562000ad4565b888452602098858a86019160071b8301019136831162000a72578601905b828210620009f557505050608435916001600160a01b0390818416809403620001155760a43595828716809703620001425760c43593838516809503620004d3578383541633141580620009c8575b620009b95789519161290e90818401809d858210911117620009a85750918c9d85808e9f9c9d9e9594849562000d658639169c8d865216809b8501528c840160e090528960e08501620008f6908b62000b24565b948960608201526080015286867f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169e8f60a082015260c001523592039083f59081156200099d5750916200098193917fec5b40d7c438225388cfe6540237a9a5c4962a253675a65aecc49b101a2eeb15959316998a968a5195869560a0875260a087019062000b24565b938d8601528a850152606084015260808301520390a451908152f35b8951903d90823e3d90fd5b634e487b7160e01b855260418f5284fd5b8c8a516371ed832960e01b8152fd5b50837f00000000000000000000000038896b4ac8420b8a2b768001da44d11109f1797d16331415620008a2565b608080833603126200076b5789519081018181108c82111762000a5f578a5262000a1f8362000abf565b81528b8301358c8201528983013580151581036200037b578a8201526080918c91606062000a4f86820162000abf565b9082015281520191019062000853565b50878660418f634e487b7160e01b835252fd5b8480fd5b602435906001600160a01b038216820362000a8d57565b5f80fd5b604435906001600160a01b038216820362000a8d57565b600435906001600160a01b038216820362000a8d57565b35906001600160a01b038216820362000a8d57565b90601f8019910116810190811067ffffffffffffffff82111762000af757604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811162000af75760051b60200190565b9081518082526020808093019301915f5b82811062000b44575050505090565b835180516001600160a01b039081168752818401518785015260408083015115159088015260609182015116908601526080909401939281019260010162000b35565b9081518082526020808093019301915f5b82811062000ba7575050505090565b835180516001600160a01b031686528201517fffffffff0000000000000000000000000000000000000000000000000000000016858301526040909401939281019260010162000b98565b3d1562000c30573d9067ffffffffffffffff821162000af7576040519162000c25601f8201601f19166020018462000ad4565b82523d5f602084013e565b606090565b6001600160a01b035f5416330362000c4957565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9192901562000cf1575081511562000ca3575090565b3b1562000cad5790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b82519091501562000d055750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b82851062000d4a575050604492505f838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935062000d2756fe610120806040523462000ad5576200290e803803809162000021828562000aed565b8339810160e08282031262000ad5576200003b8262000b11565b906200004a6020840162000b11565b604084015190936001600160401b039182811162000ad557810183601f8201121562000ad5578051938385116200044857604051936200009160208760051b018662000aed565b85855260208501916020839760071b8501019381851162000ad557602001925b84841062000a62575050505050620000cc6060820162000b11565b90620000db6080820162000b11565b90620000f860c0620000f060a0840162000b11565b920162000b11565b91620001043362000c88565b6001600160a01b0387161562000a50576001600160a01b0388161562000a3e576001600160a01b038781169089161462000a2c5784516032811162000a13575f5b818110620009e3575b5f5b828110620009b3575b5f905b83821062000980575b838310156200095f5760406200017c848b62000b26565b5101516200094d576001600160a01b0360606200019a858c62000b26565b510151166200093b57838110156200091a57620001ba6040918a62000b26565b510151620008f95782811015620008d857620001d96040918962000b26565b510151620008b75760015b8281106200085457505f5b8281106200034457505050876080528360a0528060c0528160e05282610100526200021a8762000c88565b604051946080860190608087525180915260a0860196905f5b818110620002f7575050506001600160a01b039081166020860152908116604085015290811660608401529081169481169316917fdcd068b2c907d464ae5d70938ca193aea2775108a58d5abaa330686223e85acc919081900390a4604051611c3a908162000cd48239608051818181610111015261016b015260a05181818161034301528181610c290152611424015260c051818181610b6c0152610c52015260e051818181610c7b01526114680152610100518181816102cc0152610bb00152f35b9091976020608082620003386001948d516060908160018060a01b039182815116855260208101516020860152604081015115156040860152015116910152565b01990192910162000233565b81810362000500575b62000359818962000b26565b51906002548082145f146200045c575060025468010000000000000000811015620004485782620003958260016200039c940160025562000b64565b9062000c1b565b604082015162000418575b6001917f16d983bc025f9bf2de81704e1b56397e8bab39991b2e9db2b8714a60dcd022b76080848060a01b03835116926200041060405180926060908160018060a01b039182815116855260208101516020860152604081015115156040860152015116910152565ba201620001ef565b600354915f1983146200043457600192909201600355620003a7565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b805f198101116200043457620004755f19820162000b64565b50680100000000000000008210156200044857620004a690600183016002556200049f8362000b64565b9062000b81565b5f19015b818111620004c95750620004c382620003958362000b64565b6200039c565b5f1981018181116200043457620004e4620004f09162000b64565b506200049f8362000b64565b801562000434575f1901620004aa565b6200050c818962000b26565b51604081015115620006a35760608101516001600160a01b03166200068057505b60406200053b828a62000b26565b510151156200034d5762000550818962000b26565b51885181516040516338d52e0f60e01b8152919290602090839060049082906001600160a01b03165afa91821562000675575f926200062e575b505f925b808410620005f5575b831015620005ca575050620005af6040918a62000b26565b510151156200034d57604051636f9158ef60e11b8152600490fd5b516040516302b8ed3f60e01b81526001600160a01b0391821660048201529116602482015260449150fd5b926001600160a01b036200060a828e62000b26565b5151166001600160a01b038416146200062757600101926200058e565b9262000597565b90916020823d6020116200066c575b816200064c6020938362000aed565b81010312620006695750620006619062000b11565b905f6200058a565b80fd5b3d91506200063d565b6040513d5f823e3d90fd5b51604051636e0ec65b60e01b81526001600160a01b039091166004820152602490fd5b60608101516001600160a01b03161562000831576060810151604051633fabe5a360e21b81529060a090829060049082906001600160a01b03165afa90811562000675575f908192620007d4575b505f8113156200078957506020820151801515908162000767575b506200071a5750506200052d565b6040805163bc29ff2b60e01b815283516001600160a01b03908116600483015260208501516024830152918401511515604482015260609093015116606483015260a492505b6084820152fd5b905081018082116200043457610e108101809111620004345742115f6200070c565b604080516325c4b0b560e01b815284516001600160a01b0390811660048301526020860151602483015291850151151560448201526060850151909116606482015260a49162000760565b915060a0823d60a01162000828575b81620007f260a0938362000aed565b81010312620006695750620008078162000b4f565b5060208101516200082060806060840151930162000b4f565b505f620006f1565b3d9150620007e3565b5160405163fe8c11c560e01b81526001600160a01b039091166004820152602490fd5b5f19810181811162000434576001600160a01b039062000875908a62000b26565b5151166001600160a01b036200088c838b62000b26565b51511611156200089f57600101620001e4565b60249060405190631e0076f960e11b82526004820152fd5b6040516337350baf60e11b81526001600160a01b0385166004820152602490fd5b6040516347b6c6d560e01b81526001600160a01b0386166004820152602490fd5b604051630d363d0d60e21b81526001600160a01b0385166004820152602490fd5b60405163f314cd4960e01b81526001600160a01b0386166004820152602490fd5b60405163365dfa4360e11b8152600490fd5b604051631e93c13160e01b8152600490fd5b6040516378fc011760e11b81526001600160a01b0389166004820152602490fd5b906001600160a01b038681169062000999838c62000b26565b51511614620009ac57600101906200015c565b9062000165565b6001600160a01b0384811690620009cb838b62000b26565b51511614620009dd5760010162000150565b62000159565b6001600160a01b0386811690620009fb838a62000b26565b5151161462000a0d5760010162000145565b6200014e565b604051635183e72160e11b815260326004820152602490fd5b60405163687615e560e01b8152600490fd5b6040516318a4224160e11b8152600490fd5b604051630adb389560e01b8152600490fd5b608090818584031262000ad5576040519182018281108582111762000ad95760405262000a8f8562000b11565b825260208501516020830152604085015190811515820362000ad5578260209260406080950152606062000ac581890162000b11565b90820152815201930192620000b1565b5f80fd5b60245f634e487b7160e01b81526041600452fd5b601f909101601f19168101906001600160401b038211908210176200044857604052565b51906001600160a01b038216820362000ad557565b805182101562000b3b5760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b51906001600160501b038216820362000ad557565b60025481101562000b3b5760025f52600360205f20910201905f90565b919062000c085780820362000b94575050565b62000c069160028060018060a01b03928385541660018060a01b03198254161781556001850154600182015501920162000bde60ff825416849060ff801983541691151516179055565b548254610100600160a81b031916600891821c92909216901b610100600160a81b0316179055565b565b634e487b7160e01b5f525f60045260245ffd5b919062000c0857805182546001600160a01b0319166001600160a01b0390911617825560208101516001830155604081015160029092018054606090920151610100600160a81b0360089190911b166001600160a81b031990921660ff9315159390931692909217179055565b60018060a01b03199081600154166001555f5460018060a01b0380921680938216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a356fe6080604081815260049182361015610015575f80fd5b5f92833560e01c91826301ffc9a71461148c5750816317fcb39b146114485781631fb6c52d14611404578163210663d014610f955781634a5e42b114610bf35781634c478a5614610bd45781635c1bba3814610b90578163647846a514610b4c5781636ea056a91461094e578163715018a6146108ec57816371a973051461085a57816376b1d08f1461083e57816379ba5097146107675781638da5cb5b14610741578163e30c397814610719578163ed2f8603146106fc578163edf94acd146102ac578163f2fde38b14610139575063fbfa77cf146100f3575f80fd5b34610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b5080fd5b919050346102a85760203660031901126102a85761015561152a565b9161015e611adc565b6001600160a01b039182807f00000000000000000000000000000000000000000000000000000000000000001694169380851461028157602083918351928380927f452a93200000000000000000000000000000000000000000000000000000000082525afa908115610277579084918791610249575b501684146102235750506101e7611adc565b816001600160a01b031960015416176001558254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b517f54ae5328000000000000000000000000000000000000000000000000000000008152fd5b61026a915060203d8111610270575b6102628183611590565b810190611740565b5f6101d5565b503d610258565b82513d88823e3d90fd5b50517f687615e5000000000000000000000000000000000000000000000000000000008152fd5b8280fd5b839150346101355781600319360112610135576001600160a01b039281847f0000000000000000000000000000000000000000000000000000000000000000168061061b575b505060028054926003548403938085116106085761032b6103168697959497611670565b9561032385519788611590565b808752611670565b60209690601f1901855b8181106105e05750859390507f00000000000000000000000000000000000000000000000000000000000000008916845b8486106103ba5750505050505080519380850191818652845180935281818701950193905b8382106103985786860387f35b845180518916875283015186840152948501949382019360019091019061038b565b8a846103c9889c999a9c611623565b50015460ff9081166105d45783826103e08a611623565b5054160361043b57506103f287611623565b50541688519061040182611544565b8152670de0b6b3a76400008882015261041a828b611889565b52610425818a611889565b505b60018091019501935b939498969598610366565b848961045761045261044c8c611623565b50611688565b61189d565b93886104628c611623565b50015460081c168c51928380927f313ce5670000000000000000000000000000000000000000000000000000000082525afa9081156105ca578d91610590575b506012911681811015610534578103908111610521576104c19061187b565b9081810291818304149015171561050e575b8b6104dd88611623565b505416908951916104ed83611544565b8252888201526104fd828b611889565b52610508818a611889565b50610427565b60248b601186634e487b7160e01b835252fd5b60248c601187634e487b7160e01b835252fd5b818193929311610547575b5090506104d3565b601119810190811161057d5761055c9061187b565b91821561056c575004808d61053f565b634e487b7160e01b8d52855260248cfd5b60248d601188634e487b7160e01b835252fd5b90508981813d83116105c3575b6105a78183611590565b810103126105bf575181811681036105bf578e6104a2565b8c80fd5b503d61059d565b8b513d8f823e3d90fd5b50509460010193610430565b978596988196516105f081611544565b8a81528a8382015282828b0101520197959497610335565b602486601184634e487b7160e01b835252fd5b60a090835192838092633fabe5a360e21b82525afa9081156106f257849085926106be575b5061069757610e10810180911161068457421061065e5781856102f2565b517fa4a7b2a4000000000000000000000000000000000000000000000000000000008152fd5b602484601185634e487b7160e01b835252fd5b50517f73460943000000000000000000000000000000000000000000000000000000008152fd5b90506106e1915060a03d81116106eb575b6106d98183611590565b810190611846565b5050915086610640565b503d6106cf565b82513d86823e3d90fd5b50503461013557816003193601126101355760209051610e108152f35b5050346101355781600319360112610135576020906001600160a01b03600154169051908152f35b5050346101355781600319360112610135576001600160a01b0360209254169051908152f35b919050346102a857826003193601126102a857600154916001600160a01b039133838516036107d55750506001600160a01b0319809216600155825491339083161783553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152fd5b5050346101355781600319360112610135576020905160328152f35b8284346108e957806003193601126108e957906108756116ca565b81519160208080850192818652845180945285019301945b82811061089a5784840385f35b909192826080826108da6001948a51606090816001600160a01b039182815116855260208101516020860152604081015115156040860152015116910152565b0196019101949291909461088d565b80fd5b83346108e957806003193601126108e957610905611adc565b806001600160a01b036001600160a01b0319806001541660015582549081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b8391503461013557826003193601126101355761096961152a565b60243591610975611adc565b6001600160a01b038216806109e55750506109df83948480807fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779787335af1506109bd611a9d565b505b5192839283602090939291936001600160a01b0360408201951681520152565b0390a180f35b85517fa9059cbb0000000000000000000000000000000000000000000000000000000060208083019182523360248401526044808401889052835292610a7d929188908190610a35606486611590565b8b5194610a4186611544565b8786527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656488870152519082855af1610a77611a9d565b91611b33565b8051828115918215610b28575b5050905015610ac05750506109df7fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c7793946109bf565b6084925085519162461bcd60e51b8352820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b8380929350010312610b48578101518015158103610b4857808289610a8a565b8580fd5b505034610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b505034610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b5050346101355781600319360112610135576020906003549051908152f35b919050346102a85760209182600319360112610f9157610c1161152a565b91610c1a611adc565b6001600160a01b0380931692807f0000000000000000000000000000000000000000000000000000000000000000168414610f6257807f0000000000000000000000000000000000000000000000000000000000000000168414610f3357807f0000000000000000000000000000000000000000000000000000000000000000168414610f0457600291825491875b83811080610eee575b15610cbf57600101610ca9565b9394959683851015610ebf5790859291610cd886611623565b5060ff9485910154165f14610ddb5750505050610cf660035461175f565b6003555b5f1991818301918211610dc8575b818110610d8757505081548015610d74570191610d2483611623565b919091610d6257508181868093558260018201550155557f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc8280a280f35b8580602492634e487b7160e01b825252fd5b602486603186634e487b7160e01b835252fd5b6001810190818111610db557610db090610daa610da384611623565b5091611623565b9061177f565b610d08565b602488601188634e487b7160e01b835252fd5b602487601187634e487b7160e01b835252fd5b895b858110610dee575050505050610cfa565b8681141580610eaa575b80610e46575b610e0a57600101610ddd565b888484610e18602494611623565b5054169051917f21d8a3aa000000000000000000000000000000000000000000000000000000008352820152fd5b50888284610e5384611623565b5054168651928380926338d52e0f60e01b82525afa908c8215610e9f578c92869290610e82575b501614610dfe565b610e999150853d8711610270576102628183611590565b5f610e7a565b8651903d90823e3d90fd5b508488610eb683611623565b50015416610df8565b602487898551917f5c753429000000000000000000000000000000000000000000000000000000008352820152fd5b508682610efa83611623565b5054161415610cb2565b509160249251917f999c5225000000000000000000000000000000000000000000000000000000008352820152fd5b509160249251917fb56dc787000000000000000000000000000000000000000000000000000000008352820152fd5b509160249251917fb83266ba000000000000000000000000000000000000000000000000000000008352820152fd5b8380fd5b9050346102a85760803660031901126102a857610fb0611adc565b6002549060328210156113d457610fc6366115b2565b808401511561137d576001600160a01b03908160608201511661134b5750505b835b8281106112ca575b6044358015158103610b48576111ac575b61100a366115b2565b928181036110f7575050600254680100000000000000008110156110e4578261103c8260016110429401600255611623565b90611a0e565b828201516110b7575b506080816110b36001600160a01b037f16d983bc025f9bf2de81704e1b56397e8bab39991b2e9db2b8714a60dcd022b794511694518092606090816001600160a01b039182815116855260208101516020860152604081015115156040860152015116910152565ba280f35b600354905f1982146110d15750600101600355608061104b565b846011602492634e487b7160e01b835252fd5b602485604184634e487b7160e01b835252fd5b5f1990808201908082116111865761110e82611623565b5090680100000000000000008110156111995786939291610daa8260016111389401600255611623565b83811161115257505061103c61114d92611623565b611042565b908092508101818111611186579061117961116f61117e93611623565b50610daa83611623565b61175f565b908491611138565b602488601187634e487b7160e01b835252fd5b602489604188634e487b7160e01b835252fd5b6111b5366115b2565b6111bd6116ca565b805191846001600160a01b03916020838251168a51938480926338d52e0f60e01b82525afa9182156112c0578a926112a0575b5089945b80861061127a575b85101561124157505050859161121191611889565b51015115611001575082517fdf22b1de000000000000000000000000000000000000000000000000000000008152fd5b5188517f02b8ed3f0000000000000000000000000000000000000000000000000000000081529083168188015291166024820152604490fd5b94836112868287611889565b5151168484161461129a57600101946111f4565b946111fc565b6112b991925060203d8111610270576102628183611590565b905f6111f0565b89513d8c823e3d90fd5b6112d261160d565b6112db82611623565b50906001600160a01b038080935416911610611345576112f961160d565b908061130484611623565b50541691161461131657600101610fe8565b602492508351917f3859e924000000000000000000000000000000000000000000000000000000008352820152fd5b50610ff0565b5193517f6e0ec65b00000000000000000000000000000000000000000000000000000000815293169083015250602490fd5b6001600160a01b0380606083015116156113a1575061139b9061189d565b50610fe6565b60249350849151169051917ffe8c11c5000000000000000000000000000000000000000000000000000000008352820152fd5b60249060328451917fa307ce42000000000000000000000000000000000000000000000000000000008352820152fd5b505034610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b505034610135578160031936011261013557602090516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b8491346102a85760203660031901126102a857357fffffffff0000000000000000000000000000000000000000000000000000000081168091036102a857602092507f1c64cd8f000000000000000000000000000000000000000000000000000000008114908115611500575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836114f9565b600435906001600160a01b038216820361154057565b5f80fd5b6040810190811067ffffffffffffffff82111761156057604052565b634e487b7160e01b5f52604160045260245ffd5b6080810190811067ffffffffffffffff82111761156057604052565b90601f8019910116810190811067ffffffffffffffff82111761156057604052565b608090600319011261154057604051906115cb82611574565b6001600160a01b038260043582811681036115405781526024356020820152604435801515810361154057604082015260643591821682036115405760600152565b6004356001600160a01b03811681036115405790565b60025481101561165c5760039060025f52027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace01905f90565b634e487b7160e01b5f52603260045260245ffd5b67ffffffffffffffff81116115605760051b60200190565b9060405161169581611574565b6060819360026001600160a01b039182815416855260018101546020860152015460ff81161515604085015260081c16910152565b600254906116d782611670565b916116e56040519384611590565b80835260025f90815260207f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace8186015b848410611723575050505050565b60038360019261173285611688565b815201920193019290611715565b9081602091031261154057516001600160a01b03811681036115405790565b801561176b575f190190565b634e487b7160e01b5f52601160045260245ffd5b919061181c57808203611790575050565b61181a916002806001600160a01b0392838554166001600160a01b0319825416178155600185015460018201550192016117da60ff825416849060ff801983541691151516179055565b5460081c1674ffffffffffffffffffffffffffffffffffffffff001974ffffffffffffffffffffffffffffffffffffffff0083549260081b169116179055565b565b634e487b7160e01b5f525f60045260245ffd5b519069ffffffffffffffffffff8216820361154057565b908160a09103126115405761185a8161182f565b9160208201519160408101519161187860806060840151930161182f565b90565b604d811161176b57600a0a90565b805182101561165c5760209160051b010190565b60049060a06001600160a01b0360608301511660405193848092633fabe5a360e21b82525afa8015611a03575f9283916119dc575b505f831315611979576020820151801515908161195a575b506118f457505090565b604080517fbc29ff2b00000000000000000000000000000000000000000000000000000000815283516001600160a01b03908116600483015260208501516024830152918401511515604482015260609093015116606483015260a492505b6084820152fd5b9050810180821161176b57610e10810180911161176b5742115f6118ea565b50604080517f25c4b0b500000000000000000000000000000000000000000000000000000000815282516001600160a01b03908116600483015260208401516024830152918301511515604482015260609092015116606482015260a491611953565b90506119f791925060a03d81116106eb576106d98183611590565b5093925050915f6118d2565b6040513d5f823e3d90fd5b919061181c5761181a91606060026001600160a01b0392838551166001600160a01b0319825416178155602085015160018201550192611a6060408201511515859060ff801983541691151516179055565b0151825474ffffffffffffffffffffffffffffffffffffffff001916911660081b74ffffffffffffffffffffffffffffffffffffffff0016179055565b3d15611ad7573d9067ffffffffffffffff82116115605760405191611acc601f8201601f191660200184611590565b82523d5f602084013e565b606090565b6001600160a01b035f54163303611aef57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b91929015611b945750815115611b47575090565b3b15611b505790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b825190915015611ba75750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b828510611beb575050604492505f838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350611bc956fea2646970667358221220dcc00f8f3db01542a4c841c7d12c5b86e9fd0ea17ed2c8fbc951a314b8ffe05464736f6c6343000815003360a06040818152346200038f576200184c8038038091620000218286620003bb565b84398201916080818403126200038f576200003c81620003df565b906020906200004d828201620003df565b84820151916060968782015160018060401b03928382116200038f570181601f820112156200038f578051838111620003a757600593895193620000968984881b0186620003bb565b828552888086019360061b850101938185116200038f578901925b84841062000339575050505050620000c9336200041d565b6001600160a01b038381169390929084156200032857838816908115620003175785821462000306573b62000273575b50670de0b6b3a7640000958686101562000262576706f05b59d3b20000861062000251578251935f5b8581106200017957600280546001600160a01b03191688179055608088905262015180420460035560048990558a6200015b8b6200041d565b516113e3908162000469823960805181818161040001526106ef0152f35b620001858186620003f4565b51519082821684620001988389620003f4565b51015192813b1562000239578e1b6001600160601b03191660a084901c6bffffffff000000000000000016175f8181528787528e90205460ff1662000222575f528585528c5f20926001938460ff1982541617905563ffffffff60e01b16907fa10f2fe4b8a71df10b600a159be010c92558175741cec420c971a463470f04ef5f80a30162000122565b6024908e519063027cfe1560e51b82526004820152fd5b8d516369b9f78360e11b815260048101839052602490fd5b8851637c56eb2960e11b8152600490fd5b8851631e76c69d60e11b8152600490fd5b8851630229549960e51b81528781600481895afa908115620002fc579085915f91620002ba575b501614620002a9575f620000f9565b8751630a45718160e11b8152600490fd5b91508882813d8311620002f4575b620002d48183620003bb565b81010312620002f15750620002ea8591620003df565b5f6200029a565b80fd5b503d620002c8565b8a513d5f823e3d90fd5b8951635078aee360e11b8152600490fd5b895163570c35b560e11b8152600490fd5b88516318a4224160e11b8152600490fd5b8b848303126200038f578b51908c82018281108582111762000393578d526200036285620003df565b8252848b0151906001600160e01b0319821682036200038f57828c928f94840152815201930192620000b1565b5f80fd5b60245f634e487b7160e01b81526041600452fd5b634e487b7160e01b5f52604160045260245ffd5b601f909101601f19168101906001600160401b03821190821017620003a757604052565b51906001600160a01b03821682036200038f57565b8051821015620004095760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b60018060a01b03199081600154166001555f5460018060a01b0380921680938216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a356fe6080604081815260049182361015610015575f80fd5b5f92833560e01c91826301871a8314610fb55750816301ffc9a714610f2c578163162146fb146104425781632f40e5b8146104425781633280648e14610d4c57816334d184ae146104425781635c9302c914610d2d57816361e8781114610c07578163683acef014610bc95781636ea056a9146109cf578163715018a61461096057816379ba50971461087c5781637f068c0f146107fd5781638da5cb5b146107d7578163a0e38c811461045a578163b998927514610442578163bfd31dc414610423578163d20fb647146103e8578163e30c3978146103c0578163e87b3abe146102dc578163e8ae44aa146102be578163f2fde38b14610149575063fbfa77cf1461011f575f80fd5b346101455781600319360112610145576020906001600160a01b03600254169051908152f35b5080fd5b919050346102ba5760203660031901126102ba5761016561101a565b9161016e611285565b6001600160a01b039182806002541694169380851461029357602083918351928380927f452a93200000000000000000000000000000000000000000000000000000000082525afa908115610289579084918791610248575b501684146102225750506101d9611285565b8173ffffffffffffffffffffffffffffffffffffffff1960015416176001558254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b517f148ae302000000000000000000000000000000000000000000000000000000008152fd5b9150506020813d8211610281575b816102636020938361107b565b8101031261027d5751838116810361027d5783905f6101c7565b8580fd5b3d9150610256565b82513d88823e3d90fd5b50517fa0f15dc6000000000000000000000000000000000000000000000000000000008152fd5b8280fd5b9050346102ba57826003193601126102ba5760209250549051908152f35b9050346102ba57816003193601126102ba576102f661101a565b916102ff611034565b91610308611285565b606084901b6bffffffffffffffffffffffff191660a084901c6bffffffff0000000000000000161790818652600560205260ff8387205416156103925750845260056020528320805460ff191690556001600160e01b031916906001600160a01b03167f566a9a4fba10e4534371d2ea973f09830a90304a10e2a8fce319764158f9e55c8380a380f35b9060249251917ff0d5987a000000000000000000000000000000000000000000000000000000008352820152fd5b5050346101455781600319360112610145576020906001600160a01b03600154169051908152f35b505034610145578160031936011261014557602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b833461043f578060031936011261043f5761043c6111a4565b80f35b80fd5b833461043f576104513661109d565b5061043c6111a4565b9050346102ba5761046a36611157565b926001600160a01b038060025416908133036107c857845462015180420490600654801580156106a7575b505050806003540361069e575b5086600655865b8681106104b4578780f35b6104cb6104c28289886111c9565b858101906111ff565b8711610670576001600160e01b03199035167f095ea7b3000000000000000000000000000000000000000000000000000000008114908115610674575b50610519575b600101955b956104a9565b6105276104c28289886111c9565b80881161066c57810181900360031901851361067057868101359083821680920361066c5760240135156106625782610569610564848b8a6111c9565b611232565b16908486517fdd62ed3e0000000000000000000000000000000000000000000000000000000081528981806105be86602096879584019060209093929360408301946001600160a01b03809216845216910152565b0381875afa918215610658578c92610626575b50506105de57505061050e565b85517f715879af0000000000000000000000000000000000000000000000000000000081526001600160a01b0392831689820190815291909216602082015281900360400190fd5b90809250813d8311610651575b61063d818361107b565b8101031261064d57515f806105d1565b8a80fd5b503d610633565b88513d8e823e3d90fd5b5060010195610513565b8980fd5b8880fd5b7f39509351000000000000000000000000000000000000000000000000000000009150145f610508565b6003555f6104a2565b60035484036107b95782905b875191633fa4f24560e01b83526020838c818b5afa9283156107af578d93610778575b50828102928184041490151715610765576107525704907f0000000000000000000000000000000000000000000000000000000000000000821061072a578103610722575b8080610495565b86555f61071b565b8786517f47968522000000000000000000000000000000000000000000000000000000008152fd5b60248b60128b634e487b7160e01b835252fd5b60248c60118c634e487b7160e01b835252fd5b9092506020813d82116107a7575b816107936020938361107b565b810103126107a35751915f6106d6565b8c80fd5b3d9150610786565b89513d8f823e3d90fd5b670de0b6b3a7640000906106b3565b84835163152df05f60e11b8152fd5b5050346101455781600319360112610145576001600160a01b0360209254169051908152f35b838334610145578160031936011261014557600254906001600160a01b038216330361086d57509173ffffffffffffffffffffffffffffffffffffffff1982931660025581600355557f4bd04f3440c9bf56a25f7b9e1ac75a9803bd83123a127cf9748129c938630b398180a180f35b83905163152df05f60e11b8152fd5b919050346102ba57826003193601126102ba57600154916001600160a01b039133838516036108f757505073ffffffffffffffffffffffffffffffffffffffff19809216600155825491339083161783553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b906020608492519162461bcd60e51b8352820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152fd5b833461043f578060031936011261043f57610979611285565b806001600160a01b0373ffffffffffffffffffffffffffffffffffffffff19806001541660015582549081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b839150346101455782600319360112610145576109ea61101a565b602435916109f6611285565b6001600160a01b03821680610a66575050610a6083948480807fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779787335af150610a3e611246565b505b5192839283602090939291936001600160a01b0360408201951681520152565b0390a180f35b85517fa9059cbb0000000000000000000000000000000000000000000000000000000060208083019182523360248401526044808401889052835292610afe929188908190610ab660648661107b565b8b5194610ac28661104b565b8786527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656488870152519082855af1610af8611246565b916112dc565b8051828115918215610ba9575b5050905015610b41575050610a607fab2246061d7b0dd3631d037e3f6da75782ae489eeb9f6af878a4b25df9b07c779394610a40565b6084925085519162461bcd60e51b8352820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b838092935001031261027d57810151801515810361027d57808289610b0b565b8383346101455781600319360112610145576001600160a01b03600254163303610bf857508091816003555580f35b90505163152df05f60e11b8152fd5b9050346102ba57816003193601126102ba57610c2161101a565b91610c2a611034565b91610c33611285565b833b15610cf457606084901b6bffffffffffffffffffffffff191660a084901c6bffffffff0000000000000000161790818652600560205260ff8387205416610cc65750845260056020528320805460ff191660011790556001600160e01b031916906001600160a01b03167fa10f2fe4b8a71df10b600a159be010c92558175741cec420c971a463470f04ef8380a380f35b9060249251917f4f9fc2a0000000000000000000000000000000000000000000000000000000008352820152fd5b83906001600160a01b0360249351927fd373ef060000000000000000000000000000000000000000000000000000000084521690820152fd5b5050346101455781600319360112610145576020906003549051908152f35b9050346102ba57610d5c36611157565b6001600160a01b0391826002541692833303610f1d57865b838110610de45750505050602090835192838092633fa4f24560e01b82525afa918215610ddb57508291610daa575b5060065580f35b90506020813d8211610dd3575b81610dc46020938361107b565b8101031261014557515f610da3565b3d9150610db7565b513d84823e3d90fd5b610dfb610df28286866111c9565b888101906111ff565b8711610670576001600160e01b0319610e48913516610e1e6105648488886111c9565b60601b6bffffffffffffffffffffffff191660a09190911c6bffffffff0000000000000000161790565b885260206005815260ff888a20541615610e655750600101610d74565b869288610e748b9488886111c9565b91838251967fc1c440aa0000000000000000000000000000000000000000000000000000000088528701528235908116809103610f19576024860152828201356044860152810135601e1982360301811215610f15570190813591019167ffffffffffffffff821161043f57813603831361043f57908391606060648401528160848401528160a49485850137828201840152601f01601f19168101030190fd5b8380fd5b8480fd5b84865163152df05f60e11b8152fd5b9050346102ba5760203660031901126102ba5735906001600160e01b031982168092036102ba57602092507f755e7563000000000000000000000000000000000000000000000000000000008214918215610f8b575b50519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000001491505f610f82565b849084346102ba57806003193601126102ba5760ff9060209361100b610fd961101a565b610fe1611034565b6bffffffff00000000000000009060a01c16906bffffffffffffffffffffffff199060601b161790565b81526005855220541615158152f35b600435906001600160a01b038216820361103057565b5f80fd5b602435906001600160e01b03198216820361103057565b6040810190811067ffffffffffffffff82111761106757604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761106757604052565b6020806003198301126110305760043567ffffffffffffffff918282116110305783602383011215611030578160040135928311611067576040928351946110ea838360051b018761107b565b81865260248387019260061b8501019381851161103057602401915b8483106111165750505050505090565b85838303126110305785519061112b8261104b565b8335906001600160a01b0382168203611030578286928994528286013583820152815201920191611106565b9060206003198301126110305760043567ffffffffffffffff9283821161103057806023830112156110305781600401359384116110305760248460051b83010111611030576024019190565b6001600160a01b036002541633036111b857565b600460405163152df05f60e11b8152fd5b91908110156111eb5760051b81013590605e1981360301821215611030570190565b634e487b7160e01b5f52603260045260245ffd5b903590601e1981360301821215611030570180359067ffffffffffffffff82116110305760200191813603831361103057565b356001600160a01b03811681036110305790565b3d15611280573d9067ffffffffffffffff82116110675760405191611275601f8201601f19166020018461107b565b82523d5f602084013e565b606090565b6001600160a01b035f5416330361129857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9192901561133d57508151156112f0575090565b3b156112f95790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156113505750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b828510611394575050604492505f838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935061137256fea2646970667358221220a6f9c05c46cf1c4c4f1c91f80cd95902f2287cbb8736b0d2e8c1cd8d6980520f64736f6c63430008150033a2646970667358221220379d2c42f74c00aabbbe5385697bf552124f2da702b72b46753d9a3f7ce6eaf864736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000038896b4ac8420b8A2B768001Da44d11109F1797D
-----Decoded View---------------
Arg [0] : v2Factory_ (address): 0x38896b4ac8420b8A2B768001Da44d11109F1797D
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000038896b4ac8420b8A2B768001Da44d11109F1797D
Deployed Bytecode Sourcemap
506:4165:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;506:4165:2;;;;;;:::i;:::-;1090:65:19;;:::i;:::-;-1:-1:-1;;;;;506:4165:2;;;;;-1:-1:-1;;1228:24:20;506:4165:2;;;1228:24:20;506:4165:2;;;;1267:43:20;;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;926:13:20;506:4165:2;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;506:4165:2;;;;;;:::i;:::-;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;506:4165:2;;;;;2520:10;:21;;:48;;;506:4165;2516:124;;506:4165;;4346:161;;;;;;;;;;;;;;;;;506:4165;4346:161;;;;;;;;;;;506:4165;4346:161;;;;506:4165;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4346:161;;;;;;;;;506:4165;;4564:98;506:4165;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4564:98;;;506:4165;;;;;4346:161;506:4165;;;;;;;;;;4346:161;506:4165;;;-1:-1:-1;;;506:4165:2;;;;2516:124;506:4165;;;-1:-1:-1;;;2591:38:2;;;2520:48;2559:9;;;506:4165;2520:10;2545:23;;2520:48;;506:4165;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;673:34:2;506:4165;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;;;;926:13:20;506:4165:2;;-1:-1:-1;;;;;736:10:11;;506:4165:2;;;1833:24:20;506:4165:2;;;;-1:-1:-1;;506:4165:2;;;926:13:20;506:4165:2;;;736:10:11;;506:4165:2;;;;;;736:10:11;506:4165:2;;2639:40:19;;;;506:4165:2;;;;;;;;;-1:-1:-1;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1090:65:19;;:::i;:::-;506:4165:2;-1:-1:-1;;;;;;;506:4165:2;1583:20:20;506:4165:2;;1583:20:20;506:4165:2;;;;;;;;;2639:40:19;;;;506:4165:2;;;;;;;;;;;;;;;;;;:::i;:::-;;;1090:65:19;;;:::i;:::-;-1:-1:-1;;;;;506:4165:2;;548:19:4;506:4165:2;;583:10:4;;720:20;583:10;;;;;720:20;583:10;;;:34;;;;;:::i;:::-;;544:161;506:4165:2;720:20:4;;;;506:4165:2;;;;;;-1:-1:-1;;;;;506:4165:2;;;;;;;;;;720:20:4;;;;506:4165:2;;544:161:4;506:4165:2;;;;1050:58:21;;;;;;675:10:4;506:4165:2;1050:58:21;;506:4165:2;;;;;;;;1050:58:21;;506:4165:2;;1050:58:21;506:4165:2;;1050:58:21;:::i;:::-;506:4165:2;;;;;;;;;;;;;;;;;;;;;;;;;5621:31:10;5670:69;;506:4165:2;;;;;;;;5621:31:10;;;;:::i;:::-;5670:69;;:::i;:::-;506:4165:2;;5801:22:21;;;:56;;;;;544:161:4;506:4165:2;;;;;;;544:161:4;;720:20;;544:161;;;;506:4165:2;;;;;;;-1:-1:-1;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;5801:56:21;5827:30;;;;;;506:4165:2;;;;5827:30:21;;506:4165:2;;;;;;;;5801:56:21;;;;;506:4165:2;;;;;;;;;-1:-1:-1;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;752:42:2;506:4165;;;;;;;;;;;;-1:-1:-1;;506:4165:2;;;;;;:::i;:::-;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2520:10;:21;;:48;;;506:4165;2516:124;;506:4165;;3436:244;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;506:4165;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;3621:18;;;506:4165;;;;;;;;;;;3436:244;;;;;;;;;;506:4165;;;;;3746:216;506:4165;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;3746:216;;;506:4165;;;;;3436:244;506:4165;;;;;;;;;;3436:244;-1:-1:-1;;;506:4165:2;;;;;;;2516:124;506:4165;;;-1:-1:-1;;;2591:38:2;;;2520:48;2559:9;;;506:4165;2520:10;2545:23;;2520:48;;506:4165;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;506:4165:2;;;;;;;;;;;;-1:-1:-1;;;;;506:4165:2;;;;;;:::o;:::-;;;;;;;;-1:-1:-1;;;;;506:4165:2;;;;;;:::o;:::-;;;;-1:-1:-1;;;;;506:4165:2;;;;;;:::o;:::-;;;-1:-1:-1;;;;;506:4165:2;;;;;;:::o;:::-;;;1050:58:21;;506:4165:2;;;;;;;;;;;;;;;;:::o;:::-;-1:-1:-1;;;506:4165:2;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;-1:-1:-1;506:4165:2;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;506:4165:2;;;;;;;;;;;:::o;:::-;;;;;-1:-1:-1;;;;;506:4165:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1050:58:21;506:4165:2;;-1:-1:-1;;506:4165:2;;;;;:::i;:::-;;;;-1:-1:-1;506:4165:2;;;;:::o;:::-;;;:::o;1401:132:19:-;-1:-1:-1;;;;;1309:6:19;506:4165:2;;736:10:11;1465:23:19;506:4165:2;;1401:132:19:o;506:4165:2:-;;;;-1:-1:-1;;;506:4165:2;;;;;;;;;;;;;;;;;;7865:644:10;;;;8075:427;;;506:4165:2;;;8107:22:10;8103:290;;8407:17;;:::o;8103:290::-;1746:19;:23;506:4165:2;;8407:17:10;:::o;506:4165:2:-;;;;-1:-1:-1;;;506:4165:2;;;;;;;;;;;;;;;;;;8075:427:10;506:4165:2;;;;-1:-1:-1;9212:21:10;:17;;9387:145;;;;;;;9208:388;506:4165:2;;9564:20:10;-1:-1:-1;;;9564:20:10;;506:4165:2;;9564:20:10;;;;506:4165:2;;;;;;;;;9232:1:10;506:4165:2;;;;;;;;;;;;9232:1:10;506:4165:2;;;;;;;1050:58:21;;506:4165:2;;;;;9564:20:10;;;;506:4165:2;;;;;;;;;;;;;;;;;;;-1:-1:-1;506:4165:2;
Swarm Source
ipfs://379d2c42f74c00aabbbe5385697bf552124f2da702b72b46753d9a3f7ce6eaf8
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ 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.