Skip to main content

Bulk Orders

Bulk Order Proofs allow for users to sign for multiple listings or offers in one signature. To make it more transparent, the marketplace should present the signature digest in a human readable format, allowing for users to review the data they sign before completing. Due to how EIP-712 struct hashing works, a nested array of [2] * treeHeight will produce the same hash as the root hash, provided it contains the same data and is padded with empty structs. Trees of depths 1 (2^1 = 2) to 10 (2^10 = 1024) are supported on Payment Processor.

Bulk Order Typehashes​

The Bulk Order Typehash Lookup tables are generated by concatenating the hashes from each height into one bytes array. This is decoded by taking the bytes32 output of the offset of height - 1 * 32.

// keccack256("BulkSaleApproval(SaleApproval[2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_1_HASH = 0x8659f55d4c88f84030fe09241169834754ebf2e61099b616e530c6b65712c644;

// keccack256("BulkSaleApproval(SaleApproval[2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_2_HASH = 0x5106f4043cda72e04ca2c760016628ea8d5667309323ba590682ea5254b4e82e;

// keccack256("BulkSaleApproval(SaleApproval[2][2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_3_HASH = 0x71267a8f42e7ccde4ac75848a93b741df7a2f7a58e40274055f2fa51dbaa69ce;

// keccack256("BulkSaleApproval(SaleApproval[2][2][2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_4_HASH = 0x6e90557aed2a349f8b6efb2b652c4025c56cfa82424c5cd0c6801cc234ebf519;

// keccack256("BulkSaleApproval(SaleApproval[2][2][2][2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_5_HASH = 0xcaf42fc49ad57705ea6be2ca9e1835c9ccddf7bc6fdea8f851917329b1d53a7f;

// keccack256("BulkSaleApproval(SaleApproval[2][2][2][2][2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_6_HASH = 0x09b32b6b5ffee898d5fe18398652042cc8c46449329c5a1a79e425f4ede9bc2b;

// keccack256("BulkSaleApproval(SaleApproval[2][2][2][2][2][2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_7_HASH = 0xc2362dea3338b88607906397acfdcc5651f19b40a038ee7c89dc4ab54c736cac;

// keccack256("BulkSaleApproval(SaleApproval[2][2][2][2][2][2][2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_8_HASH = 0xf2bbc4f6d7ccfa2b8aab6505f0c8f2868c5a190c6c4cfce8c0de447804904df9;

// keccack256("BulkSaleApproval(SaleApproval[2][2][2][2][2][2][2][2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_9_HASH = 0x81f99e15003039550d3597e34e6426b1e230992a5a3727cb5e230754f18f3566;

// keccack256("BulkSaleApproval(SaleApproval[2][2][2][2][2][2][2][2][2][2] tree)SaleApproval(uint8 protocol,address cosigner,address seller,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,uint256 nonce,uint256 masterNonce,uint256 protocolFeeVersion)")
bytes32 constant BULK_SALE_APPROVAL_HEIGHT_10_HASH = 0x012178d0a6b8f8748e48411572bdc391435539737aafc91fcba6f2c24ae156cf;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_1_HASH = 0xfb1dd652f3a5dcde3cb90b0cbb7ff0d33df15a48f216e6ac0e2306ff3538e336;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_2_HASH = 0x32fc12675167bd2e9c23f1a9b90ce9c0a14daa7e8b3fa5a01105804ad64aa49d;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_3_HASH = 0x22beb101a4a232e5b05a7b5f4727888724dd418194d6c5b1f1ba5ead4cbeed42;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2][2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_4_HASH = 0x9ba46e6a390d8f8edfb6f752177c215b1cf8b6dcf1f5da395ead6c3e19755698;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2][2][2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_5_HASH = 0xae93fe4a03206f6bb45035fab04a39964c83e7d265e93fc31521c86dd25a3be4;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2][2][2][2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_6_HASH = 0xee3cb9e25b214af21b0d321776864470916324653397b355b267b2894a009a98;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2][2][2][2][2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_7_HASH = 0x516d5d5306f95a17cb6d0b84e71f78919a98ac5e3c723fc4b9b1a720193d590d;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2][2][2][2][2][2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_8_HASH = 0xf5b1dcad1bd5c8161d6b904513bc658d4c9b8c288b2271e0f27d5938654e4186;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2][2][2][2][2][2][2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_9_HASH = 0x63c21e3ce7e506548c01ef4e6a27a5805f9328e0da83e9a7c765dc28266a5aa1;

// keccack256("BulkCollectionOfferApproval(CollectionOfferApproval[2][2][2][2][2][2][2][2][2][2] tree)CollectionOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_COLLECTION_OFFER_APPROVAL_HEIGHT_10_HASH = 0x9802b2e35d72255f2ae69bed829f0104723aa156059e02dfccfe781ffc955356;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_1_HASH = 0x243dc86e63d73b10b2764253a38ab8763ded4ac63a632adef4019e482161964a;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_2_HASH = 0x2ed4880b2bfec74882da06ca9f461158c42fa73fa5974b5abec9fcde7cdd43ee;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_3_HASH = 0x8308607f65c90c023abf48563d2c8bd8c783d1db48ffd02ec324105d9f682f96;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2][2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_4_HASH = 0x1f7a30dcec9205ff30a5290b3b756e1fd1a1585539bccbc817ab4e59d69a055e;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2][2][2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_5_HASH = 0xcfa8c0abdff5fb2704d1818f38dc974f5bdde6dfe1a4ddc3e22a1f3e593e98f3;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2][2][2][2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_6_HASH = 0x24e3124a40922800d1eb1890240fc7d07f257a303bb383e8c0820e9910be1f97;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2][2][2][2][2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_7_HASH = 0xc72769ff919066b8d1f586bb8b7e720ad93f735ffa9570f9e9ef0e865d13251d;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2][2][2][2][2][2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_8_HASH = 0x89338818bfd140179260dbdc6d6bf38461d49661c166f2b76d3b56727acab7ad;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2][2][2][2][2][2][2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_9_HASH = 0xf3e381ed4335a28fa612f4068c58de673cad05c8a7fbfb5c1fd557c2c5a2de9f;

// keccack256("BulkItemOfferApproval(ItemOfferApproval[2][2][2][2][2][2][2][2][2][2] tree)ItemOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 tokenId,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce)")
bytes32 constant BULK_ITEM_OFFER_APPROVAL_HEIGHT_10_HASH = 0x84c94a0cfd84379f92ed5827593e2218a1dc1b975626bbe5c6948b9d2232f7d7;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_1_HASH = 0x0d0b16c0b281480a518e0ae1543bf94c612edc289e45edc04e8510dac617afa4;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_2_HASH = 0x337b9c051f65323200a3580d4917087d4d82e350fcc68b3397c654c9fc7872c3;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_3_HASH = 0x8f8f306a409d08a43b82756f57beb839c3bf5bdd388ba0850d9d21f5c1d0c4dc;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2][2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_4_HASH = 0x9f510b8ccf7bbda5c9bd4333d7dcfc8e280aac9eaa9427dcd2f2ffca1fa7a833;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2][2][2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_5_HASH = 0x8599a8fc89aae892d7419812435866d931c9da91198b2f48d1d5318acb524461;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2][2][2][2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_6_HASH = 0xa0f24864e615845dfa14bee5d4fa28950fcdcf9d31893c68c26f4cfa13402a97;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2][2][2][2][2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_7_HASH = 0x621dd1d4cc7477f0587a16f5cd40ea8750209653e7275ccaea3b68623860181b;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2][2][2][2][2][2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_8_HASH = 0x51e570aee92287102d49a7493d337e8aa332c1bc639273de546b428973379fa9;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2][2][2][2][2][2][2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_9_HASH = 0xa9415346b8de2006517a8de68b2b4147a1d6fd91ce600f4040941627c1c8c3df;

// keccack256("BulkTokenSetOfferApproval(TokenSetOfferApproval[2][2][2][2][2][2][2][2][2][2] tree)TokenSetOfferApproval(uint8 protocol,address cosigner,address buyer,address beneficiary,address marketplace,address fallbackRoyaltyRecipient,address paymentMethod,address tokenAddress,uint256 amount,uint256 itemPrice,uint256 expiration,uint256 marketplaceFeeNumerator,uint256 nonce,uint256 masterNonce,bytes32 tokenSetMerkleRoot)")
bytes32 constant BULK_TOKEN_SET_OFFER_APPROVAL_HEIGHT_10_HASH = 0xb75be8e10d720cf92518936f56974bdfa8e4a723902dd12e415ffba6eb6dde12;

Bulk Approval Signature Creation​

Creating a Bulk Order Signature requires you to create a merkle tree where the root is the bulk order, and the leaves are the approval types (e.g. SaleApproval or ItemOfferApproval). The tree must be exactly 2^N items, where N is the height of the tree calculated by taking the maximum of log2(orderCount). If the amount of approvals is not exactly equal to the computed amount of required items, you would pad with empty approvals which would be unfillable.

An example for an order with 7 items would be:

Visual Order

log2(7) = 2.8 = 3

|---------------------------------------------------|
1 | [[[sa1,sa2], [sa3,sa4]], [[sa5,sa6], [sa7,pad]]] |
|---------------------------------------------------|
2 | [[sa1,sa2], [sa3,sa4]] | [[sa5,sa6], [sa7,pad]] |
|---------------------------------------------------|
3 | [sa1, sa2] | [sa3, sa4] | [sa5, sa6] | [sa7, pad] |

Example in JavaScript

// Bulk Order Type
export const EIP_712_BULK_ORDER_TYPE = {
BulkSaleApproval: [{ name: "tree", type: "SaleApproval[2][2][2]" }],
SaleApproval: [
{ name: "protocol", type: "uint8" },
{ name: "cosigner", type: "address" },
{ name: "seller", type: "address" },
{ name: "marketplace", type: "address" },
{ name: "fallbackRoyaltyRecipient", type: "address" },
{ name: "paymentMethod", type: "address" },
{ name: "tokenAddress", type: "address" },
{ name: "tokenId", type: "uint256" },
{ name: "amount", type: "uint256" },
{ name: "itemPrice", type: "uint256" },
{ name: "expiration", type: "uint256" },
{ name: "marketplaceFeeNumerator", type: "uint256" },
{ name: "maxRoyaltyFeeNumerator", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "masterNonce", type: "uint256" },
{ name: "protocolFeeVersion", type: "uint256" }
]
};

const bulkArray: SaleApproval[][][] = [];

const exampleSaleApproval = {
protocol: 0,
cosigner: zeroAddress,
seller: '0xabc...',
marketplace: '0xbeef...',
fallbackRoyaltyRecipient: zeroAddress,
paymentMethod: zeroAddress,
tokenAddress: '0x123...',
tokenId: 1,
amount: 1,
itemPrice: 1e18,
expiration: 9999999999999,
marketplaceFeeNumerator: 0,
maxRoyaltyFeeNumerator: 0,
nonce: 0,
masterNonce: 0,
protocolFeeVersion: 0
};

const blankApproval = {
protocol: 0,
cosigner: zeroAddress,
seller: zeroAddress,
marketplace: zeroAddress,
fallbackRoyaltyRecipient: zeroAddress,
paymentMethod: zeroAddress,
tokenAddress: zeroAddress,
tokenId: 0,
amount: 0,
itemPrice: 0,
expiration: 0,
marketplaceFeeNumerator: 0,
maxRoyaltyFeeNumerator: 0,
nonce: 0,
masterNonce: 0,
protocolFeeVersion: 0
}

bulkArray[0][0][0] = exampleSaleApproval;
bulkArray[0][0][1] = exampleSaleApproval;
bulkArray[0][1][0] = exampleSaleApproval;
bulkArray[0][1][1] = exampleSaleApproval;
bulkArray[1][0][0] = exampleSaleApproval;
bulkArray[1][0][1] = exampleSaleApproval;
bulkArray[1][1][0] = exampleSaleApproval;
bulkArray[1][1][1] = blankApproval;

const dataToSign = {
BulkSaleApproval: {
tree: bulkArray;
}
}

const typedData = JSON.stringify({
primaryType: 'BulkSaleApproval',
domain: domain,
message: { tree: dataToSign },
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' }
],
... types,
}
});

const params = [signerAddress, typedData];
const method = 'eth_signTypedData_v4';

const sig = await window.ethereum.request({ method, params });

// Generate tree
const hashedData = dataToSign.flat(Infinity).map((saleApproval) => {

const encodedData = encodeAbiParameters(
parseAbiParameters(
"bytes32 hash, uint8 protocol, address cosigner, address seller, address marketplace, address fallbackRoyaltyRecipient, address paymentMethod, address tokenAddress, uint256 tokenId, uint256 amount, uint256 itemPrice, uint256 expiration, uint256 marketplaceFeeNumerator, uint256 maxRoyaltyFeeNumerator, uint256 nonce, uint256 masterNonce, uint256 protocolFeeVersion"),
[
SALE_APPROVAL_TYPE_HASH,
saleApproval.protocol,
saleApproval.cosigner,
saleApproval.seller,
saleApproval.marketplace,
saleApproval.fallbackRoyaltyRecipient,
saleApproval.paymentMethod,
saleApproval.tokenAddress,
saleApproval.tokenId,
saleApproval.amount,
saleApproval.itemPrice,
saleApproval.expiration,
saleApproval.marketplaceFeeNumerator,
saleApproval.maxRoyaltyFeeNumerator,
saleApproval.nonce,
saleApproval.masterNonce,
saleApproval.protocolFeeVersion
]
);

return keccak256(encodedData);
});

const tree: MerkleTree = new MerkleTree(hashedData, keccak256, {
complete: true,
sort: false,
hashLeaves: false,
fillDefaultHash: keccak256(encodedNullSaleApproval)
});

Processing Bulk Orders​

When submitting an order that is part of a bulk approval, the index of the approval must be provided with the proof. This is used to determine the placing of the approval in order to recreate the tree and generate the correct hash. Using the previous example, orders are indexed as below:

bulkArray[0][0][0] == 0;
bulkArray[0][0][1] == 1;
bulkArray[0][1][0] == 2;
bulkArray[0][1][1] == 3;
bulkArray[1][0][0] == 4;
bulkArray[1][0][1] == 5;
bulkArray[1][1][0] == 6;
bulkArray[1][1][1] == 7;

So to submit an order for bulkArray[0][1][0] you would submit as below:

const index = 2;
const hexProof = tree.getHexProot(hashedData[index]);

const order: AdvancedOrder = {
saleDetails: order,
signature: sig,
cosignature: nullSig,
permitContext: {
permitProcessor: zeroAddress,
permitNonce: BigInt(0),
}
}

const proof: Proof = {
proof: hexProof,
orderIndex: index
};

const feeOnTop: FeeOnTop = {
recipient: zeroAddress,
amount: BigInt(0),
}

const calldata = await publicClient.readContract({
address: PAYMENT_PROCESSOR_ENCODER_ADDRESS,
abi: paymentProcessorEncoderAbi.abi,
functionName: 'encodebuyListingAdvancedCalldata',
args: [PAYMENT_PROCESSOR_ADDRESS, order, proof, feeOnTop]
});

const { request } = await publicClient.simulateContract({
account: address,
address: PAYMENT_PROCESSOR_ADDRESS,
abi: paymentProcessorAbi.abi,
functionName: 'buyListingAdvanced',
args: [calldata]
});
await walletClient.writeContract(request);

Limit Break

TwitterLimitBreak.comMedium

© 2026 Limit Break International, Inc. All rights reserved.

Privacy PolicyTerms of ServiceCookie PolicyDo Not Sell My Info