Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
20326925 | 199 days ago | Contract Creation | 0 ETH |
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 Source Code Verified (Exact Match)
Contract Name:
TradingVaultFactory
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 500 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { ITradingVaultImplementation, BaseNativeWrapperConfig, CoreAccessControlConfig } from "./ITradingVaultImplementation.sol"; import { ITradingVaultImplementationUUPS, CoreSimpleSwapConfig, CoreFeesConfig } from "./ITradingVaultImplementationUUPS.sol"; import { SignatureVerifier } from "../../../core/libraries/SignatureVerifier.sol"; import { DeadlineExceeded, MismatchedChainId, InvalidAddress } from "../../../core/libraries/DefinitiveErrors.sol"; import { DefinitiveConstants } from "../../../core/libraries/DefinitiveConstants.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { LibClone } from "../../../tools/SoladySnippets/LibClone.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; struct DeployParams { address tradingVaultImplementation; uint256 chainId; uint256 deadline; bytes32 deploySalt; BaseNativeWrapperConfig baseNativeWrapperConfig; CoreAccessControlConfig coreAccessControlConfig; CoreSimpleSwapConfig coreSimpleSwapConfig; CoreFeesConfig coreFeesConfig; } struct BeaconDeployParams { address beaconAddress; address globalTradeGuardian; uint256 chainId; uint256 deadline; bytes32 deploySalt; BaseNativeWrapperConfig baseNativeWrapperConfig; CoreAccessControlConfig coreAccessControlConfig; } /// ! Deprecated. Remove once api is updated struct CoreAccessControlConfigOld { address admin; address definitiveAdmin; address[] definitive; address[] client; } /// ! Deprecated. Remove once api is updated interface ITradingVaultImplementationOld { function initialize( BaseNativeWrapperConfig calldata baseNativeWrapperConfig, CoreAccessControlConfigOld calldata coreAccessControlConfig, address _globalTradeGuardianOverride ) external; } /// ! Deprecated. Remove once api is updated struct BeaconDeployParamsOld { address beaconAddress; address globalTradeGuardian; uint256 chainId; uint256 deadline; bytes32 deploySalt; BaseNativeWrapperConfig baseNativeWrapperConfig; CoreAccessControlConfigOld coreAccessControlConfig; } contract TradingVaultFactory is OwnableUpgradeable, UUPSUpgradeable { event LegacyDeployOnNewSignature(); event NewVaultDeploy(address sender, address vault, bytes32 salt); event NewBeaconVaultDeploy(address sender, address vault, address upgradableBeaconAddress, bytes32 salt); event SignatureVerifierAdded(address signatureVerifier); event SignatureVerifierRemoved(address signatureVerifier); /// @custom:storage-location erc7201:openzeppelin.storage.TradingVaultFactory struct TradingVaultFactoryStorage { mapping(address => bool) isSignatureVerifier; } /* solhint-disable max-line-length */ /* keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.TradingVaultFactory")) - 1)) & ~bytes32(uint256(0xff)) */ bytes32 private constant TradingVaultFactoryStorageLocation = 0x1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e0300; /* solhint-enable max-line-length */ function _getTradingVaultFactoryStorage() private pure returns (TradingVaultFactoryStorage storage $) { assembly { $.slot := TradingVaultFactoryStorageLocation } } /// @notice Constructor on the implementation contract should call _disableInitializers() /// @dev https://forum.openzeppelin.com/t/what-does-disableinitializers-function-mean/28730/2 /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(address _owner, address[] memory _initialVerifiers) external initializer { __Ownable_init(_owner); uint256 length = _initialVerifiers.length; for (uint256 i = 0; i < length; ) { _addSignatureVerifier(_initialVerifiers[i]); unchecked { ++i; } } } function _authorizeUpgrade(address) internal override onlyOwner {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UUPS Proxy deployment */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function createVault( address tradingVaultImplementation, bytes32 salt, BaseNativeWrapperConfig calldata baseNativeWrapperConfig, CoreAccessControlConfig calldata coreAccessControlConfig, CoreSimpleSwapConfig calldata coreSimpleSwapConfig, CoreFeesConfig calldata coreFeesConfig ) external payable returns (address vault) { bytes32 deploymentSalt = encodeSalt(msg.sender, salt); /// deploy using hardcoded implementation to have implementation agnostic deploy addresses vault = LibClone.deployDeterministicERC1967( 0, DefinitiveConstants.GENERIC_UUPS_PROXY_IMPLEMENTATION, deploymentSalt ); bytes memory initializeBytes = abi.encodeWithSelector( ITradingVaultImplementationUUPS.initialize.selector, baseNativeWrapperConfig, coreAccessControlConfig, coreSimpleSwapConfig, coreFeesConfig ); // Upgrade to real trading vault implementation and initialize Address.functionCallWithValue( vault, abi.encodeWithSelector( UUPSUpgradeable.upgradeToAndCall.selector, tradingVaultImplementation, initializeBytes ), msg.value ); emit NewVaultDeploy(msg.sender, vault, deploymentSalt); } function createVaultWithPermission( DeployParams calldata deployParams, bytes calldata authorizedSignature ) external payable returns (address vault) { _verifyDeploymentParams(deployParams, authorizedSignature); /// deploy using hardcoded implementation to have implementation agnostic deploy addresses vault = LibClone.deployDeterministicERC1967( 0, DefinitiveConstants.GENERIC_UUPS_PROXY_IMPLEMENTATION, deployParams.deploySalt ); bytes memory initializeBytes = abi.encodeWithSelector( ITradingVaultImplementationUUPS.initialize.selector, deployParams.baseNativeWrapperConfig, deployParams.coreAccessControlConfig, deployParams.coreSimpleSwapConfig, deployParams.coreFeesConfig ); // Upgrade to real trading vault implementation and initialize Address.functionCallWithValue( vault, abi.encodeWithSelector( UUPSUpgradeable.upgradeToAndCall.selector, deployParams.tradingVaultImplementation, initializeBytes ), msg.value ); emit NewVaultDeploy(msg.sender, vault, deployParams.deploySalt); } function getVaultAddress(bytes32 deploymentSalt) external view returns (address) { return LibClone.predictDeterministicAddressERC1967( DefinitiveConstants.GENERIC_UUPS_PROXY_IMPLEMENTATION, deploymentSalt, address(this) ); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* Beacon Proxy deployment */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function createBeaconVault( address beaconAddress, address globalTradeGuardian, bytes32 salt, BaseNativeWrapperConfig calldata baseNativeWrapperConfig, CoreAccessControlConfig calldata coreAccessControlConfig ) external payable returns (address vault) { bytes32 deploymentSalt = encodeSalt(msg.sender, salt); (, vault) = LibClone.createDeterministicERC1967BeaconProxy(beaconAddress, deploymentSalt); try ITradingVaultImplementation(vault).initialize( baseNativeWrapperConfig, coreAccessControlConfig, globalTradeGuardian ) {} catch { createBeaconVault( beaconAddress, globalTradeGuardian, deploymentSalt, baseNativeWrapperConfig, CoreAccessControlConfigOld( coreAccessControlConfig.admin, address(0), new address[](0), coreAccessControlConfig.client ) ); emit LegacyDeployOnNewSignature(); } emit NewBeaconVaultDeploy(msg.sender, vault, beaconAddress, deploymentSalt); } function createBeaconVaultWithPermission( BeaconDeployParams calldata deployParams, bytes calldata authorizedSignature ) external payable returns (address vault) { _verifyBeaconDeploymentParams(deployParams, authorizedSignature); (, vault) = LibClone.createDeterministicERC1967BeaconProxy(deployParams.beaconAddress, deployParams.deploySalt); try ITradingVaultImplementation(vault).initialize( deployParams.baseNativeWrapperConfig, deployParams.coreAccessControlConfig, deployParams.globalTradeGuardian ) {} catch { _createBeaconVaultWithPermission( BeaconDeployParamsOld( deployParams.beaconAddress, deployParams.globalTradeGuardian, deployParams.chainId, deployParams.deadline, deployParams.deploySalt, deployParams.baseNativeWrapperConfig, CoreAccessControlConfigOld( deployParams.coreAccessControlConfig.admin, address(0), new address[](0), deployParams.coreAccessControlConfig.client ) ) ); emit LegacyDeployOnNewSignature(); } emit NewBeaconVaultDeploy(msg.sender, vault, deployParams.beaconAddress, deployParams.deploySalt); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* Old Beacon Proxy deployment flow */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// ! Deprecated. Remove once api is updated function createBeaconVault( address beaconAddress, address globalTradeGuardian, bytes32 salt, BaseNativeWrapperConfig calldata baseNativeWrapperConfig, CoreAccessControlConfigOld memory coreAccessControlConfig ) public payable returns (address vault) { bytes32 deploymentSalt = encodeSalt(msg.sender, salt); (, vault) = LibClone.createDeterministicERC1967BeaconProxy(beaconAddress, deploymentSalt); ITradingVaultImplementationOld(vault).initialize( baseNativeWrapperConfig, coreAccessControlConfig, globalTradeGuardian ); emit NewBeaconVaultDeploy(msg.sender, vault, beaconAddress, deploymentSalt); } /// ! Deprecated. Remove once api is updated function createBeaconVaultWithPermission( BeaconDeployParamsOld calldata deployParams, bytes calldata authorizedSignature ) public payable returns (address vault) { _verifyBeaconDeploymentParams(deployParams, authorizedSignature); return _createBeaconVaultWithPermission(deployParams); } /// ! Deprecated. Remove once api is updated function _createBeaconVaultWithPermission( BeaconDeployParamsOld memory deployParams ) private returns (address vault) { (, vault) = LibClone.createDeterministicERC1967BeaconProxy(deployParams.beaconAddress, deployParams.deploySalt); ITradingVaultImplementationOld(vault).initialize( deployParams.baseNativeWrapperConfig, deployParams.coreAccessControlConfig, deployParams.globalTradeGuardian ); emit NewBeaconVaultDeploy(msg.sender, vault, deployParams.beaconAddress, deployParams.deploySalt); } function getBeaconVaultAddress(address beaconAddress, bytes32 deploymentSalt) external view returns (address) { return LibClone.predictDeterministicAddressERC1967BeaconProxy(beaconAddress, deploymentSalt, address(this)); } function isSignatureVerifier(address account) external view returns (bool) { TradingVaultFactoryStorage storage $ = _getTradingVaultFactoryStorage(); return $.isSignatureVerifier[account]; } function addSignatureVerifier(address _signatureVerifier) public onlyOwner { _addSignatureVerifier(_signatureVerifier); } function removeSignatureVerifier(address _signatureVerifier) public onlyOwner { _removeSignatureVerifier(_signatureVerifier); } function _addSignatureVerifier(address _signatureVerifier) private { if (_signatureVerifier == address(0)) { revert InvalidAddress(); } TradingVaultFactoryStorage storage $ = _getTradingVaultFactoryStorage(); $.isSignatureVerifier[_signatureVerifier] = true; emit SignatureVerifierAdded(_signatureVerifier); } function _removeSignatureVerifier(address _signatureVerifier) private { if (_signatureVerifier == address(0)) { revert InvalidAddress(); } TradingVaultFactoryStorage storage $ = _getTradingVaultFactoryStorage(); $.isSignatureVerifier[_signatureVerifier] = false; emit SignatureVerifierRemoved(_signatureVerifier); } function _verifyBeaconDeploymentParams( BeaconDeployParams calldata deployParams, bytes calldata signature ) private view { if (deployParams.beaconAddress == address(0)) { revert InvalidAddress(); } if (deployParams.deadline < block.timestamp) { revert DeadlineExceeded(); } if (deployParams.chainId != block.chainid && deployParams.chainId != type(uint256).max) { revert MismatchedChainId(); } TradingVaultFactoryStorage storage $ = _getTradingVaultFactoryStorage(); SignatureVerifier.verifySignature($.isSignatureVerifier, encodeBeaconDeploymentParams(deployParams), signature); } /// ! Deprecated. Remove once api is updated function _verifyBeaconDeploymentParams( BeaconDeployParamsOld calldata deployParams, bytes calldata signature ) private view { if (deployParams.beaconAddress == address(0)) { revert InvalidAddress(); } if (deployParams.deadline < block.timestamp) { revert DeadlineExceeded(); } if (deployParams.chainId != block.chainid && deployParams.chainId != type(uint256).max) { revert MismatchedChainId(); } TradingVaultFactoryStorage storage $ = _getTradingVaultFactoryStorage(); SignatureVerifier.verifySignature($.isSignatureVerifier, encodeBeaconDeploymentParams(deployParams), signature); } function _verifyDeploymentParams(DeployParams calldata deployParams, bytes calldata signature) private view { if (deployParams.tradingVaultImplementation == address(0)) { revert InvalidAddress(); } if (deployParams.deadline < block.timestamp) { revert DeadlineExceeded(); } if (deployParams.chainId != block.chainid && deployParams.chainId != type(uint256).max) { revert MismatchedChainId(); } TradingVaultFactoryStorage storage $ = _getTradingVaultFactoryStorage(); SignatureVerifier.verifySignature($.isSignatureVerifier, encodeDeploymentParams(deployParams), signature); } function encodeSalt(address sender, bytes32 deploymentSalt) public pure returns (bytes32) { return keccak256(abi.encode(deploymentSalt, sender)); } function encodeBeaconDeploymentParams(BeaconDeployParams calldata deployParams) public pure returns (bytes32) { return keccak256(abi.encode(deployParams)); } function encodeBeaconDeploymentParams(BeaconDeployParamsOld calldata deployParams) public pure returns (bytes32) { return keccak256(abi.encode(deployParams)); } function encodeDeploymentParams(DeployParams calldata deployParams) public pure returns (bytes32) { return keccak256(abi.encode(deployParams)); } }
// 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.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC1967-compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.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/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.20; import {IBeacon} from "../beacon/IBeacon.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. */ library ERC1967Utils { // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. // This will be fixed in Solidity 0.8.21. At that point we should remove these events. /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { CoreAccessControlInitiable, CoreAccessControlConfig } from "../core/CoreAccessControl/v1/CoreAccessControlInitiable.sol"; import { CoreStopGuardian } from "../core/CoreStopGuardian/v1/CoreStopGuardian.sol"; import { CoreStopGuardianTrading } from "../core/CoreStopGuardianTrading/v1/CoreStopGuardianTrading.sol"; import { DefinitiveConstants } from "../core/libraries/DefinitiveConstants.sol"; import { ICoreSimpleSwapV1 } from "../core/CoreSimpleSwap/v1/ICoreSimpleSwapV1.sol"; import { InvalidMethod } from "../core/libraries/DefinitiveErrors.sol"; import { SignatureCheckerLib } from "../tools/SoladySnippets/SignatureCheckerLib.sol"; abstract contract BaseAccessControlInitiable is CoreAccessControlInitiable, CoreStopGuardian, CoreStopGuardianTrading { /** * @dev * Modifiers inherited from CoreAccessControl: * onlyDefinitive * onlyClients * onlyWhitelisted * onlyClientAdmin * onlyDefinitiveAdmin * * Modifiers inherited from CoreStopGuardian: * stopGuarded */ function __BaseAccessControlInitiable__init( CoreAccessControlConfig calldata coreAccessControlConfig ) internal onlyInitializing { __CoreAccessControlInitiable__init(coreAccessControlConfig); _updateGlobalTradeGuardian(DefinitiveConstants.DEFAULT_GLOBAL_TRADE_GUARDIAN); } /// @dev Validate `userOp.signature` for the `userOpHash`. function _validateSignature( PackedUserOperation calldata userOp, bytes32 userOpHash ) internal view override returns (uint256 validationData) { (address signerAddress, bytes memory signature) = abi.decode(userOp.signature, (address, bytes)); bytes4 methodSig = bytes4(userOp.callData); if (hasRole(DEFAULT_ADMIN_ROLE, signerAddress)) { // Allow the default admin to sign any method } else if (methodSig == this.entryPoint.selector) { // Allow read only call to get entrypoint address } else if (_isAuthorizedDefinitiveMethod(methodSig)) { _checkAccountIsPerformer(signerAddress); } else { revert InvalidMethod(methodSig); } bool success = SignatureCheckerLib.isValidSignatureNow( signerAddress, SignatureCheckerLib.toEthSignedMessageHash(userOpHash), signature ); // solhint-disable-next-line no-inline-assembly assembly { // Returns 0 if the recovered address matches the owner. // Else returns 1, which is equivalent to: // `(success ? 0 : 1) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48))` // where `validUntil` is 0 (indefinite) and `validAfter` is 0. validationData := iszero(success) } } function _isAuthorizedDefinitiveMethod(bytes4 methodSig) internal pure returns (bool) { return methodSig == ICoreSimpleSwapV1.swap.selector; } /** * @dev Inherited from CoreStopGuardianTrading */ function updateGlobalTradeGuardian(address _globalTradeGuardian) external override onlyAdmins { return _updateGlobalTradeGuardian(_globalTradeGuardian); } /** * @dev Inherited from CoreStopGuardian */ function enableStopGuardian() public override onlyAdmins { return _enableStopGuardian(); } /** * @dev Inherited from CoreStopGuardian */ function disableStopGuardian() public override onlyClientAdmin { return _disableStopGuardian(); } /** * @dev Inherited from CoreStopGuardianTrading */ function disableTrading() public override onlyAdmins { return _disableTrading(); } /** * @dev Inherited from CoreStopGuardianTrading */ function enableTrading() public override onlyAdmins { return _enableTrading(); } /** * @dev Inherited from CoreStopGuardianTrading */ function disableWithdrawals() public override onlyClientAdmin { return _disableWithdrawals(); } /** * @dev Inherited from CoreStopGuardianTrading */ function enableWithdrawals() public override onlyClientAdmin { return _enableWithdrawals(); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { BaseAccessControlInitiable } from "./BaseAccessControlInitiable.sol"; import { DefinitiveAssets, IERC20 } from "../core/libraries/DefinitiveAssets.sol"; import { DefinitiveConstants } from "../core/libraries/DefinitiveConstants.sol"; import { InvalidFeePercent } from "../core/libraries/DefinitiveErrors.sol"; import { IGlobalGuardian } from "../tools/GlobalGuardian/IGlobalGuardian.sol"; struct CoreFeesConfig { address payable feeAccount; } abstract contract BaseFeesInitiable is BaseAccessControlInitiable { using DefinitiveAssets for IERC20; function _handleFeesOnAmount(address token, uint256 amount, uint256 feePct) internal returns (uint256 feeAmount) { uint256 mMaxFeePCT = DefinitiveConstants.MAX_FEE_PCT; if (feePct > mMaxFeePCT) { revert InvalidFeePercent(); } feeAmount = (amount * feePct) / mMaxFeePCT; if (feeAmount == 0) { return feeAmount; } if (token == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { if (_msgSender() == entryPoint()) { DefinitiveAssets.safeTransferETH(FEE_ACCOUNT(), feeAmount); } else { DefinitiveAssets.safeTransferETH(_msgSender(), feeAmount); } } else { IERC20(token).safeTransfer(FEE_ACCOUNT(), feeAmount); } } function FEE_ACCOUNT() public view returns (address) { return payable(IGlobalGuardian(GLOBAL_TRADE_GUARDIAN()).feeAccount()); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { BaseAccessControlInitiable } from "../../BaseAccessControlInitiable.sol"; import { IBaseNativeWrapperV1 } from "./IBaseNativeWrapperV1.sol"; import { DefinitiveAssets, IERC20 } from "../../../core/libraries/DefinitiveAssets.sol"; struct BaseNativeWrapperConfig { address payable wrappedNativeAssetAddress; } abstract contract BaseNativeWrapperInitiable is IBaseNativeWrapperV1, BaseAccessControlInitiable { using DefinitiveAssets for IERC20; /// @custom:storage-location erc7201:definitive.storage.BaseNativeWrapper struct BaseNativeWrapperStorage { address payable wrappedNativeAssetAddress; } // keccak256(abi.encode(uint256(keccak256("definitive.storage.BaseNativeWrapper")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant BaseNativeWrapperStorageLocation = 0x57fbe06c102296dbdfaa9e064bb0d9f51d09253320913950d5de84e9a7e6e100; function _getBaseNativeWrapperStorage() private pure returns (BaseNativeWrapperStorage storage baseNativeWrapperStorage) { assembly { baseNativeWrapperStorage.slot := BaseNativeWrapperStorageLocation } } function __BaseNativeWrapperInitiable__init( BaseNativeWrapperConfig calldata baseNativeWrapperConfig ) internal onlyInitializing { BaseNativeWrapperStorage storage s = _getBaseNativeWrapperStorage(); s.wrappedNativeAssetAddress = baseNativeWrapperConfig.wrappedNativeAssetAddress; } function WRAPPED_NATIVE_ASSET_ADDRESS() public view returns (address payable) { return _getBaseNativeWrapperStorage().wrappedNativeAssetAddress; } /** * @notice Publicly accessible method to wrap native assets * @param amount Amount of native assets to wrap */ function wrap(uint256 amount) public onlyWhitelisted nonReentrant { _wrap(amount); emit NativeAssetWrap(_msgSender(), amount, true /* wrappingToNative */); } /** * @notice Publicly accessible method to unwrap native assets * @param amount Amount of tokenized assets to unwrap */ function unwrap(uint256 amount) public onlyWhitelisted nonReentrant { _unwrap(amount); emit NativeAssetWrap(_msgSender(), amount, false /* wrappingToNative */); } /** * @notice Publicly accessible method to unwrap full balance of native assets * @dev Method is not marked as `nonReentrant` since it is a wrapper around `unwrap` */ function unwrapAll() external onlyWhitelisted { return unwrap(DefinitiveAssets.getBalance(WRAPPED_NATIVE_ASSET_ADDRESS())); } /** * @notice Internal method to wrap native assets * @dev Override this method with native asset wrapping implementation */ function _wrap(uint256 amount) internal virtual; /** * @notice Internal method to unwrap native assets * @dev Override this method with native asset unwrapping implementation */ function _unwrap(uint256 amount) internal virtual; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; interface IBaseNativeWrapperV1 { event NativeAssetWrap(address actor, uint256 amount, bool indexed wrappingToNative); function WRAPPED_NATIVE_ASSET_ADDRESS() external view returns (address payable); function wrap(uint256 amount) external; function unwrap(uint256 amount) external; function unwrapAll() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { AccessControl as OZAccessControl } from "@openzeppelin/contracts/access/AccessControl.sol"; import { ICoreAccessControlV1 } from "./ICoreAccessControlV1.sol"; import { AccountNotAdmin, AccountNotWhitelisted, AccountMissingRole } from "../../libraries/DefinitiveErrors.sol"; import { IGlobalGuardian } from "../../../tools/GlobalGuardian/IGlobalGuardian.sol"; import { CoreGlobalGuardian } from "../../CoreGlobalGuardian/CoreGlobalGuardian.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import { CoreAccountAbstraction } from "../../CoreAccountAbstraction/CoreAccountAbstraction.sol"; struct CoreAccessControlConfig { address admin; address[] client; } abstract contract CoreAccessControlInitiable is ICoreAccessControlV1, OZAccessControl, Initializable, CoreGlobalGuardian, ReentrancyGuardUpgradeable, CoreAccountAbstraction { // roles bytes32 public constant ROLE_DEFINITIVE = keccak256("DEFINITIVE"); bytes32 public constant ROLE_DEFINITIVE_ADMIN = keccak256("DEFINITIVE_ADMIN"); bytes32 public constant ROLE_CLIENT = keccak256("CLIENT"); modifier onlyDefinitive() { if (!_accountIsPerformer(_msgSender()) && msg.sender != entryPoint()) { revert AccountMissingRole(_msgSender(), ROLE_DEFINITIVE); } _; } modifier onlyDefinitiveAdmin() { bool isDefinitiveAdmin = IGlobalGuardian(GLOBAL_TRADE_GUARDIAN()).accountIsDefinitiveAdmin(_msgSender()); if (!isDefinitiveAdmin) { revert AccountMissingRole(_msgSender(), ROLE_DEFINITIVE_ADMIN); } _; } modifier onlyClients() { if (!hasRole(ROLE_CLIENT, _msgSender()) && msg.sender != entryPoint()) { revert AccountMissingRole(_msgSender(), ROLE_CLIENT); } _; } modifier onlyClientAdmin() { if (!hasRole(DEFAULT_ADMIN_ROLE, _msgSender()) && msg.sender != entryPoint()) { revert AccountMissingRole(_msgSender(), DEFAULT_ADMIN_ROLE); } _; } // default admin + definitive admin modifier onlyAdmins() { bool isAdmins = (hasRole(DEFAULT_ADMIN_ROLE, _msgSender()) || IGlobalGuardian(GLOBAL_TRADE_GUARDIAN()).accountIsDefinitiveAdmin(_msgSender())); if (!isAdmins) { revert AccountNotAdmin(_msgSender()); } _; } // client + definitive modifier onlyWhitelisted() { bool isWhitelisted = (hasRole(ROLE_CLIENT, _msgSender()) || IGlobalGuardian(GLOBAL_TRADE_GUARDIAN()).accountIsPerformer(_msgSender())); if (!isWhitelisted) { revert AccountNotWhitelisted(_msgSender()); } _; } function __CoreAccessControlInitiable__init(CoreAccessControlConfig calldata cfg) internal onlyInitializing { __ReentrancyGuard_init(); // admin _grantRole(DEFAULT_ADMIN_ROLE, cfg.admin); // clients - implicit role admin is DEFAULT_ADMIN_ROLE uint256 cfgClientLength = cfg.client.length; for (uint256 i; i < cfgClientLength; ) { _grantRole(ROLE_CLIENT, cfg.client[i]); unchecked { ++i; } } } function _checkRole(bytes32 role, address account) internal view virtual override { if (!hasRole(role, account)) { revert AccountMissingRole(account, role); } } function _checkAccountIsPerformer(address account) internal view virtual { if (!_accountIsPerformer(account)) { revert AccountMissingRole(account, ROLE_DEFINITIVE); } } function _accountIsPerformer(address account) internal view returns (bool) { return IGlobalGuardian(GLOBAL_TRADE_GUARDIAN()).accountIsPerformer(account); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; interface ICoreAccessControlV1 is IAccessControl { function ROLE_CLIENT() external returns (bytes32); function ROLE_DEFINITIVE() external returns (bytes32); function ROLE_DEFINITIVE_ADMIN() external returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; // import { SignatureCheckerLib } from "../../tools/SoladySnippets/SignatureCheckerLib.sol"; import { DefinitiveConstants } from "../libraries/DefinitiveConstants.sol"; abstract contract CoreAccountAbstraction { error Unauthorized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The packed ERC4337 user operation (userOp) struct. struct PackedUserOperation { address sender; uint256 nonce; bytes initCode; // Factory address and `factoryData` (or empty). bytes callData; bytes32 accountGasLimits; // `verificationGas` (16 bytes) and `callGas` (16 bytes). uint256 preVerificationGas; bytes32 gasFees; // `maxPriorityFee` (16 bytes) and `maxFeePerGas` (16 bytes). bytes paymasterAndData; // Paymaster fields (or empty). bytes signature; } /// @dev Call struct for the `executeBatch` function. struct Call { address target; uint256 value; bytes data; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The function selector is not recognized. error FnSelectorNotRecognized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ENTRY POINT */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the canonical ERC4337 EntryPoint contract (0.7). /// Override this function to return a different EntryPoint. function entryPoint() public view virtual returns (address) { return DefinitiveConstants.ENTRYPOINT_0_7; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXECUTION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Execute a call from this account. function execute( address target, uint256 value, bytes calldata data ) public payable onlyEntryPoint returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) calldatacopy(result, data.offset, data.length) if iszero(call(gas(), target, value, result, data.length, codesize(), 0x00)) { // Bubble up the revert if the call reverts. returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } mstore(result, returndatasize()) // Store the length. let o := add(result, 0x20) returndatacopy(o, 0x00, returndatasize()) // Copy the returndata. mstore(0x40, add(o, returndatasize())) // Allocate the memory. } } /// @dev Execute a sequence of calls from this account. function executeBatch(Call[] calldata calls) public payable onlyEntryPoint returns (bytes[] memory results) { /// @solidity memory-safe-assembly assembly { results := mload(0x40) mstore(results, calls.length) let r := add(0x20, results) let m := add(r, shl(5, calls.length)) calldatacopy(r, calls.offset, shl(5, calls.length)) for { let end := m } iszero(eq(r, end)) { r := add(r, 0x20) } { let e := add(calls.offset, mload(r)) let o := add(e, calldataload(add(e, 0x40))) calldatacopy(m, add(o, 0x20), calldataload(o)) // forgefmt: disable-next-item if iszero( call(gas(), calldataload(e), calldataload(add(e, 0x20)), m, calldataload(o), codesize(), 0x00) ) { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } mstore(r, m) // Append `m` into `results`. mstore(m, returndatasize()) // Store the length, let p := add(m, 0x20) returndatacopy(p, 0x00, returndatasize()) // and copy the returndata. m := add(p, returndatasize()) // Advance `m`. } mstore(0x40, m) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VALIDATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Validates the signature and nonce. /// The EntryPoint will make the call to the recipient only if /// this validation call returns successfully. /// /// Signature failure should be reported by returning 1 (see: `_validateSignature`). /// This allows making a "simulation call" without a valid signature. /// Other failures (e.g. nonce mismatch, or invalid signature format) /// should still revert to signal failure. function validateUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds ) external payable virtual onlyEntryPoint payPrefund(missingAccountFunds) returns (uint256 validationData) { validationData = _validateSignature(userOp, userOpHash); _validateNonce(userOp.nonce); } /// @dev Validate `userOp.signature` for the `userOpHash`. function _validateSignature( PackedUserOperation calldata userOp, bytes32 userOpHash ) internal virtual returns (uint256 validationData); /// @dev Override to validate the nonce of the userOp. /// This method may validate the nonce requirement of this account. /// e.g. /// To limit the nonce to use sequenced userOps only (no "out of order" userOps): /// `require(nonce < type(uint64).max)` /// For a hypothetical account that *requires* the nonce to be out-of-order: /// `require(nonce & type(uint64).max == 0)` /// /// The actual nonce uniqueness is managed by the EntryPoint, and thus no other /// action is needed by the account itself. function _validateNonce(uint256 nonce) internal virtual { nonce = nonce; // Silence unused variable warning. } /// @dev Sends to the EntryPoint (i.e. `msg.sender`) the missing funds for this transaction. /// Subclass MAY override this modifier for better funds management. /// (e.g. send to the EntryPoint more than the minimum required, so that in future transactions /// it will not be required to send again) /// /// `missingAccountFunds` is the minimum value this modifier should send the EntryPoint, /// which MAY be zero, in case there is enough deposit, or the userOp has a paymaster. // solhint-disable-next-line no-inline-assembly modifier payPrefund(uint256 missingAccountFunds) virtual { _; /// @solidity memory-safe-assembly assembly { if missingAccountFunds { // Ignore failure (it's EntryPoint's job to verify, not the account's). pop(call(gas(), caller(), missingAccountFunds, codesize(), 0x00, codesize(), 0x00)) } } } /// @dev Requires that the caller is the EntryPoint. modifier onlyEntryPoint() virtual { if (msg.sender != entryPoint()) revert Unauthorized(); _; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; abstract contract CoreGlobalGuardian { event GlobalTradeGuardianUpdate(address indexed globalTradeGuardian); /// @custom:storage-location erc7201:definitive.storage.CoreGlobalGuardian struct CoreGlobalGuardianStorage { address GLOBAL_TRADE_GUARDIAN; } /// keccak256(abi.encode(uint256(keccak256("definitive.storage.CoreGlobalGuardian"))- 1)) & ~bytes32(uint256(0xff)) bytes32 private constant CoreGlobalGuardianStorageLocation = 0x96888095fca464b4a45fa21ec2cd73681252b1aee41fb5e30dbff9a53008bb00; function _getCoreGlobalGuardianStorage() private pure returns (CoreGlobalGuardianStorage storage $) { assembly { $.slot := CoreGlobalGuardianStorageLocation } } function GLOBAL_TRADE_GUARDIAN() public view returns (address) { CoreGlobalGuardianStorage storage $ = _getCoreGlobalGuardianStorage(); return $.GLOBAL_TRADE_GUARDIAN; } function updateGlobalTradeGuardian(address _globalTradeGuardian) external virtual; function _updateGlobalTradeGuardian(address _globalTradeGuardian) internal { CoreGlobalGuardianStorage storage $ = _getCoreGlobalGuardianStorage(); $.GLOBAL_TRADE_GUARDIAN = _globalTradeGuardian; emit GlobalTradeGuardianUpdate(_globalTradeGuardian); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { ICoreSimpleSwapV1 } from "./ICoreSimpleSwapV1.sol"; import { DefinitiveAssets, IERC20 } from "../../libraries/DefinitiveAssets.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { CallUtils } from "../../../tools/BubbleReverts/BubbleReverts.sol"; import { DefinitiveConstants } from "../../libraries/DefinitiveConstants.sol"; import { InvalidSwapHandler, InsufficientSwapTokenBalance, SwapTokenIsOutputToken, InvalidOutputToken, InvalidReportedOutputAmount, InvalidExecutedOutputAmount } from "../../libraries/DefinitiveErrors.sol"; import { SwapPayload } from "./ICoreSimpleSwapV1.sol"; import { CoreGlobalGuardian } from "../../CoreGlobalGuardian/CoreGlobalGuardian.sol"; import { IGlobalGuardian } from "../../../tools/GlobalGuardian/IGlobalGuardian.sol"; struct CoreSimpleSwapConfig { address[] swapHandlers; } abstract contract CoreSimpleSwap is ICoreSimpleSwapV1, Context, CoreGlobalGuardian { using DefinitiveAssets for IERC20; /// TODO(Deprecated) as GlobalGuardian handles this now constructor(CoreSimpleSwapConfig memory) {} function swap( SwapPayload[] memory payloads, address outputToken, uint256 amountOutMin, uint256 feePct ) external virtual returns (uint256 outputAmount); /* solhint-disable code-complexity */ function _swap( SwapPayload[] memory payloads, address expectedOutputToken ) internal returns (uint256[] memory inputTokenAmounts, uint256 outputTokenAmount) { uint256 payloadsLength = payloads.length; inputTokenAmounts = new uint256[](payloadsLength); uint256 outputTokenBalanceStart = DefinitiveAssets.getBalance(expectedOutputToken); address mGLOBAL_TRADE_GUARDIAN = GLOBAL_TRADE_GUARDIAN(); address mSEND_FEE_TO_SENDER_ALIAS = DefinitiveConstants.SEND_FEE_TO_SENDER_ALIAS; for (uint256 i; i < payloadsLength; ) { SwapPayload memory payload = payloads[i]; if ( payload.handler == mSEND_FEE_TO_SENDER_ALIAS && payload.swapToken == DefinitiveConstants.NATIVE_ASSET_ADDRESS ) { inputTokenAmounts[i] = payload.amount; DefinitiveAssets.safeTransferETH(_msgSender(), payload.amount); unchecked { ++i; } continue; } if (payload.handler == mSEND_FEE_TO_SENDER_ALIAS) { inputTokenAmounts[i] = payload.amount; DefinitiveAssets.safeTransfer( IERC20(payload.swapToken), IGlobalGuardian(mGLOBAL_TRADE_GUARDIAN).feeAccount(), payload.amount ); unchecked { ++i; } continue; } if (!IGlobalGuardian(GLOBAL_TRADE_GUARDIAN()).accountIsSwapHandler(payload.handler)) { revert InvalidSwapHandler(); } if (expectedOutputToken == payload.swapToken) { revert SwapTokenIsOutputToken(); } uint256 outputTokenBalanceBefore = DefinitiveAssets.getBalance(expectedOutputToken); inputTokenAmounts[i] = DefinitiveAssets.getBalance(payload.swapToken); (uint256 _outputAmount, address _outputToken) = _processSwap(payload, expectedOutputToken); if (_outputToken != expectedOutputToken) { revert InvalidOutputToken(); } if (_outputAmount < payload.amountOutMin) { revert InvalidReportedOutputAmount(); } uint256 outputTokenBalanceAfter = DefinitiveAssets.getBalance(expectedOutputToken); if ((outputTokenBalanceAfter - outputTokenBalanceBefore) < payload.amountOutMin) { revert InvalidExecutedOutputAmount(); } // Update `inputTokenAmounts` to reflect the amount of tokens actually swapped inputTokenAmounts[i] -= DefinitiveAssets.getBalance(payload.swapToken); unchecked { ++i; } } outputTokenAmount = DefinitiveAssets.getBalance(expectedOutputToken) - outputTokenBalanceStart; } /* solhint-enable code-complexity */ function _processSwap(SwapPayload memory payload, address expectedOutputToken) private returns (uint256, address) { // Override payload.amount with validated amount payload.amount = _getValidatedPayloadAmount(payload); bytes memory _calldata = _getEncodedSwapHandlerCalldata(payload, expectedOutputToken, payload.isDelegate); bool _success; bytes memory _returnBytes; if (payload.isDelegate) { // slither-disable-next-line controlled-delegatecall (_success, _returnBytes) = payload.handler.delegatecall(_calldata); } else { _prepareAssetsForNonDelegateHandlerCall(payload, payload.amount); (_success, _returnBytes) = payload.handler.call(_calldata); } if (!_success) { CallUtils.revertFromReturnedData(_returnBytes); } return abi.decode(_returnBytes, (uint256, address)); } function _getEncodedSwapHandlerCalldata( SwapPayload memory payload, address expectedOutputToken, bool isDelegateCall ) internal pure virtual returns (bytes memory); function _getValidatedPayloadAmount(SwapPayload memory payload) private view returns (uint256 amount) { uint256 balance = DefinitiveAssets.getBalance(payload.swapToken); // Ensure balance > 0 DefinitiveAssets.validateAmount(balance); amount = payload.amount; if (amount != 0 && balance < amount) { revert InsufficientSwapTokenBalance(); } // maximum available balance if amount == 0 if (amount == 0) { return balance; } } function _prepareAssetsForNonDelegateHandlerCall(SwapPayload memory payload, uint256 amount) private { if (payload.swapToken == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { // Send ETH to handler DefinitiveAssets.safeTransferETH(payable(payload.handler), amount); } else { IERC20(payload.swapToken).resetAndSafeIncreaseAllowance(payload.handler, amount); } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; struct SwapPayload { address handler; uint256 amount; // set 0 for maximum available balance address swapToken; uint256 amountOutMin; bool isDelegate; bytes handlerCalldata; bytes signature; } interface ICoreSimpleSwapV1 { event SwapHandlerUpdate(address actor, address swapHandler, bool isEnabled); event SwapHandled( address[] swapTokens, uint256[] swapAmounts, address outputToken, uint256 outputAmount, uint256 feeAmount ); function swap( SwapPayload[] memory payloads, address outputToken, uint256 amountOutMin, uint256 feePct ) external returns (uint256 outputAmount); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { ICoreStopGuardianV1 } from "./ICoreStopGuardianV1.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { StopGuardianEnabled } from "../../libraries/DefinitiveErrors.sol"; abstract contract CoreStopGuardian is ICoreStopGuardianV1, Context { /// @custom:storage-location erc7201:definitive.storage.CoreStopGuardian struct CoreStopGuardianStorage { bool stopGuardianEnabled; } // keccak256(abi.encode(uint256(keccak256("definitive.storage.CoreStopGuardian")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant CoreStopGuardianStorageLocation = 0x6e256963d8788aaa49f4ac4e7631ab95aeec255e6d6477beec524cf8dfccec00; function _getCoreStopGuardianStorage() private pure returns (CoreStopGuardianStorage storage $) { assembly { $.slot := CoreStopGuardianStorageLocation } } // recommended for every public/external function modifier stopGuarded() { if (STOP_GUARDIAN_ENABLED()) { revert StopGuardianEnabled(); } _; } function STOP_GUARDIAN_ENABLED() public view override returns (bool) { CoreStopGuardianStorage storage $ = _getCoreStopGuardianStorage(); return $.stopGuardianEnabled; } function enableStopGuardian() public virtual; function disableStopGuardian() public virtual; function _enableStopGuardian() internal { CoreStopGuardianStorage storage $ = _getCoreStopGuardianStorage(); $.stopGuardianEnabled = true; emit StopGuardianUpdate(_msgSender(), true); } function _disableStopGuardian() internal { CoreStopGuardianStorage storage $ = _getCoreStopGuardianStorage(); $.stopGuardianEnabled = false; emit StopGuardianUpdate(_msgSender(), false); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; interface ICoreStopGuardianV1 { event StopGuardianUpdate(address indexed actor, bool indexed isEnabled); function STOP_GUARDIAN_ENABLED() external view returns (bool); function enableStopGuardian() external; function disableStopGuardian() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { ICoreStopGuardianTradingV1 } from "./ICoreStopGuardianTradingV1.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { WithdrawalsDisabled, TradingDisabled, GlobalStopGuardianEnabled } from "../../libraries/DefinitiveErrors.sol"; import { IGlobalGuardian } from "../../../tools/GlobalGuardian/IGlobalGuardian.sol"; import { CoreGlobalGuardian } from "../../CoreGlobalGuardian/CoreGlobalGuardian.sol"; abstract contract CoreStopGuardianTrading is ICoreStopGuardianTradingV1, Context, CoreGlobalGuardian { /// @custom:storage-location erc7201:definitive.storage.CoreStopGuardianTrading struct CoreStopGuardianTradingStorage { bool TRADING_GUARDIAN_TRADING_DISABLED; bool TRADING_GUARDIAN_WITHDRAWALS_DISABLED; } /* solhint-disable max-line-length */ // keccak256(abi.encode(uint256(keccak256("definitive.storage.CoreStopGuardianTrading")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant CoreStopGuardianTradingStorageLocation = 0x16cbd83eaf0105ad9cb99491311ec69c270710363d0a5092df3b41a81f4a9400; /* solhint-enable max-line-length */ function _getCoreStopGuardianTradingStorage() private pure returns (CoreStopGuardianTradingStorage storage $) { assembly { $.slot := CoreStopGuardianTradingStorageLocation } } /// 0x49feb0371fc9661748a3d1bc01dbf9f5cdeb4102767351e1c6dd1f5d331acd6d bytes32 internal constant GLOBAL_TRADING_HASH = keccak256("TRADING"); modifier tradingEnabled() { CoreStopGuardianTradingStorage storage $ = _getCoreStopGuardianTradingStorage(); if (IGlobalGuardian(GLOBAL_TRADE_GUARDIAN()).functionalityIsDisabled(GLOBAL_TRADING_HASH)) { revert GlobalStopGuardianEnabled(); } if ($.TRADING_GUARDIAN_TRADING_DISABLED) { revert TradingDisabled(); } _; } modifier withdrawalsEnabled() { CoreStopGuardianTradingStorage storage $ = _getCoreStopGuardianTradingStorage(); if ($.TRADING_GUARDIAN_WITHDRAWALS_DISABLED) { revert WithdrawalsDisabled(); } _; } function TRADING_GUARDIAN_TRADING_DISABLED() public view returns (bool) { CoreStopGuardianTradingStorage storage $ = _getCoreStopGuardianTradingStorage(); return $.TRADING_GUARDIAN_TRADING_DISABLED; } function disableTrading() public virtual; function enableTrading() public virtual; function disableWithdrawals() public virtual; function enableWithdrawals() public virtual; function _disableTrading() internal { CoreStopGuardianTradingStorage storage $ = _getCoreStopGuardianTradingStorage(); $.TRADING_GUARDIAN_TRADING_DISABLED = true; emit TradingDisabledUpdate(_msgSender(), true); } function _enableTrading() internal { CoreStopGuardianTradingStorage storage $ = _getCoreStopGuardianTradingStorage(); delete $.TRADING_GUARDIAN_TRADING_DISABLED; emit TradingDisabledUpdate(_msgSender(), false); } function _disableWithdrawals() internal { CoreStopGuardianTradingStorage storage $ = _getCoreStopGuardianTradingStorage(); $.TRADING_GUARDIAN_WITHDRAWALS_DISABLED = true; emit WithdrawalsDisabledUpdate(_msgSender(), true); } function _enableWithdrawals() internal { CoreStopGuardianTradingStorage storage $ = _getCoreStopGuardianTradingStorage(); delete $.TRADING_GUARDIAN_WITHDRAWALS_DISABLED; emit WithdrawalsDisabledUpdate(_msgSender(), false); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; interface ICoreStopGuardianTradingV1 { event TradingDisabledUpdate(address indexed actor, bool indexed isEnabled); event WithdrawalsDisabledUpdate(address indexed actor, bool indexed isEnabled); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { IERC20, SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { SafeTransferLib } from "solmate/src/utils/SafeTransferLib.sol"; import { DefinitiveConstants } from "./DefinitiveConstants.sol"; import { InsufficientBalance, InvalidAmount, InvalidAmounts, InvalidERC20Address } from "./DefinitiveErrors.sol"; /** * @notice Contains methods used throughout the Definitive contracts * @dev This file should only be used as an internal library. */ library DefinitiveAssets { /** * @dev Checks if an address is a valid ERC20 token */ modifier onlyValidERC20(address erc20Token) { if (address(erc20Token) == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { revert InvalidERC20Address(); } _; } ////////////////////////////////////////////////// ////////////////////////////////////////////////// // ↓ ERC20 and Native Asset Methods ↓ ////////////////////////////////////////////////// /** * @dev Gets the balance of an ERC20 token or native asset */ function getBalance(address assetAddress) internal view returns (uint256) { if (assetAddress == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { return address(this).balance; } else { return IERC20(assetAddress).balanceOf(address(this)); } } /** * @dev internal function to validate balance is higher than a given amount for ERC20 and native assets */ function validateBalance(address token, uint256 amount) internal view { if (token == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { validateNativeBalance(amount); } else { validateERC20Balance(token, amount); } } ////////////////////////////////////////////////// ////////////////////////////////////////////////// // ↓ Native Asset Methods ↓ ////////////////////////////////////////////////// /** * @dev validates amount and balance, then uses SafeTransferLib to transfer native asset */ function safeTransferETH(address recipient, uint256 amount) internal { if (amount > 0) { SafeTransferLib.safeTransferETH(payable(recipient), amount); } } ////////////////////////////////////////////////// ////////////////////////////////////////////////// // ↓ ERC20 Methods ↓ ////////////////////////////////////////////////// /** * @dev Resets and increases the allowance of a spender for an ERC20 token */ function resetAndSafeIncreaseAllowance( IERC20 token, address spender, uint256 amount ) internal onlyValidERC20(address(token)) { return SafeERC20.forceApprove(token, spender, amount); } function safeTransfer(IERC20 token, address to, uint256 amount) internal onlyValidERC20(address(token)) { if (amount > 0) { SafeERC20.safeTransfer(token, to, amount); } } function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal onlyValidERC20(address(token)) { if (amount > 0) { //slither-disable-next-line arbitrary-send-erc20 SafeERC20.safeTransferFrom(token, from, to, amount); } } ////////////////////////////////////////////////// ////////////////////////////////////////////////// // ↓ Asset Amount Helper Methods ↓ ////////////////////////////////////////////////// /** * @dev internal function to validate that amounts contains a value greater than zero */ function validateAmounts(uint256[] calldata amounts) internal pure { bool hasValidAmounts; uint256 amountsLength = amounts.length; for (uint256 i; i < amountsLength; ) { if (amounts[i] > 0) { hasValidAmounts = true; break; } unchecked { ++i; } } if (!hasValidAmounts) { revert InvalidAmounts(); } } /** * @dev internal function to validate if native asset balance is higher than the amount requested */ function validateNativeBalance(uint256 amount) internal view { if (getBalance(DefinitiveConstants.NATIVE_ASSET_ADDRESS) < amount) { revert InsufficientBalance(); } } /** * @dev internal function to validate balance is higher than the amount requested for a token */ function validateERC20Balance(address token, uint256 amount) internal view onlyValidERC20(token) { if (getBalance(token) < amount) { revert InsufficientBalance(); } } function validateAmount(uint256 _amount) internal pure { if (_amount == 0) { revert InvalidAmount(); } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; /** * @notice Contains constants used throughout the Definitive contracts * @dev This file should only be used as an internal library. */ library DefinitiveConstants { /** * @notice Maximum fee percentage */ uint256 internal constant MAX_FEE_PCT = 10000; /** * @notice Address to signify native assets */ address internal constant NATIVE_ASSET_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /** * @notice Maximum number of swaps allowed per block */ uint8 internal constant MAX_SWAPS_PER_BLOCK = 25; struct Assets { uint256[] amounts; address[] addresses; } address internal constant DEFAULT_GLOBAL_TRADE_GUARDIAN = 0xE3F35754954B0B77958C72b83EC5205971463064; address internal constant STAGING_GLOBAL_TRADE_GUARDIAN = 0xE217abF1077eC4772E4E78Ca0802046A974cba90; address internal constant LOCAL_GLOBAL_TRADE_GUARDIAN = 0x92d4Ba061336C223f774A23f9a385B7eAdFA64A6; address internal constant GENERIC_UUPS_PROXY_IMPLEMENTATION = 0x4aEb164998DB4eB8ab945620d4d1db59E2Ad5513; address internal constant SEND_FEE_TO_SENDER_ALIAS = address(0xFEE); address internal constant BLAST_NATIVE_YIELD_CONTRACT = 0x4300000000000000000000000000000000000002; address internal constant BLAST_POINTS_ADDRESS = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800; address internal constant BLAST_DEFINITIVE_OPERATOR_PROD = 0xaba36De8208002e05a757377A76D50093233Eb51; address internal constant BLAST_DEFINITIVE_OPERATOR_STAGING = 0xaf212671793921BCb84F04cEeEd1dec1EF742DAC; address internal constant ENTRYPOINT_0_7 = 0x0000000071727De22E5E9d8BAf0edAc6f37da032; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; /** * @notice Contains all errors used throughout the Definitive contracts * @dev This file should only be used as an internal library. * @dev When adding a new error, add alphabetically */ error AccountMissingRole(address _account, bytes32 _role); error AccountNotAdmin(address); error AccountNotWhitelisted(address); error AddLiquidityFailed(); error AlreadyDeployed(); error AlreadyInitialized(); error BytecodeEmpty(); error DeadlineExceeded(); error DeployInitFailed(); error DeployFailed(); error BorrowFailed(uint256 errorCode); error DecollateralizeFailed(uint256 errorCode); error DepositMoreThanMax(); error EmptyBytecode(); error EnterAllFailed(); error EnforcedSafeLTV(uint256 invalidLTV); error ExceededMaxDelta(); error ExceededMaxLTV(); error ExceededShareToAssetRatioDeltaThreshold(); error ExitAllFailed(); error ExitOneCoinFailed(); error GlobalStopGuardianEnabled(); error InitializeMarketsFailed(); error InputGreaterThanStaked(); error InsufficientBalance(); error InsufficientSwapTokenBalance(); error InvalidAddress(); error InvalidAmount(); error InvalidAmounts(); error InvalidCalldata(); error InvalidDestinationSwapper(); error InvalidERC20Address(); error InvalidExecutedOutputAmount(); error InvalidFeePercent(); error InvalidHandler(); error InvalidInputs(); error InvalidMsgValue(); error InvalidSingleHopSwap(); error InvalidMethod(bytes4 methodSig); error InvalidMultiHopSwap(); error InvalidOutputToken(); error InvalidRedemptionRecipient(); // Used in cross-chain redeptions error InvalidReportedOutputAmount(); error InvalidRewardsClaim(); error InvalidSignature(); error InvalidSignatureLength(); error InvalidSwapHandler(); error InvalidSwapInputAmount(); error InvalidSwapOutputToken(); error InvalidSwapPath(); error InvalidSwapPayload(); error InvalidSwapToken(); error MintMoreThanMax(); error MismatchedChainId(); error NativeAssetWrapFailed(bool wrappingToNative); error NoSignatureVerificationSignerSet(); error RedeemMoreThanMax(); error RemoveLiquidityFailed(); error RepayDebtFailed(); error SafeHarborModeEnabled(); error SafeHarborRedemptionDisabled(); error SlippageExceeded(uint256 _outputAmount, uint256 _outputAmountMin); error StakeFailed(); error SupplyFailed(); error StopGuardianEnabled(); error TradingDisabled(); error SwapDeadlineExceeded(); error SwapLimitExceeded(); error SwapTokenIsOutputToken(); error TransfersLimitExceeded(); error UnstakeFailed(); error UnauthenticatedFlashloan(); error UntrustedFlashLoanSender(address); error WithdrawMoreThanMax(); error WithdrawalsDisabled(); error ZeroShares();
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { InvalidSignature, InvalidSignatureLength } from "./DefinitiveErrors.sol"; library SignatureVerifier { function verifySignature( mapping(address => bool) storage validSigners, bytes32 messageHash, bytes memory signature ) internal view { bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash); address signer = recoverSigner(ethSignedMessageHash, signature); if (!validSigners[signer]) { revert InvalidSignature(); } } /* cSpell:disable */ function getEthSignedMessageHash(bytes32 messageHash) public pure returns (bytes32) { /* Signature is produced by signing a keccak256 hash with the following format: "\x19Ethereum Signed Message\n" + len(msg) + msg */ return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash)); } /* cSpell:enable */ function recoverSigner(bytes32 ethSignedMessageHash, bytes memory signature) private pure returns (address signer) { (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature); return ecrecover(ethSignedMessageHash, v, r, s); } // https://solidity-by-example.org/signature function splitSignature(bytes memory sig) private pure returns (bytes32 r, bytes32 s, uint8 v) { if (sig.length != 65) { revert InvalidSignatureLength(); } // solhint-disable-next-line no-inline-assembly assembly { /* First 32 bytes stores the length of the signature add(sig, 32) = pointer of sig + 32 effectively, skips first 32 bytes of signature mload(p) loads next 32 bytes starting at the memory address p into memory */ // first 32 bytes, after the length prefix r := mload(add(sig, 32)) // second 32 bytes s := mload(add(sig, 64)) // final byte (first byte of the next 32 bytes) v := byte(0, mload(add(sig, 96))) } // implicitly return (r, s, v) } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { BaseNativeWrapperInitiable, BaseNativeWrapperConfig } from "../../base/BaseNativeWrapper/v1/BaseNativeWrapperInitiable.sol"; import { IWETH9 } from "../../vendor/interfaces/IWETH9.sol"; abstract contract WETH9NativeWrapperInitiable is BaseNativeWrapperInitiable { function __WETH9NativeWrapperInitiable__init(BaseNativeWrapperConfig calldata config) internal onlyInitializing { __BaseNativeWrapperInitiable__init(config); } function _wrap(uint256 amount) internal override { // slither-disable-next-line arbitrary-send-eth IWETH9(WRAPPED_NATIVE_ASSET_ADDRESS()).deposit{ value: amount }(); } function _unwrap(uint256 amount) internal override { IWETH9(WRAPPED_NATIVE_ASSET_ADDRESS()).withdraw(amount); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { CoreAccessControlConfig } from "../../../base/BaseAccessControlInitiable.sol"; import { BaseNativeWrapperConfig } from "../../../modules/native-asset-wrappers/WETH9NativeWrapperInitiable.sol"; interface ITradingVaultImplementation { function initialize( BaseNativeWrapperConfig calldata baseNativeWrapperConfig, CoreAccessControlConfig calldata coreAccessControlConfig, address _globalTradeGuardianOverride ) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; import { CoreSimpleSwapConfig } from "../../../core/CoreSimpleSwap/v1/CoreSimpleSwap.sol"; import { CoreAccessControlConfig } from "../../../base/BaseAccessControlInitiable.sol"; import { CoreFeesConfig } from "../../../base/BaseFeesInitiable.sol"; import { BaseNativeWrapperConfig } from "../../../modules/native-asset-wrappers/WETH9NativeWrapperInitiable.sol"; interface ITradingVaultImplementationUUPS { function initialize( BaseNativeWrapperConfig calldata baseNativeWrapperConfig, CoreAccessControlConfig calldata coreAccessControlConfig, CoreSimpleSwapConfig calldata coreSimpleSwapConfig, CoreFeesConfig calldata coreFeesConfig ) external; }
// SPDX-License-Identifier: AGPLv3 pragma solidity >=0.8.20; import { InvalidCalldata } from "../../core/libraries/DefinitiveErrors.sol"; /** * @title Call utilities library that is absent from the OpenZeppelin * @author Superfluid * Forked from * https://github.com/superfluid-finance/protocol-monorepo/blob * /d473b4876a689efb3bbb05552040bafde364a8b2/packages/ethereum-contracts/contracts/libs/CallUtils.sol * (Separated by 2 lines to prevent going over 120 character per line limit) */ library CallUtils { /// @dev Bubble up the revert from the returnedData (supports Panic, Error & Custom Errors) /// @notice This is needed in order to provide some human-readable revert message from a call /// @param returnedData Response of the call function revertFromReturnedData(bytes memory returnedData) internal pure { if (returnedData.length < 4) { // case 1: catch all revert("CallUtils: target revert()"); // solhint-disable-line custom-errors } else { bytes4 errorSelector; // solhint-disable-next-line no-inline-assembly assembly { errorSelector := mload(add(returnedData, 0x20)) } if (errorSelector == bytes4(0x4e487b71) /* `seth sig "Panic(uint256)"` */) { // case 2: Panic(uint256) (Defined since 0.8.0) // solhint-disable-next-line max-line-length // ref: https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require) string memory reason = "CallUtils: target panicked: 0x__"; uint256 errorCode; // solhint-disable-next-line no-inline-assembly assembly { errorCode := mload(add(returnedData, 0x24)) let reasonWord := mload(add(reason, 0x20)) // [0..9] is converted to ['0'..'9'] // [0xa..0xf] is not correctly converted to ['a'..'f'] // but since panic code doesn't have those cases, we will ignore them for now! let e1 := add(and(errorCode, 0xf), 0x30) let e2 := shl(8, add(shr(4, and(errorCode, 0xf0)), 0x30)) reasonWord := or( and(reasonWord, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000), or(e2, e1) ) mstore(add(reason, 0x20), reasonWord) } revert(reason); } else { // case 3: Error(string) (Defined at least since 0.7.0) // case 4: Custom errors (Defined since 0.8.0) uint256 len = returnedData.length; // solhint-disable-next-line no-inline-assembly assembly { revert(add(returnedData, 32), len) } } } } /** * @dev Helper method to parse data and extract the method signature (selector). * * Copied from: https://github.com/argentlabs/argent-contracts/ * blob/master/contracts/modules/common/Utils.sol#L54-L60 */ function parseSelector(bytes memory callData) internal pure returns (bytes4 selector) { if (callData.length < 4) { revert InvalidCalldata(); } // solhint-disable-next-line no-inline-assembly assembly { selector := mload(add(callData, 0x20)) } } /** * @dev Pad length to 32 bytes word boundary */ function padLength32(uint256 len) internal pure returns (uint256 paddedLen) { return ((len / 32) + (((len & 31) > 0) /* rounding? */ ? 1 : 0)) * 32; } /** * @dev Validate if the data is encoded correctly with abi.encode(bytesData) * * Expected ABI Encode Layout: * | word 1 | word 2 | word 3 | the rest... * | data length | bytesData offset | bytesData length | bytesData + padLength32 zeros | */ function isValidAbiEncodedBytes(bytes memory data) internal pure returns (bool) { if (data.length < 64) return false; uint256 bytesOffset; uint256 bytesLen; // bytes offset is always expected to be 32 // solhint-disable-next-line no-inline-assembly assembly { bytesOffset := mload(add(data, 32)) } if (bytesOffset != 32) return false; // solhint-disable-next-line no-inline-assembly assembly { bytesLen := mload(add(data, 64)) } // the data length should be bytesData.length + 64 + padded bytes length return data.length == 64 + padLength32(bytesLen); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; interface IGlobalGuardian { function disable(bytes32 keyHash) external; function enable(bytes32 keyHash) external; function functionalityIsDisabled(bytes32 keyHash) external view returns (bool); function accountIsPerformer(address _account) external view returns (bool); function accountIsSwapHandler(address _account) external view returns (bool); function isDefinitiveAdmin() external view returns (bool); function isHandlerManager() external view returns (bool); function feeAccount() external view returns (address payable); function accountIsDefinitiveAdmin(address _account) external view returns (bool); function accountIsHandlerManager(address _account) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; /* solhint-disable no-inline-assembly */ /// @notice Minimal proxy library. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SoladySnippets/LibClone.sol) /// @author Minimal proxy by 0age (https://github.com/0age) /// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie /// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args) /// @author Minimal ERC1967 proxy by jtriley-eth (https://github.com/jtriley-eth/minimum-viable-proxy) /// /// @dev Minimal proxy: /// Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime, /// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern, /// which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode. /// /// @dev Minimal proxy (PUSH0 variant): /// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai. /// It is optimized first for minimal runtime gas, then for minimal bytecode. /// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as /// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai. /// Please use with caution. /// /// @dev Clones with immutable args (CWIA): /// The implementation of CWIA here implements a `receive()` method that emits the /// `ReceiveETH(uint256)` event. This skips the `DELEGATECALL` when there is no calldata, /// enabling us to accept hard gas-capped `sends` & `transfers` for maximum backwards /// composability. The minimal proxy implementation does not offer this feature. /// /// @dev Minimal ERC1967 proxy: /// An minimal ERC1967 proxy, intended to be upgraded with UUPS. /// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic. /// This proxy is automatically verified on Etherscan. /// /// @dev ERC1967I proxy: /// An variant of the minimal ERC1967 proxy, with a special code path that activates /// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the /// `implementation` address. The returned implementation is guaranteed to be valid if the /// keccak256 of the proxy's code is equal to `ERC1967I_CODE_HASH`. library LibClone { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The keccak256 of the deployed code for the ERC1967 proxy. bytes32 internal constant ERC1967_CODE_HASH = 0xaaa52c8cc8a0e3fd27ce756cc6b4e70c51423e9b597b11f32d3e49f8b1fc890d; /// @dev The keccak256 of the deployed code for the ERC1967I proxy. bytes32 internal constant ERC1967I_CODE_HASH = 0xce700223c0d4cea4583409accfc45adac4a093b3519998a9cbbe1504dadba6f7; /// @dev The keccak256 of the deployed code for the ERC1967 beacon proxy. bytes32 internal constant ERC1967_BEACON_PROXY_CODE_HASH = 0x14044459af17bc4f0f5aa2f658cb692add77d1302c29fe2aebab005eea9d1162; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to deploy the clone. error DeploymentFailed(); /// @dev The salt must start with either the zero address or `by`. error SaltDoesNotStartWith(); /// @dev The ETH transfer has failed. error ETHTransferFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a clone of `implementation`. function clone(address implementation) internal returns (address instance) { instance = clone(0, implementation); } /// @dev Deploys a clone of `implementation`. /// Deposits `value` ETH during deployment. function clone(uint256 value, address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * --------------------------------------------------------------------------+ * CREATION (9 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * --------------------------------------------------------------------------| * RUNTIME (44 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * | * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 0 | | * | * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | | * 37 | CALLDATACOPY | 0 0 0 0 | [0..cds): calldata | * | * ::: delegate call to the implementation contract :::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata | * | * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x2a | PUSH1 0x2a | 0x2a success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * --------------------------------------------------------------------------+ */ mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) instance := create(value, 0x0c, 0x35) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Deploys a deterministic clone of `implementation` with `salt`. function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { instance = cloneDeterministic(0, implementation, salt); } /// @dev Deploys a deterministic clone of `implementation` with `salt`. /// Deposits `value` ETH during deployment. function cloneDeterministic( uint256 value, address implementation, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) instance := create2(value, 0x0c, 0x35, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the clone of `implementation`. function initCode(address implementation) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(add(result, 0x40), 0x5af43d3d93803e602a57fd5bf30000000000000000000000) mstore(add(result, 0x28), implementation) mstore(add(result, 0x14), 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) mstore(result, 0x35) // Store the length. mstore(0x40, add(result, 0x60)) // Allocate memory. } } /// @dev Returns the initialization code hash of the clone of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) hash := keccak256(0x0c, 0x35) mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the address of the deterministic clone of `implementation`, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL PROXY OPERATIONS (PUSH0 VARIANT) */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a PUSH0 clone of `implementation`. function clone_PUSH0(address implementation) internal returns (address instance) { instance = clone_PUSH0(0, implementation); } /// @dev Deploys a PUSH0 clone of `implementation`. /// Deposits `value` ETH during deployment. function clone_PUSH0(uint256 value, address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * --------------------------------------------------------------------------+ * CREATION (9 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 5f | PUSH0 | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 5f | PUSH0 | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * --------------------------------------------------------------------------| * RUNTIME (45 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * | * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: | * 5f | PUSH0 | 0 | | * 5f | PUSH0 | 0 0 | | * | * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 | | * 5f | PUSH0 | 0 cds 0 0 | | * 5f | PUSH0 | 0 0 cds 0 0 | | * 37 | CALLDATACOPY | 0 0 | [0..cds): calldata | * | * ::: delegate call to the implementation contract :::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 | [0..cds): calldata | * 5f | PUSH0 | 0 cds 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success | [0..cds): calldata | * | * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success | [0..cds): calldata | * 5f | PUSH0 | 0 rds success | [0..cds): calldata | * 5f | PUSH0 | 0 0 rds success | [0..cds): calldata | * 3e | RETURNDATACOPY | success | [0..rds): returndata | * | * 60 0x29 | PUSH1 0x29 | 0x29 success | [0..rds): returndata | * 57 | JUMPI | | [0..rds): returndata | * | * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..rds): returndata | * 5f | PUSH0 | 0 rds | [0..rds): returndata | * fd | REVERT | | [0..rds): returndata | * | * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..rds): returndata | * 3d | RETURNDATASIZE | rds | [0..rds): returndata | * 5f | PUSH0 | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * --------------------------------------------------------------------------+ */ mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 instance := create(value, 0x0e, 0x36) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x24, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`. function cloneDeterministic_PUSH0(address implementation, bytes32 salt) internal returns (address instance) { instance = cloneDeterministic_PUSH0(0, implementation, salt); } /// @dev Deploys a deterministic PUSH0 clone of `implementation` with `salt`. /// Deposits `value` ETH during deployment. function cloneDeterministic_PUSH0( uint256 value, address implementation, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 instance := create2(value, 0x0e, 0x36, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x24, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the PUSH0 clone of `implementation`. function initCode_PUSH0(address implementation) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(add(result, 0x40), 0x5af43d5f5f3e6029573d5ffd5b3d5ff300000000000000000000) // 16 mstore(add(result, 0x26), implementation) // 20 mstore(add(result, 0x12), 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 mstore(result, 0x36) // Store the length. mstore(0x40, add(result, 0x60)) // Allocate memory. } } /// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 hash := keccak256(0x0e, 0x36) mstore(0x24, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the address of the deterministic PUSH0 clone of `implementation`, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress_PUSH0( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash_PUSH0(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CLONES WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: This implementation of CWIA differs from the original implementation. // If the calldata is empty, it will emit a `ReceiveETH(uint256)` event and skip the `DELEGATECALL`. /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `data`. function clone(address implementation, bytes memory data) internal returns (address instance) { instance = clone(0, implementation, data); } /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `data`. /// Deposits `value` ETH during deployment. function clone(uint256 value, address implementation, bytes memory data) internal returns (address instance) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) // The `creationSize` is `extraLength + 108` // The `runSize` is `creationSize - 10`. /** * ---------------------------------------------------------------------------------------------------+ * CREATION (10 bytes) | * ---------------------------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------------------------| * 61 runSize | PUSH2 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------------------------| * RUNTIME (98 bytes + extraLength) | * ---------------------------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------------------------| * | * ::: if no calldata, emit event & return w/o `DELEGATECALL` ::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 60 0x2c | PUSH1 0x2c | 0x2c cds | | * 57 | JUMPI | | | * 34 | CALLVALUE | cv | | * 3d | RETURNDATASIZE | 0 cv | | * 52 | MSTORE | | [0..0x20): callvalue | * 7f sig | PUSH32 0x9e.. | sig | [0..0x20): callvalue | * 59 | MSIZE | 0x20 sig | [0..0x20): callvalue | * 3d | RETURNDATASIZE | 0 0x20 sig | [0..0x20): callvalue | * a1 | LOG1 | | [0..0x20): callvalue | * 00 | STOP | | [0..0x20): callvalue | * 5b | JUMPDEST | | | * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..cds): calldata | * | * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 0 | [0..cds): calldata | * 61 extra | PUSH2 extra | e 0 0 0 0 | [0..cds): calldata | * | * ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 80 | DUP1 | e e 0 0 0 0 | [0..cds): calldata | * 60 0x62 | PUSH1 0x62 | 0x62 e e 0 0 0 0 | [0..cds): calldata | * 36 | CALLDATASIZE | cds 0x62 e e 0 0 0 0 | [0..cds): calldata | * 39 | CODECOPY | e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * | * ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 01 | ADD | cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 3d | RETURNDATASIZE | 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 73 addr | PUSH20 addr | addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 5a | GAS | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * | * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x60 | PUSH1 0x60 | 0x60 success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * ---------------------------------------------------------------------------------------------------+ */ mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data. mstore(sub(data, 0x0d), implementation) // Write the address of the implementation. // Write the rest of the bytecode. mstore(sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)) // `keccak256("ReceiveETH(uint256)")` mstore(sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff) mstore( // Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e. // The actual EVM limit may be smaller and may change over time. sub(data, add(0x59, lt(extraLength, 0xff9e))), or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) instance := create(value, sub(data, 0x4c), add(extraLength, 0x6c)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `data` and `salt`. function cloneDeterministic( address implementation, bytes memory data, bytes32 salt ) internal returns (address instance) { instance = cloneDeterministic(0, implementation, data, salt); } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `data` and `salt`. function cloneDeterministic( uint256 value, address implementation, bytes memory data, bytes32 salt ) internal returns (address instance) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data. mstore(sub(data, 0x0d), implementation) // Write the address of the implementation. // Write the rest of the bytecode. mstore(sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)) // `keccak256("ReceiveETH(uint256)")` mstore(sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff) mstore( // Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e. // The actual EVM limit may be smaller and may change over time. sub(data, add(0x59, lt(extraLength, 0xff9e))), or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) instance := create2(value, sub(data, 0x4c), add(extraLength, 0x6c), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Returns the initialization code hash of the clone of `implementation` /// using immutable arguments encoded in `data`. function initCode(address implementation, bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let dataLength := mload(data) // Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b. // The actual EVM limit may be smaller and may change over time. returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b)) let o := add(result, 0x8c) let end := add(o, dataLength) // Copy the `data` into `result`. for { let d := sub(add(data, 0x20), o) } 1 { } { mstore(o, mload(add(o, d))) o := add(o, 0x20) if iszero(lt(o, end)) { break } } // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) mstore(add(result, 0x6c), 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data. mstore(add(result, 0x5f), implementation) // Write the address of the implementation. // Write the rest of the bytecode. mstore(add(result, 0x4b), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)) // `keccak256("ReceiveETH(uint256)")` mstore(add(result, 0x32), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff) mstore(add(result, 0x12), or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)) mstore(end, shl(0xf0, extraLength)) mstore(add(end, 0x02), 0) // Zeroize the slot after the result. mstore(result, add(extraLength, 0x6c)) // Store the length. mstore(0x40, add(0x22, end)) // Allocate memory. } } /// @dev Returns the initialization code hash of the clone of `implementation` /// using immutable arguments encoded in `data`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(address implementation, bytes memory data) internal pure returns (bytes32 hash) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b. // The actual EVM limit may be smaller and may change over time. returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b)) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data. mstore(sub(data, 0x0d), implementation) // Write the address of the implementation. // Write the rest of the bytecode. mstore(sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73)) // `keccak256("ReceiveETH(uint256)")` mstore(sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff) mstore(sub(data, 0x5a), or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f)) mstore(dataEnd, shl(0xf0, extraLength)) hash := keccak256(sub(data, 0x4c), add(extraLength, 0x6c)) // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Returns the address of the deterministic clone of /// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress( address implementation, bytes memory data, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation, data); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL ERC1967 PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: The ERC1967 proxy here is intended to be upgraded with UUPS. // This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic. /// @dev Deploys a minimal ERC1967 proxy with `implementation`. function deployERC1967(address implementation) internal returns (address instance) { instance = deployERC1967(0, implementation); } /// @dev Deploys a minimal ERC1967 proxy with `implementation`. /// Deposits `value` ETH during deployment. function deployERC1967(uint256 value, address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------------+ * CREATION (34 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * 73 impl | PUSH20 impl | impl 0 r | [0..runSize): runtime code | * 60 slotPos | PUSH1 slotPos | slotPos impl 0 r | [0..runSize): runtime code | * 51 | MLOAD | slot impl 0 r | [0..runSize): runtime code | * 55 | SSTORE | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------| * RUNTIME (61 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..calldatasize): calldata | * | * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata | * 7f slot | PUSH32 slot | s 0 cds 0 0 | [0..calldatasize): calldata | * 54 | SLOAD | i 0 cds 0 0 | [0..calldatasize): calldata | * 5a | GAS | g i 0 cds 0 0 | [0..calldatasize): calldata | * f4 | DELEGATECALL | succ | [0..calldatasize): calldata | * | * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata | * 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata | * 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata | * 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata | * | * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: | * 60 0x38 | PUSH1 0x38 | dest succ | [0..returndatasize): returndata | * 57 | JUMPI | | [0..returndatasize): returndata | * | * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * fd | REVERT | | [0..returndatasize): returndata | * | * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..returndatasize): returndata | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * f3 | RETURN | | [0..returndatasize): returndata | * ---------------------------------------------------------------------------------+ */ let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) instance := create(value, 0x21, 0x5f) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`. function deployDeterministicERC1967(address implementation, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967(0, implementation, salt); } /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967( uint256 value, address implementation, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) instance := create2(value, 0x21, 0x5f, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation` and `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967( address implementation, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967(0, implementation, salt); } /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation` and `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967( uint256 value, address implementation, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) // Compute and store the bytecode hash. mstore(add(m, 0x35), keccak256(0x21, 0x5f)) mstore(m, shl(88, address())) mstore8(m, 0xff) // Write the prefix. mstore(add(m, 0x15), salt) instance := keccak256(m, 0x55) for { } 1 { } { if iszero(extcodesize(instance)) { instance := create2(value, 0x21, 0x5f, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation`. function initCodeERC1967(address implementation) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(add(result, 0x60), 0x3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f300) mstore(add(result, 0x40), 0x55f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076cc) mstore(add(result, 0x20), or(shl(24, implementation), 0x600951)) mstore(add(result, 0x09), 0x603d3d8160223d3973) mstore(result, 0x5f) // Store the length. mstore(0x40, add(result, 0x80)) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHashERC1967(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) hash := keccak256(0x21, 0x5f) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the deterministic ERC1967 proxy of `implementation`, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967I PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: This proxy has a special code path that activates if `calldatasize() == 1`. // This code path skips the delegatecall and directly returns the `implementation` address. // The returned implementation is guaranteed to be valid if the keccak256 of the // proxy's code is equal to `ERC1967I_CODE_HASH`. /// @dev Deploys a minimal ERC1967I proxy with `implementation`. function deployERC1967I(address implementation) internal returns (address instance) { instance = deployERC1967I(0, implementation); } /// @dev Deploys a ERC1967I proxy with `implementation`. /// Deposits `value` ETH during deployment. function deployERC1967I(uint256 value, address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------------+ * CREATION (34 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * 73 impl | PUSH20 impl | impl 0 r | [0..runSize): runtime code | * 60 slotPos | PUSH1 slotPos | slotPos impl 0 r | [0..runSize): runtime code | * 51 | MLOAD | slot impl 0 r | [0..runSize): runtime code | * 55 | SSTORE | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------| * RUNTIME (82 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * | * ::: check calldatasize ::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 58 | PC | 1 cds | | * 14 | EQ | eqs | | * 60 0x43 | PUSH1 0x43 | dest eqs | | * 57 | JUMPI | | | * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..calldatasize): calldata | * | * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata | * 7f slot | PUSH32 slot | s 0 cds 0 0 | [0..calldatasize): calldata | * 54 | SLOAD | i 0 cds 0 0 | [0..calldatasize): calldata | * 5a | GAS | g i 0 cds 0 0 | [0..calldatasize): calldata | * f4 | DELEGATECALL | succ | [0..calldatasize): calldata | * | * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata | * 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata | * 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata | * 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata | * | * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: | * 60 0x3E | PUSH1 0x3E | dest succ | [0..returndatasize): returndata | * 57 | JUMPI | | [0..returndatasize): returndata | * | * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * fd | REVERT | | [0..returndatasize): returndata | * | * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..returndatasize): returndata | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * f3 | RETURN | | [0..returndatasize): returndata | * | * ::: implementation , return :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | | * 60 0x20 | PUSH1 0x20 | 32 | | * 60 0x0F | PUSH1 0x0F | o 32 | | * 3d | RETURNDATASIZE | 0 o 32 | | * 39 | CODECOPY | | [0..32): implementation slot | * 3d | RETURNDATASIZE | 0 | [0..32): implementation slot | * 51 | MLOAD | slot | [0..32): implementation slot | * 54 | SLOAD | impl | [0..32): implementation slot | * 3d | RETURNDATASIZE | 0 impl | [0..32): implementation slot | * 52 | MSTORE | | [0..32): implementation address | * 59 | MSIZE | 32 | [0..32): implementation address | * 3d | RETURNDATASIZE | 0 32 | [0..32): implementation address | * f3 | RETURN | | [0..32): implementation address | * ---------------------------------------------------------------------------------+ */ let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation)))) instance := create(value, 0x0c, 0x74) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Deploys a deterministic ERC1967I proxy with `implementation` and `salt`. function deployDeterministicERC1967I(address implementation, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967I(0, implementation, salt); } /// @dev Deploys a deterministic ERC1967I proxy with `implementation` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967I( uint256 value, address implementation, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation)))) instance := create2(value, 0x0c, 0x74, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Creates a deterministic ERC1967I proxy with `implementation` and `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967I( address implementation, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967I(0, implementation, salt); } /// @dev Creates a deterministic ERC1967I proxy with `implementation` and `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967I( uint256 value, address implementation, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation)))) // Compute and store the bytecode hash. mstore(add(m, 0x35), keccak256(0x0c, 0x74)) mstore(m, shl(88, address())) mstore8(m, 0xff) // Write the prefix. mstore(add(m, 0x15), salt) instance := keccak256(m, 0x55) for { } 1 { } { if iszero(extcodesize(instance)) { instance := create2(value, 0x0c, 0x74, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation`. function initCodeERC1967I(address implementation) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(add(result, 0x74), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(result, 0x54), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(result, 0x34), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(result, 0x1d), implementation) mstore(add(result, 0x09), 0x60523d8160223d3973) mstore(add(result, 0x94), 0) mstore(result, 0x74) // Store the length. mstore(0x40, add(result, 0xa0)) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHashERC1967I(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(0x40, 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(0x20, 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, implementation)))) hash := keccak256(0x0c, 0x74) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the deterministic ERC1967I proxy of `implementation`, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967I( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967I(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANT ERC1967 BOOTSTRAP OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: This enables an ERC1967 proxy to be deployed at a deterministic address // independent of the implementation: // ``` // address bootstrap = LibClone.constantERC1967Bootstrap(); // address instance = LibClone.deployDeterministicERC1967(0, bootstrap, salt); // LibClone.bootstrapConstantERC1967(bootstrap, implementation); // ``` /// @dev Deploys the constant ERC1967 bootstrap if it has not been deployed. function constantERC1967Bootstrap() internal returns (address bootstrap) { bootstrap = constantERC1967BootstrapAddress(); /// @solidity memory-safe-assembly assembly { if iszero(extcodesize(bootstrap)) { mstore(0x20, 0x0894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55) mstore(0x00, 0x60258060093d393df358357f36) if iszero(create2(0, 0x13, 0x2e, 0)) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } } /// @dev Returns the implementation address of the ERC1967 bootstrap for this contract. function constantERC1967BootstrapAddress() internal view returns (address bootstrap) { bytes32 hash = 0xfe1a42b9c571a6a8c083c94ac67b9cfd74e2582923426aa3b762e3431d717cd1; bootstrap = predictDeterministicAddress(hash, bytes32(0), address(this)); } /// @dev Replaces the implementation at `instance`. function bootstrapERC1967(address instance, address implementation) internal { /// @solidity memory-safe-assembly assembly { mstore(0x00, shr(96, shl(96, implementation))) if iszero(call(gas(), instance, 0, 0x00, 0x20, codesize(), 0x00)) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL ERC1967 BEACON PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: If you use this proxy, you MUST make sure that the beacon is a // valid ERC1967 beacon. This means that the beacon must always return a valid // address upon a staticcall to `implementation()`, given sufficient gas. // For performance, the deployment operations and the proxy assumes that the // beacon is always valid and will NOT validate it. /// @dev Deploys a minimal ERC1967 beacon proxy. function deployERC1967BeaconProxy(address beacon) internal returns (address instance) { instance = deployERC1967BeaconProxy(0, beacon); } /// @dev Deploys a minimal ERC1967 beacon proxy. /// Deposits `value` ETH during deployment. function deployERC1967BeaconProxy(uint256 value, address beacon) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------------+ * CREATION (34 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * 73 beac | PUSH20 beac | beac 0 r | [0..runSize): runtime code | * 60 slotPos | PUSH1 slotPos | slotPos beac 0 r | [0..runSize): runtime code | * 51 | MLOAD | slot beac 0 r | [0..runSize): runtime code | * 55 | SSTORE | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------| * RUNTIME (82 bytes) | * ---------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------| * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..calldatasize): calldata | * | * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 36 | CALLDATASIZE | cds 0 0 | [0..calldatasize): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 | [0..calldatasize): calldata | * | * ~~~~~~~ beacon staticcall sub procedure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 60 0x20 | PUSH1 0x20 | 32 | | * 36 | CALLDATASIZE | cds 32 | | * 60 0x04 | PUSH1 0x04 | 4 cds 32 | | * 36 | CALLDATASIZE | cds 4 cds 32 | | * 63 0x5c60da1b | PUSH4 0x5c60da1b | 0x5c60da1b cds 4 cds 32 | | * 60 0xe0 | PUSH1 0xe0 | 224 0x5c60da1b cds 4 cds 32 | | * 1b | SHL | sel cds 4 cds 32 | | * 36 | CALLDATASIZE | cds sel cds 4 cds 32 | | * 52 | MSTORE | cds 4 cds 32 | sel | * 7f slot | PUSH32 slot | s cds 4 cds 32 | sel | * 54 | SLOAD | beac cds 4 cds 32 | sel | * 5a | GAS | g beac cds 4 cds 32 | sel | * fa | STATICCALL | succ | impl | * 50 | POP | | impl | * 36 | CALLDATASIZE | cds | impl | * 51 | MLOAD | impl | impl | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 5a | GAS | g impl 0 cds 0 0 | [0..calldatasize): calldata | * f4 | DELEGATECALL | succ | [0..calldatasize): calldata | * | * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds succ | [0..calldatasize): calldata | * 60 0x00 | PUSH1 0x00 | 0 rds succ | [0..calldatasize): calldata | * 80 | DUP1 | 0 0 rds succ | [0..calldatasize): calldata | * 3e | RETURNDATACOPY | succ | [0..returndatasize): returndata | * | * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: | * 60 0x4d | PUSH1 0x4d | dest succ | [0..returndatasize): returndata | * 57 | JUMPI | | [0..returndatasize): returndata | * | * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * fd | REVERT | | [0..returndatasize): returndata | * | * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [0..returndatasize): returndata | * 3d | RETURNDATASIZE | rds | [0..returndatasize): returndata | * 60 0x00 | PUSH1 0x00 | 0 rds | [0..returndatasize): returndata | * f3 | RETURN | | [0..returndatasize): returndata | * ---------------------------------------------------------------------------------+ */ let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon)))) instance := create(value, 0x0c, 0x74) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `salt`. function deployDeterministicERC1967BeaconProxy(address beacon, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967BeaconProxy(0, beacon, salt); } /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967BeaconProxy( uint256 value, address beacon, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon)))) instance := create2(value, 0x0c, 0x74, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `salt`. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967BeaconProxy( address beacon, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967BeaconProxy(0, beacon, salt); } /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `salt`. /// Deposits `value` ETH during deployment. /// Note: This method is intended for use in ERC4337 factories, /// which are expected to NOT revert if the proxy is already deployed. function createDeterministicERC1967BeaconProxy( uint256 value, address beacon, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon)))) // Compute and store the bytecode hash. mstore(add(m, 0x35), keccak256(0x0c, 0x74)) mstore(m, shl(88, address())) mstore8(m, 0xff) // Write the prefix. mstore(add(m, 0x15), salt) instance := keccak256(m, 0x55) for { } 1 { } { if iszero(extcodesize(instance)) { instance := create2(value, 0x0c, 0x74, salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } break } alreadyDeployed := 1 if iszero(value) { break } if iszero(call(gas(), instance, value, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } break } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the initialization code of the minimal ERC1967 beacon proxy. function initCodeERC1967BeaconProxy(address beacon) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(add(result, 0x74), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(result, 0x54), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(result, 0x34), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(result, 0x1d), beacon) mstore(add(result, 0x09), 0x60523d8160223d3973) mstore(add(result, 0x94), 0) mstore(result, 0x74) // Store the length. mstore(0x40, add(result, 0xa0)) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 beacon proxy. /// Used for mining vanity addresses with create2crunch. function initCodeHashERC1967BeaconProxy(address beacon) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(0x40, 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(0x09, or(shl(160, 0x60523d8160223d3973), shr(96, shl(96, beacon)))) hash := keccak256(0x0c, 0x74) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the deterministic ERC1967 beacon proxy, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967BeaconProxy( address beacon, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967BeaconProxy(beacon); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the address when a contract with initialization code hash, /// `hash`, is deployed with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress( bytes32 hash, bytes32 salt, address deployer ) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, hash) mstore(0x01, shl(96, deployer)) mstore(0x15, salt) predicted := keccak256(0x00, 0x55) mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Requires that `salt` starts with either the zero address or `by`. function checkStartsWith(bytes32 salt, address by) internal pure { /// @solidity memory-safe-assembly assembly { // If the salt does not start with the zero address or `by`. if iszero(or(iszero(shr(96, salt)), eq(shr(96, shl(96, by)), shr(96, salt)))) { mstore(0x00, 0x0c4549ef) // `SaltDoesNotStartWith()`. revert(0x1c, 0x04) } } } } /* solhint-eanble no-inline-assembly */
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /* solhint-disable no-inline-assembly */ /// @notice Signature verification helper that supports both ECDSA signatures from EOAs /// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol) /// /// @dev Note: /// - The signature checking functions use the ecrecover precompile (0x1). /// - The `bytes memory signature` variants use the identity precompile (0x4) /// to copy memory internally. /// - Unlike ECDSA signatures, contract signatures are revocable. /// - As of Solady version 0.0.134, all `bytes signature` variants accept both /// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures. /// See: https://eips.ethereum.org/EIPS/eip-2098 /// This is for calldata efficiency on smart accounts prevalent on L2s. /// /// WARNING! Do NOT use signatures as unique identifiers: /// - Use a nonce in the digest to prevent replay attacks on the same contract. /// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts. /// EIP-712 also enables readable signing of typed data for better user safety. /// This implementation does NOT check if a signature is non-malleable. library SignatureCheckerLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIGNATURE CHECKING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `signature` is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer { } { let m := mload(0x40) mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. if eq(mload(signature), 64) { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } if eq(mload(signature), 65) { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. // Copy the `signature` over. let n := add(0x20, mload(signature)) pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n)) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(returndatasize(), 0x44), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) break } } } /// @dev Returns whether `signature` is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNowCalldata( address signer, bytes32 hash, bytes calldata signature ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer { } { let m := mload(0x40) mstore(0x00, hash) if eq(signature.length, 64) { let vs := calldataload(add(signature.offset, 0x20)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, calldataload(signature.offset)) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } if eq(signature.length, 65) { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), signature.length) // Copy the `signature` over. calldatacopy(add(m, 0x64), signature.offset, signature.length) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(signature.length, 0x64), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) break } } } /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow( address signer, bytes32 hash, bytes32 r, bytes32 vs ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer { } { let m := mload(0x40) mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), mload(0x60)) // `s`. mstore8(add(m, 0xa4), mload(0x20)) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } } /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow( address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer { } { let m := mload(0x40) mstore(0x00, hash) mstore(0x20, and(v, 0xff)) // `v`. mstore(0x40, r) // `r`. mstore(0x60, s) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), s) // `s`. mstore8(add(m, 0xa4), v) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1271 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: These ERC1271 operations do NOT have an ECDSA fallback. // These functions are intended to be used with the regular `isValidSignatureNow` functions // or other signature verification functions (e.g. P256). /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract. function isValidERC1271SignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. // Copy the `signature` over. let n := add(0x20, mload(signature)) pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n)) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(returndatasize(), 0x44), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract. function isValidERC1271SignatureNowCalldata( address signer, bytes32 hash, bytes calldata signature ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), signature.length) // Copy the `signature` over. calldatacopy(add(m, 0x64), signature.offset, signature.length) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(signature.length, 0x64), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash` /// for an ERC1271 `signer` contract. function isValidERC1271SignatureNow( address signer, bytes32 hash, bytes32 r, bytes32 vs ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`. mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash` /// for an ERC1271 `signer` contract. function isValidERC1271SignatureNow( address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), s) // `s`. mstore8(add(m, 0xa4), v) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC6492 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: These ERC6492 operations do NOT have an ECDSA fallback. // These functions are intended to be used with the regular `isValidSignatureNow` functions // or other signature verification functions (e.g. P256). // The calldata variants are excluded for brevity. /// @dev Returns whether `signature` is valid for `hash`. /// If the signature is postfixed with the ERC6492 magic number, it will attempt to /// deploy / prepare the `signer` smart account before doing a regular ERC1271 check. /// Note: This function is NOT reentrancy safe. function isValidERC6492SignatureNowAllowSideEffects( address signer, bytes32 hash, bytes memory signature ) internal returns (bool isValid) { /// @solidity memory-safe-assembly assembly { function callIsValidSignature(signer_, hash_, signature_) -> _isValid { let m_ := mload(0x40) let f_ := shl(224, 0x1626ba7e) mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m_, 0x04), hash_) let d_ := add(m_, 0x24) mstore(d_, 0x40) // The offset of the `signature` in the calldata. let n_ := add(0x20, mload(signature_)) pop(staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)) _isValid := and( eq(mload(d_), f_), staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20) ) } for { let n := mload(signature) } 1 { } { if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) { isValid := callIsValidSignature(signer, hash, signature) break } let o := add(signature, 0x20) // Signature bytes. let d := add(o, mload(add(o, 0x20))) // Factory calldata. if iszero(extcodesize(signer)) { if iszero(call(gas(), mload(o), 0, add(d, 0x20), mload(d), codesize(), 0x00)) { break } } let s := add(o, mload(add(o, 0x40))) // Inner signature. isValid := callIsValidSignature(signer, hash, s) if iszero(isValid) { if call(gas(), mload(o), 0, add(d, 0x20), mload(d), codesize(), 0x00) { isValid := callIsValidSignature(signer, hash, s) } } break } } } /// @dev Returns whether `signature` is valid for `hash`. /// If the signature is postfixed with the ERC6492 magic number, it will attempt /// to use a reverting verifier to deploy / prepare the `signer` smart account /// and do a `isValidSignature` check via the reverting verifier. /// Note: This function is reentrancy safe. /// The reverting verifier must be be deployed. /// Otherwise, the function will return false if `signer` is not yet deployed / prepared. /// See: https://gist.github.com/Vectorized/846a474c855eee9e441506676800a9ad function isValidERC6492SignatureNow( address signer, bytes32 hash, bytes memory signature ) internal returns (bool isValid) { /// @solidity memory-safe-assembly assembly { function callIsValidSignature(signer_, hash_, signature_) -> _isValid { let m_ := mload(0x40) let f_ := shl(224, 0x1626ba7e) mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m_, 0x04), hash_) let d_ := add(m_, 0x24) mstore(d_, 0x40) // The offset of the `signature` in the calldata. let n_ := add(0x20, mload(signature_)) pop(staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)) _isValid := and( eq(mload(d_), f_), staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20) ) } for { let n := mload(signature) } 1 { } { if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) { isValid := callIsValidSignature(signer, hash, signature) break } if extcodesize(signer) { let o := add(signature, 0x20) // Signature bytes. isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40)))) if isValid { break } } let m := mload(0x40) mstore(m, signer) mstore(add(m, 0x20), hash) let willBeZeroIfRevertingVerifierExists := call( gas(), // Remaining gas. 0x00007bd799e4A591FeA53f8A8a3E9f931626Ba7e, // Reverting verifier. 0, // Send zero ETH. m, // Start of memory. add(returndatasize(), 0x40), // Length of calldata in memory. staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1. 0x00 // Length of returndata to write. ) isValid := gt(returndatasize(), willBeZeroIfRevertingVerifierExists) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an Ethereum Signed Message, created from a `hash`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, hash) // Store into scratch space for keccak256. mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. } } /// @dev Returns an Ethereum Signed Message, created from `s`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. /// Note: Supports lengths of `s` up to 999999 bytes. function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let sLength := mload(s) let o := 0x20 mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. mstore(0x00, 0x00) // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. for { let temp := sLength } 1 { } { o := sub(o, 1) mstore8(o, add(48, mod(temp, 10))) temp := div(temp, 10) if iszero(temp) { break } } let n := sub(0x3a, o) // Header length: `26 + 32 - o`. // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) mstore(s, sLength) // Restore the length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes. function emptySignature() internal pure returns (bytes calldata signature) { /// @solidity memory-safe-assembly assembly { signature.length := 0 } } } /* solhint-enable no-inline-assembly */
// SPDX-License-Identifier: MIT pragma solidity >=0.8.20; interface IWETH9 { function balanceOf(address) external view returns (uint256); function deposit() external payable; function withdraw(uint256 wad) external; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
{ "evmVersion": "paris", "metadata": { "bytecodeHash": "none" }, "optimizer": { "enabled": true, "runs": 500 }, "viaIR": false, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureLength","type":"error"},{"inputs":[],"name":"MismatchedChainId","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":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[],"name":"LegacyDeployOnNewSignature","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"upgradableBeaconAddress","type":"address"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"NewBeaconVaultDeploy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"NewVaultDeploy","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":"signatureVerifier","type":"address"}],"name":"SignatureVerifierAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"signatureVerifier","type":"address"}],"name":"SignatureVerifierRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_signatureVerifier","type":"address"}],"name":"addSignatureVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"beaconAddress","type":"address"},{"internalType":"address","name":"globalTradeGuardian","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfig","name":"coreAccessControlConfig","type":"tuple"}],"name":"createBeaconVault","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"beaconAddress","type":"address"},{"internalType":"address","name":"globalTradeGuardian","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"definitiveAdmin","type":"address"},{"internalType":"address[]","name":"definitive","type":"address[]"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfigOld","name":"coreAccessControlConfig","type":"tuple"}],"name":"createBeaconVault","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"beaconAddress","type":"address"},{"internalType":"address","name":"globalTradeGuardian","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"deploySalt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfig","name":"coreAccessControlConfig","type":"tuple"}],"internalType":"struct BeaconDeployParams","name":"deployParams","type":"tuple"},{"internalType":"bytes","name":"authorizedSignature","type":"bytes"}],"name":"createBeaconVaultWithPermission","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"beaconAddress","type":"address"},{"internalType":"address","name":"globalTradeGuardian","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"deploySalt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"definitiveAdmin","type":"address"},{"internalType":"address[]","name":"definitive","type":"address[]"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfigOld","name":"coreAccessControlConfig","type":"tuple"}],"internalType":"struct BeaconDeployParamsOld","name":"deployParams","type":"tuple"},{"internalType":"bytes","name":"authorizedSignature","type":"bytes"}],"name":"createBeaconVaultWithPermission","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tradingVaultImplementation","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfig","name":"coreAccessControlConfig","type":"tuple"},{"components":[{"internalType":"address[]","name":"swapHandlers","type":"address[]"}],"internalType":"struct CoreSimpleSwapConfig","name":"coreSimpleSwapConfig","type":"tuple"},{"components":[{"internalType":"address payable","name":"feeAccount","type":"address"}],"internalType":"struct CoreFeesConfig","name":"coreFeesConfig","type":"tuple"}],"name":"createVault","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tradingVaultImplementation","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"deploySalt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfig","name":"coreAccessControlConfig","type":"tuple"},{"components":[{"internalType":"address[]","name":"swapHandlers","type":"address[]"}],"internalType":"struct CoreSimpleSwapConfig","name":"coreSimpleSwapConfig","type":"tuple"},{"components":[{"internalType":"address payable","name":"feeAccount","type":"address"}],"internalType":"struct CoreFeesConfig","name":"coreFeesConfig","type":"tuple"}],"internalType":"struct DeployParams","name":"deployParams","type":"tuple"},{"internalType":"bytes","name":"authorizedSignature","type":"bytes"}],"name":"createVaultWithPermission","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"beaconAddress","type":"address"},{"internalType":"address","name":"globalTradeGuardian","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"deploySalt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"definitiveAdmin","type":"address"},{"internalType":"address[]","name":"definitive","type":"address[]"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfigOld","name":"coreAccessControlConfig","type":"tuple"}],"internalType":"struct BeaconDeployParamsOld","name":"deployParams","type":"tuple"}],"name":"encodeBeaconDeploymentParams","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"beaconAddress","type":"address"},{"internalType":"address","name":"globalTradeGuardian","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"deploySalt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfig","name":"coreAccessControlConfig","type":"tuple"}],"internalType":"struct BeaconDeployParams","name":"deployParams","type":"tuple"}],"name":"encodeBeaconDeploymentParams","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tradingVaultImplementation","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"deploySalt","type":"bytes32"},{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfig","name":"coreAccessControlConfig","type":"tuple"},{"components":[{"internalType":"address[]","name":"swapHandlers","type":"address[]"}],"internalType":"struct CoreSimpleSwapConfig","name":"coreSimpleSwapConfig","type":"tuple"},{"components":[{"internalType":"address payable","name":"feeAccount","type":"address"}],"internalType":"struct CoreFeesConfig","name":"coreFeesConfig","type":"tuple"}],"internalType":"struct DeployParams","name":"deployParams","type":"tuple"}],"name":"encodeDeploymentParams","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"deploymentSalt","type":"bytes32"}],"name":"encodeSalt","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"beaconAddress","type":"address"},{"internalType":"bytes32","name":"deploymentSalt","type":"bytes32"}],"name":"getBeaconVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"deploymentSalt","type":"bytes32"}],"name":"getVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_initialVerifiers","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isSignatureVerifier","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":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_signatureVerifier","type":"address"}],"name":"removeSignatureVerifier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60a0604052306080523480156200001557600080fd5b506200002062000026565b620000da565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000775760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000d75780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051612b2662000104600039600081816111ad015281816111d601526113400152612b266000f3fe6080604052600436106101555760003560e01c80638a6c4284116100bb578063afb83ce61161007f578063f073cecd11610059578063f073cecd146103b1578063f106b91114610419578063f2fde38b1461043957600080fd5b8063afb83ce614610351578063c273ed5e14610371578063cd0bcff51461039157600080fd5b80638a6c4284146102835780638da5cb5b146102a357806393e46281146102e0578063946d9204146102f3578063ad3cb1cc1461031357600080fd5b80634f1ef2861161011d578063555b5a89116100f7578063555b5a891461023b57806370bbdc771461025b578063715018a61461026e57600080fd5b80634f1ef286146101fe57806352d1902d14610213578063545a18bc1461022857600080fd5b8063106a1cca1461015a5780631a175f88146101975780631aee9835146101aa578063450c2543146101bd5780634533ff8c146101d0575b600080fd5b34801561016657600080fd5b5061017a610175366004611d66565b610459565b6040516001600160a01b0390911681526020015b60405180910390f35b61017a6101a5366004611dbc565b61046d565b61017a6101b8366004611eb3565b6105a1565b61017a6101cb366004611f1c565b6106cc565b3480156101dc57600080fd5b506101f06101eb366004611fac565b610868565b60405190815260200161018e565b61021161020c366004612051565b610898565b005b34801561021f57600080fd5b506101f06108b7565b61017a6102363660046120f9565b6108e6565b34801561024757600080fd5b506101f0610256366004611d66565b610b4d565b61017a6102693660046120f9565b610b92565b34801561027a57600080fd5b50610211610bb8565b34801561028f57600080fd5b5061017a61029e366004612132565b610bcc565b3480156102af57600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031661017a565b61017a6102ee366004612289565b610bf3565b3480156102ff57600080fd5b5061021161030e3660046122fa565b610cc4565b34801561031f57600080fd5b50610344604051806040016040528060058152602001640352e302e360dc1b81525081565b60405161018e919061239a565b34801561035d57600080fd5b5061021161036c3660046123ad565b610e22565b34801561037d57600080fd5b506101f061038c3660046123ca565b610e36565b34801561039d57600080fd5b506102116103ac3660046123ad565b610e49565b3480156103bd57600080fd5b506104096103cc3660046123ad565b6001600160a01b031660009081527f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e0300602052604090205460ff1690565b604051901515815260200161018e565b34801561042557600080fd5b506101f0610434366004611fac565b610e5a565b34801561044557600080fd5b506102116104543660046123ad565b610e6d565b6000610466838330610ead565b9392505050565b60008061047a3388610b4d565b905061049c6000734aeb164998db4eb8ab945620d4d1db59e2ad551383610f58565b91506000631e915e8c60e01b878787876040516024016104bf9493929190612503565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050905061054b83634f1ef28660e01b8b8460405160240161051392919061257b565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915234610fe7565b50604080513381526001600160a01b03851660208201529081018390527fff81028ff235417e359d06e67d2801d23a0b5bdc1b96b34392c79b1165d2d7df9060600160405180910390a150509695505050505050565b60006105ae848484611084565b6105d26000734aeb164998db4eb8ab945620d4d1db59e2ad55138660600135610f58565b905060006307a457a360e21b608086016105ef60a088018861259d565b6105fc60c08901896125bd565b8860e0016040516024016106139493929190612503565b60408051601f19818403018152919052602080820180516001600160e01b03166001600160e01b031990941693909317909252915061067590839063278f794360e11b90610663908901896123ad565b8460405160240161051392919061257b565b50604080513381526001600160a01b0384166020820152606080880135928201929092527fff81028ff235417e359d06e67d2801d23a0b5bdc1b96b34392c79b1165d2d7df910160405180910390a1509392505050565b6000806106d93386610b4d565b90506106e58782611187565b60405163536a37d960e01b81529093506001600160a01b038416915063536a37d99061071990879087908b906004016125d3565b600060405180830381600087803b15801561073357600080fd5b505af1925050508015610744575060015b610809576107de87878387604051806080016040528089600001602081019061076d91906123ad565b6001600160a01b03168152600060208083018290526040805192835282820181528301919091526060909101906107a6908b018b612615565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050915250610bf3565b506040517f5c38fcbef6b336749ba73d53974e97e8dba84f87af5aeb0661e6cc74cf0083b990600090a15b604080513381526001600160a01b038085166020830152891691810191909152606081018290527fada83c846840018b3edf77b6a53b4e5b89e51b3a5672f3b3eb550daadf8eaedb906080015b60405180910390a15095945050505050565b60008160405160200161087b91906126d3565b604051602081830303815290604052805190602001209050919050565b6108a06111a2565b6108a982611259565b6108b38282611261565b5050565b60006108c1611335565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b60006108f384848461137e565b61090d61090360208601866123ad565b8560800135611187565b9150506001600160a01b03811663536a37d960a0860161093060c088018861259d565b6109406040890160208a016123ad565b6040518463ffffffff1660e01b815260040161095e939291906125d3565b600060405180830381600087803b15801561097857600080fd5b505af1925050508015610989575060015b610ae0576040805160e08101909152610ab590806109aa60208801886123ad565b6001600160a01b031681526020018660200160208101906109cb91906123ad565b6001600160a01b031681526020018660400135815260200186606001358152602001866080013581526020018660a001803603810190610a0b91906127be565b81526020016040518060800160405280888060c00190610a2b919061259d565b610a399060208101906123ad565b6001600160a01b0316815260006020808301829052604080519283529082018152820152606001610a6d60c08a018a61259d565b610a7b906020810190612615565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050915250905261143f565b506040517f5c38fcbef6b336749ba73d53974e97e8dba84f87af5aeb0661e6cc74cf0083b990600090a15b7fada83c846840018b3edf77b6a53b4e5b89e51b3a5672f3b3eb550daadf8eaedb3382610b1060208801886123ad565b604080516001600160a01b039485168152928416602084015292169181019190915260808087013560608301520160405180910390a19392505050565b60008183604051602001610b749291909182526001600160a01b0316602082015260400190565b60405160208183030381529060405280519060200120905092915050565b6000610b9f848484611521565b610bb0610bab856127da565b61143f565b949350505050565b610bc06115e2565b610bca600061163d565b565b6000610bed734aeb164998db4eb8ab945620d4d1db59e2ad551383306116bb565b92915050565b600080610c003386610b4d565b9050610c0c8782611187565b60405163c77fa9dd60e01b81529093506001600160a01b038416915063c77fa9dd90610c4090879087908b906004016128fa565b600060405180830381600087803b158015610c5a57600080fd5b505af1158015610c6e573d6000803e3d6000fd5b5050604080513381526001600160a01b0380871660208301528b1691810191909152606081018490527fada83c846840018b3edf77b6a53b4e5b89e51b3a5672f3b3eb550daadf8eaedb92506080019050610856565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015610d0f5750825b905060008267ffffffffffffffff166001148015610d2c5750303b155b905081158015610d3a575080155b15610d585760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610d8c57845468ff00000000000000001916680100000000000000001785555b610d9587611737565b855160005b81811015610dcc57610dc4888281518110610db757610db7612928565b6020026020010151611748565b600101610d9a565b50508315610e1957845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b610e2a6115e2565b610e33816117eb565b50565b60008160405160200161087b9190612973565b610e516115e2565b610e3381611748565b60008160405160200161087b9190612a25565b610e756115e2565b6001600160a01b038116610ea457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b610e338161163d565b604080517fb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f360609081527f1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c83527660195155f3363d3d373d3d363d602036600436635c60da6020526001600160a01b0386166860523d8160223d397360a01b176009526074600c209190925260009182905281905b9050610f4f818585611883565b95945050505050565b60006040517fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e207660405261600960205283601e5268603d3d8160223d3973600a5282605f602187f5915081610fd85763301164256000526004601cfd5b60405260006060529392505050565b60608147101561100c5760405163cd78605960e01b8152306004820152602401610e9b565b600080856001600160a01b031684866040516110289190612ab7565b60006040518083038185875af1925050503d8060008114611065576040519150601f19603f3d011682016040523d82523d6000602084013e61106a565b606091505b509150915061107a8683836118a5565b9695505050505050565b600061109360208501856123ad565b6001600160a01b0316036110ba5760405163e6c4247b60e01b815260040160405180910390fd5b42836040013510156110df5760405163559895a360e01b815260040160405180910390fd5b468360200135141580156110f95750600019836020013514155b156111175760405163029b0df160e41b815260040160405180910390fd5b7f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006111818161114586610e36565b85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061190192505050565b50505050565b6000806111966000858561195d565b915091505b9250929050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061123b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661122f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b15610bca5760405163703e46dd60e11b815260040160405180910390fd5b610e336115e2565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156112bb575060408051601f3d908101601f191682019092526112b891810190612ac9565b60015b6112e357604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610e9b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc811461132657604051632a87526960e21b815260048101829052602401610e9b565b6113308383611a5d565b505050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610bca5760405163703e46dd60e11b815260040160405180910390fd5b600061138d60208501856123ad565b6001600160a01b0316036113b45760405163e6c4247b60e01b815260040160405180910390fd5b42836060013510156113d95760405163559895a360e01b815260040160405180910390fd5b468360400135141580156113f35750600019836040013514155b156114115760405163029b0df160e41b815260040160405180910390fd5b7f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006111818161114586610e5a565b600061145382600001518360800151611187565b60a084015160c0850151602086015160405163c77fa9dd60e01b81529395506001600160a01b038616945063c77fa9dd9361149393929190600401612ae2565b600060405180830381600087803b1580156114ad57600080fd5b505af11580156114c1573d6000803e3d6000fd5b50508351608080860151604080513381526001600160a01b0380891660208301529094169084015260608301527fada83c846840018b3edf77b6a53b4e5b89e51b3a5672f3b3eb550daadf8eaedb935001905060405180910390a1919050565b600061153060208501856123ad565b6001600160a01b0316036115575760405163e6c4247b60e01b815260040160405180910390fd5b428360600135101561157c5760405163559895a360e01b815260040160405180910390fd5b468360400135141580156115965750600019836040013514155b156115b45760405163029b0df160e41b815260040160405180910390fd5b7f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006111818161114586610868565b336116147f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610bca5760405163118cdaa760e01b8152336004820152602401610e9b565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300805473ffffffffffffffffffffffffffffffffffffffff1981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b600080610f4285604080517fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f360609081527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e20768352616009602052601e9390935268603d3d8160223d3973600a52605f6021209152600090915290565b61173f611ab3565b610e3381611b01565b6001600160a01b03811661176f5760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03811660008181527f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006020818152604092839020805460ff191660011790559151928352917f0f35112fc04ac27795ba9e631146295f8a5f09f6c4016988f701e7919bdce46f91015b60405180910390a15050565b6001600160a01b0381166118125760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03811660008181527f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006020818152604092839020805460ff191690559151928352917f41913741c8622c4e49c9e9ca9ab043835b44e88899f3572dc5522aaa8f77705491016117df565b600060ff60005350603592835260601b60015260155260556000908120915290565b6060826118ba576118b582611b09565b610466565b81511580156118d157506001600160a01b0384163b155b156118fa57604051639996b31560e01b81526001600160a01b0385166004820152602401610e9b565b5080610466565b600061190c83611b32565b9050600061191a8284611b6d565b6001600160a01b03811660009081526020879052604090205490915060ff1661195657604051638baa579f60e01b815260040160405180910390fd5b5050505050565b6000806040517fb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f36060527f1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c6040527660195155f3363d3d373d3d363d602036600436635c60da6020528460601b60601c6860523d8160223d397360a01b176009526074600c2060358201523060581b815260ff8153836015820152605581209150813b611a2557836074600c88f5915081611a205763301164256000526004601cfd5b611a4b565b600192508515611a4b5760003860003889865af1611a4b5763b12d13eb6000526004601cfd5b80604052506000606052935093915050565b611a6682611bec565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611aab576113308282611c70565b6108b3611cdd565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610bca57604051631afcd79f60e31b815260040160405180910390fd5b610e75611ab3565b805115611b195780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161087b565b600080600080611b7c85611cfc565b6040805160008152602081018083528b905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015611bd7573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b806001600160a01b03163b600003611c2257604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610e9b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051611c8d9190612ab7565b600060405180830381855af49150503d8060008114611cc8576040519150601f19603f3d011682016040523d82523d6000602084013e611ccd565b606091505b5091509150610f4f8583836118a5565b3415610bca5760405163b398979f60e01b815260040160405180910390fd5b60008060008351604114611d2357604051634be6321b60e01b815260040160405180910390fd5b50505060208101516040820151606090920151909260009190911a90565b6001600160a01b0381168114610e3357600080fd5b8035611d6181611d41565b919050565b60008060408385031215611d7957600080fd5b8235611d8481611d41565b946020939093013593505050565b600060208284031215611da457600080fd5b50919050565b600060408284031215611da457600080fd5b60008060008060008060c08789031215611dd557600080fd5b8635611de081611d41565b955060208701359450611df68860408901611d92565b9350606087013567ffffffffffffffff80821115611e1357600080fd5b611e1f8a838b01611daa565b94506080890135915080821115611e3557600080fd5b50611e4289828a01611d92565b925050611e528860a08901611d92565b90509295509295509295565b60006101008284031215611da457600080fd5b60008083601f840112611e8357600080fd5b50813567ffffffffffffffff811115611e9b57600080fd5b60208301915083602082850101111561119b57600080fd5b600080600060408486031215611ec857600080fd5b833567ffffffffffffffff80821115611ee057600080fd5b611eec87838801611e5e565b94506020860135915080821115611f0257600080fd5b50611f0f86828701611e71565b9497909650939450505050565b600080600080600060a08688031215611f3457600080fd5b8535611f3f81611d41565b94506020860135611f4f81611d41565b935060408601359250611f658760608801611d92565b9150608086013567ffffffffffffffff811115611f8157600080fd5b611f8d88828901611daa565b9150509295509295909350565b600060e08284031215611da457600080fd5b600060208284031215611fbe57600080fd5b813567ffffffffffffffff811115611fd557600080fd5b610bb084828501611f9a565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff8111828210171561201a5761201a611fe1565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561204957612049611fe1565b604052919050565b6000806040838503121561206457600080fd5b823561206f81611d41565b915060208381013567ffffffffffffffff8082111561208d57600080fd5b818601915086601f8301126120a157600080fd5b8135818111156120b3576120b3611fe1565b6120c5601f8201601f19168501612020565b915080825287848285010111156120db57600080fd5b80848401858401376000848284010152508093505050509250929050565b60008060006040848603121561210e57600080fd5b833567ffffffffffffffff8082111561212657600080fd5b611eec87838801611f9a565b60006020828403121561214457600080fd5b5035919050565b600082601f83011261215c57600080fd5b8135602067ffffffffffffffff82111561217857612178611fe1565b8160051b612187828201612020565b92835284810182019282810190878511156121a157600080fd5b83870192505b848310156121c95782356121ba81611d41565b825291830191908301906121a7565b979650505050505050565b6000608082840312156121e657600080fd5b6040516080810167ffffffffffffffff828210818311171561220a5761220a611fe1565b816040528293508435915061221e82611d41565b90825260208401359061223082611d41565b816020840152604085013591508082111561224a57600080fd5b6122568683870161214b565b6040840152606085013591508082111561226f57600080fd5b5061227c8582860161214b565b6060830152505092915050565b600080600080600060a086880312156122a157600080fd5b85356122ac81611d41565b945060208601356122bc81611d41565b9350604086013592506122d28760608801611d92565b9150608086013567ffffffffffffffff8111156122ee57600080fd5b611f8d888289016121d4565b6000806040838503121561230d57600080fd5b823561231881611d41565b9150602083013567ffffffffffffffff81111561233457600080fd5b6123408582860161214b565b9150509250929050565b60005b8381101561236557818101518382015260200161234d565b50506000910152565b6000815180845261238681602086016020860161234a565b601f01601f19169290920160200192915050565b602081526000610466602083018461236e565b6000602082840312156123bf57600080fd5b813561046681611d41565b6000602082840312156123dc57600080fd5b813567ffffffffffffffff8111156123f357600080fd5b610bb084828501611e5e565b803561240a81611d41565b6001600160a01b031690915250565b6000808335601e1984360301811261243057600080fd5b830160208101925035905067ffffffffffffffff81111561245057600080fd5b8060051b360382131561119b57600080fd5b8183526000602080850194508260005b858110156124a057813561248581611d41565b6001600160a01b031687529582019590820190600101612472565b509495945050505050565b600081356124b881611d41565b6001600160a01b031683526124d06020830183612419565b60406020860152610f4f604086018284612462565b60006124f18283612419565b60208552610f4f602086018284612462565b6000853561251081611d41565b6001600160a01b0380821684526080602085015261253160808501886124ab565b915083820360408501526125458687612419565b60208452612557602085018284612462565b945050508435915061256882611d41565b8082166060850152505095945050505050565b6001600160a01b0383168152604060208201526000610bb0604083018461236e565b60008235603e198336030181126125b357600080fd5b9190910192915050565b60008235601e198336030181126125b357600080fd5b600084356125e081611d41565b6001600160a01b0380821684526060602085015261260160608501876124ab565b925080851660408501525050949350505050565b6000808335601e1984360301811261262c57600080fd5b83018035915067ffffffffffffffff82111561264757600080fd5b6020019150600581901b360382131561119b57600080fd5b6000813561266c81611d41565b6001600160a01b03908116845260208301359061268882611d41565b16602084015261269b6040830183612419565b608060408601526126b0608086018284612462565b9150506126c06060840184612419565b858303606087015261107a838284612462565b60208152600082356126e481611d41565b6001600160a01b0380821660208501526020850135915061270482611d41565b80821660408501526040850135606085015260608501356080850152608085013560a085015260a0850135915061273a82611d41565b1660c08381019190915283013536849003607e1901811261275a57600080fd5b60e080840152610bb0610100840185830161265f565b60006020828403121561278257600080fd5b6040516020810181811067ffffffffffffffff821117156127a5576127a5611fe1565b60405290508082356127b681611d41565b905292915050565b6000602082840312156127d057600080fd5b6104668383612770565b600060e082360312156127ec57600080fd5b6127f4611ff7565b6127fd83611d56565b815261280b60208401611d56565b602082015260408301356040820152606083013560608201526080830135608082015261283b3660a08501612770565b60a082015260c083013567ffffffffffffffff81111561285a57600080fd5b612866368286016121d4565b60c08301525092915050565b600081518084526020808501945080840160005b838110156124a05781516001600160a01b031687529582019590820190600101612886565b60006001600160a01b03808351168452806020840151166020850152506040820151608060408501526128e16080850182612872565b905060608301518482036060860152610f4f8282612872565b6000843561290781611d41565b6001600160a01b0380821684526060602085015261260160608501876128ab565b634e487b7160e01b600052603260045260246000fd5b60008235603e1983360301811261295457600080fd5b90910192915050565b60008235601e1983360301811261295457600080fd5b602081526000823561298481611d41565b6001600160a01b0381166020840152506020830135604083015260408301356060830152606083013560808301526129c260a08301608085016123ff565b6129cf60a084018461293e565b6101008060c08501526129e66101208501836124ab565b91506129f560c086018661295d565b848303601f190160e0860152612a0b83826124e5565b925050612a1d81850160e087016123ff565b509392505050565b6020815260008235612a3681611d41565b6001600160a01b03808216602085015260208501359150612a5682611d41565b80821660408501526040850135606085015260608501356080850152608085013560a085015260a08501359150612a8c82611d41565b80821660c08501525050612aa360c084018461293e565b60e080840152610bb06101008401826124ab565b600082516125b381846020870161234a565b600060208284031215612adb57600080fd5b5051919050565b60006001600160a01b0380865116835260606020840152612b0660608401866128ab565b915080841660408401525094935050505056fea164736f6c6343000814000a
Deployed Bytecode
0x6080604052600436106101555760003560e01c80638a6c4284116100bb578063afb83ce61161007f578063f073cecd11610059578063f073cecd146103b1578063f106b91114610419578063f2fde38b1461043957600080fd5b8063afb83ce614610351578063c273ed5e14610371578063cd0bcff51461039157600080fd5b80638a6c4284146102835780638da5cb5b146102a357806393e46281146102e0578063946d9204146102f3578063ad3cb1cc1461031357600080fd5b80634f1ef2861161011d578063555b5a89116100f7578063555b5a891461023b57806370bbdc771461025b578063715018a61461026e57600080fd5b80634f1ef286146101fe57806352d1902d14610213578063545a18bc1461022857600080fd5b8063106a1cca1461015a5780631a175f88146101975780631aee9835146101aa578063450c2543146101bd5780634533ff8c146101d0575b600080fd5b34801561016657600080fd5b5061017a610175366004611d66565b610459565b6040516001600160a01b0390911681526020015b60405180910390f35b61017a6101a5366004611dbc565b61046d565b61017a6101b8366004611eb3565b6105a1565b61017a6101cb366004611f1c565b6106cc565b3480156101dc57600080fd5b506101f06101eb366004611fac565b610868565b60405190815260200161018e565b61021161020c366004612051565b610898565b005b34801561021f57600080fd5b506101f06108b7565b61017a6102363660046120f9565b6108e6565b34801561024757600080fd5b506101f0610256366004611d66565b610b4d565b61017a6102693660046120f9565b610b92565b34801561027a57600080fd5b50610211610bb8565b34801561028f57600080fd5b5061017a61029e366004612132565b610bcc565b3480156102af57600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031661017a565b61017a6102ee366004612289565b610bf3565b3480156102ff57600080fd5b5061021161030e3660046122fa565b610cc4565b34801561031f57600080fd5b50610344604051806040016040528060058152602001640352e302e360dc1b81525081565b60405161018e919061239a565b34801561035d57600080fd5b5061021161036c3660046123ad565b610e22565b34801561037d57600080fd5b506101f061038c3660046123ca565b610e36565b34801561039d57600080fd5b506102116103ac3660046123ad565b610e49565b3480156103bd57600080fd5b506104096103cc3660046123ad565b6001600160a01b031660009081527f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e0300602052604090205460ff1690565b604051901515815260200161018e565b34801561042557600080fd5b506101f0610434366004611fac565b610e5a565b34801561044557600080fd5b506102116104543660046123ad565b610e6d565b6000610466838330610ead565b9392505050565b60008061047a3388610b4d565b905061049c6000734aeb164998db4eb8ab945620d4d1db59e2ad551383610f58565b91506000631e915e8c60e01b878787876040516024016104bf9493929190612503565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050905061054b83634f1ef28660e01b8b8460405160240161051392919061257b565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915234610fe7565b50604080513381526001600160a01b03851660208201529081018390527fff81028ff235417e359d06e67d2801d23a0b5bdc1b96b34392c79b1165d2d7df9060600160405180910390a150509695505050505050565b60006105ae848484611084565b6105d26000734aeb164998db4eb8ab945620d4d1db59e2ad55138660600135610f58565b905060006307a457a360e21b608086016105ef60a088018861259d565b6105fc60c08901896125bd565b8860e0016040516024016106139493929190612503565b60408051601f19818403018152919052602080820180516001600160e01b03166001600160e01b031990941693909317909252915061067590839063278f794360e11b90610663908901896123ad565b8460405160240161051392919061257b565b50604080513381526001600160a01b0384166020820152606080880135928201929092527fff81028ff235417e359d06e67d2801d23a0b5bdc1b96b34392c79b1165d2d7df910160405180910390a1509392505050565b6000806106d93386610b4d565b90506106e58782611187565b60405163536a37d960e01b81529093506001600160a01b038416915063536a37d99061071990879087908b906004016125d3565b600060405180830381600087803b15801561073357600080fd5b505af1925050508015610744575060015b610809576107de87878387604051806080016040528089600001602081019061076d91906123ad565b6001600160a01b03168152600060208083018290526040805192835282820181528301919091526060909101906107a6908b018b612615565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050915250610bf3565b506040517f5c38fcbef6b336749ba73d53974e97e8dba84f87af5aeb0661e6cc74cf0083b990600090a15b604080513381526001600160a01b038085166020830152891691810191909152606081018290527fada83c846840018b3edf77b6a53b4e5b89e51b3a5672f3b3eb550daadf8eaedb906080015b60405180910390a15095945050505050565b60008160405160200161087b91906126d3565b604051602081830303815290604052805190602001209050919050565b6108a06111a2565b6108a982611259565b6108b38282611261565b5050565b60006108c1611335565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b60006108f384848461137e565b61090d61090360208601866123ad565b8560800135611187565b9150506001600160a01b03811663536a37d960a0860161093060c088018861259d565b6109406040890160208a016123ad565b6040518463ffffffff1660e01b815260040161095e939291906125d3565b600060405180830381600087803b15801561097857600080fd5b505af1925050508015610989575060015b610ae0576040805160e08101909152610ab590806109aa60208801886123ad565b6001600160a01b031681526020018660200160208101906109cb91906123ad565b6001600160a01b031681526020018660400135815260200186606001358152602001866080013581526020018660a001803603810190610a0b91906127be565b81526020016040518060800160405280888060c00190610a2b919061259d565b610a399060208101906123ad565b6001600160a01b0316815260006020808301829052604080519283529082018152820152606001610a6d60c08a018a61259d565b610a7b906020810190612615565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050915250905261143f565b506040517f5c38fcbef6b336749ba73d53974e97e8dba84f87af5aeb0661e6cc74cf0083b990600090a15b7fada83c846840018b3edf77b6a53b4e5b89e51b3a5672f3b3eb550daadf8eaedb3382610b1060208801886123ad565b604080516001600160a01b039485168152928416602084015292169181019190915260808087013560608301520160405180910390a19392505050565b60008183604051602001610b749291909182526001600160a01b0316602082015260400190565b60405160208183030381529060405280519060200120905092915050565b6000610b9f848484611521565b610bb0610bab856127da565b61143f565b949350505050565b610bc06115e2565b610bca600061163d565b565b6000610bed734aeb164998db4eb8ab945620d4d1db59e2ad551383306116bb565b92915050565b600080610c003386610b4d565b9050610c0c8782611187565b60405163c77fa9dd60e01b81529093506001600160a01b038416915063c77fa9dd90610c4090879087908b906004016128fa565b600060405180830381600087803b158015610c5a57600080fd5b505af1158015610c6e573d6000803e3d6000fd5b5050604080513381526001600160a01b0380871660208301528b1691810191909152606081018490527fada83c846840018b3edf77b6a53b4e5b89e51b3a5672f3b3eb550daadf8eaedb92506080019050610856565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff16600081158015610d0f5750825b905060008267ffffffffffffffff166001148015610d2c5750303b155b905081158015610d3a575080155b15610d585760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610d8c57845468ff00000000000000001916680100000000000000001785555b610d9587611737565b855160005b81811015610dcc57610dc4888281518110610db757610db7612928565b6020026020010151611748565b600101610d9a565b50508315610e1957845468ff000000000000000019168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b610e2a6115e2565b610e33816117eb565b50565b60008160405160200161087b9190612973565b610e516115e2565b610e3381611748565b60008160405160200161087b9190612a25565b610e756115e2565b6001600160a01b038116610ea457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b610e338161163d565b604080517fb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f360609081527f1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c83527660195155f3363d3d373d3d363d602036600436635c60da6020526001600160a01b0386166860523d8160223d397360a01b176009526074600c209190925260009182905281905b9050610f4f818585611883565b95945050505050565b60006040517fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f36060527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e207660405261600960205283601e5268603d3d8160223d3973600a5282605f602187f5915081610fd85763301164256000526004601cfd5b60405260006060529392505050565b60608147101561100c5760405163cd78605960e01b8152306004820152602401610e9b565b600080856001600160a01b031684866040516110289190612ab7565b60006040518083038185875af1925050503d8060008114611065576040519150601f19603f3d011682016040523d82523d6000602084013e61106a565b606091505b509150915061107a8683836118a5565b9695505050505050565b600061109360208501856123ad565b6001600160a01b0316036110ba5760405163e6c4247b60e01b815260040160405180910390fd5b42836040013510156110df5760405163559895a360e01b815260040160405180910390fd5b468360200135141580156110f95750600019836020013514155b156111175760405163029b0df160e41b815260040160405180910390fd5b7f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006111818161114586610e36565b85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061190192505050565b50505050565b6000806111966000858561195d565b915091505b9250929050565b306001600160a01b037f0000000000000000000000000000000e9b52e475b1b54b06a427dedba4eadaf516148061123b57507f0000000000000000000000000000000e9b52e475b1b54b06a427dedba4eadaf56001600160a01b031661122f7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b031614155b15610bca5760405163703e46dd60e11b815260040160405180910390fd5b610e336115e2565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156112bb575060408051601f3d908101601f191682019092526112b891810190612ac9565b60015b6112e357604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610e9b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc811461132657604051632a87526960e21b815260048101829052602401610e9b565b6113308383611a5d565b505050565b306001600160a01b037f0000000000000000000000000000000e9b52e475b1b54b06a427dedba4eadaf51614610bca5760405163703e46dd60e11b815260040160405180910390fd5b600061138d60208501856123ad565b6001600160a01b0316036113b45760405163e6c4247b60e01b815260040160405180910390fd5b42836060013510156113d95760405163559895a360e01b815260040160405180910390fd5b468360400135141580156113f35750600019836040013514155b156114115760405163029b0df160e41b815260040160405180910390fd5b7f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006111818161114586610e5a565b600061145382600001518360800151611187565b60a084015160c0850151602086015160405163c77fa9dd60e01b81529395506001600160a01b038616945063c77fa9dd9361149393929190600401612ae2565b600060405180830381600087803b1580156114ad57600080fd5b505af11580156114c1573d6000803e3d6000fd5b50508351608080860151604080513381526001600160a01b0380891660208301529094169084015260608301527fada83c846840018b3edf77b6a53b4e5b89e51b3a5672f3b3eb550daadf8eaedb935001905060405180910390a1919050565b600061153060208501856123ad565b6001600160a01b0316036115575760405163e6c4247b60e01b815260040160405180910390fd5b428360600135101561157c5760405163559895a360e01b815260040160405180910390fd5b468360400135141580156115965750600019836040013514155b156115b45760405163029b0df160e41b815260040160405180910390fd5b7f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006111818161114586610868565b336116147f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610bca5760405163118cdaa760e01b8152336004820152602401610e9b565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300805473ffffffffffffffffffffffffffffffffffffffff1981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b600080610f4285604080517fcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f360609081527f5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e20768352616009602052601e9390935268603d3d8160223d3973600a52605f6021209152600090915290565b61173f611ab3565b610e3381611b01565b6001600160a01b03811661176f5760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03811660008181527f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006020818152604092839020805460ff191660011790559151928352917f0f35112fc04ac27795ba9e631146295f8a5f09f6c4016988f701e7919bdce46f91015b60405180910390a15050565b6001600160a01b0381166118125760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03811660008181527f1e05315c660d2d2e3b92cca2a3c5f6e530c7e4414b0a08bd1d920d985b0e03006020818152604092839020805460ff191690559151928352917f41913741c8622c4e49c9e9ca9ab043835b44e88899f3572dc5522aaa8f77705491016117df565b600060ff60005350603592835260601b60015260155260556000908120915290565b6060826118ba576118b582611b09565b610466565b81511580156118d157506001600160a01b0384163b155b156118fa57604051639996b31560e01b81526001600160a01b0385166004820152602401610e9b565b5080610466565b600061190c83611b32565b9050600061191a8284611b6d565b6001600160a01b03811660009081526020879052604090205490915060ff1661195657604051638baa579f60e01b815260040160405180910390fd5b5050505050565b6000806040517fb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f36060527f1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c6040527660195155f3363d3d373d3d363d602036600436635c60da6020528460601b60601c6860523d8160223d397360a01b176009526074600c2060358201523060581b815260ff8153836015820152605581209150813b611a2557836074600c88f5915081611a205763301164256000526004601cfd5b611a4b565b600192508515611a4b5760003860003889865af1611a4b5763b12d13eb6000526004601cfd5b80604052506000606052935093915050565b611a6682611bec565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611aab576113308282611c70565b6108b3611cdd565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610bca57604051631afcd79f60e31b815260040160405180910390fd5b610e75611ab3565b805115611b195780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c0161087b565b600080600080611b7c85611cfc565b6040805160008152602081018083528b905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015611bd7573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b806001600160a01b03163b600003611c2257604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610e9b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051611c8d9190612ab7565b600060405180830381855af49150503d8060008114611cc8576040519150601f19603f3d011682016040523d82523d6000602084013e611ccd565b606091505b5091509150610f4f8583836118a5565b3415610bca5760405163b398979f60e01b815260040160405180910390fd5b60008060008351604114611d2357604051634be6321b60e01b815260040160405180910390fd5b50505060208101516040820151606090920151909260009190911a90565b6001600160a01b0381168114610e3357600080fd5b8035611d6181611d41565b919050565b60008060408385031215611d7957600080fd5b8235611d8481611d41565b946020939093013593505050565b600060208284031215611da457600080fd5b50919050565b600060408284031215611da457600080fd5b60008060008060008060c08789031215611dd557600080fd5b8635611de081611d41565b955060208701359450611df68860408901611d92565b9350606087013567ffffffffffffffff80821115611e1357600080fd5b611e1f8a838b01611daa565b94506080890135915080821115611e3557600080fd5b50611e4289828a01611d92565b925050611e528860a08901611d92565b90509295509295509295565b60006101008284031215611da457600080fd5b60008083601f840112611e8357600080fd5b50813567ffffffffffffffff811115611e9b57600080fd5b60208301915083602082850101111561119b57600080fd5b600080600060408486031215611ec857600080fd5b833567ffffffffffffffff80821115611ee057600080fd5b611eec87838801611e5e565b94506020860135915080821115611f0257600080fd5b50611f0f86828701611e71565b9497909650939450505050565b600080600080600060a08688031215611f3457600080fd5b8535611f3f81611d41565b94506020860135611f4f81611d41565b935060408601359250611f658760608801611d92565b9150608086013567ffffffffffffffff811115611f8157600080fd5b611f8d88828901611daa565b9150509295509295909350565b600060e08284031215611da457600080fd5b600060208284031215611fbe57600080fd5b813567ffffffffffffffff811115611fd557600080fd5b610bb084828501611f9a565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff8111828210171561201a5761201a611fe1565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561204957612049611fe1565b604052919050565b6000806040838503121561206457600080fd5b823561206f81611d41565b915060208381013567ffffffffffffffff8082111561208d57600080fd5b818601915086601f8301126120a157600080fd5b8135818111156120b3576120b3611fe1565b6120c5601f8201601f19168501612020565b915080825287848285010111156120db57600080fd5b80848401858401376000848284010152508093505050509250929050565b60008060006040848603121561210e57600080fd5b833567ffffffffffffffff8082111561212657600080fd5b611eec87838801611f9a565b60006020828403121561214457600080fd5b5035919050565b600082601f83011261215c57600080fd5b8135602067ffffffffffffffff82111561217857612178611fe1565b8160051b612187828201612020565b92835284810182019282810190878511156121a157600080fd5b83870192505b848310156121c95782356121ba81611d41565b825291830191908301906121a7565b979650505050505050565b6000608082840312156121e657600080fd5b6040516080810167ffffffffffffffff828210818311171561220a5761220a611fe1565b816040528293508435915061221e82611d41565b90825260208401359061223082611d41565b816020840152604085013591508082111561224a57600080fd5b6122568683870161214b565b6040840152606085013591508082111561226f57600080fd5b5061227c8582860161214b565b6060830152505092915050565b600080600080600060a086880312156122a157600080fd5b85356122ac81611d41565b945060208601356122bc81611d41565b9350604086013592506122d28760608801611d92565b9150608086013567ffffffffffffffff8111156122ee57600080fd5b611f8d888289016121d4565b6000806040838503121561230d57600080fd5b823561231881611d41565b9150602083013567ffffffffffffffff81111561233457600080fd5b6123408582860161214b565b9150509250929050565b60005b8381101561236557818101518382015260200161234d565b50506000910152565b6000815180845261238681602086016020860161234a565b601f01601f19169290920160200192915050565b602081526000610466602083018461236e565b6000602082840312156123bf57600080fd5b813561046681611d41565b6000602082840312156123dc57600080fd5b813567ffffffffffffffff8111156123f357600080fd5b610bb084828501611e5e565b803561240a81611d41565b6001600160a01b031690915250565b6000808335601e1984360301811261243057600080fd5b830160208101925035905067ffffffffffffffff81111561245057600080fd5b8060051b360382131561119b57600080fd5b8183526000602080850194508260005b858110156124a057813561248581611d41565b6001600160a01b031687529582019590820190600101612472565b509495945050505050565b600081356124b881611d41565b6001600160a01b031683526124d06020830183612419565b60406020860152610f4f604086018284612462565b60006124f18283612419565b60208552610f4f602086018284612462565b6000853561251081611d41565b6001600160a01b0380821684526080602085015261253160808501886124ab565b915083820360408501526125458687612419565b60208452612557602085018284612462565b945050508435915061256882611d41565b8082166060850152505095945050505050565b6001600160a01b0383168152604060208201526000610bb0604083018461236e565b60008235603e198336030181126125b357600080fd5b9190910192915050565b60008235601e198336030181126125b357600080fd5b600084356125e081611d41565b6001600160a01b0380821684526060602085015261260160608501876124ab565b925080851660408501525050949350505050565b6000808335601e1984360301811261262c57600080fd5b83018035915067ffffffffffffffff82111561264757600080fd5b6020019150600581901b360382131561119b57600080fd5b6000813561266c81611d41565b6001600160a01b03908116845260208301359061268882611d41565b16602084015261269b6040830183612419565b608060408601526126b0608086018284612462565b9150506126c06060840184612419565b858303606087015261107a838284612462565b60208152600082356126e481611d41565b6001600160a01b0380821660208501526020850135915061270482611d41565b80821660408501526040850135606085015260608501356080850152608085013560a085015260a0850135915061273a82611d41565b1660c08381019190915283013536849003607e1901811261275a57600080fd5b60e080840152610bb0610100840185830161265f565b60006020828403121561278257600080fd5b6040516020810181811067ffffffffffffffff821117156127a5576127a5611fe1565b60405290508082356127b681611d41565b905292915050565b6000602082840312156127d057600080fd5b6104668383612770565b600060e082360312156127ec57600080fd5b6127f4611ff7565b6127fd83611d56565b815261280b60208401611d56565b602082015260408301356040820152606083013560608201526080830135608082015261283b3660a08501612770565b60a082015260c083013567ffffffffffffffff81111561285a57600080fd5b612866368286016121d4565b60c08301525092915050565b600081518084526020808501945080840160005b838110156124a05781516001600160a01b031687529582019590820190600101612886565b60006001600160a01b03808351168452806020840151166020850152506040820151608060408501526128e16080850182612872565b905060608301518482036060860152610f4f8282612872565b6000843561290781611d41565b6001600160a01b0380821684526060602085015261260160608501876128ab565b634e487b7160e01b600052603260045260246000fd5b60008235603e1983360301811261295457600080fd5b90910192915050565b60008235601e1983360301811261295457600080fd5b602081526000823561298481611d41565b6001600160a01b0381166020840152506020830135604083015260408301356060830152606083013560808301526129c260a08301608085016123ff565b6129cf60a084018461293e565b6101008060c08501526129e66101208501836124ab565b91506129f560c086018661295d565b848303601f190160e0860152612a0b83826124e5565b925050612a1d81850160e087016123ff565b509392505050565b6020815260008235612a3681611d41565b6001600160a01b03808216602085015260208501359150612a5682611d41565b80821660408501526040850135606085015260608501356080850152608085013560a085015260a08501359150612a8c82611d41565b80821660c08501525050612aa360c084018461293e565b60e080840152610bb06101008401826124ab565b600082516125b381846020870161234a565b600060208284031215612adb57600080fd5b5051919050565b60006001600160a01b0380865116835260606020840152612b0660608401866128ab565b915080841660408401525094935050505056fea164736f6c6343000814000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.