Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
AssetGroupRegistry
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 99999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.17; import "@openzeppelin-upgradeable/proxy/utils/Initializable.sol"; import "../interfaces/Constants.sol"; import "../interfaces/IAssetGroupRegistry.sol"; import "../access/Roles.sol"; import "../access/SpoolAccessControllable.sol"; /* ========== CONTRACTS ========== */ contract AssetGroupRegistry is IAssetGroupRegistry, SpoolAccessControllable, Initializable { /* ========== STATE VARIABLES ========== */ /** * @notice Which are allowed to be used as an assets. * @dev token address => is allowed */ mapping(address => bool) private _assetAllowlist; /** * @notice Asset groups registered in the system. */ address[][] private _assetGroups; /** * @notice Hashes of registered asset groups. * @dev asset group hash => asset group ID */ mapping(bytes32 => uint256) private _assetGroupHashes; /* ========== CONSTRUCTOR ========== */ constructor(ISpoolAccessControl accessControl_) SpoolAccessControllable(accessControl_) {} function initialize(address[] calldata allowedTokens_) external initializer { for (uint256 i; i < allowedTokens_.length; ++i) { _allowToken(allowedTokens_[i]); } // asset group IDs start at 1, so we push dummy asset group _assetGroups.push(new address[](0)); } /* ========== EXTERNAL VIEW FUNCTIONS ========== */ function isTokenAllowed(address token) external view returns (bool) { return _assetAllowlist[token]; } function numberOfAssetGroups() external view returns (uint256) { return _assetGroups.length - 1; } function listAssetGroup(uint256 assetGroupId) external view validAssetGroup(assetGroupId) returns (address[] memory) { return _assetGroups[assetGroupId]; } function assetGroupLength(uint256 assetGroupId) external view validAssetGroup(assetGroupId) returns (uint256) { return _assetGroups[assetGroupId].length; } function validateAssetGroup(uint256 assetGroupId) external view { _checkIsValidAssetGroup(assetGroupId); } function checkAssetGroupExists(address[] calldata assets) external view returns (uint256) { bytes32 assetGroupHash = _getAssetGroupHash(assets); return _assetGroupHashes[assetGroupHash]; } /* ========== EXTERNAL MUTATIVE FUNCTIONS ========== */ function allowToken(address token) external onlyRole(ROLE_SPOOL_ADMIN, msg.sender) { _allowToken(token); } function allowTokenBatch(address[] calldata tokens) external onlyRole(ROLE_SPOOL_ADMIN, msg.sender) { for (uint256 i; i < tokens.length; ++i) { _allowToken(tokens[i]); } } function registerAssetGroup(address[] calldata assets) external onlyRole(ROLE_SPOOL_ADMIN, msg.sender) returns (uint256) { bytes32 assetGroupHash = _getAssetGroupHash(assets); if (_assetGroupHashes[assetGroupHash] > 0) { revert AssetGroupAlreadyExists(_assetGroupHashes[assetGroupHash]); } _assetGroups.push(assets); uint256 assetGroupId = _assetGroups.length - 1; _assetGroupHashes[assetGroupHash] = assetGroupId; emit AssetGroupRegistered(assetGroupId); return assetGroupId; } /* ========== PRIVATE FUNCTIONS ========== */ /** * @dev Adds token to the asset allowlist. * Emits TokenAllowed event. */ function _allowToken(address token) private { if (token == address(0)) revert ConfigurationAddressZero(); if (!_assetAllowlist[token]) { _assetAllowlist[token] = true; emit TokenAllowed(token); } } /** * @dev Finds key of the asset group based on provided assets. * Reverts if assets cannot form an asset group. * @param assets Assets forming asset group. * @return Key of the asset group. */ function _getAssetGroupHash(address[] calldata assets) private view returns (bytes32) { if (assets.length == 0) { revert NoAssetsProvided(); } for (uint256 i; i < assets.length; ++i) { if (i > 0 && assets[i] <= assets[i - 1]) { revert UnsortedArray(); } if (!_assetAllowlist[assets[i]]) { revert TokenNotAllowed(assets[i]); } } return keccak256(abi.encode(assets)); } /** * @dev Checks if asset group ID is valid. * Reverts if provided asset group ID does not belong to any asset group. */ function _checkIsValidAssetGroup(uint256 assetGroupId) private view { if (assetGroupId == NULL_ASSET_GROUP_ID || assetGroupId >= _assetGroups.length) { revert InvalidAssetGroup(assetGroupId); } } /* ========== MODIFIERS ========== */ /** * @dev Only allows valid asset group IDs. */ modifier validAssetGroup(uint256 assetGroupId) { _checkIsValidAssetGroup(assetGroupId); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Internal function that returns the initialized version. Returns `_initialized` */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Internal function that returns the initialized version. Returns `_initializing` */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.17; /// @dev Number of seconds in an average year. uint256 constant SECONDS_IN_YEAR = 31_556_926; /// @dev Number of seconds in an average year. int256 constant SECONDS_IN_YEAR_INT = 31_556_926; /// @dev Represents 100%. uint256 constant FULL_PERCENT = 100_00; /// @dev Represents 100%. int256 constant FULL_PERCENT_INT = 100_00; /// @dev Represents 100% for yield. int256 constant YIELD_FULL_PERCENT_INT = 10 ** 12; /// @dev Represents 100% for yield. uint256 constant YIELD_FULL_PERCENT = uint256(YIELD_FULL_PERCENT_INT); /// @dev Maximal management fee that can be set on a smart vault. Expressed in terms of FULL_PERCENT. uint256 constant MANAGEMENT_FEE_MAX = 5_00; /// @dev Maximal deposit fee that can be set on a smart vault. Expressed in terms of FULL_PERCENT. uint256 constant DEPOSIT_FEE_MAX = 5_00; /// @dev Maximal smart vault performance fee that can be set on a smart vault. Expressed in terms of FULL_PERCENT. uint256 constant SV_PERFORMANCE_FEE_MAX = 20_00; /// @dev Maximal ecosystem fee that can be set on the system. Expressed in terms of FULL_PERCENT. uint256 constant ECOSYSTEM_FEE_MAX = 20_00; /// @dev Maximal treasury fee that can be set on the system. Expressed in terms of FULL_PERCENT. uint256 constant TREASURY_FEE_MAX = 10_00; /// @dev Maximal risk score a strategy can be assigned. uint8 constant MAX_RISK_SCORE = 10_0; /// @dev Minimal risk score a strategy can be assigned. uint8 constant MIN_RISK_SCORE = 1; /// @dev Maximal value for risk tolerance a smart vautl can have. int8 constant MAX_RISK_TOLERANCE = 10; /// @dev Minimal value for risk tolerance a smart vault can have. int8 constant MIN_RISK_TOLERANCE = -10; /// @dev If set as risk provider, system will return fixed risk score values address constant STATIC_RISK_PROVIDER = address(0xaaa); /// @dev Fixed values to use if risk provider is set to STATIC_RISK_PROVIDER uint8 constant STATIC_RISK_SCORE = 1; /// @dev Maximal value of deposit NFT ID. uint256 constant MAXIMAL_DEPOSIT_ID = 2 ** 255; /// @dev Maximal value of withdrawal NFT ID. uint256 constant MAXIMAL_WITHDRAWAL_ID = 2 ** 256 - 1; /// @dev How many shares will be minted with a NFT uint256 constant NFT_MINTED_SHARES = 10 ** 6; /// @dev Each smart vault can have up to STRATEGY_COUNT_CAP strategies. uint256 constant STRATEGY_COUNT_CAP = 16; /// @dev Maximal DHW base yield. Expressed in terms of FULL_PERCENT. uint256 constant MAX_DHW_BASE_YIELD_LIMIT = 10_00; /// @dev Smart vault and strategy share multiplier at first deposit. uint256 constant INITIAL_SHARE_MULTIPLIER = 1000; /// @dev Strategy initial locked shares. These shares will never be unlocked. uint256 constant INITIAL_LOCKED_SHARES = 10 ** 12; /// @dev Strategy initial locked shares address. address constant INITIAL_LOCKED_SHARES_ADDRESS = address(0xdead); /// @dev Maximum number of guards a smart vault can be configured with uint256 constant MAX_GUARD_COUNT = 10; /// @dev Maximum number of actions a smart vault can be configured with uint256 constant MAX_ACTION_COUNT = 10; /// @dev ID of null asset group. Should not be used by any strategy or smart vault. uint256 constant NULL_ASSET_GROUP_ID = 0;
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.17; import "@openzeppelin/token/ERC20/IERC20.sol"; /* ========== ERRORS ========== */ /** * @notice Used when invalid ID for asset group is provided. * @param assetGroupId Invalid ID for asset group. */ error InvalidAssetGroup(uint256 assetGroupId); /** * @notice Used when no assets are provided for an asset group. */ error NoAssetsProvided(); /** * @notice Used when token is not allowed to be used as an asset. * @param token Address of the token that is not allowed. */ error TokenNotAllowed(address token); /** * @notice Used when asset group already exists. * @param assetGroupId ID of the already existing asset group. */ error AssetGroupAlreadyExists(uint256 assetGroupId); /** * @notice Used when given array is unsorted. */ error UnsortedArray(); /* ========== INTERFACES ========== */ interface IAssetGroupRegistry { /* ========== EVENTS ========== */ /** * @notice Emitted when token is allowed to be used as an asset. * @param token Address of newly allowed token. */ event TokenAllowed(address indexed token); /** * @notice Emitted when asset group is registered. * @param assetGroupId ID of the newly registered asset group. */ event AssetGroupRegistered(uint256 indexed assetGroupId); /* ========== VIEW FUNCTIONS ========== */ /** * @notice Checks if token is allowed to be used as an asset. * @param token Address of token to check. * @return isAllowed True if token is allowed, false otherwise. */ function isTokenAllowed(address token) external view returns (bool isAllowed); /** * @notice Gets number of registered asset groups. * @return count Number of registered asset groups. */ function numberOfAssetGroups() external view returns (uint256 count); /** * @notice Gets asset group by its ID. * @dev Requirements: * - must provide a valid ID for the asset group * @return assets Array of assets in the asset group. */ function listAssetGroup(uint256 assetGroupId) external view returns (address[] memory assets); /** * @notice Gets asset group length. * @dev Requirements: * - must provide a valid ID for the asset group * @return length */ function assetGroupLength(uint256 assetGroupId) external view returns (uint256 length); /** * @notice Validates that provided ID represents an asset group. * @dev Function reverts when ID does not represent an asset group. * @param assetGroupId ID to validate. */ function validateAssetGroup(uint256 assetGroupId) external view; /** * @notice Checks if asset group composed of assets already exists. * Will revert if provided assets cannot form an asset group. * @param assets Assets composing the asset group. * @return Asset group ID if such asset group exists, 0 otherwise. */ function checkAssetGroupExists(address[] calldata assets) external view returns (uint256); /* ========== MUTATIVE FUNCTIONS ========== */ /** * @notice Allows a token to be used as an asset. * @dev Requirements: * - can only be called by the ROLE_SPOOL_ADMIN * @param token Address of token to be allowed. */ function allowToken(address token) external; /** * @notice Allows tokens to be used as assets. * @dev Requirements: * - can only be called by the ROLE_SPOOL_ADMIN * @param tokens Addresses of tokens to be allowed. */ function allowTokenBatch(address[] calldata tokens) external; /** * @notice Registers a new asset group. * @dev Requirements: * - must provide at least one asset * - all assets must be allowed * - assets must be sorted * - such asset group should not exist yet * - can only be called by the ROLE_SPOOL_ADMIN * @param assets Array of assets in the asset group. * @return id Sequential ID assigned to the asset group. */ function registerAssetGroup(address[] calldata assets) external returns (uint256 id); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.17; /** * @dev Grants permission to: * - acts as a default admin for other roles, * - can whitelist an action with action manager, * - can manage asset group registry. * * Is granted to the deployer of the SpoolAccessControl contract. * * Equals to the DEFAULT_ADMIN_ROLE of the OpenZeppelin AccessControl. */ bytes32 constant ROLE_SPOOL_ADMIN = 0x00; /** * @dev Grants permission to integrate a new smart vault into the Spool ecosystem. * * Should be granted to smart vault factory contracts. */ bytes32 constant ROLE_SMART_VAULT_INTEGRATOR = keccak256("SMART_VAULT_INTEGRATOR"); /** * @dev Grants permission to * - manage rewards on smart vaults, * - manage roles on smart vaults, * - redeem for another user of a smart vault. */ bytes32 constant ROLE_SMART_VAULT_ADMIN = keccak256("SMART_VAULT_ADMIN"); /** * @dev Grants permission to manage allowlists with AllowlistGuard for a smart vault. * * Should be granted to whoever is in charge of maintaining allowlists with AllowlistGuard for a smart vault. */ bytes32 constant ROLE_GUARD_ALLOWLIST_MANAGER = keccak256("GUARD_ALLOWLIST_MANAGER"); /** * @dev Grants permission to manage assets on master wallet. * * Should be granted to: * - the SmartVaultManager contract, * - the StrategyRegistry contract, * - the DepositManager contract, * - the WithdrawalManager contract. */ bytes32 constant ROLE_MASTER_WALLET_MANAGER = keccak256("MASTER_WALLET_MANAGER"); /** * @dev Marks a contract as a smart vault manager. * * Should be granted to: * - the SmartVaultManager contract, * - the DepositManager contract. */ bytes32 constant ROLE_SMART_VAULT_MANAGER = keccak256("SMART_VAULT_MANAGER"); /** * @dev Marks a contract as a strategy registry. * * Should be granted to the StrategyRegistry contract. */ bytes32 constant ROLE_STRATEGY_REGISTRY = keccak256("STRATEGY_REGISTRY"); /** * @dev Grants permission to act as a risk provider. * * Should be granted to whoever is allowed to provide risk scores. */ bytes32 constant ROLE_RISK_PROVIDER = keccak256("RISK_PROVIDER"); /** * @dev Grants permission to act as an allocation provider. * * Should be granted to contracts that are allowed to calculate allocations. */ bytes32 constant ROLE_ALLOCATION_PROVIDER = keccak256("ALLOCATION_PROVIDER"); /** * @dev Grants permission to pause the system. */ bytes32 constant ROLE_PAUSER = keccak256("SYSTEM_PAUSER"); /** * @dev Grants permission to unpause the system. */ bytes32 constant ROLE_UNPAUSER = keccak256("SYSTEM_UNPAUSER"); /** * @dev Grants permission to manage rewards payment pool. */ bytes32 constant ROLE_REWARD_POOL_ADMIN = keccak256("REWARD_POOL_ADMIN"); /** * @dev Grants permission to reallocate smart vaults. */ bytes32 constant ROLE_REALLOCATOR = keccak256("REALLOCATOR"); /** * @dev Grants permission to be used as a strategy. */ bytes32 constant ROLE_STRATEGY = keccak256("STRATEGY"); /** * @dev Grants permission to manually set strategy apy. */ bytes32 constant ROLE_STRATEGY_APY_SETTER = keccak256("STRATEGY_APY_SETTER"); /** * @dev Grants permission to manage role ROLE_STRATEGY. */ bytes32 constant ADMIN_ROLE_STRATEGY = keccak256("ADMIN_STRATEGY"); /** * @dev Grants permission vault admins to allow redeem on behalf of other users. */ bytes32 constant ROLE_SMART_VAULT_ALLOW_REDEEM = keccak256("SMART_VAULT_ALLOW_REDEEM"); /** * @dev Grants permission to manage role ROLE_SMART_VAULT_ALLOW_REDEEM. */ bytes32 constant ADMIN_ROLE_SMART_VAULT_ALLOW_REDEEM = keccak256("ADMIN_SMART_VAULT_ALLOW_REDEEM"); /** * @dev Grants permission to run do hard work. */ bytes32 constant ROLE_DO_HARD_WORKER = keccak256("DO_HARD_WORKER"); /** * @dev Grants permission to immediately withdraw assets in case of emergency. */ bytes32 constant ROLE_EMERGENCY_WITHDRAWAL_EXECUTOR = keccak256("EMERGENCY_WITHDRAWAL_EXECUTOR"); /** * @dev Grants permission to swap with swapper. * * Should be granted to the DepositSwap contract. */ bytes32 constant ROLE_SWAPPER = keccak256("SWAPPER");
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.17; import "../interfaces/ISpoolAccessControl.sol"; import "../interfaces/CommonErrors.sol"; import "./Roles.sol"; /** * @notice Account access role verification middleware */ abstract contract SpoolAccessControllable { /* ========== CONSTANTS ========== */ /** * @dev Spool access control manager. */ ISpoolAccessControl internal immutable _accessControl; /* ========== CONSTRUCTOR ========== */ /** * @param accessControl_ Spool access control manager. */ constructor(ISpoolAccessControl accessControl_) { if (address(accessControl_) == address(0)) revert ConfigurationAddressZero(); _accessControl = accessControl_; } /* ========== INTERNAL FUNCTIONS ========== */ /** * @dev Reverts if an account is missing a role.\ * @param role Role to check for. * @param account Account to check. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!_accessControl.hasRole(role, account)) { revert MissingRole(role, account); } } /** * @dev Revert if an account is missing a role for a smartVault. * @param smartVault Address of the smart vault. * @param role Role to check for. * @param account Account to check. */ function _checkSmartVaultRole(address smartVault, bytes32 role, address account) internal view { if (!_accessControl.hasSmartVaultRole(smartVault, role, account)) { revert MissingRole(role, account); } } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (_accessControl.paused()) { revert SystemPaused(); } } function _checkNonReentrant() internal view { _accessControl.checkNonReentrant(); } function _nonReentrantBefore() internal { _accessControl.nonReentrantBefore(); } function _nonReentrantAfter() internal { _accessControl.nonReentrantAfter(); } /* ========== MODIFIERS ========== */ /** * @notice Only allows accounts with granted role. * @dev Reverts when the account fails check. * @param role Role to check for. * @param account Account to check. */ modifier onlyRole(bytes32 role, address account) { _checkRole(role, account); _; } /** * @notice Only allows accounts with granted role for a smart vault. * @dev Reverts when the account fails check. * @param smartVault Address of the smart vault. * @param role Role to check for. * @param account Account to check. */ modifier onlySmartVaultRole(address smartVault, bytes32 role, address account) { _checkSmartVaultRole(smartVault, role, account); _; } /** * @notice Only allows accounts that are Spool admins or admins of a smart vault. * @dev Reverts when the account fails check. * @param smartVault Address of the smart vault. * @param account Account to check. */ modifier onlyAdminOrVaultAdmin(address smartVault, address account) { _accessControl.checkIsAdminOrVaultAdmin(smartVault, account); _; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Prevents a contract from calling itself, or other contracts using this modifier. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } /** * @dev Check if a system has already entered in the non-reentrant state. */ modifier checkNonReentrant() { _checkNonReentrant(); _; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * ==== * * [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.5.11/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 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.6.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.17; import "@openzeppelin-upgradeable/access/IAccessControlUpgradeable.sol"; /** * @notice Used when an account is missing a required role. * @param role Required role. * @param account Account missing the required role. */ error MissingRole(bytes32 role, address account); /** * @notice Used when interacting with Spool when the system is paused. */ error SystemPaused(); /** * @notice Used when setting smart vault owner */ error SmartVaultOwnerAlreadySet(address smartVault); /** * @notice Used when a contract tries to enter in a non-reentrant state. */ error ReentrantCall(); /** * @notice Used when a contract tries to call in a non-reentrant function and doesn't have the correct role. */ error NoReentrantRole(); interface ISpoolAccessControl is IAccessControlUpgradeable { /* ========== VIEW FUNCTIONS ========== */ /** * @notice Gets owner of a smart vault. * @param smartVault Smart vault. * @return owner Owner of the smart vault. */ function smartVaultOwner(address smartVault) external view returns (address owner); /** * @notice Looks if an account has a role for a smart vault. * @param smartVault Address of the smart vault. * @param role Role to look for. * @param account Account to check. * @return hasRole True if account has the role for the smart vault, false otherwise. */ function hasSmartVaultRole(address smartVault, bytes32 role, address account) external view returns (bool hasRole); /** * @notice Checks if an account is either Spool admin or admin for a smart vault. * @dev The function reverts if account is neither. * @param smartVault Address of the smart vault. * @param account to check. */ function checkIsAdminOrVaultAdmin(address smartVault, address account) external view; /** * @notice Checks if system is paused or not. * @return isPaused True if system is paused, false otherwise. */ function paused() external view returns (bool isPaused); /* ========== MUTATIVE FUNCTIONS ========== */ /** * @notice Pauses the whole system. * @dev Requirements: * - caller must have role ROLE_PAUSER */ function pause() external; /** * @notice Unpauses the whole system. * @dev Requirements: * - caller must have role ROLE_UNPAUSER */ function unpause() external; /** * @notice Grants role to an account for a smart vault. * @dev Requirements: * - caller must have either role ROLE_SPOOL_ADMIN or role ROLE_SMART_VAULT_ADMIN for the smart vault * @param smartVault Address of the smart vault. * @param role Role to grant. * @param account Account to grant the role to. */ function grantSmartVaultRole(address smartVault, bytes32 role, address account) external; /** * @notice Revokes role from an account for a smart vault. * @dev Requirements: * - caller must have either role ROLE_SPOOL_ADMIN or role ROLE_SMART_VAULT_ADMIN for the smart vault * @param smartVault Address of the smart vault. * @param role Role to revoke. * @param account Account to revoke the role from. */ function revokeSmartVaultRole(address smartVault, bytes32 role, address account) external; /** * @notice Renounce role for a smart vault. * @param smartVault Address of the smart vault. * @param role Role to renounce. */ function renounceSmartVaultRole(address smartVault, bytes32 role) external; /** * @notice Grant ownership to smart vault and assigns admin role. * @dev Ownership can only be granted once and it should be done at vault creation time. * @param smartVault Address of the smart vault. * @param owner address to which grant ownership to */ function grantSmartVaultOwnership(address smartVault, address owner) external; /** * @notice Checks and reverts if a system has already entered in the non-reentrant state. */ function checkNonReentrant() external view; /** * @notice Sets the entered flag to true when entering for the first time. * @dev Reverts if a system has already entered before. */ function nonReentrantBefore() external; /** * @notice Resets the entered flag after the call is finished. */ function nonReentrantAfter() external; /** * @notice Emitted when ownership of a smart vault is granted to an address * @param smartVault Smart vault address * @param address_ Address of the new smart vault owner */ event SmartVaultOwnershipGranted(address indexed smartVault, address indexed address_); /** * @notice Smart vault specific role was granted * @param smartVault Smart vault address * @param role Role ID * @param account Account to which the role was granted */ event SmartVaultRoleGranted(address indexed smartVault, bytes32 indexed role, address indexed account); /** * @notice Smart vault specific role was revoked * @param smartVault Smart vault address * @param role Role ID * @param account Account for which the role was revoked */ event SmartVaultRoleRevoked(address indexed smartVault, bytes32 indexed role, address indexed account); /** * @notice Smart vault specific role was renounced * @param smartVault Smart vault address * @param role Role ID * @param account Account that renounced the role */ event SmartVaultRoleRenounced(address indexed smartVault, bytes32 indexed role, address indexed account); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.17; /** * @notice Used when an array has invalid length. */ error InvalidArrayLength(); /** * @notice Used when group of smart vaults or strategies do not have same asset group. */ error NotSameAssetGroup(); /** * @notice Used when configuring an address with a zero address. */ error ConfigurationAddressZero(); /** * @notice Used when constructor or intializer parameters are invalid. */ error InvalidConfiguration(); /** * @notice Used when fetched exchange rate is out of slippage range. */ error ExchangeRateOutOfSlippages(); /** * @notice Used when an invalid strategy is provided. * @param address_ Address of the invalid strategy. */ error InvalidStrategy(address address_); /** * @notice Used when doing low-level call on an address that is not a contract. * @param address_ Address of the contract */ error AddressNotContract(address address_); /** * @notice Used when invoking an only view execution and tx.origin is not address zero. * @param address_ Address of the tx.origin */ error OnlyViewExecution(address address_);
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
{ "remappings": [ "@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/=lib/openzeppelin-contracts/contracts/", "@solmate/=lib/solmate/src/", "create3/=lib/create3/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/", "sstore2/=lib/sstore2/contracts/", "lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/", "lib/openzeppelin-contracts:ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", "lib/openzeppelin-contracts:erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "lib/openzeppelin-contracts:forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/", "lib/openzeppelin-contracts-upgradeable:ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/", "lib/openzeppelin-contracts-upgradeable:forge-std/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/src/", "lib/solmate:ds-test/=lib/solmate/lib/ds-test/src/" ], "optimizer": { "enabled": true, "runs": 99999 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": { "script/helper/ArraysHelper.sol": { "ArraysHelper": "0x92076039b4b69576e99e338899f76dfc19f6b18c" }, "src/libraries/ArrayMapping.sol": { "ArrayMappingUint256": "0x5589c1a93ad9c910eeb31496f514b0def2cc0b3d" }, "src/libraries/SpoolUtils.sol": { "SpoolUtils": "0xee2748274586db8e4a227f39b1fd95f5ed35d81e" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ISpoolAccessControl","name":"accessControl_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"assetGroupId","type":"uint256"}],"name":"AssetGroupAlreadyExists","type":"error"},{"inputs":[],"name":"ConfigurationAddressZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"assetGroupId","type":"uint256"}],"name":"InvalidAssetGroup","type":"error"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"MissingRole","type":"error"},{"inputs":[],"name":"NoAssetsProvided","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"TokenNotAllowed","type":"error"},{"inputs":[],"name":"UnsortedArray","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetGroupId","type":"uint256"}],"name":"AssetGroupRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"TokenAllowed","type":"event"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"allowToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"allowTokenBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetGroupId","type":"uint256"}],"name":"assetGroupLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"}],"name":"checkAssetGroupExists","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"allowedTokens_","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isTokenAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetGroupId","type":"uint256"}],"name":"listAssetGroup","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberOfAssetGroups","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"}],"name":"registerAssetGroup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetGroupId","type":"uint256"}],"name":"validateAssetGroup","outputs":[],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a060405234801561001057600080fd5b50604051610f30380380610f3083398101604081905261002f91610069565b806001600160a01b0381166100575760405163bb0e4c3560e01b815260040160405180910390fd5b6001600160a01b031660805250610099565b60006020828403121561007b57600080fd5b81516001600160a01b038116811461009257600080fd5b9392505050565b608051610e7c6100b460003960006106be0152610e7c6000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c8063b53472ef11610076578063dd0fe31a1161005b578063dd0fe31a14610152578063e065ce6e14610172578063f9eaee0d1461018557600080fd5b8063b53472ef1461012c578063c1925bb61461013f57600080fd5b806346598eb4116100a757806346598eb4146100fe5780636184bcc814610111578063a224cee71461011957600080fd5b806317abe90c146100c3578063256f5300146100e9575b600080fd5b6100d66100d1366004610bef565b6101ce565b6040519081526020015b60405180910390f35b6100fc6100f7366004610bef565b6102e0565b005b6100d661010c366004610c64565b61033e565b6100d6610370565b6100fc610127366004610bef565b610387565b6100fc61013a366004610ca6565b610593565b6100d661014d366004610bef565b6105a9565b610165610160366004610c64565b6105cf565b6040516100e09190610cc8565b6100fc610180366004610c64565b610666565b6101be610193366004610ca6565b73ffffffffffffffffffffffffffffffffffffffff1660009081526032602052604090205460ff1690565b60405190151581526020016100e0565b600080336101dc8282610672565b60006101e88686610782565b6000818152603460205260409020549091501561024a57600081815260346020526040908190205490517fb725061700000000000000000000000000000000000000000000000000000000815260048101919091526024015b60405180910390fd5b60338054600181018255600091909152610287907f82a75bdeeae8604d839476ae9efd8b0e15aa447e21bfd7f41283bb54e22c9a82018787610ad8565b5060335460009061029a90600190610d51565b6000838152603460205260408082208390555191925082917fd7103fa7f47b4e44d49a12038d0409e12dd4cd610f3f78c4ca2b9aa0589157269190a29695505050505050565b6000336102ed8282610672565b60005b838110156103375761032785858381811061030d5761030d610d64565b90506020020160208101906103229190610ca6565b61099e565b61033081610d93565b90506102f0565b5050505050565b60008161034a81610a8f565b6033838154811061035d5761035d610d64565b6000918252602090912001549392505050565b60335460009061038290600190610d51565b905090565b603154610100900460ff16158080156103a75750603154600160ff909116105b806103c15750303b1580156103c1575060315460ff166001145b61044d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610241565b603180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156104ab57603180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b60005b828110156104db576104cb84848381811061030d5761030d610d64565b6104d481610d93565b90506104ae565b506040805160008082526020820192839052603380546001810182559152905161052a927f82a75bdeeae8604d839476ae9efd8b0e15aa447e21bfd7f41283bb54e22c9a829092019190610b60565b50801561058e57603180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000336105a08282610672565b61058e8361099e565b6000806105b68484610782565b6000908152603460205260409020549150505b92915050565b6060816105db81610a8f565b603383815481106105ee576105ee610d64565b9060005260206000200180548060200260200160405190810160405280929190818152602001828054801561065957602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161062e575b5050505050915050919050565b61066f81610a8f565b50565b6040517f91d148540000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82811660248301527f000000000000000000000000000000000000000000000000000000000000000016906391d1485490604401602060405180830381865afa158015610705573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107299190610dcb565b61077e576040517f75000dc00000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82166024820152604401610241565b5050565b60008181036107bd576040517fdde4739400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8281101561096c5760008111801561085a575083836107e0600184610d51565b8181106107ef576107ef610d64565b90506020020160208101906108049190610ca6565b73ffffffffffffffffffffffffffffffffffffffff1684848381811061082c5761082c610d64565b90506020020160208101906108419190610ca6565b73ffffffffffffffffffffffffffffffffffffffff1611155b15610891576040517fbd5903a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603260008585848181106108a7576108a7610d64565b90506020020160208101906108bc9190610ca6565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1661095c578383828181106108fc576108fc610d64565b90506020020160208101906109119190610ca6565b6040517f94403b7000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610241565b61096581610d93565b90506107c0565b508282604051602001610980929190610ded565b60405160208183030381529060405280519060200120905092915050565b73ffffffffffffffffffffffffffffffffffffffff81166109eb576040517fbb0e4c3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526032602052604090205460ff1661066f5773ffffffffffffffffffffffffffffffffffffffff811660008181526032602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fbeceb48aeaa805aeae57be163cca6249077a18734e408a85aa74e875c43738099190a250565b801580610a9e57506033548110155b1561066f576040517f4b1f57ad00000000000000000000000000000000000000000000000000000000815260048101829052602401610241565b828054828255906000526020600020908101928215610b50579160200282015b82811115610b505781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610af8565b50610b5c929150610bda565b5090565b828054828255906000526020600020908101928215610b50579160200282015b82811115610b5057825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b80565b5b80821115610b5c5760008155600101610bdb565b60008060208385031215610c0257600080fd5b823567ffffffffffffffff80821115610c1a57600080fd5b818501915085601f830112610c2e57600080fd5b813581811115610c3d57600080fd5b8660208260051b8501011115610c5257600080fd5b60209290920196919550909350505050565b600060208284031215610c7657600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610ca157600080fd5b919050565b600060208284031215610cb857600080fd5b610cc182610c7d565b9392505050565b6020808252825182820181905260009190848201906040850190845b81811015610d1657835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610ce4565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105c9576105c9610d22565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610dc457610dc4610d22565b5060010190565b600060208284031215610ddd57600080fd5b81518015158114610cc157600080fd5b60208082528181018390526000908460408401835b86811015610e3b5773ffffffffffffffffffffffffffffffffffffffff610e2884610c7d565b1682529183019190830190600101610e02565b50969550505050505056fea2646970667358221220a55d386dfa06405d7d6b8c43e0a70f82eccf048f9132b7ef64c5dc63d618282e64736f6c634300081100330000000000000000000000007b533e72e0cdc63aacd8cdb926ac402b846fbd13
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100be5760003560e01c8063b53472ef11610076578063dd0fe31a1161005b578063dd0fe31a14610152578063e065ce6e14610172578063f9eaee0d1461018557600080fd5b8063b53472ef1461012c578063c1925bb61461013f57600080fd5b806346598eb4116100a757806346598eb4146100fe5780636184bcc814610111578063a224cee71461011957600080fd5b806317abe90c146100c3578063256f5300146100e9575b600080fd5b6100d66100d1366004610bef565b6101ce565b6040519081526020015b60405180910390f35b6100fc6100f7366004610bef565b6102e0565b005b6100d661010c366004610c64565b61033e565b6100d6610370565b6100fc610127366004610bef565b610387565b6100fc61013a366004610ca6565b610593565b6100d661014d366004610bef565b6105a9565b610165610160366004610c64565b6105cf565b6040516100e09190610cc8565b6100fc610180366004610c64565b610666565b6101be610193366004610ca6565b73ffffffffffffffffffffffffffffffffffffffff1660009081526032602052604090205460ff1690565b60405190151581526020016100e0565b600080336101dc8282610672565b60006101e88686610782565b6000818152603460205260409020549091501561024a57600081815260346020526040908190205490517fb725061700000000000000000000000000000000000000000000000000000000815260048101919091526024015b60405180910390fd5b60338054600181018255600091909152610287907f82a75bdeeae8604d839476ae9efd8b0e15aa447e21bfd7f41283bb54e22c9a82018787610ad8565b5060335460009061029a90600190610d51565b6000838152603460205260408082208390555191925082917fd7103fa7f47b4e44d49a12038d0409e12dd4cd610f3f78c4ca2b9aa0589157269190a29695505050505050565b6000336102ed8282610672565b60005b838110156103375761032785858381811061030d5761030d610d64565b90506020020160208101906103229190610ca6565b61099e565b61033081610d93565b90506102f0565b5050505050565b60008161034a81610a8f565b6033838154811061035d5761035d610d64565b6000918252602090912001549392505050565b60335460009061038290600190610d51565b905090565b603154610100900460ff16158080156103a75750603154600160ff909116105b806103c15750303b1580156103c1575060315460ff166001145b61044d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610241565b603180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156104ab57603180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b60005b828110156104db576104cb84848381811061030d5761030d610d64565b6104d481610d93565b90506104ae565b506040805160008082526020820192839052603380546001810182559152905161052a927f82a75bdeeae8604d839476ae9efd8b0e15aa447e21bfd7f41283bb54e22c9a829092019190610b60565b50801561058e57603180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000336105a08282610672565b61058e8361099e565b6000806105b68484610782565b6000908152603460205260409020549150505b92915050565b6060816105db81610a8f565b603383815481106105ee576105ee610d64565b9060005260206000200180548060200260200160405190810160405280929190818152602001828054801561065957602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161062e575b5050505050915050919050565b61066f81610a8f565b50565b6040517f91d148540000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82811660248301527f0000000000000000000000007b533e72e0cdc63aacd8cdb926ac402b846fbd1316906391d1485490604401602060405180830381865afa158015610705573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107299190610dcb565b61077e576040517f75000dc00000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82166024820152604401610241565b5050565b60008181036107bd576040517fdde4739400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8281101561096c5760008111801561085a575083836107e0600184610d51565b8181106107ef576107ef610d64565b90506020020160208101906108049190610ca6565b73ffffffffffffffffffffffffffffffffffffffff1684848381811061082c5761082c610d64565b90506020020160208101906108419190610ca6565b73ffffffffffffffffffffffffffffffffffffffff1611155b15610891576040517fbd5903a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603260008585848181106108a7576108a7610d64565b90506020020160208101906108bc9190610ca6565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1661095c578383828181106108fc576108fc610d64565b90506020020160208101906109119190610ca6565b6040517f94403b7000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610241565b61096581610d93565b90506107c0565b508282604051602001610980929190610ded565b60405160208183030381529060405280519060200120905092915050565b73ffffffffffffffffffffffffffffffffffffffff81166109eb576040517fbb0e4c3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526032602052604090205460ff1661066f5773ffffffffffffffffffffffffffffffffffffffff811660008181526032602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fbeceb48aeaa805aeae57be163cca6249077a18734e408a85aa74e875c43738099190a250565b801580610a9e57506033548110155b1561066f576040517f4b1f57ad00000000000000000000000000000000000000000000000000000000815260048101829052602401610241565b828054828255906000526020600020908101928215610b50579160200282015b82811115610b505781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610af8565b50610b5c929150610bda565b5090565b828054828255906000526020600020908101928215610b50579160200282015b82811115610b5057825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b80565b5b80821115610b5c5760008155600101610bdb565b60008060208385031215610c0257600080fd5b823567ffffffffffffffff80821115610c1a57600080fd5b818501915085601f830112610c2e57600080fd5b813581811115610c3d57600080fd5b8660208260051b8501011115610c5257600080fd5b60209290920196919550909350505050565b600060208284031215610c7657600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610ca157600080fd5b919050565b600060208284031215610cb857600080fd5b610cc182610c7d565b9392505050565b6020808252825182820181905260009190848201906040850190845b81811015610d1657835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610ce4565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105c9576105c9610d22565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610dc457610dc4610d22565b5060010190565b600060208284031215610ddd57600080fd5b81518015158114610cc157600080fd5b60208082528181018390526000908460408401835b86811015610e3b5773ffffffffffffffffffffffffffffffffffffffff610e2884610c7d565b1682529183019190830190600101610e02565b50969550505050505056fea2646970667358221220a55d386dfa06405d7d6b8c43e0a70f82eccf048f9132b7ef64c5dc63d618282e64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007b533e72e0cdc63aacd8cdb926ac402b846fbd13
-----Decoded View---------------
Arg [0] : accessControl_ (address): 0x7b533e72E0cDC63AacD8cDB926AC402b846Fbd13
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000007b533e72e0cdc63aacd8cdb926ac402b846fbd13
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.