Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 15 from a total of 15 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deploy Clone | 129101900 | 2 days ago | IN | 0 ETH | 0.000001828853 | ||||
Deploy Clone | 128782190 | 9 days ago | IN | 0 ETH | 0.000001483664 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000691078 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000695974 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000701232 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000701227 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000717004 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000701236 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000690716 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000769598 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000732781 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000695974 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000648657 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000732805 | ||||
Register | 128536711 | 15 days ago | IN | 0 ETH | 0.000000690725 |
Latest 3 internal transactions
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
129101900 | 2 days ago | Contract Creation | 0 ETH | |||
128782190 | 9 days ago | Contract Creation | 0 ETH | |||
128536648 | 15 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:
BoostRegistry
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 10000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {LibClone} from "@solady/utils/LibClone.sol"; import {ReentrancyGuard} from "@solady/utils/ReentrancyGuard.sol"; import {ABoostRegistry} from "contracts/ABoostRegistry.sol"; import {BoostLib} from "contracts/shared/BoostLib.sol"; import {ACloneable} from "contracts/shared/ACloneable.sol"; import {AAllowList} from "contracts/allowlists/AAllowList.sol"; /// @title Boost Registry /// @notice A registry for base implementations and cloned instances /// @dev This contract is used to register base implementations and deploy new instances of those implementations for use within the Boost protocol contract BoostRegistry is ABoostRegistry, ReentrancyGuard { using BoostLib for address; /// @notice The registry of base implementations mapping(bytes32 => ACloneable) private _bases; /// @notice The registry of deployed clones mapping(bytes32 => Clone) private _clones; /// @notice The registry of clones created by a given deployer mapping(address => bytes32[]) private _deployedClones; /// @notice A modifier to ensure the given address holds a valid {ACloneable} base /// @param implementation_ The address of the implementation to check modifier onlyACloneables(address implementation_) { if (!ACloneable(implementation_).supportsInterface(type(ACloneable).interfaceId)) { revert NotACloneable(implementation_); } _; } /// @notice Register a new base implementation of a given type /// @param type_ The base type for the implementation /// @param name_ A name for the implementation (must be unique within the given type) /// @param implementation_ The address of the implementation contract /// @dev This function will either emit a `Registered` event or revert if the identifier has already been registered /// @dev The given address must implement the given type interface (See {ERC165-supportsInterface}) function register(RegistryType type_, string calldata name_, address implementation_) external override onlyACloneables(implementation_) { bytes32 identifier = getIdentifier(type_, name_); if (address(_bases[identifier]) != address(0)) revert AlreadyRegistered(type_, identifier); _bases[identifier] = ACloneable(implementation_); emit Registered(type_, identifier, implementation_); } /// @notice Deploy a new instance of a registered base implementation /// @param type_ The type of base implementation to be cloned /// @param base_ The address of the base implementation to clone /// @param name_ The display name for the clone /// @param data_ The data payload for the cloned instance's initializer /// @return instance The address of the deployed instance /// @dev This function will either emit a `Deployed` event and return the clone or revert function deployClone(RegistryType type_, address base_, string calldata name_, bytes calldata data_) external override nonReentrant returns (ACloneable instance) { // Deploy and initialize the clone instance = ACloneable(base_.cloneAndInitialize(keccak256(abi.encodePacked(type_, base_, name_, msg.sender)), data_)); // Ensure the clone's identifier is unique bytes32 identifier = getCloneIdentifier(type_, base_, msg.sender, name_); if (address(_clones[identifier].instance) != address(0)) revert AlreadyRegistered(type_, identifier); // Register and report the newly deployed clone _deployedClones[msg.sender].push(identifier); _clones[identifier] = Clone({baseType: type_, instance: instance, deployer: msg.sender, name: name_}); emit Deployed(type_, identifier, base_, instance); } /// @notice Get the address of a registered base implementation /// @param identifier_ The unique identifier for the implementation (see {getIdentifier}) /// @return implementation The address of the implementation /// @dev This function will revert if the implementation is not registered function getBaseImplementation(bytes32 identifier_) public view override returns (ACloneable implementation) { implementation = _bases[identifier_]; if (address(implementation) == address(0)) revert NotRegistered(identifier_); } /// @notice Get the address of a deployed clone by its identifier /// @param identifier_ The unique identifier for the deployed clone (see {getCloneIdentifier}) /// @return clone The address of the deployed clone function getClone(bytes32 identifier_) external view override returns (Clone memory clone) { clone = _clones[identifier_]; if (address(clone.instance) == address(0)) revert NotRegistered(identifier_); } /// @notice Get the list of identifiers of deployed clones for a given deployer /// @param deployer_ The address of the deployer /// @return clones The list of deployed clones for the given deployer /// @dev WARNING: This function may return a large amount of data and is primarily intended for off-chain usage. It should be avoided in on-chain logic. function getClones(address deployer_) external view override returns (bytes32[] memory) { return _deployedClones[deployer_]; } /// @notice Build the identifier for a clone of a base implementation /// @param type_ The base type for the implementation /// @param base_ The address of the base implementation /// @param deployer_ The address of the deployer /// @param name_ The display name of the clone /// @return identifier The unique identifier for the clone function getCloneIdentifier(RegistryType type_, address base_, address deployer_, string calldata name_) public pure override returns (bytes32 identifier) { return _getIdentifier(type_, keccak256(abi.encodePacked(base_, deployer_, name_))); } /// @notice Build the identifier for a base implementation /// @param type_ The base type for the implementation /// @param name_ The name of the implementation /// @return identifier The unique identifier for the implementation function getIdentifier(RegistryType type_, string calldata name_) public pure override returns (bytes32 identifier) { return _getIdentifier(type_, keccak256(abi.encodePacked(name_))); } /// @notice Build a unique identifier for a given type and hash /// @param type_ The base type for the implementation /// @param hash_ The unique hash for the implementation /// @return identifier The unique identifier for the implementation function _getIdentifier(RegistryType type_, bytes32 hash_) internal pure returns (bytes32 identifier) { return keccak256(abi.encodePacked(type_, hash_)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Minimal proxy library. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/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) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Reentrancy guard mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol) abstract contract ReentrancyGuard { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unauthorized reentrant call. error Reentrancy(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`. /// 9 bytes is large enough to avoid collisions with lower slots, /// but not too large to result in excessive bytecode bloat. uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* REENTRANCY GUARD */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Guards a function from reentrancy. modifier nonReentrant() virtual { /// @solidity memory-safe-assembly assembly { if eq(sload(_REENTRANCY_GUARD_SLOT), address()) { mstore(0x00, 0xab143c06) // `Reentrancy()`. revert(0x1c, 0x04) } sstore(_REENTRANCY_GUARD_SLOT, address()) } _; /// @solidity memory-safe-assembly assembly { sstore(_REENTRANCY_GUARD_SLOT, codesize()) } } /// @dev Guards a view function from read-only reentrancy. modifier nonReadReentrant() virtual { /// @solidity memory-safe-assembly assembly { if eq(sload(_REENTRANCY_GUARD_SLOT), address()) { mstore(0x00, 0xab143c06) // `Reentrancy()`. revert(0x1c, 0x04) } } _; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import {ACloneable} from "contracts/shared/ACloneable.sol"; abstract contract ABoostRegistry is ERC165 { /// @notice The types of bases that can be registered enum RegistryType { ACTION, ALLOW_LIST, BUDGET, INCENTIVE, VALIDATOR } /// @notice The data structure for a deployed clone /// @param baseType The type of base implementation /// @param name The display name for the clone /// @param instance The address of the clone /// @param deployer The address of the deployer struct Clone { RegistryType baseType; ACloneable instance; address deployer; string name; } /// @notice Emitted when a new base implementation is registered event Registered(RegistryType indexed registryType, bytes32 indexed identifier, address implementation); /// @notice Emitted when a new instance of a base implementation is deployed event Deployed( RegistryType indexed registryType, bytes32 indexed identifier, address baseImplementation, ACloneable deployedInstance ); /// @notice Thrown when a base implementation is already registered error AlreadyRegistered(RegistryType registryType, bytes32 identifier); /// @notice Thrown when no match is found for the given identifier error NotRegistered(bytes32 identifier); /// @notice Thrown when the implementation is not a valid {ACloneable} base error NotACloneable(address implementation); /// @notice Register a new base implementation of a given type /// @param type_ The base type for the implementation /// @param name_ A name for the implementation (must be unique within the given type) /// @param implementation_ The address of the implementation contract /// @dev This function will either emit a `Registered` event or revert if the identifier has already been registered /// @dev The given address must implement the given type interface (See {ERC165-supportsInterface}) function register(RegistryType type_, string calldata name_, address implementation_) external virtual; /// @notice Deploy a new instance of a registered base implementation /// @param type_ The type of base implementation to be cloned /// @param base_ The address of the base implementation to clone /// @param name_ The display name for the clone /// @param data_ The data payload for the cloned instance's initializer /// @return instance The address of the deployed instance /// @dev This function will either emit a `Deployed` event and return the clone or revert function deployClone(RegistryType type_, address base_, string calldata name_, bytes calldata data_) external virtual returns (ACloneable instance); /// @notice Get the address of a registered base implementation /// @param identifier_ The unique identifier for the implementation (see {getIdentifier}) /// @return implementation The address of the implementation /// @dev This function will revert if the implementation is not registered function getBaseImplementation(bytes32 identifier_) external view virtual returns (ACloneable implementation); /// @notice Get the address of a deployed clone by its identifier /// @param identifier_ The unique identifier for the deployed clone (see {getCloneIdentifier}) /// @return clone The address of the deployed clone function getClone(bytes32 identifier_) external view virtual returns (Clone memory clone); /// @notice Get the list of identifiers of deployed clones for a given deployer /// @param deployer_ The address of the deployer /// @return clones The list of deployed clones for the given deployer /// @dev WARNING: This function may return a large amount of data and is primarily intended for off-chain usage. It should be avoided in on-chain logic. function getClones(address deployer_) external view virtual returns (bytes32[] memory); /// @notice Build the identifier for a clone of a base implementation /// @param type_ The base type for the implementation /// @param base_ The address of the base implementation /// @param deployer_ The address of the deployer /// @param name_ The display name of the clone /// @return identifier The unique identifier for the clone function getCloneIdentifier(RegistryType type_, address base_, address deployer_, string calldata name_) external pure virtual returns (bytes32 identifier); /// @notice Build the identifier for a base implementation /// @param type_ The base type for the implementation /// @param name_ The name of the implementation /// @return identifier The unique identifier for the implementation function getIdentifier(RegistryType type_, string calldata name_) external pure virtual returns (bytes32 identifier); function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(ABoostRegistry).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {LibClone} from "@solady/utils/LibClone.sol"; import {LibZip} from "@solady/utils/LibZip.sol"; import {AAction} from "contracts/actions/AAction.sol"; import {AAllowList} from "contracts/allowlists/AAllowList.sol"; import {ABudget} from "contracts/budgets/ABudget.sol"; import {ACloneable} from "contracts/shared/ACloneable.sol"; import {AIncentive} from "contracts/incentives/AIncentive.sol"; import {AValidator} from "contracts/validators/AValidator.sol"; library BoostLib { using LibClone for address; using LibZip for bytes; /// @notice A struct representing a single Boost struct Boost { AAction action; AValidator validator; AAllowList allowList; ABudget budget; AIncentive[] incentives; uint64 protocolFee; uint256 maxParticipants; address owner; } /// @notice A base struct for a contract and its initialization parameters /// @dev This is used to pass the base contract and its initialization parameters in an efficient manner struct Target { bool isBase; address instance; bytes parameters; } /// @notice Clone and initialize a contract with a deterministic salt /// @param $ The contract to clone and initialize /// @param salt_ The salt for the deterministic clone /// @param initData_ The initialization data for the contract /// @return _clone The cloned and initialized contract function cloneAndInitialize(address $, bytes32 salt_, bytes memory initData_) internal returns (address _clone) { _clone = $.cloneDeterministic(salt_); // wake-disable-next-line reentrancy (false positive) ACloneable(_clone).initialize(initData_); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {Initializable} from "@solady/utils/Initializable.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; /// @title ACloneable /// @notice A contract that can be cloned and initialized only once abstract contract ACloneable is Initializable, ERC165 { /// @notice Thrown when an inheriting contract does not implement the initializer function error InitializerNotImplemented(); /// @notice Thrown when the provided initialization data is invalid /// @dev This error indicates that the given data is not valid for the implementation (i.e. does not decode to the expected types) error InvalidInitializationData(); /// @notice Thrown when the contract has already been initialized error CloneAlreadyInitialized(); /// @notice Initialize the clone with the given arbitrary data /// @param - The compressed initialization data (if required) /// @dev The data is expected to be ABI encoded bytes compressed using {LibZip-cdCompress} /// @dev All implementations must override this function to initialize the contract function initialize(bytes calldata) public virtual initializer { revert InitializerNotImplemented(); } /// @notice /// @param - Return a cloneable's unique identifier for downstream consumers to differentiate various targets /// @dev All implementations must override this function function getComponentInterface() public pure virtual returns (bytes4); /// @inheritdoc ERC165 /// @notice Check if the contract supports the given interface /// @param interfaceId The interface identifier /// @return True if the contract supports the interface function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(ACloneable).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {ACloneable} from "contracts/shared/ACloneable.sol"; import {RBAC} from "contracts/shared/RBAC.sol"; /// @title Boost AllowList /// @notice Abstract contract for a generic Allow List within the Boost protocol /// @dev Allow List classes are expected to implement the authorization of users based on implementation-specific criteria, which may involve validation of a data payload. If no data is required, calldata should be empty. abstract contract AAllowList is ACloneable, RBAC { /// @notice Check if a user is authorized /// @param user_ The address of the user /// @param data_ The data payload for the authorization check, if applicable /// @return True if the user is authorized function isAllowed(address user_, bytes calldata data_) external view virtual returns (bool); /// @inheritdoc ACloneable function supportsInterface(bytes4 interfaceId) public view virtual override(ACloneable) returns (bool) { return interfaceId == type(AAllowList).interfaceId || super.supportsInterface(interfaceId); } }
// 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 ERC-165 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 pragma solidity ^0.8.4; /// @notice Library for compressing and decompressing bytes. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibZip.sol) /// @author Calldata compression by clabby (https://github.com/clabby/op-kompressor) /// @author FastLZ by ariya (https://github.com/ariya/FastLZ) /// /// @dev Note: /// The accompanying solady.js library includes implementations of /// FastLZ and calldata operations for convenience. library LibZip { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FAST LZ OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // LZ77 implementation based on FastLZ. // Equivalent to level 1 compression and decompression at the following commit: // https://github.com/ariya/FastLZ/commit/344eb4025f9ae866ebf7a2ec48850f7113a97a42 // Decompression is backwards compatible. /// @dev Returns the compressed `data`. function flzCompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { function ms8(d_, v_) -> _d { mstore8(d_, v_) _d := add(d_, 1) } function u24(p_) -> _u { _u := mload(p_) _u := or(shl(16, byte(2, _u)), or(shl(8, byte(1, _u)), byte(0, _u))) } function cmp(p_, q_, e_) -> _l { for { e_ := sub(e_, q_) } lt(_l, e_) { _l := add(_l, 1) } { e_ := mul(iszero(byte(0, xor(mload(add(p_, _l)), mload(add(q_, _l))))), e_) } } function literals(runs_, src_, dest_) -> _o { for { _o := dest_ } iszero(lt(runs_, 0x20)) { runs_ := sub(runs_, 0x20) } { mstore(ms8(_o, 31), mload(src_)) _o := add(_o, 0x21) src_ := add(src_, 0x20) } if iszero(runs_) { leave } mstore(ms8(_o, sub(runs_, 1)), mload(src_)) _o := add(1, add(_o, runs_)) } function mt(l_, d_, o_) -> _o { for { d_ := sub(d_, 1) } iszero(lt(l_, 263)) { l_ := sub(l_, 262) } { o_ := ms8(ms8(ms8(o_, add(224, shr(8, d_))), 253), and(0xff, d_)) } if iszero(lt(l_, 7)) { _o := ms8(ms8(ms8(o_, add(224, shr(8, d_))), sub(l_, 7)), and(0xff, d_)) leave } _o := ms8(ms8(o_, add(shl(5, l_), shr(8, d_))), and(0xff, d_)) } function setHash(i_, v_) { let p_ := add(mload(0x40), shl(2, i_)) mstore(p_, xor(mload(p_), shl(224, xor(shr(224, mload(p_)), v_)))) } function getHash(i_) -> _h { _h := shr(224, mload(add(mload(0x40), shl(2, i_)))) } function hash(v_) -> _r { _r := and(shr(19, mul(2654435769, v_)), 0x1fff) } function setNextHash(ip_, ipStart_) -> _ip { setHash(hash(u24(ip_)), sub(ip_, ipStart_)) _ip := add(ip_, 1) } result := mload(0x40) codecopy(result, codesize(), 0x8000) // Zeroize the hashmap. let op := add(result, 0x8000) let a := add(data, 0x20) let ipStart := a let ipLimit := sub(add(ipStart, mload(data)), 13) for { let ip := add(2, a) } lt(ip, ipLimit) {} { let r := 0 let d := 0 for {} 1 {} { let s := u24(ip) let h := hash(s) r := add(ipStart, getHash(h)) setHash(h, sub(ip, ipStart)) d := sub(ip, r) if iszero(lt(ip, ipLimit)) { break } ip := add(ip, 1) if iszero(gt(d, 0x1fff)) { if eq(s, u24(r)) { break } } } if iszero(lt(ip, ipLimit)) { break } ip := sub(ip, 1) if gt(ip, a) { op := literals(sub(ip, a), a, op) } let l := cmp(add(r, 3), add(ip, 3), add(ipLimit, 9)) op := mt(l, d, op) ip := setNextHash(setNextHash(add(ip, l), ipStart), ipStart) a := ip } // Copy the result to compact the memory, overwriting the hashmap. let end := sub(literals(sub(add(ipStart, mload(data)), a), a, op), 0x7fe0) let o := add(result, 0x20) mstore(result, sub(end, o)) // Store the length. for {} iszero(gt(o, end)) { o := add(o, 0x20) } { mstore(o, mload(add(o, 0x7fe0))) } mstore(end, 0) // Zeroize the slot after the string. mstore(0x40, add(end, 0x20)) // Allocate the memory. } } /// @dev Returns the decompressed `data`. function flzDecompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let op := add(result, 0x20) let end := add(add(data, 0x20), mload(data)) for { data := add(data, 0x20) } lt(data, end) {} { let w := mload(data) let c := byte(0, w) let t := shr(5, c) if iszero(t) { mstore(op, mload(add(data, 1))) data := add(data, add(2, c)) op := add(op, add(1, c)) continue } for { let g := eq(t, 7) let l := add(2, xor(t, mul(g, xor(t, add(7, byte(1, w)))))) // M let s := add(add(shl(8, and(0x1f, c)), byte(add(1, g), w)), 1) // R let r := sub(op, s) let f := xor(s, mul(gt(s, 0x20), xor(s, 0x20))) let j := 0 } 1 {} { mstore(add(op, j), mload(add(r, j))) j := add(j, f) if lt(j, l) { continue } data := add(data, add(2, g)) op := add(op, l) break } } mstore(result, sub(op, add(result, 0x20))) // Store the length. mstore(op, 0) // Zeroize the slot after the string. mstore(0x40, add(op, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CALLDATA OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Calldata compression and decompression using selective run length encoding: // - Sequences of 0x00 (up to 128 consecutive). // - Sequences of 0xff (up to 32 consecutive). // // A run length encoded block consists of two bytes: // (0) 0x00 // (1) A control byte with the following bit layout: // - [7] `0: 0x00, 1: 0xff`. // - [0..6] `runLength - 1`. // // The first 4 bytes are bitwise negated so that the compressed calldata // can be dispatched into the `fallback` and `receive` functions. /// @dev Returns the compressed `data`. function cdCompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { function rle(v_, o_, d_) -> _o, _d { mstore(o_, shl(240, or(and(0xff, add(d_, 0xff)), and(0x80, v_)))) _o := add(o_, 2) } result := mload(0x40) let o := add(result, 0x20) let z := 0 // Number of consecutive 0x00. let y := 0 // Number of consecutive 0xff. for { let end := add(data, mload(data)) } iszero(eq(data, end)) {} { data := add(data, 1) let c := byte(31, mload(data)) if iszero(c) { if y { o, y := rle(0xff, o, y) } z := add(z, 1) if eq(z, 0x80) { o, z := rle(0x00, o, 0x80) } continue } if eq(c, 0xff) { if z { o, z := rle(0x00, o, z) } y := add(y, 1) if eq(y, 0x20) { o, y := rle(0xff, o, 0x20) } continue } if y { o, y := rle(0xff, o, y) } if z { o, z := rle(0x00, o, z) } mstore8(o, c) o := add(o, 1) } if y { o, y := rle(0xff, o, y) } if z { o, z := rle(0x00, o, z) } // Bitwise negate the first 4 bytes. mstore(add(result, 4), not(mload(add(result, 4)))) mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /// @dev Returns the decompressed `data`. function cdDecompress(bytes memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { if mload(data) { result := mload(0x40) let o := add(result, 0x20) let s := add(data, 4) let v := mload(s) let end := add(data, mload(data)) mstore(s, not(v)) // Bitwise negate the first 4 bytes. for {} lt(data, end) {} { data := add(data, 1) let c := byte(31, mload(data)) if iszero(c) { data := add(data, 1) let d := byte(31, mload(data)) // Fill with either 0xff or 0x00. mstore(o, not(0)) if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) } o := add(o, add(and(d, 0x7f), 1)) continue } mstore8(o, c) o := add(o, 1) } mstore(s, v) // Restore the first 4 bytes. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } } /// @dev To be called in the `fallback` function. /// ``` /// fallback() external payable { LibZip.cdFallback(); } /// receive() external payable {} // Silence compiler warning to add a `receive` function. /// ``` /// For efficiency, this function will directly return the results, terminating the context. /// If called internally, it must be called at the end of the function. function cdFallback() internal { assembly { if iszero(calldatasize()) { return(calldatasize(), calldatasize()) } let o := 0 let f := not(3) // For negating the first 4 bytes. for { let i := 0 } lt(i, calldatasize()) {} { let c := byte(0, xor(add(i, f), calldataload(i))) i := add(i, 1) if iszero(c) { let d := byte(0, xor(add(i, f), calldataload(i))) i := add(i, 1) // Fill with either 0xff or 0x00. mstore(o, not(0)) if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) } o := add(o, add(and(d, 0x7f), 1)) continue } mstore8(o, c) o := add(o, 1) } let success := delegatecall(gas(), address(), 0x00, o, codesize(), 0x00) returndatacopy(0x00, 0x00, returndatasize()) if iszero(success) { revert(0x00, returndatasize()) } return(0x00, returndatasize()) } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {ACloneable} from "contracts/shared/ACloneable.sol"; import {AValidator} from "contracts/validators/AValidator.sol"; /// @title Boost AAction /// @notice Abstract contract for a generic AAction within the Boost protocol /// @dev AAction classes are expected to decode the calldata for implementation-specific handling. If no data is required, calldata should be empty. abstract contract AAction is ACloneable { /// @notice Emitted when the action is executed by a proxy. /// @dev The `data` field should contain the return data from the action, if any. event ActionExecuted(address indexed executor, address caller, bool success, bytes data); /// @notice Emitted when the action is validated /// @dev The `data` field should contain implementation-specific context, if applicable. event ActionValidated(address indexed user, bool isValidated, bytes data); /// @notice The validator for the action (which may be the action itself where appropriate) AValidator public immutable VALIDATOR; /// @notice Execute the action /// @param data_ The data payload for the action /// @return (success, data) A tuple of the success status and the returned data function execute(bytes calldata data_) external payable virtual returns (bool, bytes memory); /// @notice Prepare the action for execution and return the expected payload /// @param data_ The data payload for the action /// @return The prepared payload function prepare(bytes calldata data_) external virtual returns (bytes memory); /// @inheritdoc ACloneable function supportsInterface(bytes4 interfaceId) public view virtual override(ACloneable) returns (bool) { return interfaceId == type(AAction).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {Receiver} from "@solady/accounts/Receiver.sol"; import {BoostError} from "contracts/shared/BoostError.sol"; import {ACloneable} from "contracts/shared/ACloneable.sol"; import {AIncentive} from "contracts/incentives/AIncentive.sol"; import {RBAC} from "contracts/shared/RBAC.sol"; import {IClaw} from "contracts/shared/IClaw.sol"; /// @title Boost ABudget /// @notice Abstract contract for a generic ABudget within the Boost protocol /// @dev ABudget classes are expected to implement the allocation, reclamation, and disbursement of assets. /// @dev WARNING: Budgets currently support only ETH, ERC20, and ERC1155 assets. Other asset types may be added in the future. abstract contract ABudget is ACloneable, Receiver, RBAC { enum AssetType { ETH, ERC20, ERC1155 } /// @notice A struct representing the inputs for an allocation /// @param assetType The type of asset to allocate /// @param asset The address of the asset to allocate /// @param target The address of the payee or payer (from or to, depending on the operation) /// @param data The implementation-specific data for the allocation (amount, token ID, etc.) struct Transfer { AssetType assetType; address asset; address target; bytes data; } /// @notice The payload for an ETH or ERC20 transfer /// @param amount The amount of the asset to transfer struct FungiblePayload { uint256 amount; } /// @notice The payload for an ERC1155 transfer /// @param tokenId The ID of the token to transfer /// @param amount The amount of the token to transfer /// @param data Any additional data to forward to the ERC1155 contract struct ERC1155Payload { uint256 tokenId; uint256 amount; bytes data; } /// @notice Emitted when assets are distributed from the budget event Distributed(address indexed asset, address to, uint256 amount); /// @notice Thrown when the allocation is invalid error InvalidAllocation(address asset, uint256 amount); /// @notice Thrown when there are insufficient funds for an operation error InsufficientFunds(address asset, uint256 available, uint256 required); /// @notice Thrown when a transfer fails for an unknown reason error TransferFailed(address asset, address to, uint256 amount); /// @notice Allocate assets to the budget /// @param data_ The compressed data for the allocation (amount, token address, token ID, etc.) /// @return True if the allocation was successful function allocate(bytes calldata data_) external payable virtual returns (bool); /// @notice Reclaim assets from the budget /// @param data_ The compressed data for the reclamation (amount, token address, token ID, etc.) /// @return True if the reclamation was successful function clawback(bytes calldata data_) external virtual returns (uint256); /// @notice Pull assets from an Incentive back into a budget /// @param target The address of the target contract to claw back from /// @param data_ The packed {AIncentive.ClawbackPayload.data} request /// @return True if the reclamation was successful /// @dev admins and managers can directly reclaim assets from an incentive /// @dev the budget can only clawback funds from incentives it originally funded /// @dev If the asset transfer fails, the reclamation will revert function clawbackFromTarget(address target, bytes calldata data_, uint256 boostId, uint256 incentiveId) external virtual onlyAuthorized returns (uint256, address) { AIncentive.ClawbackPayload memory payload = AIncentive.ClawbackPayload({target: address(this), data: data_}); return IClaw(target).clawback(abi.encode(payload), boostId, incentiveId); } /// @notice Disburse assets from the budget to a single recipient /// @param data_ The compressed {Transfer} request /// @return True if the disbursement was successful function disburse(bytes calldata data_) external virtual returns (bool); /// @notice Disburse assets from the budget to multiple recipients /// @param data_ The array of compressed {Transfer} requests /// @return True if all disbursements were successful function disburseBatch(bytes[] calldata data_) external virtual returns (bool); /// @notice Get the total amount of assets allocated to the budget, including any that have been distributed /// @param asset_ The address of the asset /// @return The total amount of assets function total(address asset_) external view virtual returns (uint256); /// @notice Get the amount of assets available for distribution from the budget /// @param asset_ The address of the asset /// @return The amount of assets available function available(address asset_) external view virtual returns (uint256); /// @notice Get the amount of assets that have been distributed from the budget /// @param asset_ The address of the asset /// @return The amount of assets distributed function distributed(address asset_) external view virtual returns (uint256); /// @notice Reconcile the budget to ensure the known state matches the actual state /// @param data_ The compressed data for the reconciliation (amount, token address, token ID, etc.) /// @return The amount of assets reconciled function reconcile(bytes calldata data_) external virtual returns (uint256); /// @inheritdoc ACloneable function supportsInterface(bytes4 interfaceId) public view virtual override(ACloneable) returns (bool) { return interfaceId == type(ABudget).interfaceId || super.supportsInterface(interfaceId); } /// @inheritdoc Receiver receive() external payable virtual override { return; } /// @inheritdoc Receiver fallback() external payable virtual override { revert BoostError.NotImplemented(); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {ReentrancyGuard} from "@solady/utils/ReentrancyGuard.sol"; import {ACloneable} from "contracts/shared/ACloneable.sol"; import {IBoostClaim} from "contracts/shared/IBoostClaim.sol"; /// @title Boost AIncentive /// @notice Abstract contract for a generic AIncentive within the Boost protocol /// @dev AIncentive classes are expected to decode the calldata for implementation-specific handling. If no data is required, calldata should be empty. abstract contract AIncentive is IBoostClaim, ACloneable { /// @notice Emitted when an incentive is claimed /// @dev The `data` field contains implementation-specific context. See the implementation's `claim` function for details. event Claimed(address indexed recipient, bytes data); /// @notice Thrown when a claim fails error ClaimFailed(); /// @notice Thrown when the incentive is not claimable error NotClaimable(); /// @notice A struct representing the payload for an incentive claim /// @param target The address of the recipient /// @param data The implementation-specific data for the claim, if needed struct ClawbackPayload { address target; bytes data; } /// @notice The reward amount issued for each claim uint256 public reward; /// @notice The number of claims that have been made function claims() external virtual returns (uint256); /// @notice Claim the incentive /// @param data_ The data payload for the incentive claim /// @return True if the incentive was successfully claimed function claim(address claimant, bytes calldata data_) external virtual returns (bool); /// @notice Reclaim assets from the incentive /// @param data_ The data payload for the reclaim /// @return True if the assets were successfully reclaimed function clawback(bytes calldata data_) external virtual returns (uint256, address); /// @notice Check if an incentive is claimable /// @param data_ The data payload for the claim check (data, signature, etc.) /// @return True if the incentive is claimable based on the data payload function isClaimable(address claimant, bytes calldata data_) external view virtual returns (bool); /// @notice Get the required allowance for the incentive /// @param data_ The initialization payload for the incentive /// @return The data payload to be passed to the {ABudget} for interpretation /// @dev This function is to be called by {BoostCore} before the incentive is initialized to determine the required budget allowance. It returns an ABI-encoded payload that can be passed directly to the {ABudget} contract for interpretation. function preflight(bytes calldata data_) external view virtual returns (bytes memory); function asset() external view virtual returns (address) { return address(0xdeaDDeADDEaDdeaDdEAddEADDEAdDeadDEADDEaD); } /// @return The current reward function currentReward() public view virtual returns (uint256) { return reward; } /// @inheritdoc ACloneable function supportsInterface(bytes4 interfaceId) public view virtual override(ACloneable) returns (bool) { return interfaceId == type(AIncentive).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {ACloneable} from "contracts/shared/ACloneable.sol"; /// @title Boost Validator /// @notice Abstract contract for a generic Validator within the Boost protocol /// @dev Validator classes are expected to decode the calldata for implementation-specific handling. If no data is required, calldata should be empty. abstract contract AValidator is ACloneable { /// @notice Validate that a given user has completed an acction successfully /// @param boostId The Id from the available boosts /// @param incentiveId The Id from the available boost incentives to be claimed /// @param claimant The address of the user claiming the incentive /// @param data The encoded payload to be validated /// @return True if the action has been validated based on the data payload /// @dev The decompressed payload contains freeform bytes that are entirely implementation-specific function validate(uint256 boostId, uint256 incentiveId, address claimant, bytes calldata data) external virtual returns (bool); /// @inheritdoc ACloneable function supportsInterface(bytes4 interfaceId) public view virtual override(ACloneable) returns (bool) { return interfaceId == type(AValidator).interfaceId || super.supportsInterface(interfaceId); } /// @inheritdoc ACloneable function getComponentInterface() public pure virtual override(ACloneable) returns (bytes4) { return type(AValidator).interfaceId; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Initializable mixin for the upgradeable contracts. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Initializable.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/proxy/utils/Initializable.sol) abstract contract Initializable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The contract is already initialized. error InvalidInitialization(); /// @dev The contract is not initializing. error NotInitializing(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Triggered when the contract has been initialized. event Initialized(uint64 version); /// @dev `keccak256(bytes("Initialized(uint64)"))`. bytes32 private constant _INTIALIZED_EVENT_SIGNATURE = 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default initializable slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_INITIALIZABLE_SLOT")))))`. /// /// Bits Layout: /// - [0] `initializing` /// - [1..64] `initializedVersion` bytes32 private constant _INITIALIZABLE_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf601132; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return a custom storage slot if required. function _initializableSlot() internal pure virtual returns (bytes32) { return _INITIALIZABLE_SLOT; } /// @dev Guards an initializer function so that it can be invoked at most once. /// /// You can guard a function with `onlyInitializing` such that it can be called /// through a function guarded with `initializer`. /// /// This is similar to `reinitializer(1)`, except that in the context of a constructor, /// an `initializer` guarded function can be invoked multiple times. /// This can be useful during testing and is not expected to be used in production. /// /// Emits an {Initialized} event. modifier initializer() virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { let i := sload(s) // Set `initializing` to 1, `initializedVersion` to 1. sstore(s, 3) // If `!(initializing == 0 && initializedVersion == 0)`. if i { // If `!(address(this).code.length == 0 && initializedVersion == 1)`. if iszero(lt(extcodesize(address()), eq(shr(1, i), 1))) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } s := shl(shl(255, i), s) // Skip initializing if `initializing == 1`. } } _; /// @solidity memory-safe-assembly assembly { if s { // Set `initializing` to 0, `initializedVersion` to 1. sstore(s, 2) // Emit the {Initialized} event. mstore(0x20, 1) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } } /// @dev Guards an reinitialzer function so that it can be invoked at most once. /// /// You can guard a function with `onlyInitializing` such that it can be called /// through a function guarded with `reinitializer`. /// /// Emits an {Initialized} event. modifier reinitializer(uint64 version) virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { version := and(version, 0xffffffffffffffff) // Clean upper bits. let i := sload(s) // If `initializing == 1 || initializedVersion >= version`. if iszero(lt(and(i, 1), lt(shr(1, i), version))) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } // Set `initializing` to 1, `initializedVersion` to `version`. sstore(s, or(1, shl(1, version))) } _; /// @solidity memory-safe-assembly assembly { // Set `initializing` to 0, `initializedVersion` to `version`. sstore(s, shl(1, version)) // Emit the {Initialized} event. mstore(0x20, version) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } /// @dev Guards a function such that it can only be called in the scope /// of a function guarded with `initializer` or `reinitializer`. modifier onlyInitializing() virtual { _checkInitializing(); _; } /// @dev Reverts if the contract is not initializing. function _checkInitializing() internal view virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { if iszero(and(1, sload(s))) { mstore(0x00, 0xd7e6bcf8) // `NotInitializing()`. revert(0x1c, 0x04) } } } /// @dev Locks any future initializations by setting the initialized version to `2**64 - 1`. /// /// Calling this in the constructor will prevent the contract from being initialized /// or reinitialized. 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 called. function _disableInitializers() internal virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { let i := sload(s) if and(i, 1) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } let uint64max := shr(192, s) // Computed to save bytecode. if iszero(eq(shr(1, i), uint64max)) { // Set `initializing` to 0, `initializedVersion` to `2**64 - 1`. sstore(s, shl(1, uint64max)) // Emit the {Initialized} event. mstore(0x20, uint64max) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } } /// @dev Returns the highest version that has been initialized. function _getInitializedVersion() internal view virtual returns (uint64 version) { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { version := shr(1, sload(s)) } } /// @dev Returns whether the contract is currently initializing. function _isInitializing() internal view virtual returns (bool result) { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { result := and(1, sload(s)) } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; import {OwnableRoles} from "@solady/auth/OwnableRoles.sol"; import {BoostError} from "contracts/shared/BoostError.sol"; /// @title RBAC Functionality /// @notice A minimal ) /// @dev This type of budget supports ETH, ERC20, and ERC1155 assets only contract RBAC is OwnableRoles { /// @notice The role for managing allocations to Incentives. uint256 public constant MANAGER_ROLE = _ROLE_0; /// @notice The role for depositing, withdrawal, and manager management uint256 public constant ADMIN_ROLE = _ROLE_1; /// @notice A modifier that allows only authorized addresses to call the function modifier onlyAuthorized() { if (!isAuthorized(msg.sender)) revert BoostError.Unauthorized(); _; } /// @notice Check if the given account has any level of access to modify permissions on the resource /// @param account_ The account to check /// @return True if the account is authorized /// @dev The mechanism for checking authorization is left to the implementing contract function isAuthorized(address account_) public view virtual returns (bool) { return owner() == account_ || hasAnyRole(account_, MANAGER_ROLE | ADMIN_ROLE); } /// @notice Set roles for accounts authoried to use the resource as managers /// @param accounts_ The accounts to grant or revoke the MANAGER_ROLE by index /// @param authorized_ Whether to grant or revoke the MANAGER_ROLE function setAuthorized(address[] calldata accounts_, bool[] calldata authorized_) external virtual onlyOwnerOrRoles(ADMIN_ROLE) { if (accounts_.length != authorized_.length) { revert BoostError.LengthMismatch(); } for (uint256 i = 0; i < accounts_.length; i++) { bool authorization = authorized_[i]; if (authorization == true) { _grantRoles(accounts_[i], MANAGER_ROLE); } else { _removeRoles(accounts_[i], MANAGER_ROLE); } } } /// @notice Set roles for accounts authorized to use the resource /// @param accounts_ The accounts to assign the corresponding role by index /// @param roles_ The roles to assign function grantManyRoles(address[] calldata accounts_, uint256[] calldata roles_) external virtual onlyOwnerOrRoles(ADMIN_ROLE) { if (accounts_.length != roles_.length) { revert BoostError.LengthMismatch(); } for (uint256 i = 0; i < accounts_.length; i++) { _grantRoles(accounts_[i], roles_[i]); } } /// @notice Revoke roles for accounts authorized to use the resource /// @param accounts_ The accounts to assign the corresponding role by index /// @param roles_ The roles to remove function revokeManyRoles(address[] calldata accounts_, uint256[] calldata roles_) external virtual onlyOwnerOrRoles(ADMIN_ROLE) { if (accounts_.length != roles_.length) { revert BoostError.LengthMismatch(); } for (uint256 i = 0; i < accounts_.length; i++) { _removeRoles(accounts_[i], roles_[i]); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Receiver mixin for ETH and safe-transferred ERC721 and ERC1155 tokens. /// @author Solady (https://github.com/Vectorized/solady/blob/main/src/accounts/Receiver.sol) /// /// @dev Note: /// - Handles all ERC721 and ERC1155 token safety callbacks. /// - Collapses function table gas overhead and code size. /// - Utilizes fallback so unknown calldata will pass on. abstract contract Receiver { /// @dev For receiving ETH. receive() external payable virtual {} /// @dev Fallback function with the `receiverFallback` modifier. fallback() external payable virtual receiverFallback {} /// @dev Modifier for the fallback function to handle token callbacks. modifier receiverFallback() virtual { /// @solidity memory-safe-assembly assembly { let s := shr(224, calldataload(0)) // 0x150b7a02: `onERC721Received(address,address,uint256,bytes)`. // 0xf23a6e61: `onERC1155Received(address,address,uint256,uint256,bytes)`. // 0xbc197c81: `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`. if or(eq(s, 0x150b7a02), or(eq(s, 0xf23a6e61), eq(s, 0xbc197c81))) { mstore(0x20, s) // Store `msg.sig`. return(0x3c, 0x20) // Return `msg.sig`. } } _; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; /// @title BoostError /// @notice Standardized errors for the Boost protocol /// @dev Some of these errors are introduced by third-party libraries, rather than Boost contracts directly, and are copied here for clarity and ease of testing. library BoostError { /// @notice Thrown when a claim attempt fails error ClaimFailed(address caller, bytes data); /// @notice Thrown when there are insufficient funds for an operation error InsufficientFunds(address asset, uint256 available, uint256 required); /// @notice Thrown when a non-conforming instance for a given type is encountered error InvalidInstance(bytes4 expectedInterface, address instance); /// @notice Thrown when an invalid initialization is attempted error InvalidInitialization(); /// @notice Thrown when the length of two arrays are not equal error LengthMismatch(); /// @notice Thrown when a method is not implemented error NotImplemented(); /// @notice Thrown when a previously used signature is replayed error Replayed(address signer, bytes32 hash, bytes signature); /// @notice Thrown when a transfer fails for an unknown reason error TransferFailed(address asset, address to, uint256 amount); /// @notice Thrown when the requested action is unauthorized error Unauthorized(); /// @notice Thrown when an incentive id exceeds the available incentives error InvalidIncentive(uint8 available, uint256 id); /// @notice thrown when an incentiveId is larger than 7 error IncentiveToBig(uint8 incentiveId); /// @notice thrown when an incentiveId is already claimed against error IncentiveClaimed(uint8 incentiveId); /// @notice thrown when a clawback attempt result in a zero amount error ClawbackFailed(address caller, bytes data); /// @notice thrown when an address has claimed the maximum possible quantity error MaximumClaimed(address claimant); /// @notice thrown when an impossible math percentage is calculated error InvalidPercentage(uint256 percent); /// @notice thrown when a payout fails due to a zero-balance payout error ZeroBalancePayout(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; interface IClaw { /// @notice Reclaim assets from the incentive /// @param data_ The data payload for the reclaim /// @return True if the assets were successfully reclaimed function clawback(bytes calldata data_, uint256 boostId, uint256 incentiveId) external returns (uint256, address); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.24; interface IBoostClaim { /// @notice A higher order struct for encoding and decoding arbitrary claims struct BoostClaimData { bytes validatorData; bytes incentiveData; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {Ownable} from "./Ownable.sol"; /// @notice Simple single owner and multiroles authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) /// for compatibility, the nomenclature for the 2-step ownership handover and roles /// may be unique to this codebase. abstract contract OwnableRoles is Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `user`'s roles is updated to `roles`. /// Each bit of `roles` represents whether the role is set. event RolesUpdated(address indexed user, uint256 indexed roles); /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) /// let roleSlot := keccak256(0x00, 0x20) /// ``` /// This automatically ignores the upper bits of the `user` in case /// they are not clean, as well as keep the `keccak256` under 32-bytes. /// /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`. uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Overwrite the roles directly without authorization guard. function _setRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Store the new value. sstore(keccak256(0x0c, 0x20), roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @dev Updates the roles directly without authorization guard. /// If `on` is true, each set bit of `roles` will be turned on, /// otherwise, each set bit of `roles` will be turned off. function _updateRoles(address user, uint256 roles, bool on) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value. let current := sload(roleSlot) // Compute the updated roles if `on` is true. let updated := or(current, roles) // Compute the updated roles if `on` is false. // Use `and` to compute the intersection of `current` and `roles`, // `xor` it with `current` to flip the bits in the intersection. if iszero(on) { updated := xor(current, and(current, roles)) } // Then, store the new value. sstore(roleSlot, updated) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) } } /// @dev Grants the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn on. function _grantRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, true); } /// @dev Removes the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn off. function _removeRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, false); } /// @dev Throws if the sender does not have any of the `roles`. function _checkRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Throws if the sender is not the owner, /// and does not have any of the `roles`. /// Checks for ownership first, then lazily checks for roles. function _checkOwnerOrRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Throws if the sender does not have any of the `roles`, /// and is not the owner. /// Checks for roles first, then lazily checks for ownership. function _checkRolesOrOwner(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { // We don't need to mask the values of `ordinals`, as Solidity // cleans dirty upper bits when storing variables into memory. roles := or(shl(mload(add(ordinals, i)), 1), roles) } } } /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { /// @solidity memory-safe-assembly assembly { // Grab the pointer to the free memory. ordinals := mload(0x40) let ptr := add(ordinals, 0x20) let o := 0 // The absence of lookup tables, De Bruijn, etc., here is intentional for // smaller bytecode, as this function is not meant to be called on-chain. for { let t := roles } 1 {} { mstore(ptr, o) // `shr` 5 is equivalent to multiplying by 0x20. // Push back into the ordinals array if the bit is set. ptr := add(ptr, shl(5, and(t, 1))) o := add(o, 1) t := shr(o, roles) if iszero(t) { break } } // Store the length of `ordinals`. mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) // Allocate the memory. mstore(0x40, ptr) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to grant `user` `roles`. /// If the `user` already has a role, then it will be an no-op for the role. function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { _grantRoles(user, roles); } /// @dev Allows the owner to remove `user` `roles`. /// If the `user` does not have a role, then it will be an no-op for the role. function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { _removeRoles(user, roles); } /// @dev Allow the caller to remove their own roles. /// If the caller does not have a role, then it will be an no-op for the role. function renounceRoles(uint256 roles) public payable virtual { _removeRoles(msg.sender, roles); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the roles of `user`. function rolesOf(address user) public view virtual returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Load the stored value. roles := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles != 0; } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles == roles; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by an account with `roles`. modifier onlyRoles(uint256 roles) virtual { _checkRoles(roles); _; } /// @dev Marks a function as only callable by the owner or by an account /// with `roles`. Checks for ownership first, then lazily checks for roles. modifier onlyOwnerOrRoles(uint256 roles) virtual { _checkOwnerOrRoles(roles); _; } /// @dev Marks a function as only callable by an account with `roles` /// or the owner. Checks for roles first, then lazily checks for ownership. modifier onlyRolesOrOwner(uint256 roles) virtual { _checkRolesOrOwner(roles); _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ROLE CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // IYKYK uint256 internal constant _ROLE_0 = 1 << 0; uint256 internal constant _ROLE_1 = 1 << 1; uint256 internal constant _ROLE_2 = 1 << 2; uint256 internal constant _ROLE_3 = 1 << 3; uint256 internal constant _ROLE_4 = 1 << 4; uint256 internal constant _ROLE_5 = 1 << 5; uint256 internal constant _ROLE_6 = 1 << 6; uint256 internal constant _ROLE_7 = 1 << 7; uint256 internal constant _ROLE_8 = 1 << 8; uint256 internal constant _ROLE_9 = 1 << 9; uint256 internal constant _ROLE_10 = 1 << 10; uint256 internal constant _ROLE_11 = 1 << 11; uint256 internal constant _ROLE_12 = 1 << 12; uint256 internal constant _ROLE_13 = 1 << 13; uint256 internal constant _ROLE_14 = 1 << 14; uint256 internal constant _ROLE_15 = 1 << 15; uint256 internal constant _ROLE_16 = 1 << 16; uint256 internal constant _ROLE_17 = 1 << 17; uint256 internal constant _ROLE_18 = 1 << 18; uint256 internal constant _ROLE_19 = 1 << 19; uint256 internal constant _ROLE_20 = 1 << 20; uint256 internal constant _ROLE_21 = 1 << 21; uint256 internal constant _ROLE_22 = 1 << 22; uint256 internal constant _ROLE_23 = 1 << 23; uint256 internal constant _ROLE_24 = 1 << 24; uint256 internal constant _ROLE_25 = 1 << 25; uint256 internal constant _ROLE_26 = 1 << 26; uint256 internal constant _ROLE_27 = 1 << 27; uint256 internal constant _ROLE_28 = 1 << 28; uint256 internal constant _ROLE_29 = 1 << 29; uint256 internal constant _ROLE_30 = 1 << 30; uint256 internal constant _ROLE_31 = 1 << 31; uint256 internal constant _ROLE_32 = 1 << 32; uint256 internal constant _ROLE_33 = 1 << 33; uint256 internal constant _ROLE_34 = 1 << 34; uint256 internal constant _ROLE_35 = 1 << 35; uint256 internal constant _ROLE_36 = 1 << 36; uint256 internal constant _ROLE_37 = 1 << 37; uint256 internal constant _ROLE_38 = 1 << 38; uint256 internal constant _ROLE_39 = 1 << 39; uint256 internal constant _ROLE_40 = 1 << 40; uint256 internal constant _ROLE_41 = 1 << 41; uint256 internal constant _ROLE_42 = 1 << 42; uint256 internal constant _ROLE_43 = 1 << 43; uint256 internal constant _ROLE_44 = 1 << 44; uint256 internal constant _ROLE_45 = 1 << 45; uint256 internal constant _ROLE_46 = 1 << 46; uint256 internal constant _ROLE_47 = 1 << 47; uint256 internal constant _ROLE_48 = 1 << 48; uint256 internal constant _ROLE_49 = 1 << 49; uint256 internal constant _ROLE_50 = 1 << 50; uint256 internal constant _ROLE_51 = 1 << 51; uint256 internal constant _ROLE_52 = 1 << 52; uint256 internal constant _ROLE_53 = 1 << 53; uint256 internal constant _ROLE_54 = 1 << 54; uint256 internal constant _ROLE_55 = 1 << 55; uint256 internal constant _ROLE_56 = 1 << 56; uint256 internal constant _ROLE_57 = 1 << 57; uint256 internal constant _ROLE_58 = 1 << 58; uint256 internal constant _ROLE_59 = 1 << 59; uint256 internal constant _ROLE_60 = 1 << 60; uint256 internal constant _ROLE_61 = 1 << 61; uint256 internal constant _ROLE_62 = 1 << 62; uint256 internal constant _ROLE_63 = 1 << 63; uint256 internal constant _ROLE_64 = 1 << 64; uint256 internal constant _ROLE_65 = 1 << 65; uint256 internal constant _ROLE_66 = 1 << 66; uint256 internal constant _ROLE_67 = 1 << 67; uint256 internal constant _ROLE_68 = 1 << 68; uint256 internal constant _ROLE_69 = 1 << 69; uint256 internal constant _ROLE_70 = 1 << 70; uint256 internal constant _ROLE_71 = 1 << 71; uint256 internal constant _ROLE_72 = 1 << 72; uint256 internal constant _ROLE_73 = 1 << 73; uint256 internal constant _ROLE_74 = 1 << 74; uint256 internal constant _ROLE_75 = 1 << 75; uint256 internal constant _ROLE_76 = 1 << 76; uint256 internal constant _ROLE_77 = 1 << 77; uint256 internal constant _ROLE_78 = 1 << 78; uint256 internal constant _ROLE_79 = 1 << 79; uint256 internal constant _ROLE_80 = 1 << 80; uint256 internal constant _ROLE_81 = 1 << 81; uint256 internal constant _ROLE_82 = 1 << 82; uint256 internal constant _ROLE_83 = 1 << 83; uint256 internal constant _ROLE_84 = 1 << 84; uint256 internal constant _ROLE_85 = 1 << 85; uint256 internal constant _ROLE_86 = 1 << 86; uint256 internal constant _ROLE_87 = 1 << 87; uint256 internal constant _ROLE_88 = 1 << 88; uint256 internal constant _ROLE_89 = 1 << 89; uint256 internal constant _ROLE_90 = 1 << 90; uint256 internal constant _ROLE_91 = 1 << 91; uint256 internal constant _ROLE_92 = 1 << 92; uint256 internal constant _ROLE_93 = 1 << 93; uint256 internal constant _ROLE_94 = 1 << 94; uint256 internal constant _ROLE_95 = 1 << 95; uint256 internal constant _ROLE_96 = 1 << 96; uint256 internal constant _ROLE_97 = 1 << 97; uint256 internal constant _ROLE_98 = 1 << 98; uint256 internal constant _ROLE_99 = 1 << 99; uint256 internal constant _ROLE_100 = 1 << 100; uint256 internal constant _ROLE_101 = 1 << 101; uint256 internal constant _ROLE_102 = 1 << 102; uint256 internal constant _ROLE_103 = 1 << 103; uint256 internal constant _ROLE_104 = 1 << 104; uint256 internal constant _ROLE_105 = 1 << 105; uint256 internal constant _ROLE_106 = 1 << 106; uint256 internal constant _ROLE_107 = 1 << 107; uint256 internal constant _ROLE_108 = 1 << 108; uint256 internal constant _ROLE_109 = 1 << 109; uint256 internal constant _ROLE_110 = 1 << 110; uint256 internal constant _ROLE_111 = 1 << 111; uint256 internal constant _ROLE_112 = 1 << 112; uint256 internal constant _ROLE_113 = 1 << 113; uint256 internal constant _ROLE_114 = 1 << 114; uint256 internal constant _ROLE_115 = 1 << 115; uint256 internal constant _ROLE_116 = 1 << 116; uint256 internal constant _ROLE_117 = 1 << 117; uint256 internal constant _ROLE_118 = 1 << 118; uint256 internal constant _ROLE_119 = 1 << 119; uint256 internal constant _ROLE_120 = 1 << 120; uint256 internal constant _ROLE_121 = 1 << 121; uint256 internal constant _ROLE_122 = 1 << 122; uint256 internal constant _ROLE_123 = 1 << 123; uint256 internal constant _ROLE_124 = 1 << 124; uint256 internal constant _ROLE_125 = 1 << 125; uint256 internal constant _ROLE_126 = 1 << 126; uint256 internal constant _ROLE_127 = 1 << 127; uint256 internal constant _ROLE_128 = 1 << 128; uint256 internal constant _ROLE_129 = 1 << 129; uint256 internal constant _ROLE_130 = 1 << 130; uint256 internal constant _ROLE_131 = 1 << 131; uint256 internal constant _ROLE_132 = 1 << 132; uint256 internal constant _ROLE_133 = 1 << 133; uint256 internal constant _ROLE_134 = 1 << 134; uint256 internal constant _ROLE_135 = 1 << 135; uint256 internal constant _ROLE_136 = 1 << 136; uint256 internal constant _ROLE_137 = 1 << 137; uint256 internal constant _ROLE_138 = 1 << 138; uint256 internal constant _ROLE_139 = 1 << 139; uint256 internal constant _ROLE_140 = 1 << 140; uint256 internal constant _ROLE_141 = 1 << 141; uint256 internal constant _ROLE_142 = 1 << 142; uint256 internal constant _ROLE_143 = 1 << 143; uint256 internal constant _ROLE_144 = 1 << 144; uint256 internal constant _ROLE_145 = 1 << 145; uint256 internal constant _ROLE_146 = 1 << 146; uint256 internal constant _ROLE_147 = 1 << 147; uint256 internal constant _ROLE_148 = 1 << 148; uint256 internal constant _ROLE_149 = 1 << 149; uint256 internal constant _ROLE_150 = 1 << 150; uint256 internal constant _ROLE_151 = 1 << 151; uint256 internal constant _ROLE_152 = 1 << 152; uint256 internal constant _ROLE_153 = 1 << 153; uint256 internal constant _ROLE_154 = 1 << 154; uint256 internal constant _ROLE_155 = 1 << 155; uint256 internal constant _ROLE_156 = 1 << 156; uint256 internal constant _ROLE_157 = 1 << 157; uint256 internal constant _ROLE_158 = 1 << 158; uint256 internal constant _ROLE_159 = 1 << 159; uint256 internal constant _ROLE_160 = 1 << 160; uint256 internal constant _ROLE_161 = 1 << 161; uint256 internal constant _ROLE_162 = 1 << 162; uint256 internal constant _ROLE_163 = 1 << 163; uint256 internal constant _ROLE_164 = 1 << 164; uint256 internal constant _ROLE_165 = 1 << 165; uint256 internal constant _ROLE_166 = 1 << 166; uint256 internal constant _ROLE_167 = 1 << 167; uint256 internal constant _ROLE_168 = 1 << 168; uint256 internal constant _ROLE_169 = 1 << 169; uint256 internal constant _ROLE_170 = 1 << 170; uint256 internal constant _ROLE_171 = 1 << 171; uint256 internal constant _ROLE_172 = 1 << 172; uint256 internal constant _ROLE_173 = 1 << 173; uint256 internal constant _ROLE_174 = 1 << 174; uint256 internal constant _ROLE_175 = 1 << 175; uint256 internal constant _ROLE_176 = 1 << 176; uint256 internal constant _ROLE_177 = 1 << 177; uint256 internal constant _ROLE_178 = 1 << 178; uint256 internal constant _ROLE_179 = 1 << 179; uint256 internal constant _ROLE_180 = 1 << 180; uint256 internal constant _ROLE_181 = 1 << 181; uint256 internal constant _ROLE_182 = 1 << 182; uint256 internal constant _ROLE_183 = 1 << 183; uint256 internal constant _ROLE_184 = 1 << 184; uint256 internal constant _ROLE_185 = 1 << 185; uint256 internal constant _ROLE_186 = 1 << 186; uint256 internal constant _ROLE_187 = 1 << 187; uint256 internal constant _ROLE_188 = 1 << 188; uint256 internal constant _ROLE_189 = 1 << 189; uint256 internal constant _ROLE_190 = 1 << 190; uint256 internal constant _ROLE_191 = 1 << 191; uint256 internal constant _ROLE_192 = 1 << 192; uint256 internal constant _ROLE_193 = 1 << 193; uint256 internal constant _ROLE_194 = 1 << 194; uint256 internal constant _ROLE_195 = 1 << 195; uint256 internal constant _ROLE_196 = 1 << 196; uint256 internal constant _ROLE_197 = 1 << 197; uint256 internal constant _ROLE_198 = 1 << 198; uint256 internal constant _ROLE_199 = 1 << 199; uint256 internal constant _ROLE_200 = 1 << 200; uint256 internal constant _ROLE_201 = 1 << 201; uint256 internal constant _ROLE_202 = 1 << 202; uint256 internal constant _ROLE_203 = 1 << 203; uint256 internal constant _ROLE_204 = 1 << 204; uint256 internal constant _ROLE_205 = 1 << 205; uint256 internal constant _ROLE_206 = 1 << 206; uint256 internal constant _ROLE_207 = 1 << 207; uint256 internal constant _ROLE_208 = 1 << 208; uint256 internal constant _ROLE_209 = 1 << 209; uint256 internal constant _ROLE_210 = 1 << 210; uint256 internal constant _ROLE_211 = 1 << 211; uint256 internal constant _ROLE_212 = 1 << 212; uint256 internal constant _ROLE_213 = 1 << 213; uint256 internal constant _ROLE_214 = 1 << 214; uint256 internal constant _ROLE_215 = 1 << 215; uint256 internal constant _ROLE_216 = 1 << 216; uint256 internal constant _ROLE_217 = 1 << 217; uint256 internal constant _ROLE_218 = 1 << 218; uint256 internal constant _ROLE_219 = 1 << 219; uint256 internal constant _ROLE_220 = 1 << 220; uint256 internal constant _ROLE_221 = 1 << 221; uint256 internal constant _ROLE_222 = 1 << 222; uint256 internal constant _ROLE_223 = 1 << 223; uint256 internal constant _ROLE_224 = 1 << 224; uint256 internal constant _ROLE_225 = 1 << 225; uint256 internal constant _ROLE_226 = 1 << 226; uint256 internal constant _ROLE_227 = 1 << 227; uint256 internal constant _ROLE_228 = 1 << 228; uint256 internal constant _ROLE_229 = 1 << 229; uint256 internal constant _ROLE_230 = 1 << 230; uint256 internal constant _ROLE_231 = 1 << 231; uint256 internal constant _ROLE_232 = 1 << 232; uint256 internal constant _ROLE_233 = 1 << 233; uint256 internal constant _ROLE_234 = 1 << 234; uint256 internal constant _ROLE_235 = 1 << 235; uint256 internal constant _ROLE_236 = 1 << 236; uint256 internal constant _ROLE_237 = 1 << 237; uint256 internal constant _ROLE_238 = 1 << 238; uint256 internal constant _ROLE_239 = 1 << 239; uint256 internal constant _ROLE_240 = 1 << 240; uint256 internal constant _ROLE_241 = 1 << 241; uint256 internal constant _ROLE_242 = 1 << 242; uint256 internal constant _ROLE_243 = 1 << 243; uint256 internal constant _ROLE_244 = 1 << 244; uint256 internal constant _ROLE_245 = 1 << 245; uint256 internal constant _ROLE_246 = 1 << 246; uint256 internal constant _ROLE_247 = 1 << 247; uint256 internal constant _ROLE_248 = 1 << 248; uint256 internal constant _ROLE_249 = 1 << 249; uint256 internal constant _ROLE_250 = 1 << 250; uint256 internal constant _ROLE_251 = 1 << 251; uint256 internal constant _ROLE_252 = 1 << 252; uint256 internal constant _ROLE_253 = 1 << 253; uint256 internal constant _ROLE_254 = 1 << 254; uint256 internal constant _ROLE_255 = 1 << 255; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin-upgrades/contracts/=lib/openzeppelin-contracts-upgradeable/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "@solady/=lib/solady/src/", "@eigenlayer/contracts/=lib/eigenlayer-contracts/src/contracts/", "@eigenlayer-middleware/=lib/eigenlayer-middleware/src/", "eigenlayer-contracts/=lib/eigenlayer-middleware/lib/eigenlayer-contracts/", "@eth-infinitism/account-abstraction/=lib/account-abstraction/contracts/", "@boost/contracts/=contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "account-abstraction/=lib/account-abstraction/contracts/", "eigenlayer-middleware/=lib/eigenlayer-middleware/src/", "hardhat/=node_modules/hardhat/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solady/=lib/solady/src/" ], "optimizer": { "enabled": true, "runs": 10000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"enum ABoostRegistry.RegistryType","name":"registryType","type":"uint8"},{"internalType":"bytes32","name":"identifier","type":"bytes32"}],"name":"AlreadyRegistered","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"NotACloneable","type":"error"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"}],"name":"NotRegistered","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum ABoostRegistry.RegistryType","name":"registryType","type":"uint8"},{"indexed":true,"internalType":"bytes32","name":"identifier","type":"bytes32"},{"indexed":false,"internalType":"address","name":"baseImplementation","type":"address"},{"indexed":false,"internalType":"contract ACloneable","name":"deployedInstance","type":"address"}],"name":"Deployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum ABoostRegistry.RegistryType","name":"registryType","type":"uint8"},{"indexed":true,"internalType":"bytes32","name":"identifier","type":"bytes32"},{"indexed":false,"internalType":"address","name":"implementation","type":"address"}],"name":"Registered","type":"event"},{"inputs":[{"internalType":"enum ABoostRegistry.RegistryType","name":"type_","type":"uint8"},{"internalType":"address","name":"base_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"deployClone","outputs":[{"internalType":"contract ACloneable","name":"instance","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier_","type":"bytes32"}],"name":"getBaseImplementation","outputs":[{"internalType":"contract ACloneable","name":"implementation","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier_","type":"bytes32"}],"name":"getClone","outputs":[{"components":[{"internalType":"enum ABoostRegistry.RegistryType","name":"baseType","type":"uint8"},{"internalType":"contract ACloneable","name":"instance","type":"address"},{"internalType":"address","name":"deployer","type":"address"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct ABoostRegistry.Clone","name":"clone","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum ABoostRegistry.RegistryType","name":"type_","type":"uint8"},{"internalType":"address","name":"base_","type":"address"},{"internalType":"address","name":"deployer_","type":"address"},{"internalType":"string","name":"name_","type":"string"}],"name":"getCloneIdentifier","outputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"deployer_","type":"address"}],"name":"getClones","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum ABoostRegistry.RegistryType","name":"type_","type":"uint8"},{"internalType":"string","name":"name_","type":"string"}],"name":"getIdentifier","outputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum ABoostRegistry.RegistryType","name":"type_","type":"uint8"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"address","name":"implementation_","type":"address"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6080604052348015600e575f80fd5b5061131d8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610085575f3560e01c8063acc83fc811610058578063acc83fc814610129578063d12dd4811461014a578063f16687921461015f578063fd97064b14610172575f80fd5b806301ffc9a7146100895780633aaf1626146100b1578063792aa01c146100d157806383f38859146100f1575b5f80fd5b61009c610097366004610b7b565b610185565b60405190151581526020015b60405180910390f35b6100c46100bf366004610bba565b61021d565b6040516100a89190610c83565b6100e46100df366004610d11565b6103ae565b6040516100a89190610d2a565b6101046100ff366004610bba565b610424565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100a8565b61013c610137366004610dbf565b610482565b6040519081526020016100a8565b61015d610158366004610e30565b6104c3565b005b61013c61016d366004610e91565b6106dc565b610104610180366004610ee0565b6106fc565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167fb09d9d5400000000000000000000000000000000000000000000000000000000148061021757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6102456040805160808101909152805f81525f60208201819052604082015260609081015290565b5f82815260016020526040908190208151608081019092528054829060ff16600481111561027557610275610bd1565b600481111561028657610286610bd1565b8152815473ffffffffffffffffffffffffffffffffffffffff6101009091048116602083015260018301541660408201526002820180546060909201916102cc90610f70565b80601f01602080910402602001604051908101604052809291908181526020018280546102f890610f70565b80156103435780601f1061031a57610100808354040283529160200191610343565b820191905f5260205f20905b81548152906001019060200180831161032657829003601f168201915b50505091909252505050602081015190915073ffffffffffffffffffffffffffffffffffffffff166103a9576040517f8cc00d16000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b919050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526002602090815260409182902080548351818402810184019094528084526060939283018282801561041857602002820191905f5260205f20905b815481526020019060010190808311610404575b50505050509050919050565b5f8181526020819052604090205473ffffffffffffffffffffffffffffffffffffffff16806103a9576040517f8cc00d16000000000000000000000000000000000000000000000000000000008152600481018390526024016103a0565b5f6104b9868686868660405160200161049e9493929190610fc1565b60405160208183030381529060405280519060200120610a39565b9695505050505050565b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f6ab67a0d000000000000000000000000000000000000000000000000000000006004820152819073ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa15801561054d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610571919061102b565b6105bf576040517f903b13fd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016103a0565b5f6105cb8686866106dc565b5f8181526020819052604090205490915073ffffffffffffffffffffffffffffffffffffffff161561062d5785816040517f96b5684c0000000000000000000000000000000000000000000000000000000081526004016103a092919061104a565b5f81815260208190526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85161790558086600481111561068b5761068b610bd1565b60405173ffffffffffffffffffffffffffffffffffffffff861681527f660d31df25c96b8a337fcf12a56b7363e5a997639db853d5dbaec7c01f31bd809060200160405180910390a3505050505050565b5f6106f484848460405160200161049e929190611065565b949350505050565b5f3068929eee149b4bd21268540361071b5763ab143c065f526004601cfd5b3068929eee149b4bd21268556107ad87878787336040516020016107439594939291906110b0565b6040516020818303038152906040528051906020012084848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505073ffffffffffffffffffffffffffffffffffffffff8b169392915050610a6b565b90505f6107bd8888338989610482565b5f81815260016020526040902054909150610100900473ffffffffffffffffffffffffffffffffffffffff16156108245787816040517f96b5684c0000000000000000000000000000000000000000000000000000000081526004016103a092919061104a565b335f908152600260209081526040808320805460018101825590845291909220018290558051608081019091528089600481111561086457610864610bd1565b81526020018373ffffffffffffffffffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920182905250939094525050838152600160208190526040909120835181549193509183917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169083600481111561092657610926610bd1565b0217905550602082015181547fffffffffffffffffffffff0000000000000000000000000000000000000000ff1661010073ffffffffffffffffffffffffffffffffffffffff9283160217825560408301516001830180547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055606082015160028201906109bb90826111a4565b50905050808860048111156109d2576109d2610bd1565b6040805173ffffffffffffffffffffffffffffffffffffffff808c168252861660208201527f2348fcdb9847b17a183e53aa32c0c5c76afdef8fcb14bb51f216c6611701ab1a910160405180910390a3503868929eee149b4bd21268559695505050505050565b5f8282604051602001610a4d9291906112bb565b60405160208183030381529060405280519060200120905092915050565b5f610a8c73ffffffffffffffffffffffffffffffffffffffff851684610b15565b6040517f439fab9100000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff82169063439fab9190610ae19085906004016112d5565b5f604051808303815f87803b158015610af8575f80fd5b505af1158015610b0a573d5f803e3d5ffd5b505050509392505050565b5f610b215f8484610b28565b9392505050565b5f6c5af43d3d93803e602a57fd5bf36021528260145273602c3d8160093d39f33d3d3d3d363d3d37363d735f52816035600c86f5905080610b705763301164255f526004601cfd5b5f6021529392505050565b5f60208284031215610b8b575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b21575f80fd5b5f60208284031215610bca575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110610c33577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152610c95602082018351610bfe565b73ffffffffffffffffffffffffffffffffffffffff602083015116604082015273ffffffffffffffffffffffffffffffffffffffff60408301511660608201525f60608301516080808401526106f460a0840182610c37565b803573ffffffffffffffffffffffffffffffffffffffff811681146103a9575f80fd5b5f60208284031215610d21575f80fd5b610b2182610cee565b602080825282518282018190525f918401906040840190835b81811015610d61578351835260209384019390920191600101610d43565b509095945050505050565b8035600581106103a9575f80fd5b5f8083601f840112610d8a575f80fd5b50813567ffffffffffffffff811115610da1575f80fd5b602083019150836020828501011115610db8575f80fd5b9250929050565b5f805f805f60808688031215610dd3575f80fd5b610ddc86610d6c565b9450610dea60208701610cee565b9350610df860408701610cee565b9250606086013567ffffffffffffffff811115610e13575f80fd5b610e1f88828901610d7a565b969995985093965092949392505050565b5f805f8060608587031215610e43575f80fd5b610e4c85610d6c565b9350602085013567ffffffffffffffff811115610e67575f80fd5b610e7387828801610d7a565b9094509250610e86905060408601610cee565b905092959194509250565b5f805f60408486031215610ea3575f80fd5b610eac84610d6c565b9250602084013567ffffffffffffffff811115610ec7575f80fd5b610ed386828701610d7a565b9497909650939450505050565b5f805f805f8060808789031215610ef5575f80fd5b610efe87610d6c565b9550610f0c60208801610cee565b9450604087013567ffffffffffffffff811115610f27575f80fd5b610f3389828a01610d7a565b909550935050606087013567ffffffffffffffff811115610f52575f80fd5b610f5e89828a01610d7a565b979a9699509497509295939492505050565b600181811c90821680610f8457607f821691505b602082108103610fbb577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b1681527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008460601b166014820152818360288301375f91016028019081529392505050565b5f6020828403121561103b575f80fd5b81518015158114610b21575f80fd5b604081016110588285610bfe565b8260208301529392505050565b818382375f9101908152919050565b600581106110a9577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60f81b9052565b6110ba8187611074565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b1660018201528284601583013760609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016601591909201908101919091526029019392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b601f82111561119f57805f5260205f20601f840160051c8101602085101561117d5750805b601f840160051c820191505b8181101561119c575f8155600101611189565b50505b505050565b815167ffffffffffffffff8111156111be576111be61112b565b6111d2816111cc8454610f70565b84611158565b6020601f821160018114611223575f83156111ed5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b17845561119c565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b828110156112705787850151825560209485019460019092019101611250565b50848210156112ac57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b6112c58184611074565b6001810191909152602101919050565b602081525f610b216020830184610c3756fea26469706673582212207654bccac9090d321e6c2cca0614e206dfe9988d6765aa4c170cebf851b034a164736f6c634300081a0033
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610085575f3560e01c8063acc83fc811610058578063acc83fc814610129578063d12dd4811461014a578063f16687921461015f578063fd97064b14610172575f80fd5b806301ffc9a7146100895780633aaf1626146100b1578063792aa01c146100d157806383f38859146100f1575b5f80fd5b61009c610097366004610b7b565b610185565b60405190151581526020015b60405180910390f35b6100c46100bf366004610bba565b61021d565b6040516100a89190610c83565b6100e46100df366004610d11565b6103ae565b6040516100a89190610d2a565b6101046100ff366004610bba565b610424565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100a8565b61013c610137366004610dbf565b610482565b6040519081526020016100a8565b61015d610158366004610e30565b6104c3565b005b61013c61016d366004610e91565b6106dc565b610104610180366004610ee0565b6106fc565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167fb09d9d5400000000000000000000000000000000000000000000000000000000148061021757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6102456040805160808101909152805f81525f60208201819052604082015260609081015290565b5f82815260016020526040908190208151608081019092528054829060ff16600481111561027557610275610bd1565b600481111561028657610286610bd1565b8152815473ffffffffffffffffffffffffffffffffffffffff6101009091048116602083015260018301541660408201526002820180546060909201916102cc90610f70565b80601f01602080910402602001604051908101604052809291908181526020018280546102f890610f70565b80156103435780601f1061031a57610100808354040283529160200191610343565b820191905f5260205f20905b81548152906001019060200180831161032657829003601f168201915b50505091909252505050602081015190915073ffffffffffffffffffffffffffffffffffffffff166103a9576040517f8cc00d16000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b919050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526002602090815260409182902080548351818402810184019094528084526060939283018282801561041857602002820191905f5260205f20905b815481526020019060010190808311610404575b50505050509050919050565b5f8181526020819052604090205473ffffffffffffffffffffffffffffffffffffffff16806103a9576040517f8cc00d16000000000000000000000000000000000000000000000000000000008152600481018390526024016103a0565b5f6104b9868686868660405160200161049e9493929190610fc1565b60405160208183030381529060405280519060200120610a39565b9695505050505050565b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f6ab67a0d000000000000000000000000000000000000000000000000000000006004820152819073ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa15801561054d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610571919061102b565b6105bf576040517f903b13fd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016103a0565b5f6105cb8686866106dc565b5f8181526020819052604090205490915073ffffffffffffffffffffffffffffffffffffffff161561062d5785816040517f96b5684c0000000000000000000000000000000000000000000000000000000081526004016103a092919061104a565b5f81815260208190526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85161790558086600481111561068b5761068b610bd1565b60405173ffffffffffffffffffffffffffffffffffffffff861681527f660d31df25c96b8a337fcf12a56b7363e5a997639db853d5dbaec7c01f31bd809060200160405180910390a3505050505050565b5f6106f484848460405160200161049e929190611065565b949350505050565b5f3068929eee149b4bd21268540361071b5763ab143c065f526004601cfd5b3068929eee149b4bd21268556107ad87878787336040516020016107439594939291906110b0565b6040516020818303038152906040528051906020012084848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505073ffffffffffffffffffffffffffffffffffffffff8b169392915050610a6b565b90505f6107bd8888338989610482565b5f81815260016020526040902054909150610100900473ffffffffffffffffffffffffffffffffffffffff16156108245787816040517f96b5684c0000000000000000000000000000000000000000000000000000000081526004016103a092919061104a565b335f908152600260209081526040808320805460018101825590845291909220018290558051608081019091528089600481111561086457610864610bd1565b81526020018373ffffffffffffffffffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff16815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920182905250939094525050838152600160208190526040909120835181549193509183917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169083600481111561092657610926610bd1565b0217905550602082015181547fffffffffffffffffffffff0000000000000000000000000000000000000000ff1661010073ffffffffffffffffffffffffffffffffffffffff9283160217825560408301516001830180547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055606082015160028201906109bb90826111a4565b50905050808860048111156109d2576109d2610bd1565b6040805173ffffffffffffffffffffffffffffffffffffffff808c168252861660208201527f2348fcdb9847b17a183e53aa32c0c5c76afdef8fcb14bb51f216c6611701ab1a910160405180910390a3503868929eee149b4bd21268559695505050505050565b5f8282604051602001610a4d9291906112bb565b60405160208183030381529060405280519060200120905092915050565b5f610a8c73ffffffffffffffffffffffffffffffffffffffff851684610b15565b6040517f439fab9100000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff82169063439fab9190610ae19085906004016112d5565b5f604051808303815f87803b158015610af8575f80fd5b505af1158015610b0a573d5f803e3d5ffd5b505050509392505050565b5f610b215f8484610b28565b9392505050565b5f6c5af43d3d93803e602a57fd5bf36021528260145273602c3d8160093d39f33d3d3d3d363d3d37363d735f52816035600c86f5905080610b705763301164255f526004601cfd5b5f6021529392505050565b5f60208284031215610b8b575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b21575f80fd5b5f60208284031215610bca575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110610c33577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152610c95602082018351610bfe565b73ffffffffffffffffffffffffffffffffffffffff602083015116604082015273ffffffffffffffffffffffffffffffffffffffff60408301511660608201525f60608301516080808401526106f460a0840182610c37565b803573ffffffffffffffffffffffffffffffffffffffff811681146103a9575f80fd5b5f60208284031215610d21575f80fd5b610b2182610cee565b602080825282518282018190525f918401906040840190835b81811015610d61578351835260209384019390920191600101610d43565b509095945050505050565b8035600581106103a9575f80fd5b5f8083601f840112610d8a575f80fd5b50813567ffffffffffffffff811115610da1575f80fd5b602083019150836020828501011115610db8575f80fd5b9250929050565b5f805f805f60808688031215610dd3575f80fd5b610ddc86610d6c565b9450610dea60208701610cee565b9350610df860408701610cee565b9250606086013567ffffffffffffffff811115610e13575f80fd5b610e1f88828901610d7a565b969995985093965092949392505050565b5f805f8060608587031215610e43575f80fd5b610e4c85610d6c565b9350602085013567ffffffffffffffff811115610e67575f80fd5b610e7387828801610d7a565b9094509250610e86905060408601610cee565b905092959194509250565b5f805f60408486031215610ea3575f80fd5b610eac84610d6c565b9250602084013567ffffffffffffffff811115610ec7575f80fd5b610ed386828701610d7a565b9497909650939450505050565b5f805f805f8060808789031215610ef5575f80fd5b610efe87610d6c565b9550610f0c60208801610cee565b9450604087013567ffffffffffffffff811115610f27575f80fd5b610f3389828a01610d7a565b909550935050606087013567ffffffffffffffff811115610f52575f80fd5b610f5e89828a01610d7a565b979a9699509497509295939492505050565b600181811c90821680610f8457607f821691505b602082108103610fbb577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b1681527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008460601b166014820152818360288301375f91016028019081529392505050565b5f6020828403121561103b575f80fd5b81518015158114610b21575f80fd5b604081016110588285610bfe565b8260208301529392505050565b818382375f9101908152919050565b600581106110a9577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60f81b9052565b6110ba8187611074565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b1660018201528284601583013760609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016601591909201908101919091526029019392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b601f82111561119f57805f5260205f20601f840160051c8101602085101561117d5750805b601f840160051c820191505b8181101561119c575f8155600101611189565b50505b505050565b815167ffffffffffffffff8111156111be576111be61112b565b6111d2816111cc8454610f70565b84611158565b6020601f821160018114611223575f83156111ed5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b17845561119c565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b828110156112705787850151825560209485019460019092019101611250565b50848210156112ac57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b6112c58184611074565b6001810191909152602101919050565b602081525f610b216020830184610c3756fea26469706673582212207654bccac9090d321e6c2cca0614e206dfe9988d6765aa4c170cebf851b034a164736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.