Skip to content
Merged
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "opensea-js",
"version": "8.0.3",
"version": "8.0.4",
"description": "TypeScript SDK for the OpenSea marketplace helps developers build new experiences using NFTs and our marketplace data",
"license": "MIT",
"author": "OpenSea Developers",
Expand Down
6 changes: 6 additions & 0 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ export class OpenSeaAPI {
* @side The side of the order (buy or sell)
* @param assetContractAddress Optional address of the NFT contract for criteria offers (e.g., collection offers)
* @param tokenId Optional token ID for criteria offers (e.g., collection offers)
* @param unitsToFill Optional number of units to fill. For listings, defaults to remaining quantity. For offers, defaults to 1.
* @param recipientAddress Optional recipient address for the NFT when fulfilling a listing. Not applicable for offers.
* @returns The {@link FulfillmentDataResponse}
*/
public async generateFulfillmentData(
Expand All @@ -268,6 +270,8 @@ export class OpenSeaAPI {
side: OrderSide,
assetContractAddress?: string,
tokenId?: string,
unitsToFill?: string,
recipientAddress?: string,
): Promise<FulfillmentDataResponse> {
return this.ordersAPI.generateFulfillmentData(
fulfillerAddress,
Expand All @@ -276,6 +280,8 @@ export class OpenSeaAPI {
side,
assetContractAddress,
tokenId,
unitsToFill,
recipientAddress,
);
}

Expand Down
5 changes: 5 additions & 0 deletions src/api/orders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ export class OrdersAPI {
side: OrderSide,
assetContractAddress?: string,
tokenId?: string,
unitsToFill?: string,
recipientAddress?: string,
): Promise<FulfillmentDataResponse> {
let payload: object | null = null;
if (side === OrderSide.LISTING) {
Expand All @@ -145,6 +147,8 @@ export class OrdersAPI {
this.chain,
assetContractAddress,
tokenId,
unitsToFill,
recipientAddress,
);
} else {
payload = getFulfillOfferPayload(
Expand All @@ -154,6 +158,7 @@ export class OrdersAPI {
this.chain,
assetContractAddress,
tokenId,
unitsToFill,
);
}
const response = await this.fetcher.post<FulfillmentDataResponse>(
Expand Down
28 changes: 25 additions & 3 deletions src/orders/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,31 @@ type Transaction = {
chain: number;
to: string;
value: number;
input_data: {
orders: OrderWithCounter[] | AdvancedOrder[] | BasicOrderParametersStruct[];
};
input_data:
| {
// For fulfillAdvancedOrder
advancedOrder: AdvancedOrder;
criteriaResolvers?: unknown[];
fulfillerConduitKey?: string;
recipient: string;
}
| {
// For fulfillBasicOrder
basicOrderParameters: BasicOrderParametersStruct;
}
| {
// For fulfillOrder
order: OrderWithCounter;
fulfillerConduitKey?: string;
recipient: string;
}
| {
// Legacy: for backward compatibility
orders:
| OrderWithCounter[]
| AdvancedOrder[]
| BasicOrderParametersStruct[];
};
};

// API query types
Expand Down
21 changes: 21 additions & 0 deletions src/orders/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export const getFulfillListingPayload = (
chain: Chain,
assetContractAddress?: string,
tokenId?: string,
unitsToFill?: string,
recipientAddress?: string,
) => {
const payload: {
listing: {
Expand All @@ -89,6 +91,8 @@ export const getFulfillListingPayload = (
asset_contract_address: string;
token_id: string;
};
units_to_fill?: string;
recipient?: string;
} = {
listing: {
hash: order_hash,
Expand All @@ -108,6 +112,16 @@ export const getFulfillListingPayload = (
};
}

// Add optional units_to_fill
if (unitsToFill !== undefined) {
payload.units_to_fill = unitsToFill;
}

// Add optional recipient for listings
if (recipientAddress) {
payload.recipient = recipientAddress;
}

return payload;
};

Expand All @@ -118,6 +132,7 @@ export const getFulfillOfferPayload = (
chain: Chain,
assetContractAddress?: string,
tokenId?: string,
unitsToFill?: string,
) => {
const payload: {
offer: {
Expand All @@ -132,6 +147,7 @@ export const getFulfillOfferPayload = (
asset_contract_address: string;
token_id: string;
};
units_to_fill?: string;
} = {
offer: {
hash: order_hash,
Expand All @@ -151,6 +167,11 @@ export const getFulfillOfferPayload = (
};
}

// Add optional units_to_fill for offers
if (unitsToFill !== undefined) {
payload.units_to_fill = unitsToFill;
}

return payload;
};

Expand Down
23 changes: 11 additions & 12 deletions src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,47 +478,46 @@ export class OpenSeaSDK {

/**
* Fulfill an order for an asset. The order can be either a listing or an offer.
* Uses the OpenSea API to generate fulfillment transaction data and executes it directly.
* @param options
* @param options.order The order to fulfill, a.k.a. "take"
* @param options.accountAddress Address of the wallet taking the offer.
* @param options.recipientAddress The optional address to receive the order's item(s) or currencies. If not specified, defaults to accountAddress.
* @param options.domain An optional domain to be hashed and included at the end of fulfillment calldata. This can be used for on-chain order attribution to assist with analytics.
* @param options.assetContractAddress Optional address of the NFT contract for criteria offers (e.g., collection offers). Required when fulfilling collection offers.
* @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. For listings, defaults to remaining quantity. For offers, defaults to 1.
* @param options.recipientAddress Optional recipient address for the NFT when fulfilling a listing. Not applicable for offers.
* @param options.overrides Transaction overrides, ignored if not set.
* @returns Transaction hash of the order.
*
* @throws Error if the accountAddress is not available through wallet or provider.
* @throws Error if the order's protocol address is not supported by OpenSea. See {@link isValidProtocol}.
* @throws Error if attempting to fulfill the order with a recipient address which does not match a private listing.
* @throws Error if a signer is not provided (read-only providers cannot fulfill orders).
* @throws Error if the order hash is not available.
*/
public async fulfillOrder({
order,
accountAddress,
recipientAddress,
unitsToFill,
domain,
assetContractAddress,
tokenId,
unitsToFill,
recipientAddress,
overrides,
}: {
order: OrderV2 | Order | Listing | Offer;
accountAddress: string;
recipientAddress?: string;
unitsToFill?: BigNumberish;
domain?: string;
assetContractAddress?: string;
tokenId?: string;
unitsToFill?: BigNumberish;
recipientAddress?: string;
overrides?: Overrides;
}): Promise<string> {
return this._fulfillmentManager.fulfillOrder({
order,
accountAddress,
recipientAddress,
unitsToFill,
domain,
assetContractAddress,
tokenId,
unitsToFill,
recipientAddress,
overrides,
});
}
Expand Down
Loading