QuiverMarketplaceV2

0x0b3b0d6af0e42d42d324c38bf6b09325642b9bdd

Verification
Verified
v0.8.34+commit.80d5c536
Type
Contract
15,702 bytes
ABI entries
43
13 read · 11 write
License
none

Contract information

Address
0x0b3b0d6af0e42d42d324c38bf6b09325642b9bdd
Chain
Robinhood Chain (4663)
Compiler
v0.8.34+commit.80d5c536
Optimization
Disabled
Creation tx
0x528fe1119a…acf76f50c1

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (13)

BPS_DENOMINATOR()uint96
MAX_TOTAL_FEE_BPS()uint96
approvedCollections(address)bool
cancelledOrders(bytes32)bool
eip712Domain()bytes1, string, string, uint256, address, bytes32, uint256[]
feeRecipient()address
filledOrders(bytes32)bool
hashOrder(tuple)bytes32
minimumNonces(address)uint256
owner()address
paused()bool
platformFeeBps()uint96
royaltyFallbacks(address)address, uint96

Events (11)

CollectionApprovalChangedEIP712DomainChangedFeeRecipientSetNonceIncrementedOrderCancelledOrderFilledOwnershipTransferredPausedPlatformFeeSetRoyaltyFallbackSetUnpaused

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "initialOwner",
        "type": "address"
      },
      {
        "internalType": "address payable",
        "name": "initialFeeRecipient",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "EnforcedPause",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ExpectedPause",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidShortString",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "str",
        "type": "string"
      }
    ],
    "name": "StringTooLong",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "nft",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "approved",
        "type": "bool"
      }
    ],
    "name": "CollectionApprovalChanged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "EIP712DomainChanged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "FeeRecipientSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "seller",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "nonce",
        "type": "uint256"
      }
    ],
    "name": "NonceIncremented",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "bytes32",
        "name": "orderHash",
        "type": "bytes32"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "seller",
        "type": "address"
      }
    ],
    "name": "OrderCancelled",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "bytes32",
        "name": "orderHash",
        "type": "bytes32"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "nft",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "seller",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "buyer",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "price",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "royalty",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "platformFee",
        "type": "uint256"
      }
    ],
    "name": "OrderFilled",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "Paused",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint96",
        "name": "bps",
        "type": "uint96"
      }
    ],
    "name": "PlatformFeeSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "nft",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint96",
        "name": "bps",
        "type": "uint96"
      }
    ],
    "name": "RoyaltyFallbackSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "Unpaused",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "BPS_DENOMINATOR",
    "outputs": [
      {
        "internalType": "uint96",
        "name": "",
        "type": "uint96"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_TOTAL_FEE_BPS",
    "outputs": [
      {
        "internalType": "uint96",
        "name": "",
        "type": "uint96"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "approvedCollections",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "seller",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "nft",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "tokenId",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "price",
            "type": "uint256"
          },
          {
            "internalType": "uint64",
            "name": "startTime",
            "type": "uint64"
          },
          {
            "internalType": "uint64",
            "name": "endTime",
            "type": "uint64"
          },
          {
            "internalType": "uint256",
            "name": "nonce",
            "type": "uint256"
          },
          {
            "internalType": "bytes32",
            "name": "salt",
            "type": "bytes32"
          },
          {
            "internalType": "address",
            "name": "taker",
            "type": "address"
          },
          {
            "internalType": "uint96",
            "name": "maxPlatformFeeBps",
            "type": "uint96"
          },
          {
            "internalType": "uint96",
            "name": "maxRoyaltyBps",
            "type": "uint96"
          }
        ],
        "internalType": "struct QuiverMarketplaceV2.Order",
        "name": "order",
        "type": "tuple"
      }
    ],
    "name": "cancelOrder",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "name": "cancelledOrders",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "eip712Domain",
    "outputs": [
      {
        "internalType": "bytes1",
        "name": "fields",
        "type": "bytes1"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "version",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "chainId",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "verifyingContract",
        "type": "address"
      },
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      },
      {
        "internalType": "uint256[]",
        "name": "extensions",
        "type": "uint256[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "feeRecipient",
    "outputs": [
      {
        "internalType": "address payable",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "name": "filledOrders",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "seller",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "nft",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "tokenId",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "price",
            "type": "uint256"
          },
          {
            "internalType": "uint64",
            "name": "startTime",
            "type": "uint64"
          },
          {
            "internalType": "uint64",
            "name": "endTime",
            "type": "uint64"
          },
          {
            "internalType": "uint256",
            "name": "nonce",
            "type": "uint256"
          },
          {
            "internalType": "bytes32",
            "name": "salt",
            "type": "bytes32"
          },
          {
            "internalType": "address",
            "name": "taker",
            "type": "address"
          },
          {
            "internalType": "uint96",
            "name": "maxPlatformFeeBps",
            "type": "uint96"
          },
          {
            "internalType": "uint96",
            "name": "maxRoyaltyBps",
            "type": "uint96"
          }
        ],
        "internalType": "struct QuiverMarketplaceV2.Order",
        "name": "order",
        "type": "tuple"
      },
      {
        "internalType": "bytes",
        "name": "signature",
        "type": "bytes"
      }
    ],
    "name": "fulfillOrder",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "seller",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "nft",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "tokenId",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "price",
            "type": "uint256"
          },
          {
            "internalType": "uint64",
            "name": "startTime",
            "type": "uint64"
          },
          {
            "internalType": "uint64",
            "name": "endTime",
            "type": "uint64"
          },
          {
            "internalType": "uint256",
            "name": "nonce",
            "type": "uint256"
          },
          {
            "internalType": "bytes32",
            "name": "salt",
            "type": "bytes32"
          },
          {
            "internalType": "address",
            "name": "taker",
            "type": "address"
          },
          {
            "internalType": "uint96",
            "name": "maxPlatformFeeBps",
            "type": "uint96"
          },
          {
            "internalType": "uint96",
            "name": "maxRoyaltyBps",
            "type": "uint96"
          }
        ],
        "internalType": "struct QuiverMarketplaceV2.Order",
        "name": "order",
        "type": "tuple"
      }
    ],
    "name": "hashOrder",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "incrementNonce",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "minimumNonces",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pause",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "paused",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "platformFeeBps",
    "outputs": [
      {
        "internalType": "uint96",
        "name": "",
        "type": "uint96"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "royaltyFallbacks",
    "outputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      },
      {
        "internalType": "uint96",
        "name": "bps",
        "type": "uint96"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "nft",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "approved",
        "type": "bool"
      }
    ],
    "name": "setCollectionApproved",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address payable",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "setFeeRecipient",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint96",
        "name": "bps",
        "type": "uint96"
      }
    ],
    "name": "setPlatformFee",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "nft",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      },
      {
        "internalType": "uint96",
        "name": "bps",
        "type": "uint96"
      }
    ],
    "name": "setRoyaltyFallback",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "unpause",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

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

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

contract QuiverMarketplaceV2 is Ownable, Pausable, ReentrancyGuard, EIP712 {
    uint96 public constant BPS_DENOMINATOR = 10000;
    uint96 public constant MAX_TOTAL_FEE_BPS = 2000;
    bytes32 private constant ORDER_TYPEHASH =
        keccak256(
            "Order(address seller,address nft,uint256 tokenId,uint256 price,uint64 startTime,uint64 endTime,uint256 nonce,bytes32 salt,address taker,uint96 maxPlatformFeeBps,uint96 maxRoyaltyBps)"
        );

    struct Order {
        address seller;
        address nft;
        uint256 tokenId;
        uint256 price;
        uint64 startTime;
        uint64 endTime;
        uint256 nonce;
        bytes32 salt;
        address taker;
        uint96 maxPlatformFeeBps;
        uint96 maxRoyaltyBps;
    }

    struct RoyaltyFallback {
        address receiver;
        uint96 bps;
    }

    mapping(address => bool) public approvedCollections;
    mapping(address => RoyaltyFallback) public royaltyFallbacks;
    mapping(bytes32 => bool) public filledOrders;
    mapping(bytes32 => bool) public cancelledOrders;
    mapping(address => uint256) public minimumNonces;

    uint96 public platformFeeBps = 500;
    address payable public feeRecipient;

    event CollectionApprovalChanged(address indexed nft, bool approved);
    event RoyaltyFallbackSet(
        address indexed nft,
        address indexed receiver,
        uint96 bps
    );
    event PlatformFeeSet(uint96 bps);
    event FeeRecipientSet(address indexed recipient);
    event OrderCancelled(bytes32 indexed orderHash, address indexed seller);
    event NonceIncremented(address indexed seller, uint256 nonce);
    event OrderFilled(
        bytes32 indexed orderHash,
        address indexed nft,
        uint256 indexed tokenId,
        address seller,
        address buyer,
        uint256 price,
        uint256 royalty,
        uint256 platformFee
    );

    constructor(address initialOwner, address payable initialFeeRecipient)
        Ownable(initialOwner)
        EIP712("Quiver Marketplace", "2")
    {
        require(initialFeeRecipient != address(0), "zero address");
        feeRecipient = initialFeeRecipient;
    }

    function setCollectionApproved(address nft, bool approved) external onlyOwner {
        require(nft != address(0), "zero address");
        approvedCollections[nft] = approved;
        emit CollectionApprovalChanged(nft, approved);
    }

    function setRoyaltyFallback(address nft, address receiver, uint96 bps)
        external
        onlyOwner
    {
        require(nft != address(0), "zero address");
        require(bps <= MAX_TOTAL_FEE_BPS, "fee too high");
        royaltyFallbacks[nft] = RoyaltyFallback({receiver: receiver, bps: bps});
        emit RoyaltyFallbackSet(nft, receiver, bps);
    }

    function setPlatformFee(uint96 bps) external onlyOwner {
        require(bps <= MAX_TOTAL_FEE_BPS, "fee too high");
        platformFeeBps = bps;
        emit PlatformFeeSet(bps);
    }

    function setFeeRecipient(address payable recipient) external onlyOwner {
        require(recipient != address(0), "zero address");
        feeRecipient = recipient;
        emit FeeRecipientSet(recipient);
    }

    function pause() external onlyOwner {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }

    function hashOrder(Order calldata order) external view returns (bytes32) {
        return _hashOrder(order);
    }

    function fulfillOrder(Order calldata order, bytes calldata signature)
        external
        payable
        nonReentrant
        whenNotPaused
    {
        IERC721 token = IERC721(order.nft);
        bytes32 orderHash = _hashOrder(order);

        _validateOrder(order, signature, token, orderHash);
        (
            address royaltyReceiver,
            uint256 royalty,
            uint256 platformFee,
            uint256 totalFee
        ) = _fees(order);

        filledOrders[orderHash] = true;
        token.safeTransferFrom(order.seller, msg.sender, order.tokenId);

        if (royalty > 0) {
            _pay(payable(royaltyReceiver), royalty);
        }
        if (platformFee > 0) {
            _pay(feeRecipient, platformFee);
        }
        _pay(payable(order.seller), order.price - totalFee);

        emit OrderFilled(
            orderHash,
            order.nft,
            order.tokenId,
            order.seller,
            msg.sender,
            order.price,
            royalty,
            platformFee
        );
    }

    function cancelOrder(Order calldata order) external {
        require(order.seller == msg.sender, "not seller");
        bytes32 orderHash = _hashOrder(order);
        cancelledOrders[orderHash] = true;
        emit OrderCancelled(orderHash, msg.sender);
    }

    function incrementNonce() external {
        minimumNonces[msg.sender] += 1;
        emit NonceIncremented(msg.sender, minimumNonces[msg.sender]);
    }

    function _validateOrder(
        Order calldata order,
        bytes calldata signature,
        IERC721 token,
        bytes32 orderHash
    ) private view {
        require(order.seller != address(0), "zero seller");
        require(approvedCollections[order.nft], "collection not approved");
        require(order.price > 0, "price zero");
        require(msg.value == order.price, "bad value");
        require(order.startTime <= block.timestamp, "not started");
        require(block.timestamp < order.endTime, "ended");
        require(order.taker == address(0) || order.taker == msg.sender, "not taker");
        require(!filledOrders[orderHash], "filled");
        require(!cancelledOrders[orderHash], "cancelled");
        require(order.nonce >= minimumNonces[order.seller], "nonce too low");
        require(order.maxPlatformFeeBps >= platformFeeBps, "platform fee too high");
        require(token.ownerOf(order.tokenId) == order.seller, "not owner");
        require(_isApproved(token, order.tokenId, order.seller), "not approved");
        require(
            SignatureChecker.isValidSignatureNow(
                order.seller,
                orderHash,
                signature
            ),
            "bad signature"
        );
    }

    function _fees(Order calldata order)
        private
        view
        returns (
            address royaltyReceiver,
            uint256 royalty,
            uint256 platformFee,
            uint256 totalFee
        )
    {
        (royaltyReceiver, royalty) = _royalty(
            order.nft,
            order.tokenId,
            order.price
        );
        uint256 maxRoyalty = (order.price * order.maxRoyaltyBps) /
            BPS_DENOMINATOR;
        require(royalty <= maxRoyalty, "royalty too high");

        platformFee = _platformFee(order.price);
        totalFee = royalty + platformFee;
        uint256 maxFee = (order.price * MAX_TOTAL_FEE_BPS) / BPS_DENOMINATOR;
        require(totalFee <= maxFee, "fee too high");
    }

    function _hashOrder(Order calldata order) private view returns (bytes32) {
        return
            _hashTypedDataV4(
                keccak256(
                    abi.encode(
                        ORDER_TYPEHASH,
                        order.seller,
                        order.nft,
                        order.tokenId,
                        order.price,
                        order.startTime,
                        order.endTime,
                        order.nonce,
                        order.salt,
                        order.taker,
                        order.maxPlatformFeeBps,
                        order.maxRoyaltyBps
                    )
                )
            );
    }

    function _isApproved(
        IERC721 token,
        uint256 tokenId,
        address owner
    ) private view returns (bool) {
        return
            token.getApproved(tokenId) == address(this) ||
            token.isApprovedForAll(owner, address(this));
    }

    function _platformFee(uint256 price) private view returns (uint256) {
        return (price * platformFeeBps) / BPS_DENOMINATOR;
    }

    function _royalty(
        address nft,
        uint256 tokenId,
        uint256 price
    ) private view returns (address receiver, uint256 amount) {
        try IERC165(nft).supportsInterface(type(IERC2981).interfaceId) returns (
            bool supported
        ) {
            if (supported) {
                try IERC2981(nft).royaltyInfo(tokenId, price) returns (
                    address royaltyReceiver,
                    uint256 royaltyAmount
                ) {
                    if (royaltyReceiver != address(0) && royaltyAmount > 0) {
                        return (royaltyReceiver, royaltyAmount);
                    }
                } catch {}
            }
        } catch {}

        RoyaltyFallback memory fallbackRoyalty = royaltyFallbacks[nft];
        if (
            fallbackRoyalty.receiver == address(0) || fallbackRoyalty.bps == 0
        ) {
            return (address(0), 0);
        }

        return (
            fallbackRoyalty.receiver,
            (price * fallbackRoyalty.bps) / BPS_DENOMINATOR
        );
    }

    function _pay(address payable to, uint256 amount) private {
        if (amount == 0) {
            return;
        }
        (bool sent, ) = to.call{value: amount}("");
        require(sent, "payout failed");
    }
}
Chain explorer3565msChain node74ms