Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 115 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Create Liquidity... | 20055810 | 202 days ago | IN | 0 ETH | 0.00192002 | ||||
Create Liquidity... | 20055789 | 202 days ago | IN | 0 ETH | 0.00196626 | ||||
Create Liquidity... | 20033312 | 205 days ago | IN | 0 ETH | 0.00500005 | ||||
Create Liquidity... | 20026311 | 206 days ago | IN | 0 ETH | 0.00477104 | ||||
Create Liquidity... | 20020201 | 207 days ago | IN | 0 ETH | 0.00252325 | ||||
Create Liquidity... | 19996111 | 211 days ago | IN | 0 ETH | 0.00108507 | ||||
Create Liquidity... | 19993970 | 211 days ago | IN | 0 ETH | 0.00115109 | ||||
Create Liquidity... | 19982066 | 213 days ago | IN | 0 ETH | 0.00149117 | ||||
Create Liquidity... | 19980386 | 213 days ago | IN | 0 ETH | 0.00122226 | ||||
Create Liquidity... | 19969539 | 214 days ago | IN | 0 ETH | 0.00352072 | ||||
Create Liquidity... | 19935747 | 219 days ago | IN | 0 ETH | 0.00155715 | ||||
Create Liquidity... | 19933912 | 219 days ago | IN | 0 ETH | 0.00286737 | ||||
Create Liquidity... | 19905282 | 223 days ago | IN | 0 ETH | 0.00076822 | ||||
Create Liquidity... | 19901946 | 224 days ago | IN | 0 ETH | 0.00067358 | ||||
Create Liquidity... | 19878165 | 227 days ago | IN | 0 ETH | 0.00114078 | ||||
Create Liquidity... | 19863457 | 229 days ago | IN | 0 ETH | 0.00228266 | ||||
Create Liquidity... | 19854382 | 230 days ago | IN | 0 ETH | 0.0019109 | ||||
Create Liquidity... | 19833035 | 233 days ago | IN | 0 ETH | 0.00121927 | ||||
Create Liquidity... | 19819343 | 235 days ago | IN | 0 ETH | 0.00150989 | ||||
Create Liquidity... | 19806002 | 237 days ago | IN | 0 ETH | 0.00126384 | ||||
Create Liquidity... | 19797270 | 238 days ago | IN | 0 ETH | 0.00132089 | ||||
Create Liquidity... | 19768219 | 242 days ago | IN | 0 ETH | 0.00523678 | ||||
Create Liquidity... | 19767353 | 243 days ago | IN | 0 ETH | 0.00222941 | ||||
Create Liquidity... | 19748225 | 245 days ago | IN | 0 ETH | 0.0016438 | ||||
Create Liquidity... | 19713491 | 250 days ago | IN | 0 ETH | 0.0022436 |
Latest 25 internal transactions (View All)
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
LiquidityBootstrapPoolFactory
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 1000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity =0.8.21; import "solady/src/auth/Ownable.sol"; import "solady/src/utils/LibClone.sol"; import "solady/src/utils/SafeTransferLib.sol"; struct PoolSettings { address asset; address share; address creator; uint88 virtualAssets; uint88 virtualShares; uint88 maxSharePrice; uint88 maxSharesOut; uint88 maxAssetsIn; uint64 weightStart; uint64 weightEnd; uint40 saleStart; uint40 saleEnd; uint40 vestCliff; uint40 vestEnd; bool sellingAllowed; bytes32 whitelistMerkleRoot; } struct FactorySettings { address feeRecipient; uint48 platformFee; uint48 referrerFee; uint48 swapFee; } uint256 constant MAX_FEE_BIPS = 0.1e4; contract LiquidityBootstrapPoolFactory is Ownable { /// ----------------------------------------------------------------------- /// Dependencies /// ----------------------------------------------------------------------- using LibClone for *; using SafeTransferLib for *; /// ----------------------------------------------------------------------- /// Events /// ----------------------------------------------------------------------- /// @dev Emitted when a new Liquidity Bootstrap Pool is created. /// @param pool The address of the newly created Liquidity Bootstrap Pool. event PoolCreated(address pool); /// @dev Emitted when the fee recipient address is updated. /// @param recipient The new fee recipient address. event FeeRecipientSet(address recipient); /// @dev Emitted when the platform fee is updated. /// @param fee The new platform fee value. event PlatformFeeSet(uint256 fee); /// @dev Emitted when the referrer fee is updated. /// @param fee The new referrer fee value. event ReferrerFeeSet(uint256 fee); /// @dev Emitted when the swap fee is updated. /// @param fee The new swap fee value. event SwapFeeSet(uint256 fee); /// ----------------------------------------------------------------------- /// Errors /// ----------------------------------------------------------------------- /// @dev Error thrown when the maximum fee is exceeded. error MaxFeeExceeded(); /// @dev Error thrown when the sale period is too low. error SalePeriodLow(); /// @dev Error thrown when the weight config is not correct. error InvalidWeightConfig(); /// @dev Error thrown when the asset or share address is invalid. error InvalidAssetOrShare(); /// @dev Error thrown when the asset value is 0. error InvalidAssetValue(); /// @dev Error thrown when the vestCliff is less than saleEnd. error InvalidVestCliff(); /// @dev Error thrown when the vestCliff is greater or equal to vestEnd. error InvalidVestEnd(); /// ----------------------------------------------------------------------- /// Mutable Storage /// ----------------------------------------------------------------------- /// @notice Storage for factory-specific settings. FactorySettings public factorySettings; /// ----------------------------------------------------------------------- /// Immutable Storage /// ----------------------------------------------------------------------- /// @dev Immutable storage for the implementation address of Liquidity Bootstrap Pools. address internal immutable implementation; /// ----------------------------------------------------------------------- /// Constructor /// ----------------------------------------------------------------------- /// @param _implementation The address of the Liquidity Bootstrap Pool implementation contract. /// @param _owner The owner of the factory contract. /// @param _feeRecipient The address that will receive platform and referrer fees. /// @param _platformFee The platform fee, represented as a fraction with a denominator of 10,000. /// @param _referrerFee The referrer fee, represented as a fraction with a denominator of 10,000. /// @param _swapFee The referrer fee, represented as a fraction with a denominator of 10,000. constructor( address _implementation, address _owner, address _feeRecipient, uint48 _platformFee, uint48 _referrerFee, uint48 _swapFee ) { // Check that the platform and referrer fees are within the allowed range. if (_platformFee > MAX_FEE_BIPS) revert MaxFeeExceeded(); if (_referrerFee > MAX_FEE_BIPS) revert MaxFeeExceeded(); if (_swapFee > MAX_FEE_BIPS) revert MaxFeeExceeded(); // Initialize the owner and implementation address. _initializeOwner(_owner); implementation = _implementation; // Set the initial factory settings including fee recipient and fees. factorySettings = FactorySettings(_feeRecipient, _platformFee, _referrerFee, _swapFee); // Emit events for the initial fee settings. emit FeeRecipientSet(_feeRecipient); emit PlatformFeeSet(_platformFee); emit ReferrerFeeSet(_referrerFee); emit SwapFeeSet(_swapFee); } /// ----------------------------------------------------------------------- /// Creation Logic /// ----------------------------------------------------------------------- /// @notice Creates a new Liquidity Bootstrap Pool with the provided settings and parameters. /// @param args The PoolSettings struct containing pool-specific parameters. /// @param shares The number of shares to transfer to the newly created pool. /// @param salt The salt value for deterministic pool creation. /// @return pool The address of the newly created Liquidity Bootstrap Pool. function createLiquidityBootstrapPool( PoolSettings memory args, uint256 shares, uint256 assets, bytes32 salt ) external virtual returns (address pool) { if (args.share == args.asset || args.share == address(0) || args.asset == address(0)) { revert InvalidAssetOrShare(); } // Check timestamps to ensure the sale will not immediately end. if ( uint40(block.timestamp + 1 days) > args.saleEnd || args.saleEnd - args.saleStart < uint40(1 days) ) { revert SalePeriodLow(); } // Vesting must start after the sale ends. if (args.saleEnd < args.vestEnd) { if (args.saleEnd > args.vestCliff) { revert InvalidVestCliff(); } if (args.vestCliff >= args.vestEnd) { revert InvalidVestEnd(); } } if ( args.weightStart < 0.01 ether || args.weightStart > 0.99 ether || args.weightEnd > 0.99 ether || args.weightEnd < 0.01 ether ) { revert InvalidWeightConfig(); } if (assets == 0 && args.virtualAssets == 0) revert InvalidAssetValue(); pool = implementation.cloneDeterministic(_encodeImmutableArgs(args), salt); args.share.safeTransferFrom(msg.sender, pool, shares); args.asset.safeTransferFrom(msg.sender, pool, assets); emit PoolCreated(pool); } /// ----------------------------------------------------------------------- /// Settings Modification Logic /// ----------------------------------------------------------------------- /// @notice Sets the fee recipient address. /// @param recipient The new fee recipient address. function setFeeRecipient(address recipient) external virtual onlyOwner { factorySettings.feeRecipient = recipient; emit FeeRecipientSet(recipient); } /// @notice Sets the platform fee percentage. /// @param fee The new platform fee value, represented as a fraction with a denominator of 10,000. function setPlatformFee(uint48 fee) external virtual onlyOwner { if (fee > MAX_FEE_BIPS) revert MaxFeeExceeded(); factorySettings.platformFee = fee; emit PlatformFeeSet(fee); } /// @notice Sets the referrer fee percentage. /// @param fee The new referrer fee value, represented as a fraction with a denominator of 10,000. function setReferrerFee(uint48 fee) external virtual onlyOwner { if (fee > MAX_FEE_BIPS) revert MaxFeeExceeded(); factorySettings.referrerFee = fee; emit ReferrerFeeSet(fee); } /// @notice Sets the swap fee percentage. /// @param fee The new swap fee value, represented as a fraction with a denominator of 10,000. function setSwapFee(uint48 fee) external virtual onlyOwner { if (fee > MAX_FEE_BIPS) revert MaxFeeExceeded(); factorySettings.swapFee = fee; emit SwapFeeSet(fee); } /// @notice Modifies multiple factory settings at once. /// @param feeRecipient The new fee recipient address. /// @param platformFee The new platform fee value, represented as a fraction with a denominator of 10,000. /// @param referrerFee The new referrer fee value, represented as a fraction with a denominator of 10,000. /// @param swapFee The new swap fee value, represented as a fraction with a denominator of 10,000. function modifySettings( address feeRecipient, uint48 platformFee, uint48 referrerFee, uint48 swapFee ) external virtual onlyOwner { if (platformFee > MAX_FEE_BIPS) revert MaxFeeExceeded(); if (referrerFee > MAX_FEE_BIPS) revert MaxFeeExceeded(); if (swapFee > MAX_FEE_BIPS) revert MaxFeeExceeded(); factorySettings = FactorySettings(feeRecipient, platformFee, referrerFee, swapFee); emit FeeRecipientSet(feeRecipient); emit PlatformFeeSet(platformFee); emit ReferrerFeeSet(referrerFee); emit SwapFeeSet(swapFee); } /// ----------------------------------------------------------------------- /// Factory Helper Logic /// ----------------------------------------------------------------------- /// @notice Predicts the deterministic address of a Liquidity Bootstrap Pool. /// @param args The PoolSettings struct containing pool-specific parameters. /// @param salt The salt value for deterministic pool creation. /// @return The deterministic address of the pool. function predictDeterministicAddress( PoolSettings memory args, bytes32 salt ) external view virtual returns (address) { return implementation.predictDeterministicAddress( _encodeImmutableArgs(args), salt, address(this) ); } /// @notice Predicts the init code hash for a Liquidity Bootstrap Pool. /// @param args The PoolSettings struct containing pool-specific parameters. /// @return The init code hash of the pool. function predictInitCodeHash(PoolSettings memory args) external view virtual returns (bytes32) { return implementation.initCodeHash(_encodeImmutableArgs(args)); } function _encodeImmutableArgs(PoolSettings memory args) internal view virtual returns (bytes memory) { FactorySettings memory settings = factorySettings; unchecked { return abi.encodePacked( // forgefmt: disable-start abi.encodePacked( args.asset, args.share, settings.feeRecipient, args.creator ), abi.encodePacked( args.virtualAssets, args.virtualShares, args.maxSharePrice, args.maxSharesOut, args.maxAssetsIn ), abi.encodePacked( uint64(settings.platformFee) * 1e14, uint64(settings.referrerFee) * 1e14, args.weightStart, args.weightEnd ), abi.encodePacked( args.saleStart, args.saleEnd ), abi.encodePacked( args.vestCliff, args.vestEnd, uint64(settings.swapFee) * 1e14 ), abi.encodePacked( args.sellingAllowed, args.whitelistMerkleRoot ) );// forgefmt: disable-end } } }
// 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 Minimal proxy library. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol) /// @author Minimal proxy by 0age (https://github.com/0age) /// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie /// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args) /// @author Minimal ERC1967 proxy by jtriley-eth (https://github.com/jtriley-eth/minimum-viable-proxy) /// /// @dev Minimal proxy: /// Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime, /// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern, /// which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode. /// /// @dev Minimal proxy (PUSH0 variant): /// This is a new minimal proxy that uses the PUSH0 opcode introduced during Shanghai. /// It is optimized first for minimal runtime gas, then for minimal bytecode. /// The PUSH0 clone functions are intentionally postfixed with a jarring "_PUSH0" as /// many EVM chains may not support the PUSH0 opcode in the early months after Shanghai. /// Please use with caution. /// /// @dev Clones with immutable args (CWIA): /// The implementation of CWIA here implements a `receive()` method that emits the /// `ReceiveETH(uint256)` event. This skips the `DELEGATECALL` when there is no calldata, /// enabling us to accept hard gas-capped `sends` & `transfers` for maximum backwards /// composability. The minimal proxy implementation does not offer this feature. /// /// @dev Minimal ERC1967 proxy: /// An minimal ERC1967 proxy, intended to be upgraded with UUPS. /// This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic. library LibClone { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to deploy the clone. error DeploymentFailed(); /// @dev The salt must start with either the zero address or `by`. error SaltDoesNotStartWith(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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`. 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`. 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 hash of the clone of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) hash := keccak256(0x0c, 0x35) mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the address of the deterministic clone of `implementation`, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress(address implementation, bytes32 salt, address deployer) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL PROXY OPERATIONS (PUSH0 VARIANT) */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a PUSH0 clone of `implementation`. function clone_PUSH0(address implementation) internal returns (address instance) { instance = clone_PUSH0(0, implementation); } /// @dev Deploys a PUSH0 clone of `implementation`. 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`. 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 hash of the PUSH0 clone of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHash_PUSH0(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x24, 0x5af43d5f5f3e6029573d5ffd5b3d5ff3) // 16 mstore(0x14, implementation) // 20 mstore(0x00, 0x602d5f8160095f39f35f5f365f5f37365f73) // 9 + 9 hash := keccak256(0x0e, 0x36) mstore(0x24, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the address of the deterministic PUSH0 clone of `implementation`, /// with `salt` by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress_PUSH0( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash_PUSH0(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CLONES WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: This implementation of CWIA differs from the original implementation. // If the calldata is empty, it will emit a `ReceiveETH(uint256)` event and skip the `DELEGATECALL`. /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `data`. function clone(address implementation, bytes memory data) internal returns (address instance) { instance = clone(0, implementation, data); } /// @dev Deploys a clone of `implementation` with immutable arguments encoded in `data`. function clone(uint256 value, address implementation, bytes memory data) internal returns (address instance) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) // The `creationSize` is `extraLength + 108` // The `runSize` is `creationSize - 10`. /** * ---------------------------------------------------------------------------------------------------+ * CREATION (10 bytes) | * ---------------------------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------------------------| * 61 runSize | PUSH2 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------------------------| * RUNTIME (98 bytes + extraLength) | * ---------------------------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------------------------| * | * ::: if no calldata, emit event & return w/o `DELEGATECALL` ::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 60 0x2c | PUSH1 0x2c | 0x2c cds | | * 57 | JUMPI | | | * 34 | CALLVALUE | cv | | * 3d | RETURNDATASIZE | 0 cv | | * 52 | MSTORE | | [0..0x20): callvalue | * 7f sig | PUSH32 0x9e.. | sig | [0..0x20): callvalue | * 59 | MSIZE | 0x20 sig | [0..0x20): callvalue | * 3d | RETURNDATASIZE | 0 0x20 sig | [0..0x20): callvalue | * a1 | LOG1 | | [0..0x20): callvalue | * 00 | STOP | | [0..0x20): callvalue | * 5b | JUMPDEST | | | * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..cds): calldata | * | * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 0 | [0..cds): calldata | * 61 extra | PUSH2 extra | e 0 0 0 0 | [0..cds): calldata | * | * ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 80 | DUP1 | e e 0 0 0 0 | [0..cds): calldata | * 60 0x62 | PUSH1 0x62 | 0x62 e e 0 0 0 0 | [0..cds): calldata | * 36 | CALLDATASIZE | cds 0x62 e e 0 0 0 0 | [0..cds): calldata | * 39 | CODECOPY | e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * | * ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 01 | ADD | cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 3d | RETURNDATASIZE | 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 73 addr | PUSH20 addr | addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 5a | GAS | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * | * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x60 | PUSH1 0x60 | 0x60 success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * ---------------------------------------------------------------------------------------------------+ */ mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data. mstore(sub(data, 0x0d), implementation) // Write the address of the implementation. // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( // Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e. // The actual EVM limit may be smaller and may change over time. sub(data, add(0x59, lt(extraLength, 0xff9e))), or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) instance := create(value, sub(data, 0x4c), add(extraLength, 0x6c)) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `data` and `salt`. function cloneDeterministic(address implementation, bytes memory data, bytes32 salt) internal returns (address instance) { instance = cloneDeterministic(0, implementation, data, salt); } /// @dev Deploys a deterministic clone of `implementation` /// with immutable arguments encoded in `data` and `salt`. function cloneDeterministic( uint256 value, address implementation, bytes memory data, bytes32 salt ) internal returns (address instance) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data. mstore(sub(data, 0x0d), implementation) // Write the address of the implementation. // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( // Do a out-of-gas revert if `extraLength` is too big. 0xffff - 0x62 + 0x01 = 0xff9e. // The actual EVM limit may be smaller and may change over time. sub(data, add(0x59, lt(extraLength, 0xff9e))), or(shl(0x78, add(extraLength, 0x62)), 0xfd6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) instance := create2(value, sub(data, 0x4c), add(extraLength, 0x6c), salt) if iszero(instance) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Returns the initialization code hash of the clone of `implementation` /// using immutable arguments encoded in `data`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(address implementation, bytes memory data) internal pure returns (bytes32 hash) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // Do a out-of-gas revert if `dataLength` is too big. 0xffff - 0x02 - 0x62 = 0xff9b. // The actual EVM limit may be smaller and may change over time. returndatacopy(returndatasize(), returndatasize(), gt(dataLength, 0xff9b)) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the bytecode before the data. mstore(sub(data, 0x0d), implementation) // Write the address of the implementation. // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( sub(data, 0x5a), or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) hash := keccak256(sub(data, 0x4c), add(extraLength, 0x6c)) // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Returns the address of the deterministic clone of /// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress( address implementation, bytes memory data, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation, data); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL ERC1967 PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: The ERC1967 proxy here is intended to be upgraded with UUPS. // This is NOT the same as ERC1967Factory's transparent proxy, which includes admin logic. /// @dev Deploys a minimal ERC1967 proxy with `implementation`. function deployERC1967(address implementation) internal returns (address instance) { instance = deployERC1967(0, implementation); } /// @dev Deploys a minimal ERC1967 proxy with `implementation`. 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 (62 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`. 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 Returns the initialization code hash of the clone of `implementation` /// using immutable arguments encoded in `data`. /// Used for mining vanity addresses with create2crunch. function initCodeHashERC1967(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, 0xcc3735a920a3ca505d382bbc545af43d6000803e6038573d6000fd5b3d6000f3) mstore(0x40, 0x5155f3363d3d373d3d363d7f360894a13ba1a3210667c828492db98dca3e2076) mstore(0x20, 0x6009) mstore(0x1e, implementation) mstore(0x0a, 0x603d3d8160223d3973) hash := keccak256(0x21, 0x5f) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero slot. } } /// @dev Returns the address of the deterministic clone of /// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddressERC1967( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHashERC1967(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the address when a contract with initialization code hash, /// `hash`, is deployed with `salt`, by `deployer`. /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, hash) mstore(0x01, shl(96, deployer)) mstore(0x15, salt) predicted := keccak256(0x00, 0x55) mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Requires that `salt` starts with either the zero address or `by`. function checkStartsWith(bytes32 salt, address by) internal pure { /// @solidity memory-safe-assembly assembly { // If the salt does not start with the zero address or `by`. if iszero(or(iszero(shr(96, salt)), eq(shr(96, shl(96, by)), shr(96, salt)))) { mstore(0x00, 0x0c4549ef) // `SaltDoesNotStartWith()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// /// @dev Note: /// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection. /// - For ERC20s, this implementation won't check that a token has code, /// responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes. uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants. // // The regular variants: // - Forwards all remaining gas to the target. // - Reverts if the target reverts. // - Reverts if the current contract has insufficient balance. // // The force variants: // - Forwards with an optional gas stipend // (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases). // - If the target reverts, or if the gas stipend is exhausted, // creates a temporary contract to force send the ETH via `SELFDESTRUCT`. // Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758. // - Reverts if the current contract has insufficient balance. // // The try variants: // - Forwards with a mandatory gas stipend. // - Instead of reverting, returns whether the transfer succeeded. /// @dev Sends `amount` (in wei) ETH to `to`. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Sends all the ETH in the current contract to `to`. function safeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // Transfer all the ETH and check if it succeeded or not. if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`. function forceSafeTransferAllETH(address to, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if lt(selfbalance(), amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`. function forceSafeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // forgefmt: disable-next-item if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation. } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00) } } /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`. function trySafeTransferAllETH(address to, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have their entire balance approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`. amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// If the initial attempt to approve fails, attempts to reset the approved amount to zero, /// then retries the approval again (some tokens, e.g. USDT, requires this). /// Reverts upon failure. function safeApproveWithRetry(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, retrying upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x34, 0) // Store 0 for the `amount`. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval. mstore(0x34, amount) // Store back the original `amount`. // Retry the approval, reverting upon failure. if iszero( and( or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing. call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x14, account) // Store the `account` argument. mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`. amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) ) ) } } }
{ "remappings": [ "@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/", "@prb/math/=lib/v2-core/lib/prb-math/", "@prb/test/=lib/v2-core/lib/prb-test/src/", "ds-test/=lib/solady/lib/ds-test/src/", "erc4626-tests/=lib/v2-core/lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "murky/=lib/murky/", "openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/", "openzeppelin/=lib/v2-core/lib/openzeppelin-contracts/contracts/", "prb-math/=lib/v2-core/lib/prb-math/src/", "prb-test/=lib/v2-core/lib/prb-test/src/", "solady/=lib/solady/", "solarray/=lib/v2-core/lib/solarray/src/", "solplot/=lib/weighted-math-lib/lib/solplot/src/", "v2-core/=lib/v2-core/", "weighted-math-lib/=lib/weighted-math-lib/src/", "lib/forge-std:ds-test/=lib/weighted-math-lib/lib/forge-std/lib/ds-test/src/", "lib/solady:ds-test/=lib/weighted-math-lib/lib/solady/lib/ds-test/src/", "lib/solady:forge-std/=lib/weighted-math-lib/lib/solady/test/utils/forge-std/" ], "optimizer": { "enabled": true, "runs": 1000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_implementation","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"uint48","name":"_platformFee","type":"uint48"},{"internalType":"uint48","name":"_referrerFee","type":"uint48"},{"internalType":"uint48","name":"_swapFee","type":"uint48"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InvalidAssetOrShare","type":"error"},{"inputs":[],"name":"InvalidAssetValue","type":"error"},{"inputs":[],"name":"InvalidVestCliff","type":"error"},{"inputs":[],"name":"InvalidVestEnd","type":"error"},{"inputs":[],"name":"InvalidWeightConfig","type":"error"},{"inputs":[],"name":"MaxFeeExceeded","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"SalePeriodLow","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"FeeRecipientSet","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PlatformFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"ReferrerFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"SwapFeeSet","type":"event"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"share","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint88","name":"virtualAssets","type":"uint88"},{"internalType":"uint88","name":"virtualShares","type":"uint88"},{"internalType":"uint88","name":"maxSharePrice","type":"uint88"},{"internalType":"uint88","name":"maxSharesOut","type":"uint88"},{"internalType":"uint88","name":"maxAssetsIn","type":"uint88"},{"internalType":"uint64","name":"weightStart","type":"uint64"},{"internalType":"uint64","name":"weightEnd","type":"uint64"},{"internalType":"uint40","name":"saleStart","type":"uint40"},{"internalType":"uint40","name":"saleEnd","type":"uint40"},{"internalType":"uint40","name":"vestCliff","type":"uint40"},{"internalType":"uint40","name":"vestEnd","type":"uint40"},{"internalType":"bool","name":"sellingAllowed","type":"bool"},{"internalType":"bytes32","name":"whitelistMerkleRoot","type":"bytes32"}],"internalType":"struct PoolSettings","name":"args","type":"tuple"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"createLiquidityBootstrapPool","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factorySettings","outputs":[{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"uint48","name":"platformFee","type":"uint48"},{"internalType":"uint48","name":"referrerFee","type":"uint48"},{"internalType":"uint48","name":"swapFee","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"uint48","name":"platformFee","type":"uint48"},{"internalType":"uint48","name":"referrerFee","type":"uint48"},{"internalType":"uint48","name":"swapFee","type":"uint48"}],"name":"modifySettings","outputs":[],"stateMutability":"nonpayable","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":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"share","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint88","name":"virtualAssets","type":"uint88"},{"internalType":"uint88","name":"virtualShares","type":"uint88"},{"internalType":"uint88","name":"maxSharePrice","type":"uint88"},{"internalType":"uint88","name":"maxSharesOut","type":"uint88"},{"internalType":"uint88","name":"maxAssetsIn","type":"uint88"},{"internalType":"uint64","name":"weightStart","type":"uint64"},{"internalType":"uint64","name":"weightEnd","type":"uint64"},{"internalType":"uint40","name":"saleStart","type":"uint40"},{"internalType":"uint40","name":"saleEnd","type":"uint40"},{"internalType":"uint40","name":"vestCliff","type":"uint40"},{"internalType":"uint40","name":"vestEnd","type":"uint40"},{"internalType":"bool","name":"sellingAllowed","type":"bool"},{"internalType":"bytes32","name":"whitelistMerkleRoot","type":"bytes32"}],"internalType":"struct PoolSettings","name":"args","type":"tuple"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"predictDeterministicAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"share","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint88","name":"virtualAssets","type":"uint88"},{"internalType":"uint88","name":"virtualShares","type":"uint88"},{"internalType":"uint88","name":"maxSharePrice","type":"uint88"},{"internalType":"uint88","name":"maxSharesOut","type":"uint88"},{"internalType":"uint88","name":"maxAssetsIn","type":"uint88"},{"internalType":"uint64","name":"weightStart","type":"uint64"},{"internalType":"uint64","name":"weightEnd","type":"uint64"},{"internalType":"uint40","name":"saleStart","type":"uint40"},{"internalType":"uint40","name":"saleEnd","type":"uint40"},{"internalType":"uint40","name":"vestCliff","type":"uint40"},{"internalType":"uint40","name":"vestEnd","type":"uint40"},{"internalType":"bool","name":"sellingAllowed","type":"bool"},{"internalType":"bytes32","name":"whitelistMerkleRoot","type":"bytes32"}],"internalType":"struct PoolSettings","name":"args","type":"tuple"}],"name":"predictInitCodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"fee","type":"uint48"}],"name":"setPlatformFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"fee","type":"uint48"}],"name":"setReferrerFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"fee","type":"uint48"}],"name":"setSwapFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60a03462000279576001600160401b0390601f6200194938819003918201601f19168301929190848411838510176200027e578160c092849260409687528339810103126200027957620000538162000294565b6020916200006383820162000294565b916200007185830162000294565b916200008060608201620002a9565b906200009d60a06200009560808401620002a9565b9201620002a9565b9765ffffffffffff95868416956103e89788881162000268578085169b898d1162000257571697881162000246576001600160a01b03918216638b78c6d81981905560009690877f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a360805289519260808401908482109082111762000232577f4cc356a4f0cf9460d4d6f22c6c58a7cb56a92755a9d27d92b2dff03c5b3e9438977fbf9a9534339a9d6b81696e05dcfb614b7dc518a31d48be3cfb757988381fb3238b8e819a8f9d9a8e7f11388023ce3c3ee3995ef04b4ad33102dab6bed131ac79d8531163e61a34f93b9b8d6060879d879d7fdc4e4be378c228e1b7b13787e1d0620609304c2f71ed3a6ee69e4aae99d58cd99d8a9d8752169788958683528c8b840152820152015260018060d01b03199060d01b169165ffffffffffff60a01b9060a01b16171790558965ffffffffffff1960015416176001558c51908152a18951908152a18651908152a18351908152a15161168b9081620002be82396080518181816107840152610aba0152f35b634e487b7160e01b87526041600452602487fd5b895163f4df6ae560e01b8152600490fd5b8b5163f4df6ae560e01b8152600490fd5b8a5163f4df6ae560e01b8152600490fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036200027957565b519065ffffffffffff82168203620002795756fe6080604052600436101561001257600080fd5b60003560e01c80630d4dfc2114610117578063256929621461011257806354bba6071461010d57806354d1f13d1461010857806357e94d3214610103578063715018a6146100fe5780638054480b146100f95780638da5cb5b146100f4578063a034d11b146100ef578063a781d208146100ea578063d4522b3c146100e5578063dce92425146100e0578063e74b981b146100db578063f04e283e146100d6578063f2fde38b146100d15763fee81cf4146100cc57600080fd5b610ee5565b610ea9565b610e57565b610dd7565b610d67565b610d13565b610cc6565b610b11565b610ae6565b610a90565b610a49565b610636565b610335565b61029a565b61024b565b610175565b6004359065ffffffffffff8216820361013157565b600080fd5b6024359065ffffffffffff8216820361013157565b6044359065ffffffffffff8216820361013157565b6064359065ffffffffffff8216820361013157565b346101315760203660031901126101315761018e61011c565b610196610f52565b65ffffffffffff8116906103e88211610221577f11388023ce3c3ee3995ef04b4ad33102dab6bed131ac79d8531163e61a34f93b9160209179ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff00000000000000000000000000000000000000000000000000006000549260d01b16911617600055604051908152a1005b60046040517ff4df6ae5000000000000000000000000000000000000000000000000000000008152fd5b6000806003193601126102975763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b80fd5b34610131576020366003190112610131576102b361011c565b6102bb610f52565b65ffffffffffff8116906103e88211610221577fdc4e4be378c228e1b7b13787e1d0620609304c2f71ed3a6ee69e4aae99d58cd9916020917fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff65ffffffffffff60a01b6000549260a01b16911617600055604051908152a1005b6000806003193601126102975763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b90601f8019910116810190811067ffffffffffffffff82111761039e57604052565b634e487b7160e01b600052604160045260246000fd5b60405190610200820182811067ffffffffffffffff82111761039e57604052565b604051906080820182811067ffffffffffffffff82111761039e57604052565b600435906001600160a01b038216820361013157565b602435906001600160a01b038216820361013157565b604435906001600160a01b038216820361013157565b606435906affffffffffffffffffffff8216820361013157565b608435906affffffffffffffffffffff8216820361013157565b60a435906affffffffffffffffffffff8216820361013157565b60c435906affffffffffffffffffffff8216820361013157565b60e435906affffffffffffffffffffff8216820361013157565b610104359067ffffffffffffffff8216820361013157565b610124359067ffffffffffffffff8216820361013157565b610144359064ffffffffff8216820361013157565b610164359064ffffffffff8216820361013157565b610184359064ffffffffff8216820361013157565b6101a4359064ffffffffff8216820361013157565b6101c43590811515820361013157565b610200906003190112610131576105626103b4565b9061056b6103f5565b825261057561040b565b6020830152610582610421565b604083015261058f610437565b606083015261059c610451565b60808301526105a961046b565b60a08301526105b6610485565b60c08301526105c361049f565b60e08301526105d06104b9565b6101008301526105de6104d1565b6101208301526105ec6104e9565b6101408301526105fa6104fe565b610160830152610608610513565b610180830152610616610528565b6101a083015261062461053d565b6101c08301526101e4356101e0830152565b3461013157610260366003190112610131576106513661054d565b6020810180516102243592906001600160a01b03166001600160a01b038061068084516001600160a01b031690565b16911690808214918215610a40575b508115610a37575b50610a0d576106b26106a842610f85565b64ffffffffff1690565b6101608201805164ffffffffff1664ffffffffff8093818084169116119182156109e1575b50506109b7575164ffffffffff16906101a0830191816106ff6106a8855164ffffffffff1690565b9116908110610915575b50505067ffffffffffffffff8061072c61010084015167ffffffffffffffff1690565b1690662386f26fc1000090818310928315610903575b5082156108d8575b5081156108a9575b5061087f57821580610853575b61082957610825926107b8926107d6926107c56107a8610244356107828461123e565b7f0000000000000000000000000000000000000000000000000000000000000000610fb1565b958693516001600160a01b031690565b8361020435913390611098565b5133906001600160a01b0316611098565b6040516001600160a01b03821681527f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc90602090a16040516001600160a01b0390911681529081906020820190565b0390f35b60046040517f3b707781000000000000000000000000000000000000000000000000000000008152fd5b506affffffffffffffffffffff61087860608301516affffffffffffffffffffff1690565b161561075f565b60046040517f31c93d56000000000000000000000000000000000000000000000000000000008152fd5b90506108d16108c461012084015167ffffffffffffffff1690565b67ffffffffffffffff1690565b1038610752565b670dbd2fc137a300009192506108fa61012085015167ffffffffffffffff1690565b1611903861074a565b670dbd2fc137a3000010925038610742565b61018084019061092d6106a8835164ffffffffff1690565b1061098d576106a8610947610953925164ffffffffff1690565b935164ffffffffff1690565b9116101561096357388080610709565b60046040517fd75478aa000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd651d50e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5e0c84c8000000000000000000000000000000000000000000000000000000008152fd5b620151809250610a04906109fe61014088015164ffffffffff1690565b90610f9a565b161082386106d7565b60046040517f98d3f40b000000000000000000000000000000000000000000000000000000008152fd5b90501538610697565b1591503861068f565b60008060031936011261029757610a5e610f52565b80638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b3461013157610200366003190112610131576020610ade610ab8610ab33661054d565b61123e565b7f00000000000000000000000000000000000000000000000000000000000000006110f1565b604051908152f35b34610131576000366003190112610131576020638b78c6d819546001600160a01b0360405191168152f35b3461013157608036600319011261013157610b2a6103f5565b610b32610136565b610b3a61014b565b90610b43610160565b90610b4c610f52565b6103e865ffffffffffff81818416116102215781818616116102215783161161022157610ca5610cc1937fdc4e4be378c228e1b7b13787e1d0620609304c2f71ed3a6ee69e4aae99d58cd9610ca57f11388023ce3c3ee3995ef04b4ad33102dab6bed131ac79d8531163e61a34f93b947fbf9a9534339a9d6b81696e05dcfb614b7dc518a31d48be3cfb757988381fb323610ca57f4cc356a4f0cf9460d4d6f22c6c58a7cb56a92755a9d27d92b2dff03c5b3e94389a610c8b610c0d6103d5565b6001600160a01b03831680825265ffffffffffff87811660208401528a811660408401528d16606090920182905260a087901b65ffffffffffff60a01b161760d08a901b7fffffffffffff000000000000000000000000000000000000000000000000000016176000556001805465ffffffffffff19169091179055565b6040516001600160a01b0390911681529081906020820190565b0390a160405165ffffffffffff90911681529081906020820190565b0390a1005b3461013157600036600319011261013157608060005465ffffffffffff90816001541690604051926001600160a01b03821684528160a01c16602084015260d01c60408301526060820152f35b346101315761022036600319011261013157610d34610ab8610ab33661054d565b60ff6000536035523060601b600152610204356015526020605560002060006035526001600160a01b0360405191168152f35b346101315760203660031901126101315765ffffffffffff610d8761011c565b610d8f610f52565b166103e88111610221576020817f4cc356a4f0cf9460d4d6f22c6c58a7cb56a92755a9d27d92b2dff03c5b3e94389265ffffffffffff196001541617600155604051908152a1005b34610131576020366003190112610131577fbf9a9534339a9d6b81696e05dcfb614b7dc518a31d48be3cfb757988381fb32360206001600160a01b03610e1b6103f5565b610e23610f52565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000006000541617600055604051908152a1005b602036600319011261013157610e6b6103f5565b610e73610f52565b63389a75e1600c52806000526020600c209081544211610e9b576000610e999255610f18565b005b636f5e88186000526004601cfd5b602036600319011261013157610ebd6103f5565b610ec5610f52565b8060601b15610ed757610e9990610f18565b637448fbae6000526004601cfd5b3461013157602036600319011261013157610efe6103f5565b63389a75e1600c52600052602080600c2054604051908152f35b6001600160a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b638b78c6d819543303610f6157565b6382b429006000526004601cfd5b634e487b7160e01b600052601160045260246000fd5b90620151808201809211610f9557565b610f6f565b64ffffffffff9182169082160391908211610f9557565b929192605f19820190815192603f19810190815192601f198201908151928051916020838301019a8b519160028501906c5af43d3d93803e606057fd5bf38552600c1985015278593da1005b363d3d373d3d3d3d610000806062363936013d738160481b176020198501527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff60391985015272fd6100003d81600a3d39f336602c57343d527f6064860160781b1760581961ff9e83108603015260f01b8c52606e8401604b1984016000f59a8b1561108a575252525252565b63301164256000526004601cfd5b601c600060649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d156001600051141716156110e3576000606052604052565b637939f4246000526004601cfd5b9190605f198101805191603f198101805191601f198101805191805190602082820101998a519061ff9b84113d3d3e6c5af43d3d93803e606057fd5bf38352600c1983015260028301604881901b78593da1005b363d3d373d3d3d3d610000806062363936013d73176020198401527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff6039198401526064840160781b716100003d81600a3d39f336602c57343d527f1760591984015260f01b8b52606e8301604b198301209a5252525252565b604051906080820182811067ffffffffffffffff82111761039e576040528160606000546001600160a01b038116835265ffffffffffff90818160a01c16602085015260d01c604084015260015416910152565b9081519160005b83811061122b575050016000815290565b806020809284010151818501520161121a565b6112466111bf565b908051611259906001600160a01b031690565b9060209081810151611271906001600160a01b031690565b938051611284906001600160a01b031690565b946040948584015161129c906001600160a01b031690565b86516bffffffffffffffffffffffff19606093841b811688830190815294841b8116601486015298831b89166028850152911b909616603c82015285906050010393601f199485810187526112f1908761037c565b60608301516affffffffffffffffffffff1660808401516affffffffffffffffffffff1660a08501516affffffffffffffffffffff169160c0860151611341906affffffffffffffffffffff1690565b60e08701516affffffffffffffffffffff1685517fffffffffffffffffffffff00000000000000000000000000000000000000000060a894851b81168b830190815295851b8116600b87015295841b8616601686015291831b8516602185015290911b909216602c82015281906037010386810182526113c1908261037c565b848301518284015167ffffffffffffffff655af3107a400065ffffffffffff938416021692911665ffffffffffff16655af3107a40000267ffffffffffffffff1661010086015167ffffffffffffffff169261012087015161142a9067ffffffffffffffff1690565b85517fffffffffffffffff00000000000000000000000000000000000000000000000060c093841b81168b830190815294841b8116600886015295831b86166010850152911b9093166018820152829060200103878101835261148d908361037c565b61014085015164ffffffffff16926101608601516114af9064ffffffffff1690565b8151948591898301916114f69290600a927fffffffffff000000000000000000000000000000000000000000000000000000809260d81b16835260d81b1660058201520190565b038881018552611506908561037c565b61018086015164ffffffffff16946101a08701516115289064ffffffffff1690565b60609091015165ffffffffffff1665ffffffffffff16655af3107a40000267ffffffffffffffff16825160d897881b7fffffffffff0000000000000000000000000000000000000000000000000000009081168b83019081529390981b909716600583015260c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016600a82015285906012010388810186526115cc908661037c565b6101c086015115156101e090960151815196151560f81b88880190815260018101919091528690602101038881018752611606908761037c565b51978896870161161591611213565b61161e91611213565b61162791611213565b61163091611213565b61163991611213565b61164291611213565b039081018252611652908261037c565b9056fea2646970667358221220ea0172d2e586887a333c827d277abbd609a41b2efd352f4862e34454b276df3c64736f6c6343000815003300000000000000000000000081a89a3c934b688f93368b07d1210c7d669e27bc000000000000000000000000495920e33d7bf188c1d9cff96b96bed9cdfa04dc000000000000000000000000a5033a6bdb31e52ce6ba9c67bff7331ac2686e72000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c8
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c80630d4dfc2114610117578063256929621461011257806354bba6071461010d57806354d1f13d1461010857806357e94d3214610103578063715018a6146100fe5780638054480b146100f95780638da5cb5b146100f4578063a034d11b146100ef578063a781d208146100ea578063d4522b3c146100e5578063dce92425146100e0578063e74b981b146100db578063f04e283e146100d6578063f2fde38b146100d15763fee81cf4146100cc57600080fd5b610ee5565b610ea9565b610e57565b610dd7565b610d67565b610d13565b610cc6565b610b11565b610ae6565b610a90565b610a49565b610636565b610335565b61029a565b61024b565b610175565b6004359065ffffffffffff8216820361013157565b600080fd5b6024359065ffffffffffff8216820361013157565b6044359065ffffffffffff8216820361013157565b6064359065ffffffffffff8216820361013157565b346101315760203660031901126101315761018e61011c565b610196610f52565b65ffffffffffff8116906103e88211610221577f11388023ce3c3ee3995ef04b4ad33102dab6bed131ac79d8531163e61a34f93b9160209179ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff00000000000000000000000000000000000000000000000000006000549260d01b16911617600055604051908152a1005b60046040517ff4df6ae5000000000000000000000000000000000000000000000000000000008152fd5b6000806003193601126102975763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b80fd5b34610131576020366003190112610131576102b361011c565b6102bb610f52565b65ffffffffffff8116906103e88211610221577fdc4e4be378c228e1b7b13787e1d0620609304c2f71ed3a6ee69e4aae99d58cd9916020917fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff65ffffffffffff60a01b6000549260a01b16911617600055604051908152a1005b6000806003193601126102975763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b90601f8019910116810190811067ffffffffffffffff82111761039e57604052565b634e487b7160e01b600052604160045260246000fd5b60405190610200820182811067ffffffffffffffff82111761039e57604052565b604051906080820182811067ffffffffffffffff82111761039e57604052565b600435906001600160a01b038216820361013157565b602435906001600160a01b038216820361013157565b604435906001600160a01b038216820361013157565b606435906affffffffffffffffffffff8216820361013157565b608435906affffffffffffffffffffff8216820361013157565b60a435906affffffffffffffffffffff8216820361013157565b60c435906affffffffffffffffffffff8216820361013157565b60e435906affffffffffffffffffffff8216820361013157565b610104359067ffffffffffffffff8216820361013157565b610124359067ffffffffffffffff8216820361013157565b610144359064ffffffffff8216820361013157565b610164359064ffffffffff8216820361013157565b610184359064ffffffffff8216820361013157565b6101a4359064ffffffffff8216820361013157565b6101c43590811515820361013157565b610200906003190112610131576105626103b4565b9061056b6103f5565b825261057561040b565b6020830152610582610421565b604083015261058f610437565b606083015261059c610451565b60808301526105a961046b565b60a08301526105b6610485565b60c08301526105c361049f565b60e08301526105d06104b9565b6101008301526105de6104d1565b6101208301526105ec6104e9565b6101408301526105fa6104fe565b610160830152610608610513565b610180830152610616610528565b6101a083015261062461053d565b6101c08301526101e4356101e0830152565b3461013157610260366003190112610131576106513661054d565b6020810180516102243592906001600160a01b03166001600160a01b038061068084516001600160a01b031690565b16911690808214918215610a40575b508115610a37575b50610a0d576106b26106a842610f85565b64ffffffffff1690565b6101608201805164ffffffffff1664ffffffffff8093818084169116119182156109e1575b50506109b7575164ffffffffff16906101a0830191816106ff6106a8855164ffffffffff1690565b9116908110610915575b50505067ffffffffffffffff8061072c61010084015167ffffffffffffffff1690565b1690662386f26fc1000090818310928315610903575b5082156108d8575b5081156108a9575b5061087f57821580610853575b61082957610825926107b8926107d6926107c56107a8610244356107828461123e565b7f00000000000000000000000081a89a3c934b688f93368b07d1210c7d669e27bc610fb1565b958693516001600160a01b031690565b8361020435913390611098565b5133906001600160a01b0316611098565b6040516001600160a01b03821681527f83a48fbcfc991335314e74d0496aab6a1987e992ddc85dddbcc4d6dd6ef2e9fc90602090a16040516001600160a01b0390911681529081906020820190565b0390f35b60046040517f3b707781000000000000000000000000000000000000000000000000000000008152fd5b506affffffffffffffffffffff61087860608301516affffffffffffffffffffff1690565b161561075f565b60046040517f31c93d56000000000000000000000000000000000000000000000000000000008152fd5b90506108d16108c461012084015167ffffffffffffffff1690565b67ffffffffffffffff1690565b1038610752565b670dbd2fc137a300009192506108fa61012085015167ffffffffffffffff1690565b1611903861074a565b670dbd2fc137a3000010925038610742565b61018084019061092d6106a8835164ffffffffff1690565b1061098d576106a8610947610953925164ffffffffff1690565b935164ffffffffff1690565b9116101561096357388080610709565b60046040517fd75478aa000000000000000000000000000000000000000000000000000000008152fd5b60046040517fd651d50e000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5e0c84c8000000000000000000000000000000000000000000000000000000008152fd5b620151809250610a04906109fe61014088015164ffffffffff1690565b90610f9a565b161082386106d7565b60046040517f98d3f40b000000000000000000000000000000000000000000000000000000008152fd5b90501538610697565b1591503861068f565b60008060031936011261029757610a5e610f52565b80638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b3461013157610200366003190112610131576020610ade610ab8610ab33661054d565b61123e565b7f00000000000000000000000081a89a3c934b688f93368b07d1210c7d669e27bc6110f1565b604051908152f35b34610131576000366003190112610131576020638b78c6d819546001600160a01b0360405191168152f35b3461013157608036600319011261013157610b2a6103f5565b610b32610136565b610b3a61014b565b90610b43610160565b90610b4c610f52565b6103e865ffffffffffff81818416116102215781818616116102215783161161022157610ca5610cc1937fdc4e4be378c228e1b7b13787e1d0620609304c2f71ed3a6ee69e4aae99d58cd9610ca57f11388023ce3c3ee3995ef04b4ad33102dab6bed131ac79d8531163e61a34f93b947fbf9a9534339a9d6b81696e05dcfb614b7dc518a31d48be3cfb757988381fb323610ca57f4cc356a4f0cf9460d4d6f22c6c58a7cb56a92755a9d27d92b2dff03c5b3e94389a610c8b610c0d6103d5565b6001600160a01b03831680825265ffffffffffff87811660208401528a811660408401528d16606090920182905260a087901b65ffffffffffff60a01b161760d08a901b7fffffffffffff000000000000000000000000000000000000000000000000000016176000556001805465ffffffffffff19169091179055565b6040516001600160a01b0390911681529081906020820190565b0390a160405165ffffffffffff90911681529081906020820190565b0390a1005b3461013157600036600319011261013157608060005465ffffffffffff90816001541690604051926001600160a01b03821684528160a01c16602084015260d01c60408301526060820152f35b346101315761022036600319011261013157610d34610ab8610ab33661054d565b60ff6000536035523060601b600152610204356015526020605560002060006035526001600160a01b0360405191168152f35b346101315760203660031901126101315765ffffffffffff610d8761011c565b610d8f610f52565b166103e88111610221576020817f4cc356a4f0cf9460d4d6f22c6c58a7cb56a92755a9d27d92b2dff03c5b3e94389265ffffffffffff196001541617600155604051908152a1005b34610131576020366003190112610131577fbf9a9534339a9d6b81696e05dcfb614b7dc518a31d48be3cfb757988381fb32360206001600160a01b03610e1b6103f5565b610e23610f52565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000006000541617600055604051908152a1005b602036600319011261013157610e6b6103f5565b610e73610f52565b63389a75e1600c52806000526020600c209081544211610e9b576000610e999255610f18565b005b636f5e88186000526004601cfd5b602036600319011261013157610ebd6103f5565b610ec5610f52565b8060601b15610ed757610e9990610f18565b637448fbae6000526004601cfd5b3461013157602036600319011261013157610efe6103f5565b63389a75e1600c52600052602080600c2054604051908152f35b6001600160a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b638b78c6d819543303610f6157565b6382b429006000526004601cfd5b634e487b7160e01b600052601160045260246000fd5b90620151808201809211610f9557565b610f6f565b64ffffffffff9182169082160391908211610f9557565b929192605f19820190815192603f19810190815192601f198201908151928051916020838301019a8b519160028501906c5af43d3d93803e606057fd5bf38552600c1985015278593da1005b363d3d373d3d3d3d610000806062363936013d738160481b176020198501527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff60391985015272fd6100003d81600a3d39f336602c57343d527f6064860160781b1760581961ff9e83108603015260f01b8c52606e8401604b1984016000f59a8b1561108a575252525252565b63301164256000526004601cfd5b601c600060649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d156001600051141716156110e3576000606052604052565b637939f4246000526004601cfd5b9190605f198101805191603f198101805191601f198101805191805190602082820101998a519061ff9b84113d3d3e6c5af43d3d93803e606057fd5bf38352600c1983015260028301604881901b78593da1005b363d3d373d3d3d3d610000806062363936013d73176020198401527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff6039198401526064840160781b716100003d81600a3d39f336602c57343d527f1760591984015260f01b8b52606e8301604b198301209a5252525252565b604051906080820182811067ffffffffffffffff82111761039e576040528160606000546001600160a01b038116835265ffffffffffff90818160a01c16602085015260d01c604084015260015416910152565b9081519160005b83811061122b575050016000815290565b806020809284010151818501520161121a565b6112466111bf565b908051611259906001600160a01b031690565b9060209081810151611271906001600160a01b031690565b938051611284906001600160a01b031690565b946040948584015161129c906001600160a01b031690565b86516bffffffffffffffffffffffff19606093841b811688830190815294841b8116601486015298831b89166028850152911b909616603c82015285906050010393601f199485810187526112f1908761037c565b60608301516affffffffffffffffffffff1660808401516affffffffffffffffffffff1660a08501516affffffffffffffffffffff169160c0860151611341906affffffffffffffffffffff1690565b60e08701516affffffffffffffffffffff1685517fffffffffffffffffffffff00000000000000000000000000000000000000000060a894851b81168b830190815295851b8116600b87015295841b8616601686015291831b8516602185015290911b909216602c82015281906037010386810182526113c1908261037c565b848301518284015167ffffffffffffffff655af3107a400065ffffffffffff938416021692911665ffffffffffff16655af3107a40000267ffffffffffffffff1661010086015167ffffffffffffffff169261012087015161142a9067ffffffffffffffff1690565b85517fffffffffffffffff00000000000000000000000000000000000000000000000060c093841b81168b830190815294841b8116600886015295831b86166010850152911b9093166018820152829060200103878101835261148d908361037c565b61014085015164ffffffffff16926101608601516114af9064ffffffffff1690565b8151948591898301916114f69290600a927fffffffffff000000000000000000000000000000000000000000000000000000809260d81b16835260d81b1660058201520190565b038881018552611506908561037c565b61018086015164ffffffffff16946101a08701516115289064ffffffffff1690565b60609091015165ffffffffffff1665ffffffffffff16655af3107a40000267ffffffffffffffff16825160d897881b7fffffffffff0000000000000000000000000000000000000000000000000000009081168b83019081529390981b909716600583015260c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016600a82015285906012010388810186526115cc908661037c565b6101c086015115156101e090960151815196151560f81b88880190815260018101919091528690602101038881018752611606908761037c565b51978896870161161591611213565b61161e91611213565b61162791611213565b61163091611213565b61163991611213565b61164291611213565b039081018252611652908261037c565b9056fea2646970667358221220ea0172d2e586887a333c827d277abbd609a41b2efd352f4862e34454b276df3c64736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000081a89a3c934b688f93368b07d1210c7d669e27bc000000000000000000000000495920e33d7bf188c1d9cff96b96bed9cdfa04dc000000000000000000000000a5033a6bdb31e52ce6ba9c67bff7331ac2686e72000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c8
-----Decoded View---------------
Arg [0] : _implementation (address): 0x81A89a3c934B688F93368B07D1210C7d669E27Bc
Arg [1] : _owner (address): 0x495920e33d7bF188c1D9cFf96B96Bed9CDfa04dc
Arg [2] : _feeRecipient (address): 0xA5033A6BDb31E52Ce6ba9c67Bff7331aC2686e72
Arg [3] : _platformFee (uint48): 300
Arg [4] : _referrerFee (uint48): 0
Arg [5] : _swapFee (uint48): 200
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 00000000000000000000000081a89a3c934b688f93368b07d1210c7d669e27bc
Arg [1] : 000000000000000000000000495920e33d7bf188c1d9cff96b96bed9cdfa04dc
Arg [2] : 000000000000000000000000a5033a6bdb31e52ce6ba9c67bff7331ac2686e72
Arg [3] : 000000000000000000000000000000000000000000000000000000000000012c
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 00000000000000000000000000000000000000000000000000000000000000c8
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.