Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 419848004 | 14 days ago | Contract Creation | 0 ETH | |||
| 418932303 | 16 days ago | 0.0003 ETH | ||||
| 418932303 | 16 days ago | Contract Creation | 0 ETH | |||
| 418895310 | 17 days ago | Contract Creation | 0 ETH | |||
| 418263540 | 18 days ago | Contract Creation | 0 ETH | |||
| 418015606 | 19 days ago | Contract Creation | 0 ETH | |||
| 415819492 | 25 days ago | Contract Creation | 0 ETH | |||
| 415713724 | 26 days ago | Contract Creation | 0 ETH | |||
| 415713424 | 26 days ago | Contract Creation | 0 ETH | |||
| 415344312 | 27 days ago | Contract Creation | 0 ETH | |||
| 415343754 | 27 days ago | Contract Creation | 0 ETH | |||
| 415342540 | 27 days ago | Contract Creation | 0 ETH | |||
| 414968175 | 28 days ago | Contract Creation | 0 ETH | |||
| 413660506 | 32 days ago | 0.005 ETH | ||||
| 413660506 | 32 days ago | Contract Creation | 0 ETH | |||
| 413016526 | 34 days ago | Contract Creation | 0 ETH | |||
| 412923086 | 34 days ago | 0.02 ETH | ||||
| 412923086 | 34 days ago | Contract Creation | 0 ETH | |||
| 412416811 | 35 days ago | Contract Creation | 0 ETH | |||
| 412079534 | 36 days ago | 0.038 ETH | ||||
| 412079534 | 36 days ago | Contract Creation | 0 ETH | |||
| 412079171 | 36 days ago | Contract Creation | 0 ETH | |||
| 412078916 | 36 days ago | Contract Creation | 0 ETH | |||
| 412076804 | 36 days ago | Contract Creation | 0 ETH | |||
| 411703207 | 37 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
VaultFactory
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 150 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
import "../interfaces/core/IVaultFactory.sol";
import "../interfaces/core/IVault.sol";
import "../interfaces/IWETH9.sol";
/// @title VaultFactory
contract VaultFactory is OwnableUpgradeable, PausableUpgradeable, IVaultFactory {
using SafeERC20 for IERC20;
address public override WETH;
address public configManager;
address public vaultImplementation;
mapping(address => address[]) public vaultsByAddress;
address[] public allVaults;
function initialize(address _owner, address _weth, address _configManager, address _vaultImplementation)
external
initializer
{
require(
_owner != address(0) && _weth != address(0) && _configManager != address(0) && _vaultImplementation != address(0),
ZeroAddress()
);
__Ownable_init(_owner);
__Pausable_init();
WETH = _weth;
configManager = _configManager;
vaultImplementation = _vaultImplementation;
}
/// @notice Create a new vault
/// @param params Vault creation parameters
/// @return vault Address of the new vault
function createVault(VaultCreateParams memory params) external payable override whenNotPaused returns (address vault) {
vault = _createVault(params);
IVault(vault).transferOwnership(_msgSender());
}
/// @notice Create a new vault and allocate
/// @param params Vault creation parameters
/// @param inputAssets Assets to allocate
/// @param strategy Strategy to use for allocation
/// @param data Additional data for allocation
/// @return vault Address of the new vault
function createVaultAndAllocate(
VaultCreateParams memory params,
AssetLib.Asset[] calldata inputAssets,
IStrategy strategy,
bytes calldata data
) external payable override whenNotPaused returns (address vault) {
vault = _createVault(params);
IVault(vault).allocate(inputAssets, strategy, 0, data);
IVault(vault).transferOwnership(_msgSender());
}
function _createVault(VaultCreateParams memory params) internal returns (address vault) {
vault = Clones.cloneDeterministic(
vaultImplementation, keccak256(abi.encodePacked(params.name, params.symbol, _msgSender(), "3.0"))
);
address sender = _msgSender();
address principalToken = params.config.principalToken;
uint256 principalAmount = params.principalTokenAmount;
if (msg.value > 0) {
require(principalToken == WETH && principalAmount == msg.value, InvalidPrincipalToken());
IWETH9(WETH).deposit{ value: msg.value }();
IERC20(WETH).safeTransfer(vault, msg.value);
} else if (principalAmount > 0) {
IERC20(principalToken).safeTransferFrom(sender, vault, principalAmount);
}
IVault(vault).initialize(params, sender, owner(), configManager, WETH);
vaultsByAddress[sender].push(vault);
allVaults.push(vault);
emit VaultCreated(sender, vault, params);
}
/// @notice Pause the contract
function pause() external onlyOwner {
_pause();
}
/// @notice Unpause the contract
function unpause() external onlyOwner {
_unpause();
}
/// @notice Set the ConfigManager address
/// @param _configManager Address of the new ConfigManager
function setConfigManager(address _configManager) external onlyOwner {
require(_configManager != address(0), ZeroAddress());
configManager = _configManager;
emit ConfigManagerSet(_configManager);
}
/// @notice Set the Vault implementation
/// @param _vaultImplementation Address of the new vault implementation
function setVaultImplementation(address _vaultImplementation) external onlyOwner {
require(_vaultImplementation != address(0), ZeroAddress());
vaultImplementation = _vaultImplementation;
emit VaultImplementationSet(_vaultImplementation);
}
/// @notice Check if a vault created by this factory
/// @param vault Address of the vault to check
function isVault(address vault) external view override returns (bool) {
for (uint256 i = 0; i < allVaults.length; i++) {
if (allVaults[i] == vault) return true;
}
return false;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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.
*
* The initial owner is set to the address provided by the deployer. 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 OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @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) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
}
/**
* @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 Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
return $._paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
import {Create2} from "../utils/Create2.sol";
import {Errors} from "../utils/Errors.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
error CloneArgumentsTooLong();
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
return clone(implementation, 0);
}
/**
* @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
* to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function clone(address implementation, uint256 value) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
assembly ("memory-safe") {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(value, 0x09, 0x37)
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple times will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
return cloneDeterministic(implementation, salt, 0);
}
/**
* @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
* a `value` parameter to send native currency to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneDeterministic(
address implementation,
bytes32 salt,
uint256 value
) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
assembly ("memory-safe") {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(value, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
* immutable arguments. These are provided through `args` and cannot be changed after deployment. To
* access the arguments within the implementation, use {fetchCloneArgs}.
*
* This function uses the create opcode, which should never revert.
*/
function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
return cloneWithImmutableArgs(implementation, args, 0);
}
/**
* @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
* parameter to send native currency to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneWithImmutableArgs(
address implementation,
bytes memory args,
uint256 value
) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
assembly ("memory-safe") {
instance := create(value, add(bytecode, 0x20), mload(bytecode))
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation` with custom
* immutable arguments. These are provided through `args` and cannot be changed after deployment. To
* access the arguments within the implementation, use {fetchCloneArgs}.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
* `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
* at the same address.
*/
function cloneDeterministicWithImmutableArgs(
address implementation,
bytes memory args,
bytes32 salt
) internal returns (address instance) {
return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);
}
/**
* @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],
* but with a `value` parameter to send native currency to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneDeterministicWithImmutableArgs(
address implementation,
bytes memory args,
bytes32 salt,
uint256 value
) internal returns (address instance) {
bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
return Create2.deploy(value, salt, bytecode);
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
*/
function predictDeterministicAddressWithImmutableArgs(
address implementation,
bytes memory args,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
return Create2.computeAddress(salt, keccak256(bytecode), deployer);
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
*/
function predictDeterministicAddressWithImmutableArgs(
address implementation,
bytes memory args,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));
}
/**
* @dev Get the immutable args attached to a clone.
*
* - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this
* function will return an empty array.
* - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or
* `cloneDeterministicWithImmutableArgs`, this function will return the args array used at
* creation.
* - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This
* function should only be used to check addresses that are known to be clones.
*/
function fetchCloneArgs(address instance) internal view returns (bytes memory) {
bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
assembly ("memory-safe") {
extcodecopy(instance, add(result, 32), 45, mload(result))
}
return result;
}
/**
* @dev Helper that prepares the initcode of the proxy with immutable args.
*
* An assembly variant of this function requires copying the `args` array, which can be efficiently done using
* `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using
* abi.encodePacked is more expensive but also more portable and easier to review.
*
* NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.
* With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.
*/
function _cloneCodeWithImmutableArgs(
address implementation,
bytes memory args
) private pure returns (bytes memory) {
if (args.length > 24531) revert CloneArgumentsTooLong();
return
abi.encodePacked(
hex"61",
uint16(args.length + 45),
hex"3d81600a3d39f3363d3d373d3d3d363d73",
implementation,
hex"5af43d82803e903d91602b57fd5bf3",
args
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev There's no code to deploy.
*/
error Create2EmptyBytecode();
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
if (bytecode.length == 0) {
revert Create2EmptyBytecode();
}
assembly ("memory-safe") {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
// if no address was created, and returndata is not empty, bubble revert
if and(iszero(addr), not(iszero(returndatasize()))) {
let p := mload(0x40)
returndatacopy(p, 0, returndatasize())
revert(p, returndatasize())
}
}
if (addr == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
assembly ("memory-safe") {
let ptr := mload(0x40) // Get free memory pointer
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import "../ICommon.sol";
import "../strategies/IStrategy.sol";
interface IVault is ICommon {
event VaultDeposit(address indexed vaultFactory, address indexed account, uint256 principalAmount, uint256 shares);
event VaultWithdraw(address indexed vaultFactory, address indexed account, uint256 principalAmount, uint256 shares);
event VaultAllocate(
address indexed vaultFactory, AssetLib.Asset[] inputAssets, IStrategy strategy, AssetLib.Asset[] newAssets
);
event VaultHarvest(address indexed vaultFactory, AssetLib.Asset[] harvestedAssets);
event VaultHarvestPrivate(address indexed vaultFactory, address indexed owner, uint256 principalHarvestedAmount);
event SetVaultConfig(address indexed vaultFactory, VaultConfig config, uint16 vaultOwnerFeeBasisPoint);
event VaultOwnerChanged(address indexed vaultFactory, address indexed oldOwner, address indexed newOwner);
event SetVaultAdmin(address indexed vaultFactory, address indexed _address, bool indexed _isAdmin);
error VaultPaused();
error InvalidAssetToken();
error InvalidAssetAmount();
error InvalidSweepAsset();
error InvalidAssetStrategy();
error DepositAllowed();
error DepositNotAllowed();
error MaxPositionsReached();
error InvalidShares();
error Unauthorized();
error InsufficientShares();
error FailedToSendEther();
error InvalidWETH();
error InsufficientReturnAmount();
error ExceedMaxAllocatePerBlock();
error StrategyDelegateCallFailed();
function vaultOwner() external view returns (address);
function WETH() external view returns (address);
function initialize(
VaultCreateParams calldata params,
address _owner,
address _operator,
address _configManager,
address _weth
) external;
function deposit(uint256 principalAmount, uint256 minShares) external payable returns (uint256 returnShares);
function depositPrincipal(uint256 principalAmount) external payable returns (uint256 shares);
function withdraw(uint256 shares, bool unwrap, uint256 minReturnAmount) external returns (uint256 returnAmount);
function withdrawPrincipal(uint256 amount, bool unwrap) external returns (uint256 returnAmount);
function allocate(
AssetLib.Asset[] calldata inputAssets,
IStrategy strategy,
uint64 gasFeeBasisPoint,
bytes calldata data
) external;
function harvest(AssetLib.Asset calldata asset, uint64 gasFeeBasisPoint, uint256 amountTokenOutMin)
external
returns (AssetLib.Asset[] memory harvestedAssets);
function harvestPrivate(
AssetLib.Asset[] calldata asset,
bool unwrap,
uint64 gasFeeBasisPoint,
uint256 amountTokenOutMin
) external;
function getTotalValue() external view returns (uint256);
function grantAdminRole(address _address) external;
function revokeAdminRole(address _address) external;
function sweepToken(address[] calldata tokens) external;
function sweepERC721(address[] calldata _tokens, uint256[] calldata _tokenIds) external;
function sweepERC1155(address[] calldata _tokens, uint256[] calldata _tokenIds) external;
function allowDeposit(VaultConfig calldata _config, uint16 _vaultOwnerFeeBasisPoint) external;
function transferOwnership(address _newOwner) external;
function getInventory() external view returns (AssetLib.Asset[] memory assets);
function getVaultConfig()
external
view
returns (
bool allowDeposit,
uint8 rangeStrategyType,
uint8 tvlStrategyType,
address principalToken,
address[] memory supportedAddresses,
uint16 vaultOwnerFeeBasisPoint
);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import "../strategies/IStrategy.sol";
import "../ICommon.sol";
interface IVaultFactory is ICommon {
event VaultCreated(address owner, address vault, VaultCreateParams params);
event ConfigManagerSet(address configManager);
event VaultImplementationSet(address vaultImplementation);
error InvalidPrincipalToken();
function createVault(VaultCreateParams memory params) external payable returns (address vault);
function createVaultAndAllocate(
VaultCreateParams memory params,
AssetLib.Asset[] calldata inputAssets,
IStrategy strategy,
bytes calldata data
) external payable returns (address vault);
function setConfigManager(address _configManager) external;
function setVaultImplementation(address _vaultImplementation) external;
function WETH() external view returns (address);
function isVault(address vault) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
interface ICommon {
struct VaultConfig {
bool allowDeposit;
uint8 rangeStrategyType;
uint8 tvlStrategyType;
address principalToken;
address[] supportedAddresses;
}
struct VaultCreateParams {
string name;
string symbol;
uint256 principalTokenAmount;
uint16 vaultOwnerFeeBasisPoint;
VaultConfig config;
}
struct FeeConfig {
uint16 vaultOwnerFeeBasisPoint;
address vaultOwner;
uint16 platformFeeBasisPoint;
address platformFeeRecipient;
uint64 gasFeeX64;
address gasFeeRecipient;
}
struct Instruction {
uint8 instructionType;
bytes params;
}
error ZeroAddress();
error TransferFailed();
error ExternalCallFailed();
error InvalidVaultConfig();
error InvalidFeeConfig();
error InvalidStrategy();
error InvalidSwapRouter();
error InvalidInstructionType();
error InvalidSigner();
error SignatureExpired();
error ApproveFailed();
error InvalidParams();
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @title Interface for WETH9
interface IWETH9 is IERC20 {
/// @notice Deposit ether to get wrapped ether
function deposit() external payable;
/// @notice Withdraw wrapped ether to get ether
function withdraw(uint256) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
interface IFeeTaker {
enum FeeType {
PLATFORM,
OWNER,
GAS
}
event FeeCollected(
address indexed vaultAddress, FeeType indexed feeType, address indexed recipient, address token, uint256 amount
);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import "../ICommon.sol";
import { AssetLib } from "../../libraries/AssetLib.sol";
import { IFeeTaker } from "./IFeeTaker.sol";
interface IStrategy is ICommon, IFeeTaker {
error InvalidAsset();
error InvalidNumberOfAssets();
error InsufficientAmountOut();
function valueOf(AssetLib.Asset calldata asset, address principalToken) external view returns (uint256);
function convert(
AssetLib.Asset[] calldata assets,
VaultConfig calldata config,
FeeConfig calldata feeConfig,
bytes calldata data
) external payable returns (AssetLib.Asset[] memory);
function harvest(
AssetLib.Asset calldata asset,
address tokenOut,
uint256 amountTokenOutMin,
VaultConfig calldata vaultConfig,
FeeConfig calldata feeConfig
) external payable returns (AssetLib.Asset[] memory);
function convertFromPrincipal(
AssetLib.Asset calldata existingAsset,
uint256 principalTokenAmount,
VaultConfig calldata config
) external payable returns (AssetLib.Asset[] memory);
function convertToPrincipal(
AssetLib.Asset memory existingAsset,
uint256 shares,
uint256 totalSupply,
VaultConfig calldata config,
FeeConfig calldata feeConfig
) external payable returns (AssetLib.Asset[] memory);
function revalidate(AssetLib.Asset calldata asset, VaultConfig calldata config) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.28;
library AssetLib {
enum AssetType {
ERC20,
ERC721,
ERC1155
}
struct Asset {
AssetType assetType;
address strategy;
address token;
uint256 tokenId;
uint256 amount;
}
}{
"viaIR": true,
"optimizer": {
"enabled": true,
"runs": 150
},
"evmVersion": "cancun",
"metadata": {
"bytecodeHash": "none"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"ApproveFailed","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"ExternalCallFailed","type":"error"},{"inputs":[],"name":"FailedDeployment","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidFeeConfig","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidInstructionType","type":"error"},{"inputs":[],"name":"InvalidParams","type":"error"},{"inputs":[],"name":"InvalidPrincipalToken","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidStrategy","type":"error"},{"inputs":[],"name":"InvalidSwapRouter","type":"error"},{"inputs":[],"name":"InvalidVaultConfig","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"configManager","type":"address"}],"name":"ConfigManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","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":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"principalTokenAmount","type":"uint256"},{"internalType":"uint16","name":"vaultOwnerFeeBasisPoint","type":"uint16"},{"components":[{"internalType":"bool","name":"allowDeposit","type":"bool"},{"internalType":"uint8","name":"rangeStrategyType","type":"uint8"},{"internalType":"uint8","name":"tvlStrategyType","type":"uint8"},{"internalType":"address","name":"principalToken","type":"address"},{"internalType":"address[]","name":"supportedAddresses","type":"address[]"}],"internalType":"struct ICommon.VaultConfig","name":"config","type":"tuple"}],"indexed":false,"internalType":"struct ICommon.VaultCreateParams","name":"params","type":"tuple"}],"name":"VaultCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vaultImplementation","type":"address"}],"name":"VaultImplementationSet","type":"event"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allVaults","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"configManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"principalTokenAmount","type":"uint256"},{"internalType":"uint16","name":"vaultOwnerFeeBasisPoint","type":"uint16"},{"components":[{"internalType":"bool","name":"allowDeposit","type":"bool"},{"internalType":"uint8","name":"rangeStrategyType","type":"uint8"},{"internalType":"uint8","name":"tvlStrategyType","type":"uint8"},{"internalType":"address","name":"principalToken","type":"address"},{"internalType":"address[]","name":"supportedAddresses","type":"address[]"}],"internalType":"struct ICommon.VaultConfig","name":"config","type":"tuple"}],"internalType":"struct ICommon.VaultCreateParams","name":"params","type":"tuple"}],"name":"createVault","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"principalTokenAmount","type":"uint256"},{"internalType":"uint16","name":"vaultOwnerFeeBasisPoint","type":"uint16"},{"components":[{"internalType":"bool","name":"allowDeposit","type":"bool"},{"internalType":"uint8","name":"rangeStrategyType","type":"uint8"},{"internalType":"uint8","name":"tvlStrategyType","type":"uint8"},{"internalType":"address","name":"principalToken","type":"address"},{"internalType":"address[]","name":"supportedAddresses","type":"address[]"}],"internalType":"struct ICommon.VaultConfig","name":"config","type":"tuple"}],"internalType":"struct ICommon.VaultCreateParams","name":"params","type":"tuple"},{"components":[{"internalType":"enum AssetLib.AssetType","name":"assetType","type":"uint8"},{"internalType":"address","name":"strategy","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct AssetLib.Asset[]","name":"inputAssets","type":"tuple[]"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"createVaultAndAllocate","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_configManager","type":"address"},{"internalType":"address","name":"_vaultImplementation","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"isVault","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_configManager","type":"address"}],"name":"setConfigManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultImplementation","type":"address"}],"name":"setVaultImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"vaultsByAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60808060405234601557611330908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f5f3560e01c8063168cd754146109885780633f4ba83a1461090857806340e274cc146108c057806353e78b6b1461084e5780635c975abb1461081f578063652b9b41146107f1578063715018a6146107885780637fdaa55b146105275780638456cb59146104b45780638da5cb5b1461047f5780639094a91e1461043b578063ad5c464814610414578063b4e25e8014610393578063bba48a901461036a578063ca0ab07514610341578063f2fde38b146103195763f8c8765e146100d5575f80fd5b34610316576080366003190112610316576100ee610adc565b6024356001600160a01b03811690819003610314576044356001600160a01b03811690819003610310576064356001600160a01b038116929083900361030c575f5160206113045f395f51905f52549360ff8560401c1615946001600160401b03811680159081610304575b60011490816102fa575b1590816102f1575b506102e25767ffffffffffffffff1981166001175f5160206113045f395f51905f5255856102b6575b506001600160a01b0381161515806102ad575b806102a4575b8061029b575b1561028c576101d2906101c5611240565b6101cd611240565b610d05565b6101da611240565b6101e2611240565b60ff195f5160206112e45f395f51905f5254165f5160206112e45f395f51905f525560018060a01b031985541617845560018060a01b0319600154161760015560018060a01b031960025416176002556102395780f35b60ff60401b195f5160206113045f395f51905f5254165f5160206113045f395f51905f52557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b63d92e233d60e01b8652600486fd5b508315156101b4565b508215156101ae565b508115156101a8565b68ffffffffffffffffff191668010000000000000001175f5160206113045f395f51905f52555f610195565b63f92ee8a960e01b8752600487fd5b9050155f61016c565b303b159150610164565b87915061015a565b8480fd5b8380fd5b825b80fd5b50346103165760203660031901126103165761033e610336610adc565b6101cd61120d565b80f35b50346103165780600319360112610316576001546040516001600160a01b039091168152602090f35b50346103165780600319360112610316576002546040516001600160a01b039091168152602090f35b5034610316576020366003190112610316576103ad610adc565b6103b561120d565b6001600160a01b0316801561040557600180546001600160a01b031916821790556040519081527ff96974158959e95a21cb52b8ea5c0d8069c4c441e428137669ec305940dc1d1890602090a180f35b63d92e233d60e01b8252600482fd5b5034610316578060031936011261031657546040516001600160a01b039091168152602090f35b5034610316576020366003190112610316576004359060045482101561031657602061046683610c7b565b905460405160039290921b1c6001600160a01b03168152f35b50346103165780600319360112610316575f5160206112c45f395f51905f52546040516001600160a01b039091168152602090f35b50346103165780600319360112610316576104cd61120d565b6104d5610d76565b600160ff195f5160206112e45f395f51905f525416175f5160206112e45f395f51905f52557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b506080366003190112610316576004356001600160401b0381116106d957610553903690600401610b06565b816024356001600160401b0381116106d957366023820112156106d9578060040135906001600160401b0382116103145736602460a0840283010111610314576044356001600160a01b0381169490859003610310576064356001600160401b03811161030c573660238201121561030c578060040135916001600160401b038311610784573660248484010111610784576105ed610d76565b6001600160a01b03906105ff90610e8c565b1695863b15610784579391859391604051958694632578f7af60e21b865280608487016080600489015252602460a48701950190875b81811061070857505050918060246020959387958287015288604487015260031986860301606487015282855201858401378181018401869052601f01601f19160103018183875af180156106fd576106e8575b5050803b156106d95760405163f2fde38b60e01b8152336004820152828160248183865af180156106dd576106c4575b602082604051908152f35b6106cf838092610a58565b6106d957816106b9565b5080fd5b6040513d85823e3d90fd5b816106f291610a58565b6106d957815f610689565b6040513d84823e3d90fd5b92949650929490809750359060038210156107805790815260019060a09081906001600160a01b0361073c60208c01610af2565b1660208201528380831b0361075360408c01610af2565b16604082015260608a0135606082015260808a013560808201520197019101908896949288969492610635565b8980fd5b8580fd5b50346103165780600319360112610316576107a161120d565b5f5160206112c45f395f51905f5280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034610316576020366003190112610316576020610815610810610adc565b610cbc565b6040519015158152f35b5034610316578060031936011261031657602060ff5f5160206112e45f395f51905f5254166040519015158152f35b503461031657602036600319011261031657610868610adc565b61087061120d565b6001600160a01b0316801561040557600280546001600160a01b031916821790556040519081527fbdd9d70e247e204f3a2fdc76dac537ab22655589149095edf3db28d50d7baafa90602090a180f35b5034610316576040366003190112610316576108da610adc565b6001600160a01b03168152600360205260408120805460243592908310156103165760206104668484610ca7565b503461031657806003193601126103165761092161120d565b5f5160206112e45f395f51905f525460ff8116156109795760ff19165f5160206112e45f395f51905f52557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b638dfc202b60e01b8252600482fd5b6020366003190112610a25576004356001600160401b038111610a25576109b3903690600401610b06565b6109bb610d76565b6001600160a01b03906109cd90610e8c565b16803b15610a255760405163f2fde38b60e01b8152336004820152905f8260248183855af1918215610a1a57602092610a0a575b50604051908152f35b5f610a1491610a58565b5f610a01565b6040513d5f823e3d90fd5b5f80fd5b60a081019081106001600160401b03821117610a4457604052565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b03821117610a4457604052565b81601f82011215610a25578035906001600160401b038211610a445760405192610aad601f8401601f191660200185610a58565b82845260208383010111610a2557815f926020809301838601378301015290565b359060ff82168203610a2557565b600435906001600160a01b0382168203610a2557565b35906001600160a01b0382168203610a2557565b919060a083820312610a2557604051610b1e81610a29565b809380356001600160401b038111610a255783610b3c918301610a79565b825260208101356001600160401b038111610a255783610b5d918301610a79565b602083015260408101356040830152606081013561ffff81168103610a255760608301526080810135906001600160401b038211610a2557019160a083820312610a255760405192610bae84610a29565b80358015158103610a25578452610bc760208201610ace565b6020850152610bd860408201610ace565b6040850152610be960608201610af2565b60608501526080810135906001600160401b038211610a2557019080601f83011215610a25578135916001600160401b038311610a44578260051b9060405193610c366020840186610a58565b8452602080850192820101928311610a2557602001905b828210610c635750505090608091828401520152565b60208091610c7084610af2565b815201910190610c4d565b600454811015610c935760045f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b8054821015610c93575f5260205f2001905f90565b600454905f5b828110610cd0575050505f90565b610cd981610c7b565b905460039190911b1c6001600160a01b0390811690831614610cfd57600101610cc2565b505050600190565b6001600160a01b03168015610d63575f5160206112c45f395f51905f5280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b631e4fbdf760e01b5f525f60045260245ffd5b60ff5f5160206112e45f395f51905f525416610d8e57565b63d93c066560e01b5f5260045ffd5b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b906080610dec610dda845160a0855260a0850190610d9d565b60208501518482036020860152610d9d565b926040810151604084015261ffff60608201511660608401520151906080818403910152602060c0608060a085019380511515865260ff84820151168487015260ff604082015116604087015260018060a01b03606082015116606087015201519360a060808201528451809452019201905f5b818110610e6d5750505090565b82516001600160a01b0316845260209384019390920191600101610e60565b90600254915f926e5af43d82803e903d91602b57fd5bf382516020610ef86017828701518360405194859281808501988051918291018a5e8401908282015f8152815193849201905e01013360601b8152620332e360ec1b601482015203600819810184520182610a58565b51902091763d602d80600a3d3981f3363d3d373d3d3d363d7300000062ffffff8260881c16175f526effffffffffffffffffffffffffffff199060781b1617602052603760095ff56001600160a01b0381169081156111fe5760808301516060015160408401519195916001600160a01b039091169034156111b5575f546001600160a01b031691821490816111ab575b501561119c57803b15610a25575f60049160405192838092630d0e30db60e41b825234905af18015610a1a57611189575b50805460405163a9059cbb60e01b602082015260248101849052346044808301919091528152610ffd916001600160a01b0316610ff8606483610a58565b61126b565b5f5160206112c45f395f51905f525460015482546001600160a01b03928316929081169116843b1561031057604051630efbea2f60e21b815260a0600482015292849284928392919061105360a485018b610dc1565b92336024860152604485015260648401526084830152038183875af180156106fd57908291611174575b5050338152600360205260408120805490600160401b82101561116057906110aa91600182018155610ca7565b81546001600160a01b0360039290921b91821b19169084901b17905560045490600160401b82101561114c57509061110c8260017f64ebc17e4f1cfa3b3dc33c6b6e50fd0cb0f9fe4fd739a3742ddfad53b50107c79594016004556004610ca7565b81549060031b9083821b9160018060a01b03901b19161790556111476040519283923384526020840152606060408401526060830190610dc1565b0390a1565b634e487b7160e01b81526041600452602490fd5b634e487b7160e01b83526041600452602483fd5b8161117e91610a58565b61031657805f61107d565b61119591505f90610a58565b5f5f610fba565b6312b97cdb60e31b5f5260045ffd5b905034145f610f89565b806111c2575b5050610ffd565b6111f791604051916323b872dd60e01b6020840152336024840152856044840152606483015260648252610ff8608483610a58565b5f806111bb565b63b06ebf3d60e01b5f5260045ffd5b5f5160206112c45f395f51905f52546001600160a01b0316330361122d57565b63118cdaa760e01b5f523360045260245ffd5b60ff5f5160206113045f395f51905f525460401c161561125c57565b631afcd79f60e31b5f5260045ffd5b905f602091828151910182855af115610a1a575f513d6112ba57506001600160a01b0381163b155b61129a5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b6001141561129356fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a164736f6c634300081c000a
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f5f3560e01c8063168cd754146109885780633f4ba83a1461090857806340e274cc146108c057806353e78b6b1461084e5780635c975abb1461081f578063652b9b41146107f1578063715018a6146107885780637fdaa55b146105275780638456cb59146104b45780638da5cb5b1461047f5780639094a91e1461043b578063ad5c464814610414578063b4e25e8014610393578063bba48a901461036a578063ca0ab07514610341578063f2fde38b146103195763f8c8765e146100d5575f80fd5b34610316576080366003190112610316576100ee610adc565b6024356001600160a01b03811690819003610314576044356001600160a01b03811690819003610310576064356001600160a01b038116929083900361030c575f5160206113045f395f51905f52549360ff8560401c1615946001600160401b03811680159081610304575b60011490816102fa575b1590816102f1575b506102e25767ffffffffffffffff1981166001175f5160206113045f395f51905f5255856102b6575b506001600160a01b0381161515806102ad575b806102a4575b8061029b575b1561028c576101d2906101c5611240565b6101cd611240565b610d05565b6101da611240565b6101e2611240565b60ff195f5160206112e45f395f51905f5254165f5160206112e45f395f51905f525560018060a01b031985541617845560018060a01b0319600154161760015560018060a01b031960025416176002556102395780f35b60ff60401b195f5160206113045f395f51905f5254165f5160206113045f395f51905f52557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b63d92e233d60e01b8652600486fd5b508315156101b4565b508215156101ae565b508115156101a8565b68ffffffffffffffffff191668010000000000000001175f5160206113045f395f51905f52555f610195565b63f92ee8a960e01b8752600487fd5b9050155f61016c565b303b159150610164565b87915061015a565b8480fd5b8380fd5b825b80fd5b50346103165760203660031901126103165761033e610336610adc565b6101cd61120d565b80f35b50346103165780600319360112610316576001546040516001600160a01b039091168152602090f35b50346103165780600319360112610316576002546040516001600160a01b039091168152602090f35b5034610316576020366003190112610316576103ad610adc565b6103b561120d565b6001600160a01b0316801561040557600180546001600160a01b031916821790556040519081527ff96974158959e95a21cb52b8ea5c0d8069c4c441e428137669ec305940dc1d1890602090a180f35b63d92e233d60e01b8252600482fd5b5034610316578060031936011261031657546040516001600160a01b039091168152602090f35b5034610316576020366003190112610316576004359060045482101561031657602061046683610c7b565b905460405160039290921b1c6001600160a01b03168152f35b50346103165780600319360112610316575f5160206112c45f395f51905f52546040516001600160a01b039091168152602090f35b50346103165780600319360112610316576104cd61120d565b6104d5610d76565b600160ff195f5160206112e45f395f51905f525416175f5160206112e45f395f51905f52557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b506080366003190112610316576004356001600160401b0381116106d957610553903690600401610b06565b816024356001600160401b0381116106d957366023820112156106d9578060040135906001600160401b0382116103145736602460a0840283010111610314576044356001600160a01b0381169490859003610310576064356001600160401b03811161030c573660238201121561030c578060040135916001600160401b038311610784573660248484010111610784576105ed610d76565b6001600160a01b03906105ff90610e8c565b1695863b15610784579391859391604051958694632578f7af60e21b865280608487016080600489015252602460a48701950190875b81811061070857505050918060246020959387958287015288604487015260031986860301606487015282855201858401378181018401869052601f01601f19160103018183875af180156106fd576106e8575b5050803b156106d95760405163f2fde38b60e01b8152336004820152828160248183865af180156106dd576106c4575b602082604051908152f35b6106cf838092610a58565b6106d957816106b9565b5080fd5b6040513d85823e3d90fd5b816106f291610a58565b6106d957815f610689565b6040513d84823e3d90fd5b92949650929490809750359060038210156107805790815260019060a09081906001600160a01b0361073c60208c01610af2565b1660208201528380831b0361075360408c01610af2565b16604082015260608a0135606082015260808a013560808201520197019101908896949288969492610635565b8980fd5b8580fd5b50346103165780600319360112610316576107a161120d565b5f5160206112c45f395f51905f5280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034610316576020366003190112610316576020610815610810610adc565b610cbc565b6040519015158152f35b5034610316578060031936011261031657602060ff5f5160206112e45f395f51905f5254166040519015158152f35b503461031657602036600319011261031657610868610adc565b61087061120d565b6001600160a01b0316801561040557600280546001600160a01b031916821790556040519081527fbdd9d70e247e204f3a2fdc76dac537ab22655589149095edf3db28d50d7baafa90602090a180f35b5034610316576040366003190112610316576108da610adc565b6001600160a01b03168152600360205260408120805460243592908310156103165760206104668484610ca7565b503461031657806003193601126103165761092161120d565b5f5160206112e45f395f51905f525460ff8116156109795760ff19165f5160206112e45f395f51905f52557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b638dfc202b60e01b8252600482fd5b6020366003190112610a25576004356001600160401b038111610a25576109b3903690600401610b06565b6109bb610d76565b6001600160a01b03906109cd90610e8c565b16803b15610a255760405163f2fde38b60e01b8152336004820152905f8260248183855af1918215610a1a57602092610a0a575b50604051908152f35b5f610a1491610a58565b5f610a01565b6040513d5f823e3d90fd5b5f80fd5b60a081019081106001600160401b03821117610a4457604052565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b03821117610a4457604052565b81601f82011215610a25578035906001600160401b038211610a445760405192610aad601f8401601f191660200185610a58565b82845260208383010111610a2557815f926020809301838601378301015290565b359060ff82168203610a2557565b600435906001600160a01b0382168203610a2557565b35906001600160a01b0382168203610a2557565b919060a083820312610a2557604051610b1e81610a29565b809380356001600160401b038111610a255783610b3c918301610a79565b825260208101356001600160401b038111610a255783610b5d918301610a79565b602083015260408101356040830152606081013561ffff81168103610a255760608301526080810135906001600160401b038211610a2557019160a083820312610a255760405192610bae84610a29565b80358015158103610a25578452610bc760208201610ace565b6020850152610bd860408201610ace565b6040850152610be960608201610af2565b60608501526080810135906001600160401b038211610a2557019080601f83011215610a25578135916001600160401b038311610a44578260051b9060405193610c366020840186610a58565b8452602080850192820101928311610a2557602001905b828210610c635750505090608091828401520152565b60208091610c7084610af2565b815201910190610c4d565b600454811015610c935760045f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b8054821015610c93575f5260205f2001905f90565b600454905f5b828110610cd0575050505f90565b610cd981610c7b565b905460039190911b1c6001600160a01b0390811690831614610cfd57600101610cc2565b505050600190565b6001600160a01b03168015610d63575f5160206112c45f395f51905f5280546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b631e4fbdf760e01b5f525f60045260245ffd5b60ff5f5160206112e45f395f51905f525416610d8e57565b63d93c066560e01b5f5260045ffd5b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b906080610dec610dda845160a0855260a0850190610d9d565b60208501518482036020860152610d9d565b926040810151604084015261ffff60608201511660608401520151906080818403910152602060c0608060a085019380511515865260ff84820151168487015260ff604082015116604087015260018060a01b03606082015116606087015201519360a060808201528451809452019201905f5b818110610e6d5750505090565b82516001600160a01b0316845260209384019390920191600101610e60565b90600254915f926e5af43d82803e903d91602b57fd5bf382516020610ef86017828701518360405194859281808501988051918291018a5e8401908282015f8152815193849201905e01013360601b8152620332e360ec1b601482015203600819810184520182610a58565b51902091763d602d80600a3d3981f3363d3d373d3d3d363d7300000062ffffff8260881c16175f526effffffffffffffffffffffffffffff199060781b1617602052603760095ff56001600160a01b0381169081156111fe5760808301516060015160408401519195916001600160a01b039091169034156111b5575f546001600160a01b031691821490816111ab575b501561119c57803b15610a25575f60049160405192838092630d0e30db60e41b825234905af18015610a1a57611189575b50805460405163a9059cbb60e01b602082015260248101849052346044808301919091528152610ffd916001600160a01b0316610ff8606483610a58565b61126b565b5f5160206112c45f395f51905f525460015482546001600160a01b03928316929081169116843b1561031057604051630efbea2f60e21b815260a0600482015292849284928392919061105360a485018b610dc1565b92336024860152604485015260648401526084830152038183875af180156106fd57908291611174575b5050338152600360205260408120805490600160401b82101561116057906110aa91600182018155610ca7565b81546001600160a01b0360039290921b91821b19169084901b17905560045490600160401b82101561114c57509061110c8260017f64ebc17e4f1cfa3b3dc33c6b6e50fd0cb0f9fe4fd739a3742ddfad53b50107c79594016004556004610ca7565b81549060031b9083821b9160018060a01b03901b19161790556111476040519283923384526020840152606060408401526060830190610dc1565b0390a1565b634e487b7160e01b81526041600452602490fd5b634e487b7160e01b83526041600452602483fd5b8161117e91610a58565b61031657805f61107d565b61119591505f90610a58565b5f5f610fba565b6312b97cdb60e31b5f5260045ffd5b905034145f610f89565b806111c2575b5050610ffd565b6111f791604051916323b872dd60e01b6020840152336024840152856044840152606483015260648252610ff8608483610a58565b5f806111bb565b63b06ebf3d60e01b5f5260045ffd5b5f5160206112c45f395f51905f52546001600160a01b0316330361122d57565b63118cdaa760e01b5f523360045260245ffd5b60ff5f5160206113045f395f51905f525460401c161561125c57565b631afcd79f60e31b5f5260045ffd5b905f602091828151910182855af115610a1a575f513d6112ba57506001600160a01b0381163b155b61129a5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b6001141561129356fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a164736f6c634300081c000a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.