From 1fa49bc1ce38d731cb7ac0da6ce76f34e6f36d54 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Wed, 26 Nov 2025 11:33:26 -0800 Subject: [PATCH] feat: add includeOptionalCreatorFees to fulfillOrder Add includeOptionalCreatorFees parameter to fulfill offer and fulfill listing endpoints. When set to true, optional creator fees will be included in the fulfillment. If creator fees are already required, this is a no-op. Defaults to false. Changes: - Add includeOptionalCreatorFees param to getFulfillListingPayload/getFulfillOfferPayload - Add includeOptionalCreatorFees param to generateFulfillmentData in OrdersAPI and OpenSeaAPI - Add includeOptionalCreatorFees param to fulfillOrder in FulfillmentManager and OpenSeaSDK - Update tests to cover new parameter --- src/api/api.ts | 3 +++ src/api/orders.ts | 3 +++ src/orders/utils.ts | 6 ++++++ src/sdk.ts | 4 ++++ src/sdk/fulfillment.ts | 4 ++++ test/orders/utils.spec.ts | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+) diff --git a/src/api/api.ts b/src/api/api.ts index 75f55f724..e866ee489 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -280,6 +280,7 @@ export class OpenSeaAPI { * @param tokenId Optional token ID for criteria offers (e.g., collection offers) * @param unitsToFill Optional number of units to fill. Defaults to 1 for both listings and offers. * @param recipientAddress Optional recipient address for the NFT when fulfilling a listing. Not applicable for offers. + * @param includeOptionalCreatorFees Whether to include optional creator fees in the fulfillment. If creator fees are already required, this is a no-op. Defaults to false. * @returns The {@link FulfillmentDataResponse} */ public async generateFulfillmentData( @@ -291,6 +292,7 @@ export class OpenSeaAPI { tokenId?: string, unitsToFill?: string, recipientAddress?: string, + includeOptionalCreatorFees: boolean = false, ): Promise { return this.ordersAPI.generateFulfillmentData( fulfillerAddress, @@ -301,6 +303,7 @@ export class OpenSeaAPI { tokenId, unitsToFill, recipientAddress, + includeOptionalCreatorFees, ); } diff --git a/src/api/orders.ts b/src/api/orders.ts index 0ac634cce..0711a0106 100644 --- a/src/api/orders.ts +++ b/src/api/orders.ts @@ -137,6 +137,7 @@ export class OrdersAPI { tokenId?: string, unitsToFill?: string, recipientAddress?: string, + includeOptionalCreatorFees: boolean = false, ): Promise { let payload: object | null = null; if (side === OrderSide.LISTING) { @@ -149,6 +150,7 @@ export class OrdersAPI { tokenId, unitsToFill, recipientAddress, + includeOptionalCreatorFees, ); } else { payload = getFulfillOfferPayload( @@ -159,6 +161,7 @@ export class OrdersAPI { assetContractAddress, tokenId, unitsToFill, + includeOptionalCreatorFees, ); } const response = await this.fetcher.post( diff --git a/src/orders/utils.ts b/src/orders/utils.ts index 4aacff300..68996dfc4 100644 --- a/src/orders/utils.ts +++ b/src/orders/utils.ts @@ -91,6 +91,7 @@ export const getFulfillListingPayload = ( tokenId?: string, unitsToFill: string = "1", recipientAddress?: string, + includeOptionalCreatorFees: boolean = false, ) => { const payload: { listing: { @@ -107,6 +108,7 @@ export const getFulfillListingPayload = ( }; units_to_fill: string; recipient?: string; + include_optional_creator_fees: boolean; } = { listing: { hash: order_hash, @@ -117,6 +119,7 @@ export const getFulfillListingPayload = ( address: fulfillerAddress, }, units_to_fill: unitsToFill, + include_optional_creator_fees: includeOptionalCreatorFees, }; // Add consideration for criteria listings if needed @@ -143,6 +146,7 @@ export const getFulfillOfferPayload = ( assetContractAddress?: string, tokenId?: string, unitsToFill: string = "1", + includeOptionalCreatorFees: boolean = false, ) => { const payload: { offer: { @@ -158,6 +162,7 @@ export const getFulfillOfferPayload = ( token_id: string; }; units_to_fill: string; + include_optional_creator_fees: boolean; } = { offer: { hash: order_hash, @@ -168,6 +173,7 @@ export const getFulfillOfferPayload = ( address: fulfillerAddress, }, units_to_fill: unitsToFill, + include_optional_creator_fees: includeOptionalCreatorFees, }; // Add consideration for criteria offers (e.g., collection offers) diff --git a/src/sdk.ts b/src/sdk.ts index 1f5a92554..f01c48b36 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -490,6 +490,7 @@ export class OpenSeaSDK { * @param options.tokenId Optional token ID for criteria offers (e.g., collection offers). Required when fulfilling collection offers. * @param options.unitsToFill Optional number of units to fill. Defaults to 1 for both listings and offers. * @param options.recipientAddress Optional recipient address for the NFT when fulfilling a listing. Not applicable for offers. + * @param options.includeOptionalCreatorFees Whether to include optional creator fees in the fulfillment. If creator fees are already required, this is a no-op. Defaults to false. * @param options.overrides Transaction overrides, ignored if not set. * @returns Transaction hash of the order. * @@ -505,6 +506,7 @@ export class OpenSeaSDK { tokenId, unitsToFill, recipientAddress, + includeOptionalCreatorFees = false, overrides, }: { order: OrderV2 | Order | Listing | Offer; @@ -513,6 +515,7 @@ export class OpenSeaSDK { tokenId?: string; unitsToFill?: BigNumberish; recipientAddress?: string; + includeOptionalCreatorFees?: boolean; overrides?: Overrides; }): Promise { return this._fulfillmentManager.fulfillOrder({ @@ -522,6 +525,7 @@ export class OpenSeaSDK { tokenId, unitsToFill, recipientAddress, + includeOptionalCreatorFees, overrides, }); } diff --git a/src/sdk/fulfillment.ts b/src/sdk/fulfillment.ts index 83751b000..4c2332d1c 100644 --- a/src/sdk/fulfillment.ts +++ b/src/sdk/fulfillment.ts @@ -99,6 +99,7 @@ export class FulfillmentManager { * @param options.tokenId Optional token ID for criteria offers (e.g., collection offers). Required when fulfilling collection offers. * @param options.unitsToFill Optional number of units to fill. Defaults to 1 for both listings and offers. * @param options.recipientAddress Optional recipient address for the NFT when fulfilling a listing. Not applicable for offers. + * @param options.includeOptionalCreatorFees Whether to include optional creator fees in the fulfillment. If creator fees are already required, this is a no-op. Defaults to false. * @param options.overrides Transaction overrides, ignored if not set. * @returns Transaction hash of the order. * @@ -114,6 +115,7 @@ export class FulfillmentManager { tokenId, unitsToFill, recipientAddress, + includeOptionalCreatorFees = false, overrides, }: { order: OrderV2 | Order | Listing | Offer; @@ -122,6 +124,7 @@ export class FulfillmentManager { tokenId?: string; unitsToFill?: BigNumberish; recipientAddress?: string; + includeOptionalCreatorFees?: boolean; overrides?: Overrides; }): Promise { await this.context.requireAccountIsAvailable(accountAddress); @@ -167,6 +170,7 @@ export class FulfillmentManager { tokenId, unitsToFillStr, recipientAddress, + includeOptionalCreatorFees, ); // Use the transaction data returned by the API diff --git a/test/orders/utils.spec.ts b/test/orders/utils.spec.ts index f8a564607..094482b82 100644 --- a/test/orders/utils.spec.ts +++ b/test/orders/utils.spec.ts @@ -352,10 +352,27 @@ suite("Orders: utils", () => { address: "0xFulfiller", }, units_to_fill: "1", + include_optional_creator_fees: false, }); expect(result.consideration).to.be.undefined; }); + test("should include includeOptionalCreatorFees when set to true", () => { + const result = getFulfillListingPayload( + "0xFulfiller", + "0xOrderHash", + "0xProtocol", + Chain.Mainnet, + undefined, + undefined, + "1", + undefined, + true, + ); + + expect(result.include_optional_creator_fees).to.be.true; + }); + test("should add consideration for criteria listings", () => { const result = getFulfillListingPayload( "0xFulfiller", @@ -417,6 +434,7 @@ suite("Orders: utils", () => { address: "0xFulfiller", }, units_to_fill: "1", + include_optional_creator_fees: false, }); expect(result.consideration).to.be.undefined; }); @@ -436,6 +454,21 @@ suite("Orders: utils", () => { token_id: "456", }); }); + + test("should include includeOptionalCreatorFees when set to true", () => { + const result = getFulfillOfferPayload( + "0xFulfiller", + "0xOrderHash", + "0xProtocol", + Chain.Polygon, + undefined, + undefined, + "1", + true, + ); + + expect(result.include_optional_creator_fees).to.be.true; + }); }); suite("deserializeOrder", () => {