ETH Price: $3,296.59 (-0.51%)
 

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Distribute Token242225272026-01-13 1:30:353 days ago1768267835IN
0x00000008...6d140637C
0 ETH0.000255570.03340133
Create Token237941522025-11-14 1:28:4763 days ago1763083727IN
0x00000008...6d140637C
0 ETH0.003406462.10790962

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x60a06040237808712025-11-12 4:49:5964 days ago1762922999  Contract Creation0 ETH
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LiquidityLauncher

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {IERC20} from "@openzeppelin-latest/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin-latest/contracts/token/ERC20/utils/SafeERC20.sol";
import {ITokenFactory} from "./token-factories/uerc20-factory/interfaces/ITokenFactory.sol";
import {IDistributionStrategy} from "./interfaces/IDistributionStrategy.sol";
import {IDistributionContract} from "./interfaces/IDistributionContract.sol";
import {Multicall} from "./Multicall.sol";
import {Distribution} from "./types/Distribution.sol";
import {Permit2Forwarder, IAllowanceTransfer} from "./Permit2Forwarder.sol";
import {ILiquidityLauncher} from "./interfaces/ILiquidityLauncher.sol";

/// @title LiquidityLauncher
/// @notice A contract that allows users to create tokens and distribute them via one or more strategies
/// @custom:security-contact [email protected]
contract LiquidityLauncher is ILiquidityLauncher, Multicall, Permit2Forwarder {
    using SafeERC20 for IERC20;

    constructor(IAllowanceTransfer _permit2) Permit2Forwarder(_permit2) {}

    /// @inheritdoc ILiquidityLauncher
    function createToken(
        address factory,
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        uint128 initialSupply,
        address recipient,
        bytes calldata tokenData
    ) external override returns (address tokenAddress) {
        if (recipient == address(0)) {
            revert RecipientCannotBeZeroAddress();
        }
        tokenAddress = ITokenFactory(factory)
            .createToken(name, symbol, decimals, initialSupply, recipient, tokenData, getGraffiti(msg.sender));

        emit TokenCreated(tokenAddress);
    }

    /// @inheritdoc ILiquidityLauncher
    function distributeToken(address token, Distribution calldata distribution, bool payerIsUser, bytes32 salt)
        external
        override
        returns (IDistributionContract distributionContract)
    {
        // Call the strategy: it might do distributions itself or deploy a new instance.
        // If it does distributions itself, distributionContract == dist.strategy
        distributionContract = IDistributionStrategy(distribution.strategy)
            .initializeDistribution(
                token, distribution.amount, distribution.configData, keccak256(abi.encode(msg.sender, salt))
            );

        // Now transfer the tokens to the returned address
        // payerIsUser should be false if the tokens were created in the same call via multicall
        _transferToken(token, _mapPayer(payerIsUser), address(distributionContract), distribution.amount);

        // Notify the distribution contract that it has received the tokens
        distributionContract.onTokensReceived();

        emit TokenDistributed(token, address(distributionContract), distribution.amount);
    }

    /// @inheritdoc ILiquidityLauncher
    function getGraffiti(address originalCreator) public pure returns (bytes32 graffiti) {
        graffiti = keccak256(abi.encode(originalCreator));
    }

    /// @notice Transfers tokens to the distribution contract
    /// @param token The address of the token to transfer
    /// @param from The address to transfer the tokens from (this contract or the user)
    /// @param to The distribution contract address to transfer the tokens to
    /// @param amount The amount of tokens to transfer
    function _transferToken(address token, address from, address to, uint256 amount) internal {
        if (from == address(this)) {
            IERC20(token).safeTransfer(to, amount);
        } else {
            permit2.transferFrom(from, to, uint160(amount), token);
        }
    }

    /// @notice Calculates the payer for an action (this contract or the user)
    /// @param payerIsUser Whether the payer is the user
    /// @return payer The address of the payer
    function _mapPayer(bool payerIsUser) internal view returns (address) {
        return payerIsUser ? msg.sender : address(this);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

File 4 of 18 : ITokenFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title ITokenFactory
/// @notice Generic interface for a token factory.
interface ITokenFactory {
    /// @notice Emitted when a new token is created
    event TokenCreated(address tokenAddress);

    /// @notice Thrown when the recipient is the zero address
    error RecipientCannotBeZeroAddress();

    /// @notice Thrown when the initial supply is zero
    error TotalSupplyCannotBeZero();

    /// @notice Creates a new token contract
    /// @param name          The ERC20-style name of the token.
    /// @param symbol        The ERC20-style symbol of the token.
    /// @param decimals      The number of decimal places for the token.
    /// @param initialSupply The initial supply to mint upon creation.
    /// @param recipient     The recipient of the initial supply.
    /// @param data          Additional factory-specific data required for token creation.
    /// @param graffiti      Additional data to be included in the token's salt
    /// @return tokenAddress The address of the newly created token.
    function createToken(
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        uint256 initialSupply,
        address recipient,
        bytes calldata data,
        bytes32 graffiti
    ) external returns (address tokenAddress);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IDistributionContract} from "./IDistributionContract.sol";

/// @title IDistributionStrategy
/// @notice Interface for token distribution strategies.
interface IDistributionStrategy {
    /// @notice Emitted when a distribution is initialized
    /// @param distributionContract The contract that was created that will handle or manage the distribution.
    /// @param token The token that is being distributed.
    /// @param totalSupply The supply of the token that is being distributed.
    event DistributionInitialized(address indexed distributionContract, address indexed token, uint256 totalSupply);

    /// @notice Error thrown when the amount to be distributed is invalid
    /// @param amount The invalid amount
    /// @param maxAmount The maximum valid amount to be distributed
    error InvalidAmount(uint256 amount, uint256 maxAmount);

    /// @notice Initialize a distribution of tokens under this strategy.
    /// @dev Contracts can choose to deploy an instance with a factory-model or handle all distributions within the
    /// implementing contract. For some strategies this function will handle the entire distribution, for others it
    /// could merely set up initial state and provide additional entrypoints to handle the distribution logic.
    /// @param token The token that is being distributed.
    /// @param totalSupply The supply of the token that is being distributed.
    /// @param configData Arbitrary, strategy-specific parameters.
    /// @param salt The optional salt for deterministic deployment.
    /// @return distributionContract The contract that will handle or manage the distribution.
    ///         (Could be `address(this)` if the strategy is handled in-place, or a newly deployed instance).
    function initializeDistribution(address token, uint256 totalSupply, bytes calldata configData, bytes32 salt)
        external
        returns (IDistributionContract distributionContract);
}

File 6 of 18 : IDistributionContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title IDistributionContract
/// @notice Interface for token distribution contracts.
interface IDistributionContract {
    /// @notice Error thrown when the token address is invalid
    error InvalidToken(address token);

    /// @notice Error thrown when the amount received is invalid upon receiving tokens
    /// @param expected The expected amount
    /// @param received The received amount
    error InvalidAmountReceived(uint256 expected, uint256 received);

    /// @notice Notify a distribution contract that it has received the tokens to distribute
    function onTokensReceived() external;
}

File 7 of 18 : Multicall.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IMulticall} from "./interfaces/IMulticall.sol";

/// @title Multicall
/// @notice Enables calling multiple methods in a single call to the contract
abstract contract Multicall is IMulticall {
    /// @inheritdoc IMulticall
    function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // bubble up the revert reason
                assembly {
                    revert(add(result, 0x20), mload(result))
                }
            }

            results[i] = result;
        }
    }
}

File 8 of 18 : Distribution.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Distribution
/// @notice Represents one distribution instruction: which strategy to use, how many tokens, and any custom data
struct Distribution {
    address strategy;
    uint128 amount;
    bytes configData;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IPermit2Forwarder, IAllowanceTransfer} from "./interfaces/IPermit2Forwarder.sol";

/// @notice Permit2Forwarder allows permitting this contract as a spender on permit2
/// @dev This contract does not enforce the spender to be this contract, but that is the intended use case
contract Permit2Forwarder is IPermit2Forwarder {
    /// @notice the Permit2 contract to forward approvals
    IAllowanceTransfer public immutable permit2;

    constructor(IAllowanceTransfer _permit2) {
        permit2 = _permit2;
    }

    /// @inheritdoc IPermit2Forwarder
    function permit(address owner, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature)
        external
        returns (bytes memory err)
    {
        // use try/catch in case an actor front-runs the permit, which would DOS multicalls
        try permit2.permit(owner, permitSingle, signature) {}
        catch (bytes memory reason) {
            err = reason;
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Distribution} from "../types/Distribution.sol";
import {IDistributionContract} from "./IDistributionContract.sol";

/// @title ILiquidityLauncher
/// @notice Interface for the LiquidityLauncher contract
interface ILiquidityLauncher {
    /// @notice Thrown when the recipient is the zero address
    error RecipientCannotBeZeroAddress();

    /// @notice Emitted when a token is created
    /// @param tokenAddress The address of the token that was created
    event TokenCreated(address indexed tokenAddress);

    /// @notice Emitted when a token is distributed
    /// @param tokenAddress The address of the token that was distributed
    /// @param distributionContract The address of the distribution contract
    /// @param amount The amount of tokens that were distributed
    event TokenDistributed(address indexed tokenAddress, address indexed distributionContract, uint256 amount);

    /// @notice Creates and distributes tokens.
    ///      1) Deploys a token via chosen factory.
    ///      2) Distributes tokens via one or more strategies.
    ///  @param factory Address of the factory to use
    ///  @param name Token name
    ///  @param symbol Token symbol
    ///  @param decimals Token decimals
    ///  @param initialSupply Total tokens to be minted (to this contract)
    ///  @param recipient The address that will receive the newly minted tokens. Should only be set to address(this) when
    ///                   distributing tokens in the same transaction via multicall. For all other cases, use a different
    ///                   recipient address to avoid tokens being distributed by another caller
    ///  @param tokenData Extra data needed by the factory
    ///  @return tokenAddress The address of the token that was created
    function createToken(
        address factory,
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        uint128 initialSupply,
        address recipient,
        bytes calldata tokenData
    ) external returns (address tokenAddress);

    /// @notice Transfer tokens already created to this contract and distribute them via one or more strategies
    /// @param tokenAddress The address of the token to distribute
    /// @param distribution Distribution instructions
    /// @param payerIsUser Whether the payer is the user
    /// @param salt The salt to pass into the distribution strategy contract if needed
    /// @return distributionContract The address of the distribution contract
    function distributeToken(address tokenAddress, Distribution memory distribution, bool payerIsUser, bytes32 salt)
        external
        returns (IDistributionContract distributionContract);

    /// @notice Calculates the graffiti that will be used for a token creation
    /// @param originalCreator The address that will be set as the original creator
    /// @return graffiti The graffiti bytes32 that will be used
    function getGraffiti(address originalCreator) external view returns (bytes32 graffiti);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title IMulticall
/// @notice Interface for the Multicall contract
interface IMulticall {
    /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
    /// @param data The encoded function data for each of the calls to make to this contract
    /// @return results The results from each of the calls passed in via data
    function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";

/// @title IPermit2Forwarder
/// @notice Interface for the Permit2Forwarder contract
interface IPermit2Forwarder {
    /// @notice Allows forwarding a single permit to permit2
    /// @param owner the owner of the tokens
    /// @param permitSingle the permit data
    /// @param signature the signature of the permit; abi.encodePacked(r, s, v)
    /// @return err the error returned by a reverting permit call, empty if successful
    function permit(address owner, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature)
        external
        returns (bytes memory err);
}

File 14 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";

File 15 of 18 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IEIP712} from "./IEIP712.sol";

/// @title AllowanceTransfer
/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts
/// @dev Requires user's token approval on the Permit2 contract
interface IAllowanceTransfer is IEIP712 {
    /// @notice Thrown when an allowance on a token has expired.
    /// @param deadline The timestamp at which the allowed amount is no longer valid
    error AllowanceExpired(uint256 deadline);

    /// @notice Thrown when an allowance on a token has been depleted.
    /// @param amount The maximum amount allowed
    error InsufficientAllowance(uint256 amount);

    /// @notice Thrown when too many nonces are invalidated.
    error ExcessiveInvalidation();

    /// @notice Emits an event when the owner successfully invalidates an ordered nonce.
    event NonceInvalidation(
        address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce
    );

    /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.
    event Approval(
        address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration
    );

    /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.
    event Permit(
        address indexed owner,
        address indexed token,
        address indexed spender,
        uint160 amount,
        uint48 expiration,
        uint48 nonce
    );

    /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.
    event Lockdown(address indexed owner, address token, address spender);

    /// @notice The permit data for a token
    struct PermitDetails {
        // ERC20 token address
        address token;
        // the maximum amount allowed to spend
        uint160 amount;
        // timestamp at which a spender's token allowances become invalid
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice The permit message signed for a single token allowance
    struct PermitSingle {
        // the permit data for a single token alownce
        PermitDetails details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice The permit message signed for multiple token allowances
    struct PermitBatch {
        // the permit data for multiple token allowances
        PermitDetails[] details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice The saved permissions
    /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message
    /// @dev Setting amount to type(uint160).max sets an unlimited approval
    struct PackedAllowance {
        // amount allowed
        uint160 amount;
        // permission expiry
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice A token spender pair.
    struct TokenSpenderPair {
        // the token the spender is approved
        address token;
        // the spender address
        address spender;
    }

    /// @notice Details for a token transfer.
    struct AllowanceTransferDetails {
        // the owner of the token
        address from;
        // the recipient of the token
        address to;
        // the amount of the token
        uint160 amount;
        // the token to be transferred
        address token;
    }

    /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.
    /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]
    /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.
    function allowance(address user, address token, address spender)
        external
        view
        returns (uint160 amount, uint48 expiration, uint48 nonce);

    /// @notice Approves the spender to use up to amount of the specified token up until the expiration
    /// @param token The token to approve
    /// @param spender The spender address to approve
    /// @param amount The approved amount of the token
    /// @param expiration The timestamp at which the approval is no longer valid
    /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve
    /// @dev Setting amount to type(uint160).max sets an unlimited approval
    function approve(address token, address spender, uint160 amount, uint48 expiration) external;

    /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitSingle Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;

    /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitBatch Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;

    /// @notice Transfer approved tokens from one address to another
    /// @param from The address to transfer from
    /// @param to The address of the recipient
    /// @param amount The amount of the token to transfer
    /// @param token The token address to transfer
    /// @dev Requires the from address to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(address from, address to, uint160 amount, address token) external;

    /// @notice Transfer approved tokens in a batch
    /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers
    /// @dev Requires the from addresses to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;

    /// @notice Enables performing a "lockdown" of the sender's Permit2 identity
    /// by batch revoking approvals
    /// @param approvals Array of approvals to revoke.
    function lockdown(TokenSpenderPair[] calldata approvals) external;

    /// @notice Invalidate nonces for a given (token, spender) pair
    /// @param token The token to invalidate nonces for
    /// @param spender The spender to invalidate nonces for
    /// @param newNonce The new nonce to set. Invalidates all nonces less than it.
    /// @dev Can't invalidate more than 2**16 nonces per transaction.
    function invalidateNonces(address token, address spender, uint48 newNonce) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IEIP712 {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

Settings
{
  "remappings": [
    "permit2/=lib/permit2/",
    "@uniswap/v4-core/=lib/v4-core/",
    "@uniswap/v4-periphery/=lib/v4-periphery/",
    "merkle-distributor/=lib/merkle-distributor/",
    "@openzeppelin/=lib/openzeppelin-contracts-4.7/",
    "@openzeppelin-latest/=lib/openzeppelin-contracts/",
    "@solady/=lib/solady/",
    "@optimism/=lib/optimism/packages/contracts-bedrock/",
    "continuous-clearing-auction/=lib/continuous-clearing-auction/",
    "@ensdomains/=lib/v4-core/node_modules/@ensdomains/",
    "btt/=lib/continuous-clearing-auction/test/btt/",
    "ds-test/=lib/v4-core/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-snapshot/=lib/continuous-clearing-auction/lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
    "hardhat/=lib/v4-core/node_modules/hardhat/",
    "kontrol-cheatcodes/=lib/optimism/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/",
    "lib-keccak/=lib/optimism/packages/contracts-bedrock/lib/lib-keccak/contracts/",
    "openzeppelin-contracts-4.7/=lib/openzeppelin-contracts-4.7/",
    "openzeppelin-contracts-upgradeable/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts-v5/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts-v5/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "optimism/=lib/optimism/",
    "safe-contracts/=lib/optimism/packages/contracts-bedrock/lib/safe-contracts/contracts/",
    "solady-v0.0.245/=lib/optimism/packages/contracts-bedrock/lib/solady-v0.0.245/src/",
    "solady/=lib/solady/src/",
    "solmate/=lib/v4-core/lib/solmate/",
    "test/=lib/continuous-clearing-auction/test/",
    "v4-core/=lib/v4-core/src/",
    "v4-periphery/=lib/v4-periphery/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IAllowanceTransfer","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"RecipientCannotBeZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"distributionContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenDistributed","type":"event"},{"inputs":[{"internalType":"address","name":"factory","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint128","name":"initialSupply","type":"uint128"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"tokenData","type":"bytes"}],"name":"createToken","outputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"address","name":"strategy","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bytes","name":"configData","type":"bytes"}],"internalType":"struct Distribution","name":"distribution","type":"tuple"},{"internalType":"bool","name":"payerIsUser","type":"bool"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"distributeToken","outputs":[{"internalType":"contract IDistributionContract","name":"distributionContract","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"originalCreator","type":"address"}],"name":"getGraffiti","outputs":[{"internalType":"bytes32","name":"graffiti","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"permit","outputs":[{"internalType":"bytes","name":"err","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"contract IAllowanceTransfer","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60a0604052348015600e575f80fd5b50604051610e0b380380610e0b833981016040819052602b91603b565b6001600160a01b03166080526066565b5f60208284031215604a575f80fd5b81516001600160a01b0381168114605f575f80fd5b9392505050565b608051610d8061008b5f395f8181606901528181610177015261065b0152610d805ff3fe608060405234801561000f575f80fd5b5060043610610060575f3560e01c806312261ee7146100645780632b67b570146100a857806365c08017146100c8578063ac9650d814610117578063dec14be114610137578063dfa2a7451461014a575b5f80fd5b61008b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100bb6100b63660046107ec565b61015d565b60405161009f9190610885565b6101096100d636600461089e565b604080516001600160a01b03831660208201525f9101604051602081830303815290604052805190602001209050919050565b60405190815260200161009f565b61012a6101253660046108b9565b610218565b60405161009f919061092a565b61008b6101453660046109b3565b610326565b61008b610158366004610a98565b610446565b6040516302b67b5760e41b81526060906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632b67b570906101b2908890889088908890600401610b43565b5f604051808303815f87803b1580156101c9575f80fd5b505af19250505080156101da575060015b610210573d808015610207576040519150601f19603f3d011682016040523d82523d5f602084013e61020c565b606091505b5090505b949350505050565b60608167ffffffffffffffff81111561023357610233610c06565b60405190808252806020026020018201604052801561026657816020015b60608152602001906001900390816102515790505b5090505f5b8281101561031f575f803086868581811061028857610288610c1a565b905060200281019061029a9190610c2e565b6040516102a8929190610c71565b5f60405180830381855af49150503d805f81146102e0576040519150601f19603f3d011682016040523d82523d5f602084013e6102e5565b606091505b5091509150816102f757805160208201fd5b8084848151811061030a5761030a610c1a565b6020908102919091010152505060010161026b565b5092915050565b5f6001600160a01b03841661034e57604051636c38382960e11b815260040160405180910390fd5b8a6001600160a01b031663a255e0ad8b8b8b8b8b8b8b8b8b61039d33604080516001600160a01b03831660208201525f9101604051602081830303815290604052805190602001209050919050565b6040518b63ffffffff1660e01b81526004016103c29a99989796959493929190610c80565b6020604051808303815f875af11580156103de573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104029190610cfa565b6040519091506001600160a01b038216907f2e2b3f61b70d2d131b2a807371103cc98d51adcaa5e9a8f9c32658ad8426e74e905f90a29a9950505050505050505050565b5f610454602085018561089e565b6001600160a01b03166303770504866104736040880160208901610d15565b6104806040890189610c2e565b60408051336020820152908101899052606001604051602081830303815290604052805190602001206040518663ffffffff1660e01b81526004016104c9959493929190610d2e565b6020604051808303815f875af11580156104e5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105099190610cfa565b905061053785610518856105e7565b836105296040890160208a01610d15565b6001600160801b03166105fb565b806001600160a01b031663331f2f656040518163ffffffff1660e01b81526004015f604051808303815f87803b15801561056f575f80fd5b505af1158015610581573d5f803e3d5ffd5b5050506001600160a01b03828116915086167f67226bacccef969dab310a9e55dc1cf821363658e433fd330344f5cc00c79ac86105c46040880160208901610d15565b6040516001600160801b03909116815260200160405180910390a3949350505050565b5f816105f357306105f5565b335b92915050565b306001600160a01b038416036106245761061f6001600160a01b03851683836106b9565b6106b3565b604051631b63c28b60e11b81526001600160a01b0384811660048301528381166024830152828116604483015285811660648301527f000000000000000000000000000000000000000000000000000000000000000016906336c78516906084015f604051808303815f87803b15801561069c575f80fd5b505af11580156106ae573d5f803e3d5ffd5b505050505b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261070b908490610710565b505050565b5f8060205f8451602086015f885af18061072f576040513d5f823e3d81fd5b50505f513d91508115610746578060011415610753565b6001600160a01b0384163b155b156106b357604051635274afe760e01b81526001600160a01b038516600482015260240160405180910390fd5b6001600160a01b0381168114610794575f80fd5b50565b80356107a281610780565b919050565b5f8083601f8401126107b7575f80fd5b50813567ffffffffffffffff8111156107ce575f80fd5b6020830191508360208285010111156107e5575f80fd5b9250929050565b5f805f80848603610100811215610801575f80fd5b853561080c81610780565b945060c0601f198201121561081f575f80fd5b5060208501925060e085013567ffffffffffffffff81111561083f575f80fd5b61084b878288016107a7565b95989497509550505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6108976020830184610857565b9392505050565b5f602082840312156108ae575f80fd5b813561089781610780565b5f80602083850312156108ca575f80fd5b823567ffffffffffffffff8111156108e0575f80fd5b8301601f810185136108f0575f80fd5b803567ffffffffffffffff811115610906575f80fd5b8560208260051b840101111561091a575f80fd5b6020919091019590945092505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561098157603f1987860301845261096c858351610857565b94506020938401939190910190600101610950565b50929695505050505050565b803560ff811681146107a2575f80fd5b80356001600160801b03811681146107a2575f80fd5b5f805f805f805f805f8060e08b8d0312156109cc575f80fd5b8a356109d781610780565b995060208b013567ffffffffffffffff8111156109f2575f80fd5b6109fe8d828e016107a7565b909a5098505060408b013567ffffffffffffffff811115610a1d575f80fd5b610a298d828e016107a7565b9098509650610a3c905060608c0161098d565b9450610a4a60808c0161099d565b9350610a5860a08c01610797565b925060c08b013567ffffffffffffffff811115610a73575f80fd5b610a7f8d828e016107a7565b915080935050809150509295989b9194979a5092959850565b5f805f8060808587031215610aab575f80fd5b8435610ab681610780565b9350602085013567ffffffffffffffff811115610ad1575f80fd5b850160608188031215610ae2575f80fd5b925060408501358015158114610af6575f80fd5b9396929550929360600135925050565b803565ffffffffffff811681146107a2575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b03851681525f8435610b5b81610780565b6001600160a01b0316602083810191909152850135610b7981610780565b6001600160a01b031660408381019190915265ffffffffffff90610b9e908701610b06565b16606083015265ffffffffffff610bb760608701610b06565b1660808301526080850135610bcb81610780565b6001600160a01b031660a08381019190915285013560c083015261010060e08301819052610bfc9083018486610b1b565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f808335601e19843603018112610c43575f80fd5b83018035915067ffffffffffffffff821115610c5d575f80fd5b6020019150368190038213156107e5575f80fd5b818382375f9101908152919050565b60e081525f610c9360e083018c8e610b1b565b8281036020840152610ca6818b8d610b1b565b60ff8a1660408501526001600160801b03891660608501526001600160a01b038816608085015283810360a08501529050610ce2818688610b1b565b9150508260c08301529b9a5050505050505050505050565b5f60208284031215610d0a575f80fd5b815161089781610780565b5f60208284031215610d25575f80fd5b6108978261099d565b6001600160a01b03861681526001600160801b03851660208201526080604082018190525f90610d619083018587610b1b565b9050826060830152969550505050505056fea164736f6c634300081a000a000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610060575f3560e01c806312261ee7146100645780632b67b570146100a857806365c08017146100c8578063ac9650d814610117578063dec14be114610137578063dfa2a7451461014a575b5f80fd5b61008b7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b6040516001600160a01b0390911681526020015b60405180910390f35b6100bb6100b63660046107ec565b61015d565b60405161009f9190610885565b6101096100d636600461089e565b604080516001600160a01b03831660208201525f9101604051602081830303815290604052805190602001209050919050565b60405190815260200161009f565b61012a6101253660046108b9565b610218565b60405161009f919061092a565b61008b6101453660046109b3565b610326565b61008b610158366004610a98565b610446565b6040516302b67b5760e41b81526060906001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31690632b67b570906101b2908890889088908890600401610b43565b5f604051808303815f87803b1580156101c9575f80fd5b505af19250505080156101da575060015b610210573d808015610207576040519150601f19603f3d011682016040523d82523d5f602084013e61020c565b606091505b5090505b949350505050565b60608167ffffffffffffffff81111561023357610233610c06565b60405190808252806020026020018201604052801561026657816020015b60608152602001906001900390816102515790505b5090505f5b8281101561031f575f803086868581811061028857610288610c1a565b905060200281019061029a9190610c2e565b6040516102a8929190610c71565b5f60405180830381855af49150503d805f81146102e0576040519150601f19603f3d011682016040523d82523d5f602084013e6102e5565b606091505b5091509150816102f757805160208201fd5b8084848151811061030a5761030a610c1a565b6020908102919091010152505060010161026b565b5092915050565b5f6001600160a01b03841661034e57604051636c38382960e11b815260040160405180910390fd5b8a6001600160a01b031663a255e0ad8b8b8b8b8b8b8b8b8b61039d33604080516001600160a01b03831660208201525f9101604051602081830303815290604052805190602001209050919050565b6040518b63ffffffff1660e01b81526004016103c29a99989796959493929190610c80565b6020604051808303815f875af11580156103de573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104029190610cfa565b6040519091506001600160a01b038216907f2e2b3f61b70d2d131b2a807371103cc98d51adcaa5e9a8f9c32658ad8426e74e905f90a29a9950505050505050505050565b5f610454602085018561089e565b6001600160a01b03166303770504866104736040880160208901610d15565b6104806040890189610c2e565b60408051336020820152908101899052606001604051602081830303815290604052805190602001206040518663ffffffff1660e01b81526004016104c9959493929190610d2e565b6020604051808303815f875af11580156104e5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105099190610cfa565b905061053785610518856105e7565b836105296040890160208a01610d15565b6001600160801b03166105fb565b806001600160a01b031663331f2f656040518163ffffffff1660e01b81526004015f604051808303815f87803b15801561056f575f80fd5b505af1158015610581573d5f803e3d5ffd5b5050506001600160a01b03828116915086167f67226bacccef969dab310a9e55dc1cf821363658e433fd330344f5cc00c79ac86105c46040880160208901610d15565b6040516001600160801b03909116815260200160405180910390a3949350505050565b5f816105f357306105f5565b335b92915050565b306001600160a01b038416036106245761061f6001600160a01b03851683836106b9565b6106b3565b604051631b63c28b60e11b81526001600160a01b0384811660048301528381166024830152828116604483015285811660648301527f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316906336c78516906084015f604051808303815f87803b15801561069c575f80fd5b505af11580156106ae573d5f803e3d5ffd5b505050505b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261070b908490610710565b505050565b5f8060205f8451602086015f885af18061072f576040513d5f823e3d81fd5b50505f513d91508115610746578060011415610753565b6001600160a01b0384163b155b156106b357604051635274afe760e01b81526001600160a01b038516600482015260240160405180910390fd5b6001600160a01b0381168114610794575f80fd5b50565b80356107a281610780565b919050565b5f8083601f8401126107b7575f80fd5b50813567ffffffffffffffff8111156107ce575f80fd5b6020830191508360208285010111156107e5575f80fd5b9250929050565b5f805f80848603610100811215610801575f80fd5b853561080c81610780565b945060c0601f198201121561081f575f80fd5b5060208501925060e085013567ffffffffffffffff81111561083f575f80fd5b61084b878288016107a7565b95989497509550505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6108976020830184610857565b9392505050565b5f602082840312156108ae575f80fd5b813561089781610780565b5f80602083850312156108ca575f80fd5b823567ffffffffffffffff8111156108e0575f80fd5b8301601f810185136108f0575f80fd5b803567ffffffffffffffff811115610906575f80fd5b8560208260051b840101111561091a575f80fd5b6020919091019590945092505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561098157603f1987860301845261096c858351610857565b94506020938401939190910190600101610950565b50929695505050505050565b803560ff811681146107a2575f80fd5b80356001600160801b03811681146107a2575f80fd5b5f805f805f805f805f8060e08b8d0312156109cc575f80fd5b8a356109d781610780565b995060208b013567ffffffffffffffff8111156109f2575f80fd5b6109fe8d828e016107a7565b909a5098505060408b013567ffffffffffffffff811115610a1d575f80fd5b610a298d828e016107a7565b9098509650610a3c905060608c0161098d565b9450610a4a60808c0161099d565b9350610a5860a08c01610797565b925060c08b013567ffffffffffffffff811115610a73575f80fd5b610a7f8d828e016107a7565b915080935050809150509295989b9194979a5092959850565b5f805f8060808587031215610aab575f80fd5b8435610ab681610780565b9350602085013567ffffffffffffffff811115610ad1575f80fd5b850160608188031215610ae2575f80fd5b925060408501358015158114610af6575f80fd5b9396929550929360600135925050565b803565ffffffffffff811681146107a2575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b03851681525f8435610b5b81610780565b6001600160a01b0316602083810191909152850135610b7981610780565b6001600160a01b031660408381019190915265ffffffffffff90610b9e908701610b06565b16606083015265ffffffffffff610bb760608701610b06565b1660808301526080850135610bcb81610780565b6001600160a01b031660a08381019190915285013560c083015261010060e08301819052610bfc9083018486610b1b565b9695505050505050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f808335601e19843603018112610c43575f80fd5b83018035915067ffffffffffffffff821115610c5d575f80fd5b6020019150368190038213156107e5575f80fd5b818382375f9101908152919050565b60e081525f610c9360e083018c8e610b1b565b8281036020840152610ca6818b8d610b1b565b60ff8a1660408501526001600160801b03891660608501526001600160a01b038816608085015283810360a08501529050610ce2818688610b1b565b9150508260c08301529b9a5050505050505050505050565b5f60208284031215610d0a575f80fd5b815161089781610780565b5f60208284031215610d25575f80fd5b6108978261099d565b6001600160a01b03861681526001600160801b03851660208201526080604082018190525f90610d619083018587610b1b565b9050826060830152969550505050505056fea164736f6c634300081a000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

-----Decoded View---------------
Arg [0] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.