Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 1,064 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 23366391 | 38 days ago | IN | 0 ETH | 0.00005139 | ||||
Claim | 23350908 | 40 days ago | IN | 0.001 ETH | 0.00015567 | ||||
Claim | 23343463 | 41 days ago | IN | 0.001 ETH | 0.00009026 | ||||
Claim | 23343459 | 41 days ago | IN | 0.001 ETH | 0.00009239 | ||||
Claim | 23340322 | 41 days ago | IN | 0.001 ETH | 0.00023327 | ||||
Claim | 23340305 | 41 days ago | IN | 0.001 ETH | 0.00025295 | ||||
Claim | 23338854 | 41 days ago | IN | 0.001 ETH | 0.00003356 | ||||
Claim | 23338496 | 41 days ago | IN | 0.001 ETH | 0.00017379 | ||||
Claim | 23338397 | 41 days ago | IN | 0.001 ETH | 0.0001586 | ||||
Claim | 23338387 | 41 days ago | IN | 0.001 ETH | 0.00015603 | ||||
Claim | 23336746 | 42 days ago | IN | 0.001 ETH | 0.00008502 | ||||
Claim | 23334395 | 42 days ago | IN | 0.001 ETH | 0.0002508 | ||||
Claim | 23333802 | 42 days ago | IN | 0.001 ETH | 0.00053389 | ||||
Claim | 23333760 | 42 days ago | IN | 0.001 ETH | 0.00043536 | ||||
Claim | 23332396 | 42 days ago | IN | 0.001 ETH | 0.00016316 | ||||
Claim | 23331292 | 42 days ago | IN | 0.001 ETH | 0.00016412 | ||||
Claim | 23328534 | 43 days ago | IN | 0.001 ETH | 0.0000168 | ||||
Claim | 23326304 | 43 days ago | IN | 0.001 ETH | 0.00016314 | ||||
Claim | 23323498 | 44 days ago | IN | 0.001 ETH | 0.00001834 | ||||
Claim | 23320341 | 44 days ago | IN | 0.001 ETH | 0.0000747 | ||||
Claim | 23316149 | 45 days ago | IN | 0.001 ETH | 0.0000907 | ||||
Claim | 23312759 | 45 days ago | IN | 0.001 ETH | 0.00016234 | ||||
Claim | 23312747 | 45 days ago | IN | 0.001 ETH | 0.00009307 | ||||
Claim | 23307793 | 46 days ago | IN | 0.001 ETH | 0.00002257 | ||||
Claim | 23304022 | 46 days ago | IN | 0.001 ETH | 0.00015251 |
Latest 25 internal transactions
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Transfer | 23350908 | 40 days ago | 0.001 ETH | ||||
Transfer | 23343463 | 41 days ago | 0.001 ETH | ||||
Transfer | 23343459 | 41 days ago | 0.001 ETH | ||||
Transfer | 23340322 | 41 days ago | 0.001 ETH | ||||
Transfer | 23340305 | 41 days ago | 0.001 ETH | ||||
Transfer | 23338854 | 41 days ago | 0.001 ETH | ||||
Transfer | 23338496 | 41 days ago | 0.001 ETH | ||||
Transfer | 23338397 | 41 days ago | 0.001 ETH | ||||
Transfer | 23338387 | 41 days ago | 0.001 ETH | ||||
Transfer | 23336746 | 42 days ago | 0.001 ETH | ||||
Transfer | 23334395 | 42 days ago | 0.001 ETH | ||||
Transfer | 23333802 | 42 days ago | 0.001 ETH | ||||
Transfer | 23333760 | 42 days ago | 0.001 ETH | ||||
Transfer | 23332396 | 42 days ago | 0.001 ETH | ||||
Transfer | 23331292 | 42 days ago | 0.001 ETH | ||||
Transfer | 23328534 | 43 days ago | 0.001 ETH | ||||
Transfer | 23326304 | 43 days ago | 0.001 ETH | ||||
Transfer | 23323498 | 44 days ago | 0.001 ETH | ||||
Transfer | 23320341 | 44 days ago | 0.001 ETH | ||||
Transfer | 23316149 | 45 days ago | 0.001 ETH | ||||
Transfer | 23312759 | 45 days ago | 0.001 ETH | ||||
Transfer | 23312747 | 45 days ago | 0.001 ETH | ||||
Transfer | 23307793 | 46 days ago | 0.001 ETH | ||||
Transfer | 23304022 | 46 days ago | 0.001 ETH | ||||
Transfer | 23303570 | 46 days ago | 0.001 ETH |
Cross-Chain Transactions
Loading...
Loading
Minimal Proxy Contract for 0x072b6037ee437a7d91b498fe45deffa57234ccd1
Contract Name:
TokenTableMerkleDistributorWithFees
Compiler Version
v0.8.29+commit.ab55807c
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL v3 pragma solidity ^0.8.24; import { BaseMerkleDistributor } from "../BaseMerkleDistributor.sol"; import { IERC20 } from "@openzeppelin-contracts/interfaces/IERC20.sol"; import { SafeERC20 } from "../../../common/utils/MinimalSafeERC20.sol"; import { TTADeployer as ITTADeployer } from "../../../TTADeployer.sol"; struct TokenTableMerkleDistributorWithFeesData { uint256 index; uint256 claimableTimestamp; uint256 claimableAmount; uint256 fees; address feesToken; } contract TokenTableMerkleDistributorWithFees is BaseMerkleDistributor { using SafeERC20 for IERC20; error OutsideClaimableTimeRange(); error ETHTransferFailed(); receive() external payable { } function withdraw(bytes memory) external virtual override onlyOwner { address token = _getBaseMerkleDistributorStorage().token; if (token == address(0)) { // Native token withdrawal uint256 balance = address(this).balance; (bool success,) = payable(owner()).call{ value: balance }(""); require(success, ETHTransferFailed()); } else { // ERC20 token withdrawal IERC20 erc20Token = IERC20(token); erc20Token.safeTransfer(owner(), erc20Token.balanceOf(address(this))); } } function decodeLeafData(bytes memory data) public pure virtual returns (TokenTableMerkleDistributorWithFeesData memory) { return abi.decode(data, (TokenTableMerkleDistributorWithFeesData)); } function _verifyAndClaim( address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data ) internal virtual override returns (uint256 claimedAmount) { bytes32 leaf = encodeLeaf(recipient, group, data); verify(proof, leaf); BaseMerkleDistributorStorage storage $ = _getBaseMerkleDistributorStorage(); $.usedLeafs[leaf] = true; TokenTableMerkleDistributorWithFeesData memory decodedData = decodeLeafData(data); if (decodedData.claimableTimestamp > block.timestamp || decodedData.claimableTimestamp < $.startTime) { revert OutsideClaimableTimeRange(); } if ( decodedData.feesToken != address(0) && msg.value > 0 || decodedData.feesToken == address(0) && msg.value != decodedData.fees ) { revert IncorrectFees(); } if (decodedData.feesToken == $.token) { // When fee token is same as airdrop token, deduct fees from claimableAmount _send(recipient, $.token, decodedData.claimableAmount - decodedData.fees); _send(ITTADeployer($.deployer).feeCollectors(address(this)), decodedData.feesToken, decodedData.fees); } else { // When fee token is different, send full amounts separately _send(recipient, $.token, decodedData.claimableAmount); _send(ITTADeployer($.deployer).feeCollectors(address(this)), decodedData.feesToken, decodedData.fees); } return decodedData.claimableAmount; } function _send(address recipient, address token, uint256 amount) internal virtual override { if (token == address(0)) { (bool success,) = payable(recipient).call{ value: amount }(""); require(success, ETHTransferFailed()); } else { IERC20(token).safeTransfer(recipient, amount); } } function _chargeFees(address, uint256) internal virtual override { } function version() public pure virtual override returns (string memory) { return string.concat(BaseMerkleDistributor.version(), "-TokenTableMerkleDistributorWithFees"); } }
// SPDX-License-Identifier: AGPL v3 pragma solidity ^0.8.24; import { Ownable } from "solady/auth/Ownable.sol"; import { ReentrancyGuard } from "solady/utils/ReentrancyGuard.sol"; import { MerkleProofLib } from "solady/utils/MerkleProofLib.sol"; import { IVersionable } from "../../common/interfaces/IVersionable.sol"; import { IClaimHook } from "../interfaces/IClaimHook.sol"; import { ITTFeeCollector } from "../../common/interfaces/ITTFeeCollector.sol"; import { IERC20 } from "@openzeppelin-contracts/interfaces/IERC20.sol"; import { SafeERC20 } from "../../common/utils/MinimalSafeERC20.sol"; import { TTADeployer as ITTADeployer } from "../../TTADeployer.sol"; import { Initializable } from "solady/utils/Initializable.sol"; import { ITTCreate3Initializable } from "../../common/interfaces/ITTCreate3Initializable.sol"; abstract contract BaseMerkleDistributor is Initializable, ITTCreate3Initializable, Ownable, ReentrancyGuard, IVersionable { using MerkleProofLib for bytes32[]; using SafeERC20 for IERC20; /// @custom:storage-location erc7201:ethsign.misc.BaseMerkleDistributor struct BaseMerkleDistributorStorage { mapping(bytes32 leaf => bool used) usedLeafs; bytes32 root; address deployer; address token; address claimDelegate; uint256 startTime; uint256 endTime; address claimHook; } // keccak256(abi.encode(uint256(keccak256("ethsign.misc.BaseMerkleDistributor")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant BaseMerkleDistributorStorageLocation = 0x452bdf2c9fe836ad357e55ed0859c19d2ac2a2c151d216523e3d37a8b9a03f00; event ClaimDelegateSet(address delegate); event Claimed(address recipient, bytes32 group, bytes data); error UnsupportedOperation(); error TimeInactive(); error InvalidProof(); error LeafUsed(); error IncorrectFees(); modifier onlyDelegate() { require(msg.sender == _getBaseMerkleDistributorStorage().claimDelegate, Unauthorized()); _; } modifier onlyActive() { if ( block.timestamp < _getBaseMerkleDistributorStorage().startTime || block.timestamp > _getBaseMerkleDistributorStorage().endTime ) revert TimeInactive(); _; } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { if (block.chainid != 31_337) { _disableInitializers(); } } function initialize(address owner_) public initializer { _initializeOwner(owner_); _getBaseMerkleDistributorStorage().deployer = msg.sender; } function setClaimDelegate(address delegate) external virtual onlyOwner { _getBaseMerkleDistributorStorage().claimDelegate = delegate; emit ClaimDelegateSet(delegate); } function claim( bytes32[] calldata proof, bytes32 group, bytes calldata data, bytes calldata extraData ) external payable virtual onlyActive nonReentrant { _beforeClaim(msg.sender, proof, group, data, extraData); uint256 claimedAmount = _verifyAndClaim(msg.sender, proof, group, data); _afterClaim(msg.sender, proof, group, data, claimedAmount, extraData); emit Claimed(msg.sender, group, data); } function batchDelegateClaim( address[] calldata recipients, bytes32[][] calldata proofs, bytes32[] calldata groups, bytes[] calldata datas, bytes[] calldata extraDatas ) external payable virtual { for (uint256 i = 0; i < recipients.length; i++) { delegateClaim(recipients[i], proofs[i], groups[i], datas[i], extraDatas[i]); } } function delegateClaim( address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data, bytes calldata extraData ) public payable virtual onlyDelegate onlyActive nonReentrant { _beforeDelegateClaim(msg.sender, recipient, proof, group, data, extraData); uint256 claimedAmount = _verifyAndClaim(recipient, proof, group, data); _afterDelegateClaim(msg.sender, recipient, proof, group, data, claimedAmount, extraData); emit Claimed(recipient, group, data); } // solhint-disable no-empty-blocks // solhint-disable ordering function withdraw(bytes memory extraData) external virtual; function getClaimDelegate() external view returns (address) { return _getBaseMerkleDistributorStorage().claimDelegate; } function getRoot() external view returns (bytes32) { return _getBaseMerkleDistributorStorage().root; } function getTime() external view returns (uint256, uint256) { return (_getBaseMerkleDistributorStorage().startTime, _getBaseMerkleDistributorStorage().endTime); } function getToken() external view returns (address) { return _getBaseMerkleDistributorStorage().token; } function getDeployer() external view returns (address) { return _getBaseMerkleDistributorStorage().deployer; } function getClaimHook() external view returns (address) { return _getBaseMerkleDistributorStorage().claimHook; } function version() public pure virtual returns (string memory) { return "0.4.3"; } function setBaseParams(address token, uint256 startTime, uint256 endTime, bytes32 root) public virtual onlyOwner { if (startTime >= endTime) revert UnsupportedOperation(); _getBaseMerkleDistributorStorage().token = token; _getBaseMerkleDistributorStorage().startTime = startTime; _getBaseMerkleDistributorStorage().endTime = endTime; _getBaseMerkleDistributorStorage().root = root; } function setClaimHook(address hook) public virtual onlyOwner { _getBaseMerkleDistributorStorage().claimHook = hook; } function encodeLeaf(address user, bytes32 group, bytes memory data) public view virtual returns (bytes32) { return keccak256(abi.encode(block.chainid, address(this), user, group, data)); } function verify(bytes32[] calldata proof, bytes32 leaf) public view virtual { if (isLeafUsed(leaf)) revert LeafUsed(); if (!proof.verifyCalldata(_getBaseMerkleDistributorStorage().root, leaf)) revert InvalidProof(); } function isLeafUsed(bytes32 leaf) public view virtual returns (bool) { return _getBaseMerkleDistributorStorage().usedLeafs[leaf]; } function _verifyAndClaim( address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data ) internal virtual returns (uint256 claimedAmount); function _send(address recipient, address token, uint256 amount) internal virtual; function _chargeFees(address payer, uint256 claimedAmount) internal virtual { BaseMerkleDistributorStorage storage $ = _getBaseMerkleDistributorStorage(); ITTADeployer deployer = ITTADeployer($.deployer); address feeCollector = deployer.feeCollectors(address(this)); if (feeCollector == address(0)) { if (msg.value > 0) revert IncorrectFees(); return; } uint256 amountToCharge = ITTFeeCollector(feeCollector).getFee(address(this), claimedAmount); if (amountToCharge == 0) { if (msg.value > 0) revert IncorrectFees(); return; } address feeToken = deployer.feeTokens(address(this)); if (feeToken == address(0)) { if (msg.value != amountToCharge) revert IncorrectFees(); (bool success, bytes memory data) = feeCollector.call{ value: amountToCharge }(""); // solhint-disable-next-line custom-errors require(success, string(data)); } else { if (msg.value > 0) revert IncorrectFees(); IERC20(feeToken).safeTransferFrom(payer, feeCollector, amountToCharge); } } function _beforeClaim( address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data, bytes calldata extraData ) internal virtual { _tryCallClaimHook(address(0), recipient, proof, group, data, 0, true, extraData); } function _afterClaim( address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data, uint256 claimedAmount, bytes calldata extraData ) internal virtual { _tryCallClaimHook(address(0), recipient, proof, group, data, claimedAmount, false, extraData); _chargeFees(recipient, claimedAmount); } function _beforeDelegateClaim( address delegate, address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data, bytes calldata extraData ) internal virtual { _tryCallClaimHook(delegate, recipient, proof, group, data, 0, true, extraData); } function _afterDelegateClaim( address delegate, address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data, uint256 claimedAmount, bytes calldata extraData ) internal virtual { _tryCallClaimHook(delegate, recipient, proof, group, data, claimedAmount, false, extraData); _chargeFees(delegate, claimedAmount); } function _getBaseMerkleDistributorStorage() internal pure returns (BaseMerkleDistributorStorage storage $) { assembly { $.slot := BaseMerkleDistributorStorageLocation } } function _tryCallClaimHook( address delegate, address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data, uint256 claimedAmount, bool isBeforeClaim, bytes calldata extraData ) private { address claimHook = _getBaseMerkleDistributorStorage().claimHook; if (claimHook != address(0)) { isBeforeClaim ? IClaimHook(claimHook).beforeClaim(delegate, recipient, proof, group, data, extraData) : IClaimHook(claimHook).afterClaim(delegate, recipient, proof, group, data, claimedAmount, extraData); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol) // Minimized by Jack @ Sign pragma solidity ^0.8.20; import { IERC20 } from "@openzeppelin-contracts/interfaces/IERC20.sol"; library SafeERC20 { error SafeERC20FailedOperation(address token); function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { revert SafeERC20FailedOperation(address(token)); } } }
// SPDX-License-Identifier: AGPL v3 pragma solidity ^0.8.24; import { Ownable } from "solady/auth/Ownable.sol"; import { LibClone } from "solady/utils/LibClone.sol"; import { BaseMerkleDistributor } from "./merkle/core/BaseMerkleDistributor.sol"; import { IVersionable } from "./common/interfaces/IVersionable.sol"; import { ITTFeeCollector } from "./common/interfaces/ITTFeeCollector.sol"; import { Initializable } from "solady/utils/Initializable.sol"; import { ITTCreate3Initializable } from "./common/interfaces/ITTCreate3Initializable.sol"; // solhint-disable max-line-length contract TTADeployer is ITTCreate3Initializable, Ownable, IVersionable, Initializable { address public defaultFeeCollector; mapping(string projectId => address deployment) public deployments; mapping(uint8 mdType => address implementation) public implementations; mapping(address deployment => address feeCollectors) internal _feeCollectors; event DidDeploy(uint8 mdType, string projectId, address instance); error UnsupportedOperation(); function initialize(address newOwner) external initializer { _setOwner(newOwner); } function setDefaultFeeParams(address feeCollector) external onlyOwner { defaultFeeCollector = feeCollector; } function setDeploymentFeeParams(address deployment, address feeCollector) external onlyOwner { _feeCollectors[deployment] = feeCollector; } function setImplementation(uint8 mdType, address implementation) external onlyOwner { implementations[mdType] = implementation; } function deploy(uint8 mdType, string calldata projectId) external returns (address instance) { if (deployments[projectId] != address(0)) revert UnsupportedOperation(); instance = LibClone.cloneDeterministic(implementations[mdType], keccak256(abi.encode(projectId))); BaseMerkleDistributor(instance).initialize(msg.sender); deployments[projectId] = instance; emit DidDeploy(mdType, projectId, instance); } function simulateDeploy(uint8 mdType, string calldata projectId) external view returns (address) { return LibClone.predictDeterministicAddress( implementations[mdType], keccak256(abi.encode(projectId)), address(this) ); } function feeTokens(address deployment) external view returns (address) { return ITTFeeCollector(feeCollectors(deployment)).getFeeToken(deployment); } function version() external pure override returns (string memory) { return "0.5.3-TTADeployer"; } function feeCollectors(address deployment) public view returns (address) { return _feeCollectors[deployment] == address(0) ? defaultFeeCollector : _feeCollectors[deployment]; } }
// 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(); _; } }
// 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: MIT pragma solidity ^0.8.4; /// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol) library MerkleProofLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MERKLE PROOF VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if mload(proof) { // Initialize `offset` to the offset of `proof` elements in memory. let offset := add(proof, 0x20) // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(offset, shl(5, mload(proof))) // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, mload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), mload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - The sum of the lengths of `proof` and `leaves` must never overflow. /// - Any non-zero word in the `flags` array is treated as true. /// - The memory offset of `proof` must be non-zero /// (i.e. `proof` is not pointing to the scratch space). function verifyMultiProof( bytes32[] memory proof, bytes32 root, bytes32[] memory leaves, bool[] memory flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // Cache the lengths of the arrays. let leavesLength := mload(leaves) let proofLength := mload(proof) let flagsLength := mload(flags) // Advance the pointers of the arrays to point to the data. leaves := add(0x20, leaves) proof := add(0x20, proof) flags := add(0x20, flags) // If the number of flags is correct. for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flagsLength) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof, shl(5, proofLength)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. leavesLength := shl(5, leavesLength) for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } { mstore(add(hashesFront, i), mload(add(leaves, i))) } // Compute the back of the hashes. let hashesBack := add(hashesFront, leavesLength) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flagsLength := add(hashesBack, shl(5, flagsLength)) for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(mload(flags)) { // Loads the next proof. b := mload(proof) proof := add(proof, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag. flags := add(flags, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flagsLength)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof) ) break } } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - Any non-zero word in the `flags` array is treated as true. /// - The calldata offset of `proof` must be non-zero /// (i.e. `proof` is from a regular Solidity function with a 4-byte selector). function verifyMultiProofCalldata( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leaves, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // If the number of flags is correct. for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flags.length) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. // forgefmt: disable-next-item isValid := eq( calldataload( xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length)) ), root ) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof.offset, shl(5, proof.length)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length)) // Compute the back of the hashes. let hashesBack := add(hashesFront, shl(5, leaves.length)) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flags.length := add(hashesBack, shl(5, flags.length)) // We don't need to make a copy of `proof.offset` or `flags.offset`, // as they are pass-by-value (this trick may not always save gas). for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(calldataload(flags.offset)) { // Loads the next proof. b := calldataload(proof.offset) proof.offset := add(proof.offset, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag offset. flags.offset := add(flags.offset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flags.length)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof.offset) ) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes32 array. function emptyProof() internal pure returns (bytes32[] calldata proof) { /// @solidity memory-safe-assembly assembly { proof.length := 0 } } /// @dev Returns an empty calldata bytes32 array. function emptyLeaves() internal pure returns (bytes32[] calldata leaves) { /// @solidity memory-safe-assembly assembly { leaves.length := 0 } } /// @dev Returns an empty calldata bool array. function emptyFlags() internal pure returns (bool[] calldata flags) { /// @solidity memory-safe-assembly assembly { flags.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title IVersionable * @author Jack Xu @ EthSign * @dev This interface is implemented by all major TokenTable contracts to keep track of their versioning for upgrade * compatibility checks. */ interface IVersionable { function version() external pure returns (string memory); }
// SPDX-License-Identifier: AGPL v3 pragma solidity ^0.8.24; interface IClaimHook { function beforeClaim( address delegate, address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data, bytes calldata extraData ) external; function afterClaim( address delegate, address recipient, bytes32[] calldata proof, bytes32 group, bytes calldata data, uint256 claimedAmount, bytes calldata extraData ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title ITTFeeCollector * @author Jack Xu @ Sign * @dev This contract handles TokenTable service fee calculation. */ interface ITTFeeCollector { event DefaultFeeSetBips(uint256 bips); event DefaultFeeSet(uint256 fee); event CustomFeeSetBips(address unlockerAddress, uint256 bips); event CustomFeeSetFixed(address unlockerAddress, uint256 fixedFee); /** * @dev 0xc9034e18 */ error FeesTooHigh(); /** * @notice Returns the amount of fees to collect. A fixed fee will always override a dynamic fee. * @param unlockerAddress The address of the Unlocker (or any contract that uses the fee collector). Used to fetch * pricing. * @param tokenTransferred The number of tokens transferred. * @return tokensCollected The number of tokens to collect as fees. */ function getFee( address unlockerAddress, uint256 tokenTransferred ) external view returns (uint256 tokensCollected); /** * @notice Returns the fee token address. * @param unlockerAddress The address of the Unlocker (or any contract that uses the fee collector). Used to fetch * pricing. */ function getFeeToken(address unlockerAddress) external view returns (address tokenAddress); }
// 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 _INITIALIZED_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; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ constructor() { // Construction time check to ensure that `_initializableSlot()` is not // overridden to zero. Will be optimized away if there is no revert. require(_initializableSlot() != bytes32(0)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return a non-zero 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, _INITIALIZED_EVENT_SIGNATURE) } } } /// @dev Guards a reinitializer 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 { // Clean upper bits, and shift left by 1 to make space for the initializing bit. version := shl(1, and(version, 0xffffffffffffffff)) let i := sload(s) // If `initializing == 1 || initializedVersion >= version`. if iszero(lt(and(i, 1), lt(i, version))) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } // Set `initializing` to 1, `initializedVersion` to `version`. sstore(s, or(1, version)) } _; /// @solidity memory-safe-assembly assembly { // Set `initializing` to 0, `initializedVersion` to `version`. sstore(s, version) // Emit the {Initialized} event. mstore(0x20, shr(1, version)) log1(0x20, 0x20, _INITIALIZED_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 := 0xffffffffffffffff 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, _INITIALIZED_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: MIT pragma solidity ^0.8.20; /** * @title ITTCreate3Initializable * @author Jack Xu @ Sign * @dev This interface enforces an initializer for contracts that are directly deployed by Create3. */ interface ITTCreate3Initializable { function initialize(address owner) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT 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 ERC1167 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 ERC1167 pattern during runtime, and has the smallest bytecode. /// - Automatically verified on Etherscan. /// /// @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. /// - Automatically verified on Etherscan. /// /// @dev Clones with immutable args (CWIA): /// The implementation of CWIA here does NOT append the immutable args into the calldata /// passed into delegatecall. It is simply an ERC1167 minimal proxy with the immutable arguments /// appended to the back of the runtime bytecode. /// - Uses the identity precompile (0x4) to copy args during deployment. /// /// @dev Minimal ERC1967 proxy: /// A minimal ERC1967 proxy, intended to be upgraded with UUPS. /// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic. /// - Automatically verified on Etherscan. /// /// @dev Minimal ERC1967 proxy with immutable args: /// - Uses the identity precompile (0x4) to copy args during deployment. /// - Automatically verified on Etherscan. /// /// @dev ERC1967I proxy: /// A 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`. /// /// @dev ERC1967I proxy with immutable args: /// A 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 /// - Uses the identity precompile (0x4) to copy args during deployment. /// /// @dev Minimal ERC1967 beacon proxy: /// A minimal beacon proxy, intended to be upgraded with an upgradable beacon. /// - Automatically verified on Etherscan. /// /// @dev Minimal ERC1967 beacon proxy with immutable args: /// - Uses the identity precompile (0x4) to copy args during deployment. /// - Automatically verified on Etherscan. /// /// @dev ERC1967I beacon proxy: /// A variant of the minimal ERC1967 beacon 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`. /// /// @dev ERC1967I proxy with immutable args: /// A variant of the minimal ERC1967 beacon proxy, with a special code path that activates /// if `calldatasize() == 1`. This code path skips the delegatecall and directly returns the /// - Uses the identity precompile (0x4) to copy args during deployment. library LibClone { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The keccak256 of deployed code for the clone proxy, /// with the implementation set to `address(0)`. bytes32 internal constant CLONE_CODE_HASH = 0x48db2cfdb2853fce0b464f1f93a1996469459df3ab6c812106074c4106a1eb1f; /// @dev The keccak256 of deployed code for the PUSH0 proxy, /// with the implementation set to `address(0)`. bytes32 internal constant PUSH0_CLONE_CODE_HASH = 0x67bc6bde1b84d66e267c718ba44cf3928a615d29885537955cb43d44b3e789dc; /// @dev The keccak256 of deployed code for the ERC-1167 CWIA proxy, /// with the implementation set to `address(0)`. bytes32 internal constant CWIA_CODE_HASH = 0x3cf92464268225a4513da40a34d967354684c32cd0edd67b5f668dfe3550e940; /// @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; /// @dev The keccak256 of the deployed code for the ERC1967 beacon proxy. bytes32 internal constant ERC1967I_BEACON_PROXY_CODE_HASH = 0xf8c46d2793d5aa984eb827aeaba4b63aedcab80119212fce827309788735519a; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x40), 0x5af43d3d93803e602a57fd5bf30000000000000000000000) mstore(add(c, 0x28), implementation) mstore(add(c, 0x14), 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) mstore(c, 0x35) // Store the length. mstore(0x40, add(c, 0x60)) // Allocate memory. } } /// @dev Returns the initialization code hash of the clone of `implementation`. 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 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 c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x40), 0x5af43d5f5f3e6029573d5ffd5b3d5ff300000000000000000000) // 16 mstore(add(c, 0x26), implementation) // 20 mstore(add(c, 0x12), 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 mstore(c, 0x36) // Store the length. mstore(0x40, add(c, 0x60)) // Allocate memory. } } /// @dev Returns the initialization code hash of the PUSH0 clone of `implementation`. 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 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 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `args`. function clone(address implementation, bytes memory args) internal returns (address instance) { instance = clone(0, implementation, args); } /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `args`. /// Deposits `value` ETH during deployment. function clone(uint256 value, address implementation, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * ---------------------------------------------------------------------------+ * 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 (45 bytes + extraLength) | * ---------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------| * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..cds): calldata | * | * ::: delegate call to the implementation contract ::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata | * 36 | CALLDATASIZE | cds 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..cds): calldata | * 82 | DUP3 | 0 rds success 0 | [0..cds): calldata | * 80 | DUP1 | 0 0 rds success 0 | [0..cds): calldata | * 3e | RETURNDATACOPY | success 0 | [0..rds): returndata | * 90 | SWAP1 | 0 success | [0..rds): returndata | * 3d | RETURNDATASIZE | rds 0 success | [0..rds): returndata | * 91 | SWAP2 | success 0 rds | [0..rds): returndata | * | * 60 0x2b | PUSH1 0x2b | 0x2b 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 | * ---------------------------------------------------------------------------+ */ let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x43), n)) mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(m, 0x14), implementation) mstore(m, add(0xfe61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. instance := create(value, add(m, add(0x0b, lt(n, 0xffd3))), add(n, 0x37)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `args` and `salt`. function cloneDeterministic(address implementation, bytes memory args, bytes32 salt) internal returns (address instance) { instance = cloneDeterministic(0, implementation, args, salt); } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `args` and `salt`. function cloneDeterministic( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x43), n)) mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(m, 0x14), implementation) mstore(m, add(0xfe61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. instance := create2(value, add(m, add(0x0b, lt(n, 0xffd3))), add(n, 0x37), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `args` and `salt`. /// This method does not revert if the clone has already been deployed. function createDeterministicClone(address implementation, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicClone(0, implementation, args, salt); } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `args` and `salt`. /// This method does not revert if the clone has already been deployed. function createDeterministicClone( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x43), n)) mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(m, 0x14), implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. // forgefmt: disable-next-item mstore(add(m, gt(n, 0xffd2)), add(0xfe61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(add(m, 0x0c), add(n, 0x37))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, add(m, 0x0c), add(n, 0x37), 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(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the clone of `implementation` /// using immutable arguments encoded in `args`. function initCode(address implementation, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffd2)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x57), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x37), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(c, 0x28), implementation) mstore(add(c, 0x14), add(0x61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) mstore(c, add(0x37, n)) // Store the length. mstore(add(c, add(n, 0x57)), 0) // Zeroize the slot after the bytes. mstore(0x40, add(c, add(n, 0x77))) // Allocate memory. } } /// @dev Returns the initialization code hash of the clone of `implementation` /// using immutable arguments encoded in `args`. function initCodeHash(address implementation, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x2d = 0xffd2`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffd2)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(m, 0x43), i), mload(add(add(args, 0x20), i))) } mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3) mstore(add(m, 0x14), implementation) mstore(m, add(0x61002d3d81600a3d39f3363d3d373d3d3d363d73, shl(136, n))) hash := keccak256(add(m, 0x0c), add(n, 0x37)) } } /// @dev Returns the address of the clone of /// `implementation` using immutable arguments encoded in `args`, 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); } /// @dev Equivalent to `argsOnClone(instance, 0, 2 ** 256 - 1)`. function argsOnClone(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x2d))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x2d, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnClone(instance, start, 2 ** 256 - 1)`. function argsOnClone(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x2d)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x0d), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the clone with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnClone(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x0d), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x2d) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x60), 0x3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f300) mstore(add(c, 0x40), 0x55f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076cc) mstore(add(c, 0x20), or(shl(24, implementation), 0x600951)) mstore(add(c, 0x09), 0x603d3d8160223d3973) mstore(c, 0x5f) // Store the length. mstore(0x40, add(c, 0x80)) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation`. 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 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); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL ERC1967 PROXY WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a minimal ERC1967 proxy with `implementation` and `args`. function deployERC1967(address implementation, bytes memory args) internal returns (address instance) { instance = deployERC1967(0, implementation, args); } /// @dev Deploys a minimal ERC1967 proxy with `implementation` and `args`. /// Deposits `value` ETH during deployment. function deployERC1967(uint256 value, address implementation, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n)) mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x16, 0x6009) mstore(0x14, implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) instance := create(value, m, add(n, 0x60)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`. function deployDeterministicERC1967(address implementation, bytes memory args, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967(0, implementation, args, salt); } /// @dev Deploys a deterministic minimal ERC1967 proxy with `implementation`, `args` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n)) mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x16, 0x6009) mstore(0x14, implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) instance := create2(value, m, add(n, 0x60), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation`, `args` 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, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967(0, implementation, args, salt); } /// @dev Creates a deterministic minimal ERC1967 proxy with `implementation`, `args` 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, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x60), n)) mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x16, 0x6009) mstore(0x14, implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. mstore(gt(n, 0xffc2), add(0xfe61003d3d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(m, add(n, 0x60))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, m, add(n, 0x60), 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(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the minimal ERC1967 proxy of `implementation` and `args`. function initCodeERC1967(address implementation, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffc2)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x80), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x60), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(c, 0x40), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(add(c, 0x20), 0x6009) mstore(add(c, 0x1e), implementation) mstore(add(c, 0x0a), add(0x61003d3d8160233d3973, shl(56, n))) mstore(c, add(n, 0x60)) // Store the length. mstore(add(c, add(n, 0x80)), 0) // Zeroize the slot after the bytes. mstore(0x40, add(c, add(n, 0xa0))) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 proxy of `implementation` and `args`. function initCodeHashERC1967(address implementation, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x3d = 0xffc2`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffc2)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(m, 0x60), i), mload(add(add(args, 0x20), i))) } mstore(add(m, 0x40), 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(add(m, 0x20), 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x16, 0x6009) mstore(0x14, implementation) mstore(0x00, add(0x61003d3d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) hash := keccak256(m, add(n, 0x60)) } } /// @dev Returns the address of the ERC1967 proxy of `implementation`, `args`, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967( address implementation, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967(implementation, args); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnERC1967(instance, start, 2 ** 256 - 1)`. function argsOnERC1967(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x3d))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x3d, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnERC1967(instance, start, 2 ** 256 - 1)`. function argsOnERC1967(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x3d)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x1d), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the ERC1967 with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnERC1967(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x1d), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x3d) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 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 ERC1967I proxy of `implementation`. function initCodeERC1967I(address implementation) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x74), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(c, 0x54), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(c, 0x34), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(c, 0x1d), implementation) mstore(add(c, 0x09), 0x60523d8160223d3973) mstore(add(c, 0x94), 0) mstore(c, 0x74) // Store the length. mstore(0x40, add(c, 0xa0)) // Allocate memory. } } /// @dev Returns the initialization code hash of the ERC1967I proxy of `implementation`. 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 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); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967I PROXY WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a minimal ERC1967I proxy with `implementation` and `args`. function deployERC1967I(address implementation, bytes memory args) internal returns (address) { return deployERC1967I(0, implementation, args); } /// @dev Deploys a minimal ERC1967I proxy with `implementation` and `args`. /// Deposits `value` ETH during deployment. function deployERC1967I(uint256 value, address implementation, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(m, 0x4b), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(m, 0x2b), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(m, 0x14), implementation) mstore(m, add(0xfe6100523d8160233d3973, shl(56, n))) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. instance := create(value, add(m, add(0x15, lt(n, 0xffae))), add(0x75, n)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic ERC1967I proxy with `implementation`, `args`, and `salt`. function deployDeterministicERC1967I(address implementation, bytes memory args, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967I(0, implementation, args, salt); } /// @dev Deploys a deterministic ERC1967I proxy with `implementation`, `args`, and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967I( uint256 value, address implementation, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(m, 0x4b), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(m, 0x2b), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(m, 0x14), implementation) mstore(m, add(0xfe6100523d8160233d3973, shl(56, n))) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. instance := create2(value, add(m, add(0x15, lt(n, 0xffae))), add(0x75, n), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Creates a deterministic ERC1967I proxy with `implementation`, `args` 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, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967I(0, implementation, args, salt); } /// @dev Creates a deterministic ERC1967I proxy with `implementation`, `args` 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, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x75), n)) mstore(add(m, 0x55), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(m, 0x35), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(m, 0x15), 0x5155f3365814604357363d3d373d3d363d7f360894) mstore(0x16, 0x600f) mstore(0x14, implementation) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. mstore(gt(n, 0xffad), add(0xfe6100523d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(m, add(n, 0x75))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, m, add(0x75, n), 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(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the ERC1967I proxy of `implementation` and `args`. function initCodeERC1967I(address implementation, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x95), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x75), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(c, 0x55), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(c, 0x35), 0x600f5155f3365814604357363d3d373d3d363d7f360894) mstore(add(c, 0x1e), implementation) mstore(add(c, 0x0a), add(0x6100523d8160233d3973, shl(56, n))) mstore(add(c, add(n, 0x95)), 0) mstore(c, add(0x75, n)) // Store the length. mstore(0x40, add(c, add(n, 0xb5))) // Allocate memory. } } /// @dev Returns the initialization code hash of the ERC1967I proxy of `implementation` and `args. function initCodeHashERC1967I(address implementation, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(m, 0x75), i), mload(add(add(args, 0x20), i))) } mstore(add(m, 0x55), 0x3d6000803e603e573d6000fd5b3d6000f35b6020600f3d393d51543d52593df3) mstore(add(m, 0x35), 0xa13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545af4) mstore(add(m, 0x15), 0x5155f3365814604357363d3d373d3d363d7f360894) mstore(0x16, 0x600f) mstore(0x14, implementation) mstore(0x00, add(0x6100523d8160233d3973, shl(56, n))) mstore(m, mload(0x16)) hash := keccak256(m, add(0x75, n)) } } /// @dev Returns the address of the ERC1967I proxy of `implementation`, `args` with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967I( address implementation, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967I(implementation, args); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnERC1967I(instance, start, 2 ** 256 - 1)`. function argsOnERC1967I(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x52))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x52, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnERC1967I(instance, start, 2 ** 256 - 1)`. function argsOnERC1967I(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x52)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x32), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the ERC1967 with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnERC1967I(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x32), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x52) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967 BOOTSTRAP OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // A bootstrap is a minimal UUPS implementation that allows an ERC1967 proxy // pointing to it to be upgraded. The ERC1967 proxy can then be deployed to a // deterministic address independent of the implementation: // ``` // address bootstrap = LibClone.erc1967Bootstrap(); // address instance = LibClone.deployDeterministicERC1967(0, bootstrap, salt); // LibClone.bootstrapERC1967(bootstrap, implementation); // ``` /// @dev Deploys the ERC1967 bootstrap if it has not been deployed. function erc1967Bootstrap() internal returns (address) { return erc1967Bootstrap(address(this)); } /// @dev Deploys the ERC1967 bootstrap if it has not been deployed. function erc1967Bootstrap(address authorizedUpgrader) internal returns (address bootstrap) { bytes memory c = initCodeERC1967Bootstrap(authorizedUpgrader); bootstrap = predictDeterministicAddress(keccak256(c), bytes32(0), address(this)); /// @solidity memory-safe-assembly assembly { if iszero(extcodesize(bootstrap)) { if iszero(create2(0, add(c, 0x20), mload(c), 0)) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } } /// @dev Replaces the implementation at `instance`. function bootstrapERC1967(address instance, address implementation) internal { /// @solidity memory-safe-assembly assembly { mstore(0x00, implementation) if iszero(call(gas(), instance, 0, 0x0c, 0x14, codesize(), 0x00)) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Replaces the implementation at `instance`, and then call it with `data`. function bootstrapERC1967AndCall(address instance, address implementation, bytes memory data) internal { /// @solidity memory-safe-assembly assembly { let n := mload(data) mstore(data, implementation) if iszero(call(gas(), instance, 0, add(data, 0x0c), add(n, 0x14), codesize(), 0x00)) { if iszero(returndatasize()) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } returndatacopy(mload(0x40), 0x00, returndatasize()) revert(mload(0x40), returndatasize()) } mstore(data, n) // Restore the length of `data`. } } /// @dev Returns the implementation address of the ERC1967 bootstrap for this contract. function predictDeterministicAddressERC1967Bootstrap() internal view returns (address) { return predictDeterministicAddressERC1967Bootstrap(address(this), address(this)); } /// @dev Returns the implementation address of the ERC1967 bootstrap for this contract. function predictDeterministicAddressERC1967Bootstrap( address authorizedUpgrader, address deployer ) internal pure returns (address) { bytes32 hash = initCodeHashERC1967Bootstrap(authorizedUpgrader); return predictDeterministicAddress(hash, bytes32(0), deployer); } /// @dev Returns the initialization code of the ERC1967 bootstrap. function initCodeERC1967Bootstrap(address authorizedUpgrader) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x80), 0x3d3560601c5af46047573d6000383e3d38fd0000000000000000000000000000) mstore(add(c, 0x60), 0xa920a3ca505d382bbc55601436116049575b005b363d3d373d3d601436036014) mstore(add(c, 0x40), 0x0338573d3560601c7f360894a13ba1a3210667c828492db98dca3e2076cc3735) mstore(add(c, 0x20), authorizedUpgrader) mstore(add(c, 0x0c), 0x606880600a3d393df3fe3373) mstore(c, 0x72) mstore(0x40, add(c, 0xa0)) } } /// @dev Returns the initialization code hash of the ERC1967 bootstrap. function initCodeHashERC1967Bootstrap(address authorizedUpgrader) internal pure returns (bytes32) { return keccak256(initCodeERC1967Bootstrap(authorizedUpgrader)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x74), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(c, 0x54), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(c, 0x34), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(c, 0x1d), beacon) mstore(add(c, 0x09), 0x60523d8160223d3973) mstore(add(c, 0x94), 0) mstore(c, 0x74) // Store the length. mstore(0x40, add(c, 0xa0)) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 beacon proxy. 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 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); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967 BEACON PROXY WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a minimal ERC1967 beacon proxy with `args`. function deployERC1967BeaconProxy(address beacon, bytes memory args) internal returns (address instance) { instance = deployERC1967BeaconProxy(0, beacon, args); } /// @dev Deploys a minimal ERC1967 beacon proxy with `args`. /// Deposits `value` ETH during deployment. function deployERC1967BeaconProxy(uint256 value, address beacon, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n))) instance := create(value, add(m, 0x16), add(n, 0x75)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `args` and `salt`. function deployDeterministicERC1967BeaconProxy(address beacon, bytes memory args, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967BeaconProxy(0, beacon, args, salt); } /// @dev Deploys a deterministic minimal ERC1967 beacon proxy with `args` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967BeaconProxy( uint256 value, address beacon, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n))) instance := create2(value, add(m, 0x16), add(n, 0x75), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `args` 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 createDeterministicERC1967BeaconProxy(address beacon, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967BeaconProxy(0, beacon, args, salt); } /// @dev Creates a deterministic minimal ERC1967 beacon proxy with `args` 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 createDeterministicERC1967BeaconProxy( uint256 value, address beacon, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x8b), n)) mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. mstore(add(m, gt(n, 0xffad)), add(0xfe6100523d8160233d3973, shl(56, n))) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(add(m, 0x16), add(n, 0x75))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, add(m, 0x16), add(n, 0x75), 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(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the minimal ERC1967 beacon proxy. function initCodeERC1967BeaconProxy(address beacon, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x95), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x75), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(c, 0x55), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(c, 0x35), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(c, 0x1e), beacon) mstore(add(c, 0x0a), add(0x6100523d8160233d3973, shl(56, n))) mstore(c, add(n, 0x75)) // Store the length. mstore(add(c, add(n, 0x95)), 0) // Zeroize the slot after the bytes. mstore(0x40, add(c, add(n, 0xb5))) // Allocate memory. } } /// @dev Returns the initialization code hash of the minimal ERC1967 beacon proxy with `args`. function initCodeHashERC1967BeaconProxy(address beacon, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x52 = 0xffad`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffad)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(m, 0x8b), i), mload(add(add(args, 0x20), i))) } mstore(add(m, 0x6b), 0xb3582b35133d50545afa5036515af43d6000803e604d573d6000fd5b3d6000f3) mstore(add(m, 0x4b), 0x1b60e01b36527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6c) mstore(add(m, 0x2b), 0x60195155f3363d3d373d3d363d602036600436635c60da) mstore(add(m, 0x14), beacon) mstore(m, add(0x6100523d8160233d3973, shl(56, n))) hash := keccak256(add(m, 0x16), add(n, 0x75)) } } /// @dev Returns the address of the ERC1967 beacon proxy with `args`, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967BeaconProxy( address beacon, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967BeaconProxy(beacon, args); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnERC1967BeaconProxy(instance, start, 2 ** 256 - 1)`. function argsOnERC1967BeaconProxy(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x52))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x52, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnERC1967BeaconProxy(instance, start, 2 ** 256 - 1)`. function argsOnERC1967BeaconProxy(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x52)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x32), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the ERC1967 beacon proxy with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnERC1967BeaconProxy(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x32), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x52) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967I BEACON 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 `ERC1967_BEACON_PROXY_CODE_HASH`. // // 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 ERC1967I beacon proxy. function deployERC1967IBeaconProxy(address beacon) internal returns (address instance) { instance = deployERC1967IBeaconProxy(0, beacon); } /// @dev Deploys a ERC1967I beacon proxy. /// Deposits `value` ETH during deployment. function deployERC1967IBeaconProxy(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 (87 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 | * ~~~~~~ check calldatasize ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | * 36 | CALLDATASIZE | cds succ | | * 14 | EQ | | impl | * 60 0x52 | PUSH1 0x52 | | impl | * 57 | JUMPI | | 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 | * 60 0x01 | PUSH1 0x01 | 1 0 rds succ | [0..calldatasize): calldata | * 3e | RETURNDATACOPY | succ | [1..returndatasize): returndata | * | * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::: | * 60 0x52 | PUSH1 0x52 | dest succ | [1..returndatasize): returndata | * 57 | JUMPI | | [1..returndatasize): returndata | * | * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds | [1..returndatasize): returndata | * 60 0x01 | PUSH1 0x01 | 1 rds | [1..returndatasize): returndata | * fd | REVERT | | [1..returndatasize): returndata | * | * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | | [1..returndatasize): returndata | * 3d | RETURNDATASIZE | rds | [1..returndatasize): returndata | * 60 0x01 | PUSH1 0x01 | 1 rds | [1..returndatasize): returndata | * f3 | RETURN | | [1..returndatasize): returndata | * ---------------------------------------------------------------------------------+ */ let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon)))) instance := create(value, 0x07, 0x79) 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 beacon proxy with `salt`. function deployDeterministicERC1967IBeaconProxy(address beacon, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967IBeaconProxy(0, beacon, salt); } /// @dev Deploys a deterministic ERC1967I beacon proxy with `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967IBeaconProxy(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, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon)))) instance := create2(value, 0x07, 0x79, 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 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 createDeterministicERC1967IBeaconProxy(address beacon, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967IBeaconProxy(0, beacon, salt); } /// @dev Creates a deterministic ERC1967I 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 createDeterministicERC1967IBeaconProxy(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, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon)))) // Compute and store the bytecode hash. mstore(add(m, 0x35), keccak256(0x07, 0x79)) 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, 0x07, 0x79, 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 ERC1967I beacon proxy. function initCodeERC1967IBeaconProxy(address beacon) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) mstore(add(c, 0x79), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(c, 0x59), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(c, 0x39), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(c, 0x1d), beacon) mstore(add(c, 0x09), 0x60573d8160223d3973) mstore(add(c, 0x99), 0) mstore(c, 0x79) // Store the length. mstore(0x40, add(c, 0xa0)) // Allocate memory. } } /// @dev Returns the initialization code hash of the ERC1967I beacon proxy. function initCodeHashERC1967IBeaconProxy(address beacon) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(0x40, 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(0x20, 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(0x04, or(shl(160, 0x60573d8160223d3973), shr(96, shl(96, beacon)))) hash := keccak256(0x07, 0x79) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the ERC1967I beacon proxy, with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967IBeaconProxy( address beacon, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967IBeaconProxy(beacon); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1967I BEACON PROXY WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a ERC1967I beacon proxy with `args. function deployERC1967IBeaconProxy(address beacon, bytes memory args) internal returns (address instance) { instance = deployERC1967IBeaconProxy(0, beacon, args); } /// @dev Deploys a ERC1967I beacon proxy with `args. /// Deposits `value` ETH during deployment. function deployERC1967IBeaconProxy(uint256 value, address beacon, bytes memory args) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n)) mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n))) instance := create(value, add(m, 0x16), add(n, 0x7a)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic ERC1967I beacon proxy with `args` and `salt`. function deployDeterministicERC1967IBeaconProxy(address beacon, bytes memory args, bytes32 salt) internal returns (address instance) { instance = deployDeterministicERC1967IBeaconProxy(0, beacon, args, salt); } /// @dev Deploys a deterministic ERC1967I beacon proxy with `args` and `salt`. /// Deposits `value` ETH during deployment. function deployDeterministicERC1967IBeaconProxy( uint256 value, address beacon, bytes memory args, bytes32 salt ) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n)) mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n))) instance := create2(value, add(m, 0x16), add(n, 0x7a), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Creates a deterministic ERC1967I beacon proxy with `args` 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 createDeterministicERC1967IBeaconProxy(address beacon, bytes memory args, bytes32 salt) internal returns (bool alreadyDeployed, address instance) { return createDeterministicERC1967IBeaconProxy(0, beacon, args, salt); } /// @dev Creates a deterministic ERC1967I beacon proxy with `args` 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 createDeterministicERC1967IBeaconProxy( uint256 value, address beacon, bytes memory args, bytes32 salt ) internal returns (bool alreadyDeployed, address instance) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let n := mload(args) pop(staticcall(gas(), 4, add(args, 0x20), n, add(m, 0x90), n)) mstore(add(m, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(m, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(m, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(m, 0x14), beacon) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. mstore(add(m, gt(n, 0xffa8)), add(0xfe6100573d8160233d3973, shl(56, n))) // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, keccak256(add(m, 0x16), add(n, 0x7a))) mstore(0x01, shl(96, address())) mstore(0x15, salt) instance := keccak256(0x00, 0x55) for {} 1 {} { if iszero(extcodesize(instance)) { instance := create2(value, add(m, 0x16), add(n, 0x7a), 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(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the initialization code of the ERC1967I beacon proxy with `args`. function initCodeERC1967IBeaconProxy(address beacon, bytes memory args) internal pure returns (bytes memory c) { /// @solidity memory-safe-assembly assembly { c := mload(0x40) let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffa8)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x9a), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x7a), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(c, 0x5a), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(c, 0x3a), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(c, 0x1e), beacon) mstore(add(c, 0x0a), add(0x6100573d8160233d3973, shl(56, n))) mstore(add(c, add(n, 0x9a)), 0) mstore(c, add(n, 0x7a)) // Store the length. mstore(0x40, add(c, add(n, 0xba))) // Allocate memory. } } /// @dev Returns the initialization code hash of the ERC1967I beacon proxy with `args`. function initCodeHashERC1967IBeaconProxy(address beacon, bytes memory args) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let c := mload(0x40) // Cache the free memory pointer. let n := mload(args) // Do a out-of-gas revert if `n` is greater than `0xffff - 0x57 = 0xffa8`. returndatacopy(returndatasize(), returndatasize(), gt(n, 0xffa8)) for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { mstore(add(add(c, 0x90), i), mload(add(add(args, 0x20), i))) } mstore(add(c, 0x70), 0x3d50545afa361460525736515af43d600060013e6052573d6001fd5b3d6001f3) mstore(add(c, 0x50), 0x527fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b3513) mstore(add(c, 0x30), 0x60195155f3363d3d373d3d363d602036600436635c60da1b60e01b36) mstore(add(c, 0x14), beacon) mstore(c, add(0x6100573d8160233d3973, shl(56, n))) hash := keccak256(add(c, 0x16), add(n, 0x7a)) } } /// @dev Returns the address of the ERC1967I beacon proxy, with `args` and salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967IBeaconProxy( address beacon, bytes memory args, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967IBeaconProxy(beacon, args); predicted = predictDeterministicAddress(hash, salt, deployer); } /// @dev Equivalent to `argsOnERC1967IBeaconProxy(instance, start, 2 ** 256 - 1)`. function argsOnERC1967IBeaconProxy(address instance) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) mstore(args, and(0xffffffffff, sub(extcodesize(instance), 0x57))) // Store the length. extcodecopy(instance, add(args, 0x20), 0x57, add(mload(args), 0x20)) mstore(0x40, add(mload(args), add(args, 0x40))) // Allocate memory. } } /// @dev Equivalent to `argsOnERC1967IBeaconProxy(instance, start, 2 ** 256 - 1)`. function argsOnERC1967IBeaconProxy(address instance, uint256 start) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) let n := and(0xffffffffff, sub(extcodesize(instance), 0x57)) let l := sub(n, and(0xffffff, mul(lt(start, n), start))) extcodecopy(instance, args, add(start, 0x37), add(l, 0x40)) mstore(args, mul(sub(n, start), lt(start, n))) // Store the length. mstore(0x40, add(args, add(0x40, mload(args)))) // Allocate memory. } } /// @dev Returns a slice of the immutable arguments on `instance` from `start` to `end`. /// `start` and `end` will be clamped to the range `[0, args.length]`. /// The `instance` MUST be deployed via the ERC1967I beacon proxy with immutable args functions. /// Otherwise, the behavior is undefined. /// Out-of-gas reverts if `instance` does not have any code. function argsOnERC1967IBeaconProxy(address instance, uint256 start, uint256 end) internal view returns (bytes memory args) { /// @solidity memory-safe-assembly assembly { args := mload(0x40) if iszero(lt(end, 0xffff)) { end := 0xffff } let d := mul(sub(end, start), lt(start, end)) extcodecopy(instance, args, add(start, 0x37), add(d, 0x20)) if iszero(and(0xff, mload(add(args, d)))) { let n := sub(extcodesize(instance), 0x57) returndatacopy(returndatasize(), returndatasize(), shr(40, n)) d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n)))) } mstore(args, d) // Store the length. mstore(add(add(args, 0x20), d), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(args, 0x40), d)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `address(0)` if the implementation address cannot be determined. function implementationOf(address instance) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { for { extcodecopy(instance, 0x00, 0x00, 0x57) } 1 {} { if mload(0x2d) { // ERC1967I and ERC1967IBeaconProxy detection. if or( eq(keccak256(0x00, 0x52), ERC1967I_CODE_HASH), eq(keccak256(0x00, 0x57), ERC1967I_BEACON_PROXY_CODE_HASH) ) { pop(staticcall(gas(), instance, 0x00, 0x01, 0x00, 0x20)) result := mload(0x0c) break } } // 0age clone detection. result := mload(0x0b) codecopy(0x0b, codesize(), 0x14) // Zeroize the 20 bytes for the address. if iszero(xor(keccak256(0x00, 0x2c), CLONE_CODE_HASH)) { break } mstore(0x0b, result) // Restore the zeroized memory. // CWIA detection. result := mload(0x0a) codecopy(0x0a, codesize(), 0x14) // Zeroize the 20 bytes for the address. if iszero(xor(keccak256(0x00, 0x2d), CWIA_CODE_HASH)) { break } mstore(0x0a, result) // Restore the zeroized memory. // PUSH0 clone detection. result := mload(0x09) codecopy(0x09, codesize(), 0x14) // Zeroize the 20 bytes for the address. result := shr(xor(keccak256(0x00, 0x2d), PUSH0_CLONE_CODE_HASH), result) break } result := shr(96, result) mstore(0x37, 0) // Restore the overwritten part of the free memory pointer. } } /// @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) } } } /// @dev Returns the `bytes32` at `offset` in `args`, without any bounds checks. /// To load an address, you can use `address(bytes20(argLoad(args, offset)))`. function argLoad(bytes memory args, uint256 offset) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(add(add(args, 0x20), offset)) } } }
{ "remappings": [ "@openzeppelin-contracts/=dependencies/@openzeppelin-contracts-5.3.0/", "createx-forge/=dependencies/createx-forge/", "erc721a-upgradeable/=dependencies/ERC721A-Upgradeable/", "forge-std/=dependencies/forge-std-1.9.7/src/", "solady/=dependencies/solady-0.1.19/src/", "@openzeppelin-contracts-5.3.0/=dependencies/@openzeppelin-contracts-5.3.0/", "ERC721A-Upgradeable/=dependencies/ERC721A-Upgradeable/contracts/", "ds-test/=dependencies/createx-forge/lib/forge-std/lib/ds-test/src/", "forge-std-1.9.7/=dependencies/forge-std-1.9.7/src/", "solady-0.1.19/=dependencies/solady-0.1.19/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": false }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "prague", "viaIR": false }
Contract ABI
API[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"IncorrectFees","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"LeafUsed","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OutsideClaimableTimeRange","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TimeInactive","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsupportedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"delegate","type":"address"}],"name":"ClaimDelegateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"bytes32","name":"group","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"bytes32[][]","name":"proofs","type":"bytes32[][]"},{"internalType":"bytes32[]","name":"groups","type":"bytes32[]"},{"internalType":"bytes[]","name":"datas","type":"bytes[]"},{"internalType":"bytes[]","name":"extraDatas","type":"bytes[]"}],"name":"batchDelegateClaim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"bytes32","name":"group","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"decodeLeafData","outputs":[{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"claimableTimestamp","type":"uint256"},{"internalType":"uint256","name":"claimableAmount","type":"uint256"},{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"address","name":"feesToken","type":"address"}],"internalType":"struct TokenTableMerkleDistributorWithFeesData","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"bytes32","name":"group","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"delegateClaim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bytes32","name":"group","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"encodeLeaf","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClaimDelegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClaimHook","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDeployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"leaf","type":"bytes32"}],"name":"isLeafUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"setBaseParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"}],"name":"setClaimDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hook","type":"address"}],"name":"setClaimHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"bytes32","name":"leaf","type":"bytes32"}],"name":"verify","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Loading...
Loading
Loading...
Loading

Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.