ETH Price: $1,799.13 (+13.59%)

Contract

0x777777EDF27Ac61671e3D5718b10bf6a8802f9f1
Age:1H
Reset Filter

Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Internal Transactions and > 10 Token Transfers found.

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
3292476982025-04-23 3:37:341 hr ago1745379454
0x777777ED...a8802f9f1
0.00004962 ETH
3292476982025-04-23 3:37:341 hr ago1745379454
0x777777ED...a8802f9f1
0.00004962 ETH
3291393052025-04-22 20:04:589 hrs ago1745352298
0x777777ED...a8802f9f1
0.00000253 ETH
3291393052025-04-22 20:04:589 hrs ago1745352298
0x777777ED...a8802f9f1
0.00000253 ETH
3291393052025-04-22 20:04:589 hrs ago1745352298
0x777777ED...a8802f9f1
0.00002784 ETH
3291393052025-04-22 20:04:589 hrs ago1745352298
0x777777ED...a8802f9f1
0.00002784 ETH
3291385382025-04-22 20:01:469 hrs ago1745352106
0x777777ED...a8802f9f1
0.00002481 ETH
3291385382025-04-22 20:01:469 hrs ago1745352106
0x777777ED...a8802f9f1
0.00002481 ETH
3291384832025-04-22 20:01:329 hrs ago1745352092
0x777777ED...a8802f9f1
0.00002481 ETH
3291384832025-04-22 20:01:329 hrs ago1745352092
0x777777ED...a8802f9f1
0.00002481 ETH
3291235852025-04-22 18:59:1810 hrs ago1745348358
0x777777ED...a8802f9f1
0.00002481 ETH
3291235852025-04-22 18:59:1810 hrs ago1745348358
0x777777ED...a8802f9f1
0.00002481 ETH
3291235032025-04-22 18:58:5810 hrs ago1745348338
0x777777ED...a8802f9f1
0.00002481 ETH
3291235032025-04-22 18:58:5810 hrs ago1745348338
0x777777ED...a8802f9f1
0.00002481 ETH
3291113862025-04-22 18:08:3211 hrs ago1745345312
0x777777ED...a8802f9f1
0.00002481 ETH
3291113862025-04-22 18:08:3211 hrs ago1745345312
0x777777ED...a8802f9f1
0.00002481 ETH
3291047802025-04-22 17:41:0211 hrs ago1745343662
0x777777ED...a8802f9f1
0.00029618 ETH
3291047802025-04-22 17:41:0211 hrs ago1745343662
0x777777ED...a8802f9f1
0.00029618 ETH
3290642752025-04-22 14:52:1214 hrs ago1745333532
0x777777ED...a8802f9f1
0.0002965 ETH
3290642752025-04-22 14:52:1214 hrs ago1745333532
0x777777ED...a8802f9f1
0.0002965 ETH
3290516702025-04-22 13:59:4015 hrs ago1745330380
0x777777ED...a8802f9f1
0.00029683 ETH
3290516702025-04-22 13:59:4015 hrs ago1745330380
0x777777ED...a8802f9f1
0.00029683 ETH
3290157972025-04-22 11:30:1917 hrs ago1745321419
0x777777ED...a8802f9f1
0.00029715 ETH
3290157972025-04-22 11:30:1917 hrs ago1745321419
0x777777ED...a8802f9f1
0.00029715 ETH
3290030522025-04-22 10:37:0918 hrs ago1745318229
0x777777ED...a8802f9f1
0.00029748 ETH
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SecondarySwap

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion
File 1 of 15 : SecondarySwap.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {ISecondarySwap} from "../interfaces/ISecondarySwap.sol";
import {IERC20Z} from "../interfaces/IERC20Z.sol";
import {ISwapRouter} from "../interfaces/uniswap/ISwapRouter.sol";
import {IZoraTimedSaleStrategy} from "../interfaces/IZoraTimedSaleStrategy.sol";
import {IWETH} from "../interfaces/IWETH.sol";

contract SecondarySwap is ISecondarySwap, ReentrancyGuard, IERC1155Receiver {
    uint256 internal constant ONE_ERC_20 = 1e18;

    bytes4 constant ON_ERC1155_RECEIVED_HASH = IERC1155Receiver.onERC1155Received.selector;

    IWETH public WETH;
    ISwapRouter public swapRouter;
    uint24 public uniswapFee;
    IZoraTimedSaleStrategy public zoraTimedSaleStrategy;

    /// @notice This must be called in the same transaction that the contract is created on.
    function initialize(IWETH weth_, ISwapRouter swapRouter_, uint24 uniswapFee_, IZoraTimedSaleStrategy zoraTimedSaleStrategy_) external {
        // Ensure a non-zero WETH address is passed upon initialization
        if (address(weth_) == address(0)) {
            revert AddressZero();
        }

        // Ensure this contract cannot be reinitialized
        if (address(WETH) != address(0)) {
            revert AlreadyInitialized();
        }

        WETH = weth_;
        swapRouter = swapRouter_;
        uniswapFee = uniswapFee_;
        zoraTimedSaleStrategy = zoraTimedSaleStrategy_;
    }

    /// @notice ETH -> WETH -> ERC20Z -> ERC1155
    function buy1155(
        address erc20zAddress,
        uint256 num1155ToBuy,
        address payable recipient,
        address payable excessRefundRecipient,
        uint256 maxEthToSpend,
        uint160 sqrtPriceLimitX96
    ) external payable nonReentrant {
        // Ensure the recipient address is valid
        if (recipient == address(0)) {
            revert InvalidRecipient();
        }

        // Get the amount of ETH sent
        uint256 amountETHIn = msg.value;

        // Ensure ETH is sent with the transaction
        if (amountETHIn == 0) {
            revert NoETHSent();
        }

        // Convert ETH to WETH
        WETH.deposit{value: amountETHIn}();

        // Approve the swap router to spend WETH
        WETH.approve(address(swapRouter), amountETHIn);

        // Calculate the expected amount of ERC20Z
        uint256 expectedAmountERC20Out = num1155ToBuy * ONE_ERC_20;

        ISwapRouter.ExactOutputSingleParams memory params = ISwapRouter.ExactOutputSingleParams({
            tokenIn: address(WETH),
            tokenOut: erc20zAddress,
            fee: uniswapFee,
            recipient: address(this),
            amountOut: expectedAmountERC20Out,
            amountInMaximum: maxEthToSpend,
            sqrtPriceLimitX96: sqrtPriceLimitX96
        });

        // Execute the swap and get the amount of WETH used
        uint256 amountWethUsed = swapRouter.exactOutputSingle(params);

        // Ensure that the expected amount of ERC20Z was received
        if (IERC20Z(erc20zAddress).balanceOf(address(this)) < expectedAmountERC20Out) {
            revert ERC20ZMinimumAmountNotReceived();
        }

        // Approve the ERC20Z tokens to be converted to ERC1155s
        IERC20Z(erc20zAddress).approve(erc20zAddress, expectedAmountERC20Out);

        // Convert ERC20Z to ERC1155
        IERC20Z(erc20zAddress).unwrap(expectedAmountERC20Out, recipient);

        // If there is any excess WETH:
        if (amountWethUsed < amountETHIn) {
            // Convert the excess WETH to ETH
            WETH.withdraw(amountETHIn - amountWethUsed);

            // Refund the excess ETH to the recipient
            Address.sendValue(excessRefundRecipient, msg.value - amountWethUsed);
        }

        emit SecondaryBuy(msg.sender, recipient, erc20zAddress, amountWethUsed, num1155ToBuy);
    }

    /// @notice ERC1155 -> ERC20Z -> WETH -> ETH
    function sell1155(
        address erc20zAddress,
        uint256 num1155ToSell,
        address payable recipient,
        uint256 minEthToAcquire,
        uint160 sqrtPriceLimitX96
    ) external nonReentrant {
        IERC20Z.TokenInfo memory tokenInfo = IERC20Z(erc20zAddress).tokenInfo();

        // Transfer ERC1155 tokens from sender to this contract and wrap them
        IERC1155(tokenInfo.collection).safeTransferFrom(msg.sender, erc20zAddress, tokenInfo.tokenId, num1155ToSell, abi.encode(address(this)));

        _sell1155(erc20zAddress, num1155ToSell, recipient, minEthToAcquire, sqrtPriceLimitX96);
    }

    /// @notice ERC1155 -> ERC20Z -> WETH -> ETH
    function _sell1155(address erc20zAddress, uint256 num1155ToSell, address payable recipient, uint256 minEthToAcquire, uint160 sqrtPriceLimitX96) private {
        // Ensure the recipient is valid
        if (recipient == address(0)) {
            revert InvalidRecipient();
        }

        // Calculate expected amount of ERC20Z
        uint256 expectedAmountERC20In = num1155ToSell * 1e18;

        // Ensure that the conversion was successful
        if (IERC20Z(erc20zAddress).balanceOf(address(this)) < expectedAmountERC20In) {
            revert ERC20ZEquivalentAmountNotConverted();
        }

        // Approve swap router to spend ERC20Z tokens
        IERC20Z(erc20zAddress).approve(address(swapRouter), expectedAmountERC20In);

        // Set up parameters for the swap from ERC20Z to WETH
        ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
            tokenIn: erc20zAddress,
            tokenOut: address(WETH),
            fee: uniswapFee,
            recipient: address(this),
            amountIn: expectedAmountERC20In,
            amountOutMinimum: minEthToAcquire,
            sqrtPriceLimitX96: sqrtPriceLimitX96
        });

        // Execute the swap and receive WETH
        uint256 amountWethOut = swapRouter.exactInputSingle(params);

        // Convert WETH to ETH
        WETH.withdraw(amountWethOut);

        // Transfer ETH to the recipient
        Address.sendValue(recipient, amountWethOut);

        emit SecondarySell(msg.sender, recipient, erc20zAddress, amountWethOut, num1155ToSell);
    }

    /// @notice Receive transfer hook that allows to sell 1155s for eth based on the secondary market value
    function onERC1155Received(address, address, uint256 id, uint256 value, bytes calldata data) external override nonReentrant returns (bytes4) {
        address collection = msg.sender;

        uint256 num1155ToSell = value;

        (address payable recipient, uint256 minEthToAcquire, uint160 sqrtPriceLimitX96) = abi.decode(data, (address, uint256, uint160));

        address erc20zAddress = zoraTimedSaleStrategy.sale(collection, id).erc20zAddress;

        if (erc20zAddress == address(0)) {
            revert SaleNotSet();
        }

        // assume this contract has 1155s, transfer them to the erc20z and wrap them
        IERC1155(collection).safeTransferFrom(address(this), erc20zAddress, id, num1155ToSell, abi.encode(address(this)));

        _sell1155(erc20zAddress, num1155ToSell, recipient, minEthToAcquire, sqrtPriceLimitX96);

        return ON_ERC1155_RECEIVED_HASH;
    }

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC1155Receiver).interfaceId;
    }

    function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) external pure override returns (bytes4) {
        revert NotSupported();
    }

    receive() external payable {
        if (msg.sender != address(WETH)) {
            revert OnlyWETH();
        }
    }
}

File 2 of 15 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the value of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155Received} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external;
}

File 3 of 15 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 4 of 15 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 5 of 15 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 6 of 15 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

File 7 of 15 : ISecondarySwap.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

/*


             ░░░░░░░░░░░░░░              
        ░░▒▒░░░░░░░░░░░░░░░░░░░░        
      ░░▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░      
    ░░▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░    
   ░▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░    
  ░▓▓▓▒▒▒▒░░░░░░░░░░░░        ░░░░░░░░  
  ░▓▓▓▒▒▒▒░░░░░░░░░░░░░░    ░░░░░░░░░░  
  ░▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░  
  ░▓▓▓▓▓▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░  
   ░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░  
    ░░▓▓▓▓▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░    
    ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▒░░    
      ░░▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░      
          ░░▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░░          

               OURS TRULY,


*/

interface ISecondarySwap {
    enum SecondaryType {
        /// @notice Buy 1155 tokens event
        BUY,
        /// @notice Sell 1155 tokens event
        SELL
    }

    /// @notice SecondaryBuy Event
    /// @param msgSender The sender of the message
    /// @param recipient The recipient of the 1155 tokens bought
    /// @param erc20zAddress The ERC20Z address
    /// @param amountEthSold The amount of ETH sold
    /// @param num1155Purchased The number of 1155 tokens purchased
    event SecondaryBuy(address indexed msgSender, address indexed recipient, address indexed erc20zAddress, uint256 amountEthSold, uint256 num1155Purchased);

    /// @notice SecondarySell Event
    /// @param msgSender The sender of the message
    /// @param recipient The recipient of the ETH purchased
    /// @param erc20zAddress The ERC20Z address
    /// @param amountEthPurchased The amount of ETH purchased
    /// @param num1155Sold The number of 1155 tokens sold
    event SecondarySell(address indexed msgSender, address indexed recipient, address indexed erc20zAddress, uint256 amountEthPurchased, uint256 num1155Sold);

    /// @notice SecondaryComment Event
    /// @param sender The sender of the comment
    /// @param collection The collection address
    /// @param tokenId The token ID
    /// @param quantity The quantity of tokens minted
    /// @param quantity The quantity of tokens minted
    /// @param comment The comment
    /// @param secondaryType The secondary event type
    event SecondaryComment(
        address indexed sender,
        address indexed collection,
        uint256 indexed tokenId,
        uint256 quantity,
        string comment,
        SecondaryType secondaryType
    );

    /// @notice Invalid recipient
    error InvalidRecipient();

    /// @notice No ETH sent
    error NoETHSent();

    /// @notice ERC20Z minimum amount not received
    error ERC20ZMinimumAmountNotReceived();

    /// @notice ERC20Z equivalent amount not converted
    error ERC20ZEquivalentAmountNotConverted();

    /// @notice Only WETH can be received
    error OnlyWETH();

    /// @notice Operation not supported
    error NotSupported();

    /// @notice Timed Sale has not been configured for the collection and token ID
    error SaleNotSet();

    /// @notice Reverts if an address param is passed as zero address
    error AddressZero();

    /// @notice Reverts if the contract is already initialized
    error AlreadyInitialized();
}

File 8 of 15 : IERC20Z.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

interface IERC20Z is IERC20Metadata {
    /// @notice TokenInfo struct returned by the information function
    struct TokenInfo {
        /// @notice The collection address
        address collection;
        /// @notice The token ID
        uint256 tokenId;
        /// @notice The creator address
        address creator;
    }

    /// @notice Event for when the ERC1155s are directly converted to ERC20Zs
    /// @param erc20z ERC20Z Address
    /// @param amount20z ERC20Z Amount
    /// @param collection Collection address
    /// @param tokenId ID for the ERC1155 token swapped
    /// @param amount1155 Amount of 1155 converted
    /// @param recipient Recipient of the conversion
    event ConvertedTo20z(address indexed erc20z, uint256 amount20z, address collection, uint256 tokenId, uint256 amount1155, address recipient);

    /// @notice Event for when ERC20Zs are directly converted to ERC1155
    /// @param erc20z ERC20Z Address
    /// @param amount20z ERC20Z Amount
    /// @param collection Collection address
    /// @param tokenId ID for the ERC1155 token swapped
    /// @param amount1155 Amount of 1155 converted
    /// @param recipient Recipient of the conversion
    event ConvertedTo1155(address indexed erc20z, uint256 amount20z, address collection, uint256 tokenId, uint256 amount1155, address recipient);

    /// @notice Event for when the secondary market is activated
    /// @param token0 Token 0 for uniswap liquidity
    /// @param amount0 Amount 0 for uniswap liquidity
    /// @param token1 Token 1 for uniswap liquidity
    /// @param amount1 Amount 1 for uniswap liquidity
    /// @param fee Uniswap fee amount
    /// @param positionId ERC721 Position ID for the default liquidity
    /// @param lpLiquidity amount of lp liquidity held by this contract
    /// @param erc20Excess ERC20 excess amount burned
    /// @param erc1155Excess ERC1155 excess amount burned
    event SecondaryMarketActivated(
        address indexed token0,
        uint256 indexed amount0,
        address token1,
        uint256 amount1,
        uint256 fee,
        uint256 positionId,
        uint256 lpLiquidity,
        uint256 erc20Excess,
        uint256 erc1155Excess
    );

    /// @notice Event for when admin mint NFTs are received
    /// @param quantity the amount received
    event ReceivedAdminMintNFTs(uint256 quantity);

    /// @notice Errors when attempts to reactivate
    error AlreadyActivatedCannotReactivate();

    /// @notice ERC1155 Ids do not match values length
    error IDsDoNotMatchValuesLength();

    /// @notice Passing in wrong ERC1155 token id to swap
    error TokenIdNotValidToSwap();

    /// @notice Action sent with ERC1155 data call is not known
    error UnknownReceiveActionDataCall();

    /// @notice Only supports receiving ERC721 Pool NFTs
    error OnlySupportReceivingERC721UniswapPoolNFTs();

    /// @notice Error when trying to swap ERC1155 to ERC20Z without the market being started.
    error SecondaryMarketHasNotYetStarted();

    /// @notice Only supports recieving ERC1155 associated with ERC20Z NFTs.
    error OnlySupportReceivingERC1155AssociatedZoraNFT();

    /// @notice Unauthorized to call this function
    error OnlySaleStrategy();

    /// @notice Pool creation failed
    error PoolCreationFailed();

    /// @notice Params are invalid
    error InvalidParams();

    /// @notice Insufficient balance
    error InsufficientBalance();

    /// @notice Invalid amount of ERC20z tokens
    error InvalidAmount20z();

    /// @notice Invalid ERC20z transfer
    error Invalid20zTransfer();

    /// @notice Recipient address cannot be zero
    error RecipientAddressZero();

    /// @notice Token URI
    function tokenURI() external view returns (string memory);

    /// @notice Token information
    function tokenInfo() external view returns (TokenInfo memory);

    /// @notice Returns the ERC20Z contract URI
    function contractURI() external view returns (string memory);

    /// @notice Token liquidity information getter
    function tokenLiquidityInfo() external view returns (address pool, uint256 initialLiquidityPositionId);

    /// @notice Initialize the ERC20Z token
    /// @param collection The collection address
    /// @param tokenId The token ID
    /// @param name The token name
    /// @param symbol The token symbol
    function initialize(address collection, uint256 tokenId, string memory name, string memory symbol) external returns (address);

    /// @notice Activate the ERC20Z token
    /// @param erc20TotalSupply The total supply of the ERC20 token
    /// @param erc20Reserve The reserve of the ERC20 token
    /// @param erc20Liquidity The liquidity of the ERC20 token
    /// @param erc20Excess The excess of the ERC20 token
    /// @param erc1155Excess The excess of the ERC1155 token
    function activate(uint256 erc20TotalSupply, uint256 erc20Reserve, uint256 erc20Liquidity, uint256 erc20Excess, uint256 erc1155Excess) external;

    /// @notice Convert 1155 to ERC20z tokens
    /// @param amount1155 The amount of 1155 tokens to convert
    /// @param recipient The recipient address
    function wrap(uint256 amount1155, address recipient) external;

    /// @notice Convert ERC20z to 1155 tokens
    /// @param amount20z The amount of ERC20z tokens to convert
    /// @param recipient The recipient address
    function unwrap(uint256 amount20z, address recipient) external;
}

File 9 of 15 : ISwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

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

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
}

File 10 of 15 : IZoraTimedSaleStrategy.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

interface IZoraTimedSaleStrategy {
    struct SalesConfig {
        /// @notice Unix timestamp for the sale start
        uint64 saleStart;
        /// @notice Unix timestamp for the sale end
        uint64 saleEnd;
        /// @notice The ERC20Z name
        string name;
        /// @notice The ERC20Z symbol
        string symbol;
    }

    /// @dev This is used to pass in parameters for the `updateSale` function
    struct SalesConfigV2 {
        /// @notice Unix timestamp for the sale start
        uint64 saleStart;
        /// @notice The amount of time after the `minimumMarketEth` is reached until the secondary market can be launched
        uint64 marketCountdown;
        /// @notice The amount of ETH required to launch a market
        uint256 minimumMarketEth;
        /// @notice The ERC20Z name
        string name;
        /// @notice The ERC20Z symbol
        string symbol;
    }

    /// @dev This is the SaleV1 style sale with a set end and start time and is used in both cases for storing key sale information
    struct SaleStorage {
        /// @notice The ERC20z address
        address payable erc20zAddress;
        /// @notice The sale start time
        uint64 saleStart;
        /// @notice The Uniswap pool address
        address poolAddress;
        /// @notice The sale end time
        uint64 saleEnd;
        /// @notice Boolean if the secondary market has been launched
        bool secondaryActivated;
    }

    /// @dev These are additional fields required for the SaleV2 style functionality. SaleV2 sets SaleV1 parameters as well.
    /// @notice SaleV2 is now the default strategy but old strategies without V2 config will operate as previously.
    struct SaleStorageV2 {
        /// @notice The amount of ETH required to launch a market
        uint256 minimumMarketEth;
        /// @notice The amount of time after the `minimumMarketEth` is reached until the secondary market can be launched.
        uint64 marketCountdown;
    }

    /// @dev Sales data virutal struct used for emitting events having SaleV1 and SaleV2 structs
    struct SaleData {
        /// @notice Unix timestamp for the sale start
        uint64 saleStart;
        /// @notice The amount of time after the `minimumMarketEth` is reached until the secondary market can be launched
        uint64 marketCountdown;
        /// @notice Unix timestamp for the sale end -- this will default to 0 until the market countdown is kicked off
        uint64 saleEnd;
        /// @notice Boolean if the secondary market has been launched
        bool secondaryActivated;
        /// @notice The amount of ETH required to launch a market
        uint256 minimumMarketEth;
        /// @notice The Uniswap pool address
        address poolAddress;
        /// @notice The ERC20z address
        address payable erc20zAddress;
        /// @notice The ERC20Z name
        string name;
        /// @notice The ERC20Z symbol
        string symbol;
    }

    /// @notice Activated ERC20 information used for the structs
    struct ERC20zActivate {
        /// @notice Total Supply of ERC20z tokens
        uint256 finalTotalERC20ZSupply;
        /// @notice ERC20z Reserve price
        uint256 erc20Reserve;
        /// @notice ERC20z Liquidity
        uint256 erc20Liquidity;
        /// @notice Excess amount of ERC20z
        uint256 excessERC20;
        /// @notice Excess amount of 1155
        uint256 excessERC1155;
        /// @notice Additional ERC1155 to mint
        uint256 additionalERC1155ToMint;
        /// @notice Final 1155 Supply
        uint256 final1155Supply;
    }

    /// @notice V1 storage structs for the timed sale
    struct ZoraTimedSaleStrategyStorage {
        /// @notice The Zora reward recipient
        address zoraRewardRecipient;
        /// @notice The sales mapping
        mapping(address collection => mapping(uint256 tokenId => SaleStorage)) sales;
    }

    /// @notice V2 storage structs for the timed sale
    struct ZoraTimedSaleStrategyStorageV2 {
        /// @notice The sales mapping
        mapping(address collection => mapping(uint256 tokenId => SaleStorageV2)) salesV2;
    }

    struct RewardsSettings {
        /// @notice The sum of all individual rewards
        uint256 totalReward;
        /// @notice Creator reward
        uint256 creatorReward;
        /// @notice Creator referral reward
        uint256 createReferralReward;
        /// @notice Mint referral reward
        uint256 mintReferralReward;
        /// @notice Market reward
        uint256 marketReward;
        /// @notice Zora reward
        uint256 zoraReward;
    }

    /// @notice SaleSet Event
    /// @param collection The collection address
    /// @param tokenId The token ID
    /// @param salesConfig The sales configuration
    /// @param erc20zAddress The ERC20Z address
    /// @param poolAddress The Uniswap pool address
    /// @param mintFee The total fee in eth to mint each token
    event SaleSet(address indexed collection, uint256 indexed tokenId, SalesConfig salesConfig, address erc20zAddress, address poolAddress, uint256 mintFee);

    /// @notice Emitted when a sale is created and updated, and when a market countdown is underway
    /// @param collection The collection address
    /// @param tokenId The token ID
    /// @param saleData The sale data
    /// @param mintFee The total fee in eth to mint each token
    event SaleSetV2(address indexed collection, uint256 indexed tokenId, SaleData saleData, uint256 mintFee);

    /// @notice MintComment Event
    /// @param sender The sender of the comment
    /// @param collection The collection address
    /// @param tokenId The token ID
    /// @param quantity The quantity of tokens minted
    /// @param comment The comment
    event MintComment(address indexed sender, address indexed collection, uint256 indexed tokenId, uint256 quantity, string comment);

    /// @notice Emitted when rewards are distributed from this sale strategy
    /// @param creator The creator of the token
    /// @param creatorReward The creator reward
    /// @param createReferral The create referral
    /// @param createReferralReward The create referral reward
    /// @param mintReferral The mint referral
    /// @param mintReferralReward The mint referral reward
    /// @param market The Uniswap market
    /// @param marketReward The Uniswap market reward
    /// @param zoraRecipient The Zora recipient
    /// @param zoraReward The Zora reward
    event ZoraTimedSaleStrategyRewards(
        address indexed collection,
        uint256 indexed tokenId,
        address creator,
        uint256 creatorReward,
        address createReferral,
        uint256 createReferralReward,
        address mintReferral,
        uint256 mintReferralReward,
        address market,
        uint256 marketReward,
        address zoraRecipient,
        uint256 zoraReward
    );

    /// @notice MarketLaunched Event
    /// @param collection The collection address
    /// @param tokenId The token ID
    /// @param erc20zAddress The ERC20Z address
    /// @param poolAddress The Uniswap pool address
    event MarketLaunched(address indexed collection, uint256 indexed tokenId, address erc20zAddress, address poolAddress);

    /// @notice ZoraRewardRecipientUpdated Event
    /// @param prevRecipient The previous Zora reward recipient
    /// @param newRecipient The new Zora reward recipient
    event ZoraRewardRecipientUpdated(address indexed prevRecipient, address indexed newRecipient);

    /// @notice Error thrown when market is attempted to be started with no sales completed
    error NeedsToBeAtLeastOneSaleToStartMarket();

    /// @notice Error thrown when market minimum is not reached
    error MarketMinimumNotReached();

    /// @notice requestMint() is not used in minter, use mint() instead
    error RequestMintInvalidUseMint();

    /// @notice Cannot set address to zero
    error AddressZero();

    /// @notice The wrong value was sent
    error WrongValueSent();

    /// @notice The sale has already been set
    error SaleAlreadySet();

    /// @notice The sale has not started
    error SaleHasNotStarted();

    /// @notice The sale has already started
    error SaleV2AlreadyStarted();

    /// @notice The sale is in progress
    error SaleInProgress();

    /// @notice The sale has ended
    error SaleEnded();

    /// @notice The v2 sale has ended
    error SaleV2Ended();

    /// @notice The sale has not been set
    error SaleNotSet();

    /// @notice The  has not been set
    error SaleV2NotSet();

    /// @notice Insufficient funds
    error InsufficientFunds();

    /// @notice Only the Zora reward recipient
    error OnlyZoraRewardRecipient();

    /// @notice ResetSale is not available in this sale strategy
    error ResetSaleNotAvailable();

    /// @notice Zora Creator 1155 Contract needs to support IReduceSupply
    error ZoraCreator1155ContractNeedsToSupportReduceSupply();

    /// @notice The sale start time cannot be after the sale ends
    error StartTimeCannotBeAfterEndTime();

    /// @notice The sale start time cannot be in the past
    error EndTimeCannotBeInThePast();

    /// @notice The market has already been launched
    error MarketAlreadyLaunched();

    /// @notice The minimum amount of ETH required to set a sale
    error MinimumMarketEthNotMet();

    /// @notice This is deprecated and used for short-term backwards compatibility, use `setSaleV2()` instead.
    ///         This creates a V2 sale under the hood and ignores the passed `saleEnd` field.
    ///         Defaults for the V2 sale: `marketCountdown` = 24 hours & `minimumMarketEth` = 0.00222 ETH (200 mints).
    /// @param tokenId The collection token id to set the sale config for
    /// @param salesConfig The sale config to set
    function setSale(uint256 tokenId, SalesConfig calldata salesConfig) external;

    /// @notice Called by an 1155 collection to set the sale config for a given token
    /// @dev Additionally creates an ERC20Z and Uniswap V3 pool for the token
    /// @param tokenId The collection token id to set the sale config for
    /// @param salesConfig The sale config to set
    function setSaleV2(uint256 tokenId, SalesConfigV2 calldata salesConfig) external;

    /// @notice Called by a collector to mint a token
    /// @param mintTo The address to mint the token to
    /// @param quantity The quantity of tokens to mint
    /// @param collection The address of the 1155 token to mint
    /// @param tokenId The ID of the token to mint
    /// @param mintReferral The address of the mint referral
    /// @param comment The optional mint comment
    function mint(address mintTo, uint256 quantity, address collection, uint256 tokenId, address mintReferral, string calldata comment) external payable;

    /// @notice Gets the create referral address for a given token
    /// @param collection The address of the collection
    /// @param tokenId The ID of the token
    function getCreateReferral(address collection, uint256 tokenId) external view returns (address createReferral);

    /// @notice Computes the rewards for a given quantity of tokens
    /// @param quantity The quantity of tokens to compute rewards for
    function computeRewards(uint256 quantity) external returns (RewardsSettings memory);

    /// @notice Update the Zora reward recipient
    function setZoraRewardRecipient(address recipient) external;

    /// @notice Returns the sale config for a given token
    /// @param collection The collection address
    /// @param tokenId The ID of the token to get the sale config for
    function sale(address collection, uint256 tokenId) external view returns (SaleStorage memory);

    /// @notice Returns the sale config for a given token
    /// @param collection The collection address
    /// @param tokenId The ID of the token to get the sale config for
    function saleV2(address collection, uint256 tokenId) external view returns (SaleData memory);

    /// @notice Calculate the ERC20z activation values
    /// @param collection The collection address
    /// @param tokenId The token ID
    /// @param erc20zAddress The ERC20Z address
    function calculateERC20zActivate(address collection, uint256 tokenId, address erc20zAddress) external view returns (ERC20zActivate memory);

    /// @notice Called by an 1155 collection to update the sale time if the sale has not started or ended.
    /// @param tokenId The 1155 token id
    /// @param newStartTime The new start time for the sale, ignored if the existing sale has already started
    /// @param newMarketCountdown The new market countdown for the sale
    function updateSale(uint256 tokenId, uint64 newStartTime, uint64 newMarketCountdown) external;

    /// @notice Called by anyone upon the end of a primary sale to launch the secondary market.
    /// @param collection The 1155 collection address
    /// @param tokenId The 1155 token id
    function launchMarket(address collection, uint256 tokenId) external;
}

File 11 of 15 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256 wad) external;

    function approve(address guy, uint256 wad) external returns (bool);

    function transfer(address dst, uint256 wad) external returns (bool);

    function transferFrom(address src, address dst, uint256 wad) external returns (bool);

    function balanceOf(address guy) external view returns (uint256);
}

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

pragma solidity ^0.8.20;

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

File 13 of 15 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 14 of 15 : IUniswapV3SwapCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
    /// @dev In the implementation you must pay the pool tokens owed for the swap.
    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}

File 15 of 15 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

Settings
{
  "remappings": [
    "ds-test/=node_modules/ds-test/src/",
    "forge-std/=node_modules/forge-std/src/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@zoralabs/protocol-rewards/=node_modules/@zoralabs/protocol-rewards/",
    "@zoralabs/shared-contracts/=node_modules/@zoralabs/shared-contracts/src/",
    "solady/=node_modules/solady/src/",
    "solmate/=node_modules/solmate/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ERC20ZEquivalentAmountNotConverted","type":"error"},{"inputs":[],"name":"ERC20ZMinimumAmountNotReceived","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"NoETHSent","type":"error"},{"inputs":[],"name":"NotSupported","type":"error"},{"inputs":[],"name":"OnlyWETH","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SaleNotSet","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"msgSender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"erc20zAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountEthSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"num1155Purchased","type":"uint256"}],"name":"SecondaryBuy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"},{"indexed":false,"internalType":"string","name":"comment","type":"string"},{"indexed":false,"internalType":"enum ISecondarySwap.SecondaryType","name":"secondaryType","type":"uint8"}],"name":"SecondaryComment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"msgSender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"erc20zAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountEthPurchased","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"num1155Sold","type":"uint256"}],"name":"SecondarySell","type":"event"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"erc20zAddress","type":"address"},{"internalType":"uint256","name":"num1155ToBuy","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"address payable","name":"excessRefundRecipient","type":"address"},{"internalType":"uint256","name":"maxEthToSpend","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"name":"buy1155","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IWETH","name":"weth_","type":"address"},{"internalType":"contract ISwapRouter","name":"swapRouter_","type":"address"},{"internalType":"uint24","name":"uniswapFee_","type":"uint24"},{"internalType":"contract IZoraTimedSaleStrategy","name":"zoraTimedSaleStrategy_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"erc20zAddress","type":"address"},{"internalType":"uint256","name":"num1155ToSell","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"minEthToAcquire","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"name":"sell1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"zoraTimedSaleStrategy","outputs":[{"internalType":"contract IZoraTimedSaleStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080806040523461001b5760016000556117aa90816100218239f35b600080fdfe6080604081815260049182361015610065575b50361561001e57600080fd5b73ffffffffffffffffffffffffffffffffffffffff60015416330361003f57005b517f01f180c9000000000000000000000000000000000000000000000000000000008152fd5b600090813560e01c90816301ffc9a714610f535750806355193c9514610d4f578063637af4df14610d0a5780638ac7052114610bb1578063ad5c464814610b5e578063b3836da914610522578063bc197c8114610464578063c31c9c0714610411578063f23a6e61146101325763f6d9b5350361001257903461012e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5080fd5b503461040e5760a092837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5761016c610fdb565b50610175610ffe565b5067ffffffffffffffff906044356064356084358481116103085761019f60609136908601611096565b908092916101ab61129a565b81010312610308576101bc81611044565b926020986101cb898401611044565b6003548a517f611efc0900000000000000000000000000000000000000000000000000000000815233818a0190815260208101869052929973ffffffffffffffffffffffffffffffffffffffff9490939092839183918716908290819060400103915afa928315610404578b93610341575b505050511694851561031a578851308b8201528a815261025c81611123565b333b1561031657889161029e8892878d5196879586957ff242432a000000000000000000000000000000000000000000000000000000008752309087016111a1565b038183335af1801561030c57908992916102ef575b50916001969593916102c895930135926112d5565b55517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b879192506102fc906110c4565b610308578790386102b3565b8580fd5b88513d89823e3d90fd5b8880fd5b88517f8928e120000000000000000000000000000000000000000000000000000000008152fd5b909180935082813d83116103fd575b61035a818361113f565b810103126103cb578b51928301908111838210176103cf578b52805183811681036103cb576103be9160809184528d610394818301611285565b908501526103a38d8201611180565b8d8501526103b360608201611285565b60608501520161123c565b608082015238808061023d565b8a80fd5b6041897f4e487b71000000000000000000000000000000000000000000000000000000006000525260246000fd5b503d610350565b8c513d8d823e3d90fd5b80fd5b50903461012e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5760209073ffffffffffffffffffffffffffffffffffffffff600254169051908152f35b503461040e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261040e5761049c610fdb565b506104a5610ffe565b5067ffffffffffffffff9060443582811161012e576104c79036908601611065565b505060643582811161012e576104e09036908601611065565b505060843591821161040e57506104fa9036908401611096565b5050517fa0387940000000000000000000000000000000000000000000000000000000008152fd5b509060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e57610556610fdb565b602435610561611021565b926064359173ffffffffffffffffffffffffffffffffffffffff938484168403610a285760a43595858716809703610a2857859061059d61129a565b16948515610b36573415610b0e57978888996001999798995416803b15610960578783918751928380927fd0e30db000000000000000000000000000000000000000000000000000000000825234905af18015610b0457908891610aec575b5050610669928160015416826002541687518092817f095ea7b3000000000000000000000000000000000000000000000000000000009c8d82528160209a8b9634908c84016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015610ae257610aaa575b50670de0b6b3a764000090818602918683041486151715610a7e578260015416988c866002549b8a51906106ab82611107565b81528685169e8f838301528d60a01c62ffffff168c83015230606083015286608083015260843560a083015260c0820152868b519d8e927f5023b4df0000000000000000000000000000000000000000000000000000000084528a840161076f9160c0908173ffffffffffffffffffffffffffffffffffffffff9182815116855282602082015116602086015262ffffff60408201511660408601528260608201511660608601526080810151608086015260a081015160a0860152015116910152565b1681845a9260e493f19a8b15610a72578d90829c610a3f575b50876024918b51928380927f70a08231000000000000000000000000000000000000000000000000000000008252308c8301525afa918215610a34579085926109fe575b50106109d65785838d8f9796959488610815958d519687958694859384528c84016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af180156109cc57610994575b508a3b1561096e57838a60448d93838b5195869485937f7647691d0000000000000000000000000000000000000000000000000000000085528a85015260248401525af1801561098a57908491610972575b50503488106108b8575b5050507f72d6b4b5ad0fb12b8a7bb3bcb60edd774c096403d611437859c156ecb3c03a36935082519485528401523392a46001815580f35b60015416906108c78834611249565b823b1561096e576024849283895195869485937f2e1a7d4d0000000000000000000000000000000000000000000000000000000085528401525af180156109645761094c575b50506109447f72d6b4b5ad0fb12b8a7bb3bcb60edd774c096403d611437859c156ecb3c03a369461093e8734611249565b90611660565b873880610880565b610955906110c4565b61096057873861090d565b8780fd5b85513d84823e3d90fd5b8380fd5b61097b906110c4565b610986578238610876565b8280fd5b87513d86823e3d90fd5b8581813d83116109c5575b6109a9818361113f565b810103126109c1576109ba9061123c565b5038610824565b8480fd5b503d61099f565b88513d87823e3d90fd5b8488517f25c596a9000000000000000000000000000000000000000000000000000000008152fd5b809250888092503d8311610a2d575b610a17818361113f565b81010312610a2857839051386107cc565b600080fd5b503d610a0d565b8a51903d90823e3d90fd5b9b505050858a813d8311610a6b575b610a58818361113f565b81010312610a28579851988c8c87610788565b503d610a4e565b508851903d90823e3d90fd5b60248c6011867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8481813d8311610adb575b610abf818361113f565b81010312610ad757610ad09061123c565b5038610678565b8b80fd5b503d610ab5565b87513d8e823e3d90fd5b610af5906110c4565b610b005786386105fc565b8680fd5b86513d8a823e3d90fd5b8884517f16f98f86000000000000000000000000000000000000000000000000000000008152fd5b8884517f9c8d2cd2000000000000000000000000000000000000000000000000000000008152fd5b50903461012e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5760209073ffffffffffffffffffffffffffffffffffffffff600154169051908152f35b5091346109865760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126109865780359073ffffffffffffffffffffffffffffffffffffffff918281168091036109c15760243590838216809203610308576044359262ffffff84168403610b005760643595858716809703610960578215610ce457600154958616610cbe5750507fffffffffffffffffffffffff0000000000000000000000000000000000000000809416176001557fffffffffffffffffff000000000000000000000000000000000000000000000076ffffff00000000000000000000000000000000000000006002549360a01b1692161717600255600354161760035580f35b517f0dc149f0000000000000000000000000000000000000000000000000000000008152fd5b517f9fabe1c1000000000000000000000000000000000000000000000000000000008152fd5b50903461012e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5760209062ffffff60025460a01c169051908152f35b50823461012e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e57610d88610fdb565b60243593610d94611021565b906084359373ffffffffffffffffffffffffffffffffffffffff8086168603610b0057610dbf61129a565b8251907f6addb6630000000000000000000000000000000000000000000000000000000082526060828481848a165afa918215610f49578892610ea8575b5060209082511691015191835130602082015260208152610e1d81611123565b823b1561031657918689869593610e6582968e9951998a97889687957ff242432a000000000000000000000000000000000000000000000000000000008752339087016111a1565b03925af1908115610e9f5750610e8c575b50610e859394606435926112d5565b6001815580f35b93610e99610e85956110c4565b93610e76565b513d87823e3d90fd5b9091506060813d606011610f41575b81610ec46060938361113f565b81010312610960578351906060820182811067ffffffffffffffff821117610f15578560209392610f0a928252610efa81611180565b8452848101518585015201611180565b858201529190610dfd565b60248a6041877f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b3d9150610eb7565b84513d8a823e3d90fd5b905083346109865760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126109865735917fffffffff00000000000000000000000000000000000000000000000000000000831680930361040e57507f4e2312e000000000000000000000000000000000000000000000000000000000602092148152f35b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b6024359073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b6044359073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b359073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b9181601f84011215610a285782359167ffffffffffffffff8311610a28576020808501948460051b010111610a2857565b9181601f84011215610a285782359167ffffffffffffffff8311610a285760208381860195010111610a2857565b67ffffffffffffffff81116110d857604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60e0810190811067ffffffffffffffff8211176110d857604052565b6040810190811067ffffffffffffffff8211176110d857604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176110d857604052565b519073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b9391929095949573ffffffffffffffffffffffffffffffffffffffff80911685526020931660208501526040840152606083015260a060808301528351938460a084015260005b858110611228575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84600060c0809697860101520116010190565b81810183015184820160c0015282016111e8565b51908115158203610a2857565b9190820391821161125657565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b519067ffffffffffffffff82168203610a2857565b6002600054146112ab576002600055565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b9192939073ffffffffffffffffffffffffffffffffffffffff9485851694851561163657670de0b6b3a764000094858402958487041484151715611256578716966040948551937f70a08231000000000000000000000000000000000000000000000000000000008552306004860152848a81602460209889935afa9081156115d157908991600091611605575b50106115dc5760025487517f095ea7b300000000000000000000000000000000000000000000000000000000815290841673ffffffffffffffffffffffffffffffffffffffff16600482015260248101899052858160448160008f5af180156115d157928b9285928895611594575b5082600154169a6002549b8b51956113e987611107565b8652868601528b60a01c62ffffff168b860152306060860152608085015260a08401521660c08201528287519889927f04e45aaf000000000000000000000000000000000000000000000000000000008452600484016114a69160c0908173ffffffffffffffffffffffffffffffffffffffff9182815116855282602082015116602086015262ffffff60408201511660408601528260608201511660608601526080810151608086015260a081015160a0860152015116910152565b16815a60e492600091f195861561155a57600096611565575b5060015416803b15610a28576000809160248751809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528b60048401525af1801561155a577fce7a9659161c4da85bb2316f11bb01521a23f37c260ae347af58e5789f1389209594939261153e92889261154b575b50611660565b82519485528401523392a4565b611554906110c4565b38611538565b85513d6000823e3d90fd5b90958382813d831161158d575b61157c818361113f565b8101031261040e57505194386114bf565b503d611572565b925092509281813d83116115ca575b6115ad818361113f565b81010312610a285785928b926115c3869361123c565b50386113d2565b503d6115a3565b88513d6000823e3d90fd5b600487517fa2b41e59000000000000000000000000000000000000000000000000000000008152fd5b809250878092503d831161162f575b61161e818361113f565b81010312610a285788905138611363565b503d611614565b60046040517f9c8d2cd2000000000000000000000000000000000000000000000000000000008152fd5b8147106117445773ffffffffffffffffffffffffffffffffffffffff90600080809481948294165af1903d1561173e573d9067ffffffffffffffff821161171157604051916116d760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116018461113f565b825260203d92013e5b156116e757565b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b506116e0565b60246040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152fdfea2646970667358221220720021680b9965fe3197933600d1c1bc3dfb9e0b2bed659bc6ef8be2e3b57e4564736f6c63430008170033

Deployed Bytecode

0x6080604081815260049182361015610065575b50361561001e57600080fd5b73ffffffffffffffffffffffffffffffffffffffff60015416330361003f57005b517f01f180c9000000000000000000000000000000000000000000000000000000008152fd5b600090813560e01c90816301ffc9a714610f535750806355193c9514610d4f578063637af4df14610d0a5780638ac7052114610bb1578063ad5c464814610b5e578063b3836da914610522578063bc197c8114610464578063c31c9c0714610411578063f23a6e61146101325763f6d9b5350361001257903461012e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b5080fd5b503461040e5760a092837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5761016c610fdb565b50610175610ffe565b5067ffffffffffffffff906044356064356084358481116103085761019f60609136908601611096565b908092916101ab61129a565b81010312610308576101bc81611044565b926020986101cb898401611044565b6003548a517f611efc0900000000000000000000000000000000000000000000000000000000815233818a0190815260208101869052929973ffffffffffffffffffffffffffffffffffffffff9490939092839183918716908290819060400103915afa928315610404578b93610341575b505050511694851561031a578851308b8201528a815261025c81611123565b333b1561031657889161029e8892878d5196879586957ff242432a000000000000000000000000000000000000000000000000000000008752309087016111a1565b038183335af1801561030c57908992916102ef575b50916001969593916102c895930135926112d5565b55517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b879192506102fc906110c4565b610308578790386102b3565b8580fd5b88513d89823e3d90fd5b8880fd5b88517f8928e120000000000000000000000000000000000000000000000000000000008152fd5b909180935082813d83116103fd575b61035a818361113f565b810103126103cb578b51928301908111838210176103cf578b52805183811681036103cb576103be9160809184528d610394818301611285565b908501526103a38d8201611180565b8d8501526103b360608201611285565b60608501520161123c565b608082015238808061023d565b8a80fd5b6041897f4e487b71000000000000000000000000000000000000000000000000000000006000525260246000fd5b503d610350565b8c513d8d823e3d90fd5b80fd5b50903461012e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5760209073ffffffffffffffffffffffffffffffffffffffff600254169051908152f35b503461040e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261040e5761049c610fdb565b506104a5610ffe565b5067ffffffffffffffff9060443582811161012e576104c79036908601611065565b505060643582811161012e576104e09036908601611065565b505060843591821161040e57506104fa9036908401611096565b5050517fa0387940000000000000000000000000000000000000000000000000000000008152fd5b509060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e57610556610fdb565b602435610561611021565b926064359173ffffffffffffffffffffffffffffffffffffffff938484168403610a285760a43595858716809703610a2857859061059d61129a565b16948515610b36573415610b0e57978888996001999798995416803b15610960578783918751928380927fd0e30db000000000000000000000000000000000000000000000000000000000825234905af18015610b0457908891610aec575b5050610669928160015416826002541687518092817f095ea7b3000000000000000000000000000000000000000000000000000000009c8d82528160209a8b9634908c84016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af18015610ae257610aaa575b50670de0b6b3a764000090818602918683041486151715610a7e578260015416988c866002549b8a51906106ab82611107565b81528685169e8f838301528d60a01c62ffffff168c83015230606083015286608083015260843560a083015260c0820152868b519d8e927f5023b4df0000000000000000000000000000000000000000000000000000000084528a840161076f9160c0908173ffffffffffffffffffffffffffffffffffffffff9182815116855282602082015116602086015262ffffff60408201511660408601528260608201511660608601526080810151608086015260a081015160a0860152015116910152565b1681845a9260e493f19a8b15610a72578d90829c610a3f575b50876024918b51928380927f70a08231000000000000000000000000000000000000000000000000000000008252308c8301525afa918215610a34579085926109fe575b50106109d65785838d8f9796959488610815958d519687958694859384528c84016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af180156109cc57610994575b508a3b1561096e57838a60448d93838b5195869485937f7647691d0000000000000000000000000000000000000000000000000000000085528a85015260248401525af1801561098a57908491610972575b50503488106108b8575b5050507f72d6b4b5ad0fb12b8a7bb3bcb60edd774c096403d611437859c156ecb3c03a36935082519485528401523392a46001815580f35b60015416906108c78834611249565b823b1561096e576024849283895195869485937f2e1a7d4d0000000000000000000000000000000000000000000000000000000085528401525af180156109645761094c575b50506109447f72d6b4b5ad0fb12b8a7bb3bcb60edd774c096403d611437859c156ecb3c03a369461093e8734611249565b90611660565b873880610880565b610955906110c4565b61096057873861090d565b8780fd5b85513d84823e3d90fd5b8380fd5b61097b906110c4565b610986578238610876565b8280fd5b87513d86823e3d90fd5b8581813d83116109c5575b6109a9818361113f565b810103126109c1576109ba9061123c565b5038610824565b8480fd5b503d61099f565b88513d87823e3d90fd5b8488517f25c596a9000000000000000000000000000000000000000000000000000000008152fd5b809250888092503d8311610a2d575b610a17818361113f565b81010312610a2857839051386107cc565b600080fd5b503d610a0d565b8a51903d90823e3d90fd5b9b505050858a813d8311610a6b575b610a58818361113f565b81010312610a28579851988c8c87610788565b503d610a4e565b508851903d90823e3d90fd5b60248c6011867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8481813d8311610adb575b610abf818361113f565b81010312610ad757610ad09061123c565b5038610678565b8b80fd5b503d610ab5565b87513d8e823e3d90fd5b610af5906110c4565b610b005786386105fc565b8680fd5b86513d8a823e3d90fd5b8884517f16f98f86000000000000000000000000000000000000000000000000000000008152fd5b8884517f9c8d2cd2000000000000000000000000000000000000000000000000000000008152fd5b50903461012e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5760209073ffffffffffffffffffffffffffffffffffffffff600154169051908152f35b5091346109865760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126109865780359073ffffffffffffffffffffffffffffffffffffffff918281168091036109c15760243590838216809203610308576044359262ffffff84168403610b005760643595858716809703610960578215610ce457600154958616610cbe5750507fffffffffffffffffffffffff0000000000000000000000000000000000000000809416176001557fffffffffffffffffff000000000000000000000000000000000000000000000076ffffff00000000000000000000000000000000000000006002549360a01b1692161717600255600354161760035580f35b517f0dc149f0000000000000000000000000000000000000000000000000000000008152fd5b517f9fabe1c1000000000000000000000000000000000000000000000000000000008152fd5b50903461012e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e5760209062ffffff60025460a01c169051908152f35b50823461012e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261012e57610d88610fdb565b60243593610d94611021565b906084359373ffffffffffffffffffffffffffffffffffffffff8086168603610b0057610dbf61129a565b8251907f6addb6630000000000000000000000000000000000000000000000000000000082526060828481848a165afa918215610f49578892610ea8575b5060209082511691015191835130602082015260208152610e1d81611123565b823b1561031657918689869593610e6582968e9951998a97889687957ff242432a000000000000000000000000000000000000000000000000000000008752339087016111a1565b03925af1908115610e9f5750610e8c575b50610e859394606435926112d5565b6001815580f35b93610e99610e85956110c4565b93610e76565b513d87823e3d90fd5b9091506060813d606011610f41575b81610ec46060938361113f565b81010312610960578351906060820182811067ffffffffffffffff821117610f15578560209392610f0a928252610efa81611180565b8452848101518585015201611180565b858201529190610dfd565b60248a6041877f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b3d9150610eb7565b84513d8a823e3d90fd5b905083346109865760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126109865735917fffffffff00000000000000000000000000000000000000000000000000000000831680930361040e57507f4e2312e000000000000000000000000000000000000000000000000000000000602092148152f35b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b6024359073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b6044359073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b359073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b9181601f84011215610a285782359167ffffffffffffffff8311610a28576020808501948460051b010111610a2857565b9181601f84011215610a285782359167ffffffffffffffff8311610a285760208381860195010111610a2857565b67ffffffffffffffff81116110d857604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60e0810190811067ffffffffffffffff8211176110d857604052565b6040810190811067ffffffffffffffff8211176110d857604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176110d857604052565b519073ffffffffffffffffffffffffffffffffffffffff82168203610a2857565b9391929095949573ffffffffffffffffffffffffffffffffffffffff80911685526020931660208501526040840152606083015260a060808301528351938460a084015260005b858110611228575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84600060c0809697860101520116010190565b81810183015184820160c0015282016111e8565b51908115158203610a2857565b9190820391821161125657565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b519067ffffffffffffffff82168203610a2857565b6002600054146112ab576002600055565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b9192939073ffffffffffffffffffffffffffffffffffffffff9485851694851561163657670de0b6b3a764000094858402958487041484151715611256578716966040948551937f70a08231000000000000000000000000000000000000000000000000000000008552306004860152848a81602460209889935afa9081156115d157908991600091611605575b50106115dc5760025487517f095ea7b300000000000000000000000000000000000000000000000000000000815290841673ffffffffffffffffffffffffffffffffffffffff16600482015260248101899052858160448160008f5af180156115d157928b9285928895611594575b5082600154169a6002549b8b51956113e987611107565b8652868601528b60a01c62ffffff168b860152306060860152608085015260a08401521660c08201528287519889927f04e45aaf000000000000000000000000000000000000000000000000000000008452600484016114a69160c0908173ffffffffffffffffffffffffffffffffffffffff9182815116855282602082015116602086015262ffffff60408201511660408601528260608201511660608601526080810151608086015260a081015160a0860152015116910152565b16815a60e492600091f195861561155a57600096611565575b5060015416803b15610a28576000809160248751809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528b60048401525af1801561155a577fce7a9659161c4da85bb2316f11bb01521a23f37c260ae347af58e5789f1389209594939261153e92889261154b575b50611660565b82519485528401523392a4565b611554906110c4565b38611538565b85513d6000823e3d90fd5b90958382813d831161158d575b61157c818361113f565b8101031261040e57505194386114bf565b503d611572565b925092509281813d83116115ca575b6115ad818361113f565b81010312610a285785928b926115c3869361123c565b50386113d2565b503d6115a3565b88513d6000823e3d90fd5b600487517fa2b41e59000000000000000000000000000000000000000000000000000000008152fd5b809250878092503d831161162f575b61161e818361113f565b81010312610a285788905138611363565b503d611614565b60046040517f9c8d2cd2000000000000000000000000000000000000000000000000000000008152fd5b8147106117445773ffffffffffffffffffffffffffffffffffffffff90600080809481948294165af1903d1561173e573d9067ffffffffffffffff821161171157604051916116d760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116018461113f565b825260203d92013e5b156116e757565b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b506116e0565b60246040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152fdfea2646970667358221220720021680b9965fe3197933600d1c1bc3dfb9e0b2bed659bc6ef8be2e3b57e4564736f6c63430008170033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.