ETH Price: $2,512.80 (-0.40%)

Transaction Decoder

Block:
21183568 at Nov-14-2024 04:32:47 AM +UTC
Transaction Fee:
0.00169983859877892 ETH $4.27
Gas Used:
62,991 Gas / 26.98542012 Gwei

Emitted Events:

215 SealedArtMarket.AuctionCancelled( auctionId=EF22B65F6DD2858CB53356064D7E45B70E69979A362E038505EF65C033679BE1 )
216 SealedArtMarket.AuctionCreated( owner=[Sender] 0x1277cc1f5d06b7f791ade9f5a326de68e524ff44, nftContract=0x89e57522...85a3de5f3, auctionDuration=259200, auctionType=E600001800000000000000000000000000000000000000000000000000000002, nftId=22, reserve=30000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x1277Cc1F...8e524ff44
(GIFT: Deployer)
0.005538443129125341 Eth
Nonce: 993
0.003838604530346421 Eth
Nonce: 994
0.00169983859877892
0x2cBe14b7...16C137F3C
(beaverbuild)
10.180224380908250037 Eth10.180230302062250037 Eth0.000005921154

Execution Trace

SealedArtMarket.changeAuction( nftContract=0x89e575222d9F1Bb3Fcc4A3d4aB9127E85a3de5f3, auctionType=E600001B00000000000000000000000000000000000000000000000000000002, nftId=22, reserve=60000000000000000, newAuctionDuration=259200, newAuctionType=E600001800000000000000000000000000000000000000000000000000000002, newReserve=30000000000000000, cancelAuctionPacket=[{name:v, type:uint8, order:1, indexed:false, value:28, valueString:28}, {name:r, type:bytes32, order:2, indexed:false, value:B2AE4A6731CE1C4EFA4CFE2E774976C6877881BD49F8771A231CAA42CAFCDEBF, valueString:B2AE4A6731CE1C4EFA4CFE2E774976C6877881BD49F8771A231CAA42CAFCDEBF}, {name:s, type:bytes32, order:3, indexed:false, value:5E09BE17F79E456BE55AEFF70FBFC74152ABC83AB96EDAEDC84967E9F0BAE03D, valueString:5E09BE17F79E456BE55AEFF70FBFC74152ABC83AB96EDAEDC84967E9F0BAE03D}, {name:auctionId, type:bytes32, order:4, indexed:false, value:EF22B65F6DD2858CB53356064D7E45B70E69979A362E038505EF65C033679BE1, valueString:EF22B65F6DD2858CB53356064D7E45B70E69979A362E038505EF65C033679BE1}, {name:deadline, type:uint256, order:5, indexed:false, value:1731559320, valueString:1731559320}] )
  • Null: 0x000...001.96fbdc2c( )
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
    pragma solidity ^0.8.0;
    import "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() {
            _transferOwnership(_msgSender());
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            _checkOwner();
            _;
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if the sender is not the owner.
         */
        function _checkOwner() internal view virtual {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby disabling any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _transferOwnership(address(0));
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            _transferOwnership(newOwner);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/BitMaps.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
     * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
     */
    library BitMaps {
        struct BitMap {
            mapping(uint256 => uint256) _data;
        }
        /**
         * @dev Returns whether the bit at `index` is set.
         */
        function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
            uint256 bucket = index >> 8;
            uint256 mask = 1 << (index & 0xff);
            return bitmap._data[bucket] & mask != 0;
        }
        /**
         * @dev Sets the bit at `index` to the boolean `value`.
         */
        function setTo(BitMap storage bitmap, uint256 index, bool value) internal {
            if (value) {
                set(bitmap, index);
            } else {
                unset(bitmap, index);
            }
        }
        /**
         * @dev Sets the bit at `index`.
         */
        function set(BitMap storage bitmap, uint256 index) internal {
            uint256 bucket = index >> 8;
            uint256 mask = 1 << (index & 0xff);
            bitmap._data[bucket] |= mask;
        }
        /**
         * @dev Unsets the bit at `index`.
         */
        function unset(BitMap storage bitmap, uint256 index) internal {
            uint256 bucket = index >> 8;
            uint256 mask = 1 << (index & 0xff);
            bitmap._data[bucket] &= ~mask;
        }
    }
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.4;
    abstract contract EIP712 {
        /// -----------------------------------------------------------------------
        /// Structs
        /// -----------------------------------------------------------------------
        /// @param v Part of the ECDSA signature
        /// @param r Part of the ECDSA signature
        /// @param s Part of the ECDSA signature
        struct WithdrawalPacket {
            uint8 v;
            bytes32 r;
            bytes32 s;
            uint256 deadline;
            uint256 amount;
            uint256 nonce;
            address account;
        }
        /// -----------------------------------------------------------------------
        /// Immutable parameters
        /// -----------------------------------------------------------------------
        /// @notice The chain ID used by EIP-712
        uint256 internal immutable INITIAL_CHAIN_ID;
        /// @notice The domain separator used by EIP-712
        bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
        /// -----------------------------------------------------------------------
        /// Constructor
        /// -----------------------------------------------------------------------
        constructor() {
            INITIAL_CHAIN_ID = block.chainid;
            INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
        }
        /// -----------------------------------------------------------------------
        /// Packet verification
        /// -----------------------------------------------------------------------
        function _verifySig(bytes memory data, uint8 v, bytes32 r, bytes32 s) internal virtual returns (address) {
            // verify signature
            address recoveredAddress =
                ecrecover(keccak256(abi.encodePacked("\\x19\\x01", DOMAIN_SEPARATOR(), keccak256(data))), v, r, s);
            return recoveredAddress;
        }
        /// @notice Verifies whether a packet is valid and returns the result.
        /// @dev The deadline, request, and signature are verified.
        /// @param packet The packet provided by the offchain data provider
        function _verifyWithdrawal(WithdrawalPacket calldata packet) internal virtual returns (address) {
            // verify deadline
            require(block.timestamp < packet.deadline, ">deadline");
            // verify signature
            address recoveredAddress = _verifySig(
                abi.encode(
                    keccak256("VerifyWithdrawal(uint256 deadline,uint256 amount,uint256 nonce,address account)"),
                    packet.deadline,
                    packet.amount,
                    packet.nonce,
                    packet.account
                ),
                packet.v,
                packet.r,
                packet.s
            );
            return recoveredAddress; // Invariant: sequencer != address(0), we maintain this every time sequencer is set
        }
        struct Bid {
            uint8 v;
            bytes32 r;
            bytes32 s;
            bytes32 auctionId;
            uint256 maxAmount;
        }
        function _verifyBid(Bid calldata packet) internal virtual returns (address) {
            address recoveredAddress = _verifySig(
                abi.encode(keccak256("Bid(bytes32 auctionId,uint256 maxAmount)"), packet.auctionId, packet.maxAmount),
                packet.v,
                packet.r,
                packet.s
            );
            require(recoveredAddress != address(0), "sig");
            return recoveredAddress;
        }
        struct BidWinner {
            uint8 v;
            bytes32 r;
            bytes32 s;
            bytes32 auctionId;
            uint256 amount;
            address winner;
        }
        function _verifyBidWinner(BidWinner calldata packet) internal virtual returns (address) {
            return _verifySig(
                abi.encode(
                    keccak256("BidWinner(bytes32 auctionId,uint256 amount,address winner)"),
                    packet.auctionId,
                    packet.amount,
                    packet.winner
                ),
                packet.v,
                packet.r,
                packet.s
            );
        }
        struct CancelAuction {
            uint8 v;
            bytes32 r;
            bytes32 s;
            bytes32 auctionId;
            uint256 deadline;
        }
        function _verifyCancelAuction(CancelAuction calldata packet) internal virtual returns (address) {
            require(block.timestamp <= packet.deadline, "deadline");
            return _verifySig(
                abi.encode(
                    keccak256("CancelAuction(bytes32 auctionId,uint256 deadline)"), packet.auctionId, packet.deadline
                ),
                packet.v,
                packet.r,
                packet.s
            );
        }
        struct Offer {
            uint8 v;
            bytes32 r;
            bytes32 s;
            address nftContract;
            uint256 nftId;
            uint256 amount;
            uint256 deadline;
            uint256 counter;
            uint256 nonce;
        }
        function _verifyBuyOffer(Offer calldata packet) internal virtual returns (address) {
            return _verifySig(
                abi.encode(
                    keccak256(
                        "BuyOffer(address nftContract,uint256 nftId,uint256 amount,uint256 deadline,uint256 counter,uint256 nonce)"
                    ),
                    packet.nftContract,
                    packet.nftId,
                    packet.amount,
                    packet.deadline,
                    packet.counter,
                    packet.nonce
                ),
                packet.v,
                packet.r,
                packet.s
            );
        }
        function _verifySellOffer(Offer calldata packet) internal virtual returns (address) {
            return _verifySig(
                abi.encode(
                    keccak256(
                        "SellOffer(address nftContract,uint256 nftId,uint256 amount,uint256 deadline,uint256 counter,uint256 nonce)"
                    ),
                    packet.nftContract,
                    packet.nftId,
                    packet.amount,
                    packet.deadline,
                    packet.counter,
                    packet.nonce
                ),
                packet.v,
                packet.r,
                packet.s
            );
        }
        struct OfferAttestation {
            uint8 v;
            bytes32 r;
            bytes32 s;
            bytes32 auctionId;
            uint256 amount;
            address buyer;
            address seller;
            uint256 deadline;
        }
        function _verifyOfferAttestation(OfferAttestation calldata packet) internal virtual returns (address) {
            return _verifySig(
                abi.encode(
                    keccak256(
                        "OfferAttestation(bytes32 auctionId,uint256 amount,address buyer,address seller,uint256 deadline)"
                    ),
                    packet.auctionId,
                    packet.amount,
                    packet.buyer,
                    packet.seller,
                    packet.deadline
                ),
                packet.v,
                packet.r,
                packet.s
            );
        }
        /// -----------------------------------------------------------------------
        /// EIP-712 compliance
        /// -----------------------------------------------------------------------
        /// @notice The domain separator used by EIP-712
        function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
            return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator();
        }
        /// @notice Computes the domain separator used by EIP-712
        function _computeDomainSeparator() internal view virtual returns (bytes32) {
            return keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256("SealedArtMarket"),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
        }
    }
    pragma solidity ^0.8.7;
    import "./EIP712.sol";
    import "@openzeppelin/contracts/access/Ownable.sol";
    import "./SealedFundingFactory.sol";
    import {BitMaps} from "@openzeppelin/contracts/utils/structs/BitMaps.sol";
    interface IERC721 {
        function ownerOf(uint256 _tokenId) external view returns (address);
        function transferFrom(address _from, address _to, uint256 _tokenId) external;
    }
    interface RoyaltyEngine {
        function getRoyalty(address tokenAddress, uint256 tokenId, uint256 value)
            external
            returns (address payable[] memory recipients, uint256[] memory amounts);
    }
    contract SealedArtMarket is EIP712, Ownable {
        using BitMaps for BitMaps.BitMap;
        event Transfer(address indexed from, address indexed to, uint256 value);
        mapping(address => uint256) private _balances;
        string public constant name = "Sealed ETH";
        string public constant symbol = "SETH";
        uint8 public constant decimals = 18;
        function totalSupply() public view returns (uint256) {
            return address(this).balance;
        }
        // sequencer and settleSequencer are separated as an extra security measure against key leakage through side attacks
        // If a side channel attack is possible that requires multiple signatures to be made, settleSequencer will be more protected
        // against it because each signature will require an onchain action, which will make the attack extremely expensive
        // It also allows us to use different security systems for the two keys, since settleSequencer is much more sensitive
        address public sequencer; // Invariant: always different than address(0)
        address public settleSequencer; // Invariant: always different than address(0)
        address payable public treasury;
        SealedFundingFactory public immutable sealedFundingFactory;
        uint256 internal constant MAX_PROTOCOL_FEE = 0.1e18; // 10%
        uint256 public feeMultiplier;
        uint256 public forcedWithdrawDelay = 2 days;
        RoyaltyEngine public constant royaltyEngine = RoyaltyEngine(0xBc40d21999b4BF120d330Ee3a2DE415287f626C9);
        enum AuctionState {
            NONE, // 0 -> doesnt exist, default state
            CREATED,
            CLOSED
        }
        mapping(bytes32 => AuctionState) public auctionState;
        mapping(address => mapping(uint256 => mapping(uint256 => uint256))) public pendingWithdrawals;
        mapping(bytes32 => uint256) public pendingAuctionCancels;
        mapping(address => bool) public guardians;
        BitMaps.BitMap private usedNonces;
        mapping(address => BitMaps.BitMap) private usedOrderNonces;
        mapping(address => uint256) public accountCounter;
        function balanceOf(address account) public view returns (uint256) {
            return _balances[account];
        }
        constructor(address _sequencer, address payable _treasury, address _settleSequencer) {
            require(_sequencer != address(0) && _settleSequencer != address(0), "0x0 sequencer not allowed");
            sequencer = _sequencer;
            treasury = _treasury;
            settleSequencer = _settleSequencer;
            sealedFundingFactory = new SealedFundingFactory(address(this));
        }
        event SequencerChanged(address newSequencer, address newSettleSequencer);
        function changeSequencer(address newSequencer, address newSettleSequencer) external onlyOwner {
            require(newSequencer != address(0) && newSettleSequencer != address(0), "0x0 sequencer not allowed");
            sequencer = newSequencer;
            settleSequencer = newSettleSequencer;
            emit SequencerChanged(newSequencer, newSettleSequencer);
        }
        event ForcedWithdrawDelayChanged(uint256 newDelay);
        function changeForcedWithdrawDelay(uint256 newDelay) external onlyOwner {
            require(newDelay < 10 days, "<10 days");
            forcedWithdrawDelay = newDelay;
            emit ForcedWithdrawDelayChanged(newDelay);
        }
        event TreasuryChanged(address newTreasury);
        function changeTreasury(address payable newTreasury) external onlyOwner {
            treasury = newTreasury;
            emit TreasuryChanged(newTreasury);
        }
        event GuardianSet(address guardian, bool value);
        function setGuardian(address guardian, bool value) external onlyOwner {
            guardians[guardian] = value;
            emit GuardianSet(guardian, value);
        }
        event SequencerDisabled(address guardian);
        function emergencyDisableSequencer() external {
            require(guardians[msg.sender] == true, "not guardian");
            // Maintain the invariant that sequencers are not 0x0
            sequencer = address(0x000000000000000000000000000000000000dEaD);
            settleSequencer = address(0x000000000000000000000000000000000000dEaD);
            emit SequencerDisabled(msg.sender);
        }
        event FeeChanged(uint256 newFeeMultiplier);
        function changeFee(uint256 newFeeMultiplier) external onlyOwner {
            require(newFeeMultiplier <= MAX_PROTOCOL_FEE, "fee too high");
            feeMultiplier = newFeeMultiplier;
            emit FeeChanged(newFeeMultiplier);
        }
        function deposit(address receiver) public payable {
            _balances[receiver] += msg.value;
            emit Transfer(address(0), receiver, msg.value);
        }
        function _withdraw(uint256 amount) internal {
            _balances[msg.sender] -= amount;
            (bool success,) = payable(msg.sender).call{value: amount}("");
            require(success);
            emit Transfer(msg.sender, address(0), amount);
        }
        event WithdrawNonceUsed(uint256 nonce);
        function withdraw(WithdrawalPacket calldata packet) public {
            require(_verifyWithdrawal(packet) == sequencer, "!sequencer");
            require(nonceState(packet.nonce) == false, "replayed");
            usedNonces.set(packet.nonce);
            require(packet.account == msg.sender, "not sender");
            _withdraw(packet.amount);
            emit WithdrawNonceUsed(packet.nonce);
        }
        event StartWithdrawal(address owner, uint256 timestamp, uint256 nonce, uint256 amount);
        function startWithdrawal(uint256 amount, uint256 nonce) external {
            pendingWithdrawals[msg.sender][block.timestamp][nonce] = amount;
            emit StartWithdrawal(msg.sender, block.timestamp, nonce, amount);
        }
        event CancelWithdrawal(address owner, uint256 timestamp, uint256 nonce);
        function cancelPendingWithdrawal(uint256 timestamp, uint256 nonce) external {
            pendingWithdrawals[msg.sender][timestamp][nonce] = 0;
            emit CancelWithdrawal(msg.sender, timestamp, nonce);
        }
        event ExecuteDelayedWithdrawal(address owner, uint256 timestamp, uint256 nonce);
        function executePendingWithdrawal(uint256 timestamp, uint256 nonce) external {
            require(timestamp + forcedWithdrawDelay < block.timestamp, "too soon");
            uint256 amount = pendingWithdrawals[msg.sender][timestamp][nonce];
            pendingWithdrawals[msg.sender][timestamp][nonce] = 0;
            _withdraw(amount);
            emit ExecuteDelayedWithdrawal(msg.sender, timestamp, nonce);
        }
        function calculateAuctionHash(
            address owner,
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve
        ) public pure returns (bytes32) {
            return keccak256(abi.encode(owner, nftContract, auctionType, nftId, reserve));
        }
        event AuctionCreated(
            address owner, address nftContract, uint256 auctionDuration, bytes32 auctionType, uint256 nftId, uint256 reserve
        );
        function _createAuction(
            address nftContract,
            uint256 auctionDuration,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve
        ) internal {
            bytes32 auctionId = calculateAuctionHash(msg.sender, nftContract, auctionType, nftId, reserve);
            require(auctionState[auctionId] == AuctionState.NONE, "repeated auction id"); // maybe this is not needed?
            auctionState[auctionId] = AuctionState.CREATED;
            emit AuctionCreated(msg.sender, nftContract, auctionDuration, auctionType, nftId, reserve);
        }
        function createAuction(
            address nftContract,
            uint256 auctionDuration,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve
        ) external {
            IERC721(nftContract).transferFrom(msg.sender, address(this), nftId);
            _createAuction(nftContract, auctionDuration, auctionType, nftId, reserve);
        }
        event AuctionCancelled(bytes32 auctionId);
        function _cancelAuction(
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve,
            CancelAuction calldata cancelAuctionPacket
        ) internal {
            require(_verifyCancelAuction(cancelAuctionPacket) == sequencer, "!sequencer");
            bytes32 auctionId = calculateAuctionHash(msg.sender, nftContract, auctionType, nftId, reserve);
            require(auctionState[auctionId] == AuctionState.CREATED, "bad state");
            require(cancelAuctionPacket.auctionId == auctionId, "!auctionId");
            auctionState[auctionId] = AuctionState.CLOSED;
            emit AuctionCancelled(auctionId);
        }
        function cancelAuction(
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve,
            CancelAuction calldata cancelAuctionPacket
        ) external {
            _cancelAuction(nftContract, auctionType, nftId, reserve, cancelAuctionPacket);
            IERC721(nftContract).transferFrom(address(this), msg.sender, nftId);
        }
        function changeAuction(
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve,
            uint256 newAuctionDuration,
            bytes32 newAuctionType,
            uint256 newReserve,
            CancelAuction calldata cancelAuctionPacket
        ) external {
            _cancelAuction(nftContract, auctionType, nftId, reserve, cancelAuctionPacket);
            _createAuction(nftContract, newAuctionDuration, newAuctionType, nftId, newReserve);
        }
        event StartDelayedAuctionCancel(bytes32 auctionId);
        function startCancelAuction(
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve
        ) external {
            bytes32 auctionId = calculateAuctionHash(msg.sender, nftContract, auctionType, nftId, reserve);
            require(auctionState[auctionId] == AuctionState.CREATED, "bad auction state");
            pendingAuctionCancels[auctionId] = block.timestamp;
            emit StartDelayedAuctionCancel(auctionId);
        }
        event ExecuteDelayedAuctionCancel(bytes32 auctionId);
        function executeCancelAuction(
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve
        ) external {
            bytes32 auctionId = calculateAuctionHash(msg.sender, nftContract, auctionType, nftId, reserve);
            uint256 timestamp = pendingAuctionCancels[auctionId];
            require(timestamp != 0 && (timestamp + forcedWithdrawDelay) < block.timestamp, "too soon");
            require(auctionState[auctionId] == AuctionState.CREATED, "not open");
            auctionState[auctionId] = AuctionState.CLOSED;
            pendingAuctionCancels[auctionId] = 0;
            emit AuctionCancelled(auctionId);
            IERC721(nftContract).transferFrom(address(this), msg.sender, nftId);
            emit ExecuteDelayedAuctionCancel(auctionId);
        }
        function _transferETH(address payable receiver, uint256 amount) internal {
            (bool success,) = receiver.call{value: amount, gas: 300_000}("");
            if (success == false) {
                _balances[receiver] += amount;
                emit Transfer(address(0), receiver, amount);
            }
        }
        function _distributeSale(address nftContract, uint256 nftId, uint256 amount, address payable seller) internal {
            uint256 totalRoyalty = 0;
            try royaltyEngine.getRoyalty{gas: 500_000}(nftContract, nftId, amount) returns (address payable[] memory recipients, uint256[] memory amounts) {
                uint length = 5; // Use a maximum of 5 items to avoid attacks that blow up gas limit
                if(recipients.length < length){
                    length = recipients.length;
                }
                if(amounts.length < length){
                    length = amounts.length;
                }
                for (uint256 i; i < length;) {
                    _transferETH(recipients[i], amounts[i]);
                    totalRoyalty += amounts[i];
                    unchecked {
                        ++i;
                    }
                }
                require(totalRoyalty <= (amount / 3), "Royalty too high"); // Protect against royalty hacks
            } catch {}
            uint256 feeAmount = (amount * feeMultiplier) / 1e18;
            _transferETH(treasury, feeAmount);
            _transferETH(seller, amount - (totalRoyalty + feeAmount)); // totalRoyalty+feeAmount <= amount*0.43
        }
        event AuctionSettled(bytes32 auctionId);
        function settleAuction(
            address payable nftOwner,
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve,
            Bid calldata bid,
            BidWinner calldata bidWinner
        ) public {
            bytes32 auctionId = calculateAuctionHash(nftOwner, nftContract, auctionType, nftId, reserve);
            require(auctionState[auctionId] == AuctionState.CREATED, "bad auction state");
            auctionState[auctionId] = AuctionState.CLOSED;
            require(bidWinner.auctionId == auctionId && bid.auctionId == auctionId, "!auctionId");
            uint256 amount = bidWinner.amount;
            require(amount <= bid.maxAmount && amount >= reserve, "!amount");
            require(_verifyBid(bid) == bidWinner.winner, "!winner");
            require(_verifyBidWinner(bidWinner) == settleSequencer, "!settleSequencer");
            _balances[bidWinner.winner] -= amount;
            emit Transfer(bidWinner.winner, address(0), amount);
            IERC721(nftContract).transferFrom(address(this), bidWinner.winner, nftId);
            _distributeSale(nftContract, nftId, amount, nftOwner);
            emit AuctionSettled(auctionId);
        }
        function _revealBids(bytes32[] calldata salts, address owner) internal {
            for (uint256 i = 0; i < salts.length;) {
                // We use try/catch here to prevent a griefing attack where someone could deploySealedFunding() one of the
                // sealed fundings of the buyer right before another user calls this function, thus making it revert
                // It's still possible for the buyer to perform this attack by frontrunning the call with a withdraw()
                // but that's trivial to solve by just revealing all the salts of the griefing user
                try sealedFundingFactory.deploySealedFunding{gas: 100_000}(salts[i], owner) {} // cost of deploySealedFunding() is between 55k and 82k
                    catch {}
                unchecked {
                    ++i;
                }
            }
        }
        function settleAuctionWithSealedBids(
            bytes32[] calldata salts,
            address payable nftOwner,
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve,
            Bid calldata bid,
            BidWinner calldata bidWinner
        ) external {
            _revealBids(salts, bidWinner.winner);
            settleAuction(nftOwner, nftContract, auctionType, nftId, reserve, bid, bidWinner);
        }
        function withdrawWithSealedBids(bytes32[] calldata salts, WithdrawalPacket calldata packet) external {
            _revealBids(salts, msg.sender);
            withdraw(packet);
        }
        event CounterIncreased(address account, uint256 newCounter);
        function increaseCounter(uint256 newCounter) external {
            require(newCounter > accountCounter[msg.sender], "too low");
            accountCounter[msg.sender] = newCounter;
            emit CounterIncreased(msg.sender, newCounter);
        }
        event OfferCancelled(address account, uint256 nonce);
        function cancelOffer(uint256 nonce) external {
            usedOrderNonces[msg.sender].set(nonce);
            emit OfferCancelled(msg.sender, nonce);
        }
        function _verifyOffer(Offer calldata offer, address creator) private {
            require(offer.deadline > block.timestamp, "!deadline");
            require(orderNonces(creator, offer.nonce) == false, "!orderNonce");
            usedOrderNonces[msg.sender].set(offer.nonce);
            require(offer.counter > accountCounter[creator], "!counter");
        }
        event OrdersMatched(bytes32 auctionId, address buyer, address sender, uint256 buyerNonce, uint256 sellerNonce);
        function matchOrders(
            Offer calldata sellerOffer,
            Offer calldata buyerOffer,
            OfferAttestation calldata sequencerStamp,
            address nftContract,
            bytes32 auctionType,
            uint256 nftId,
            uint256 reserve
        ) external {
            // First run verifications that can fail due to a delayed tx
            require(sequencerStamp.deadline > block.timestamp, "!deadline");
            if (msg.sender != sequencerStamp.buyer) {
                _verifyOffer(buyerOffer, sequencerStamp.buyer);
                require(_verifyBuyOffer(buyerOffer) == sequencerStamp.buyer && sequencerStamp.buyer != address(0), "!buyer");
            }
            if (msg.sender != sequencerStamp.seller) {
                _verifyOffer(sellerOffer, sequencerStamp.seller);
                require(
                    _verifySellOffer(sellerOffer) == sequencerStamp.seller && sequencerStamp.seller != address(0), "!seller"
                );
            }
            // Verify NFT is owned by seller
            bytes32 auctionId = calculateAuctionHash(
                sequencerStamp.seller,
                nftContract,
                auctionType,
                nftId,
                reserve
            );
            require(auctionState[auctionId] == AuctionState.CREATED && sequencerStamp.auctionId == auctionId, "bad auction state");
            // Execute sale
            _balances[sequencerStamp.buyer] -= sequencerStamp.amount;
            emit Transfer(sequencerStamp.buyer, address(0), sequencerStamp.amount);
            auctionState[auctionId] = AuctionState.CLOSED;
            // Run verifications that can't fail due to external factors
            require(sequencerStamp.amount == sellerOffer.amount && sequencerStamp.amount == buyerOffer.amount, "!amount");
            require(
                nftContract == sellerOffer.nftContract
                    && nftContract == buyerOffer.nftContract,
                "!nftContract"
            );
            require(nftId == sellerOffer.nftId && nftId == buyerOffer.nftId, "!nftId");
            require(_verifyOfferAttestation(sequencerStamp) == sequencer, "!sequencer"); // This needs sequencer approval to avoid someone rugging their bids by buying another NFT
            // Finish executing sale
            IERC721(nftContract).transferFrom(address(this), sequencerStamp.buyer, nftId);
            _distributeSale(
                nftContract, nftId, sequencerStamp.amount, payable(sequencerStamp.seller)
            );
            emit OrdersMatched(auctionId, sequencerStamp.buyer, msg.sender, buyerOffer.nonce, sellerOffer.nonce);
        }
        function nonceState(uint256 nonce) public view returns (bool) {
            return usedNonces.get(nonce);
        }
        function orderNonces(address account, uint256 nonce) public view returns (bool) {
            return usedOrderNonces[account].get(nonce);
        }
    }
    pragma solidity ^0.8.7;
    interface IExchange {
        function deposit(address receiver) external payable;
    }
    contract SealedFunding {
        constructor(address _owner, address _exchange) {
            IExchange(_exchange).deposit{value: address(this).balance}(_owner);
            assembly {
                // Ensures the runtime bytecode is a single opcode: `INVALID`. This reduces contract
                // deploy costs & ensures that no one can accidentally send ETH to the contract once
                // deployed.
                mstore8(0, 0xfe)
                return(0, 1)
            }
        }
    }
    pragma solidity ^0.8.7;
    import "./SealedFunding.sol";
    contract SealedFundingFactory {
        address public immutable exchange;
        constructor(address _exchange) {
            exchange = _exchange;
        }
        event SealedFundingRevealed(bytes32 salt, address owner);
        function deploySealedFunding(bytes32 salt, address owner) public {
            new SealedFunding{salt: salt}(owner, exchange);
            emit SealedFundingRevealed(salt, owner);
        }
        function computeSealedFundingAddress(bytes32 salt, address owner)
            external
            view
            returns (address predictedAddress, bool isDeployed)
        {
            predictedAddress = address(
                uint160(
                    uint256(
                        keccak256(
                            abi.encodePacked(
                                bytes1(0xff),
                                address(this),
                                salt,
                                keccak256(abi.encodePacked(type(SealedFunding).creationCode, abi.encode(owner, exchange)))
                            )
                        )
                    )
                )
            );
            isDeployed = predictedAddress.code.length != 0;
        }
    }