Skip to content

Commit 7cdfb9e

Browse files
authored
getOrderByHash handle os2 order response (#1839)
* getOrderByHash handle os2 order response * add tests * fix
1 parent 48a1b5d commit 7cdfb9e

7 files changed

Lines changed: 440 additions & 38 deletions

File tree

src/api/api.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
GetBestListingResponse,
3535
GetOffersResponse,
3636
GetListingsResponse,
37+
GetOrderByHashResponse,
3738
CollectionOffer,
3839
CollectionOrderByOption,
3940
CancelOrderResponse,
@@ -126,14 +127,14 @@ export class OpenSeaAPI {
126127
* @param orderHash The hash of the order to fetch
127128
* @param protocolAddress The address of the seaport contract
128129
* @param chain The chain where the order is located. Defaults to the chain set in the constructor.
129-
* @returns The {@link OrderV2} returned by the API
130+
* @returns The {@link GetOrderByHashResponse} returned by the API (can be Offer or Listing)
130131
* @throws An error if the order is not found
131132
*/
132133
public async getOrderByHash(
133134
orderHash: string,
134135
protocolAddress: string,
135136
chain: Chain = this.chain,
136-
): Promise<OrderV2> {
137+
): Promise<GetOrderByHashResponse> {
137138
return this.ordersAPI.getOrderByHash(orderHash, protocolAddress, chain);
138139
}
139140

src/api/orders.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import {
33
getOrderByHashPath,
44
getCancelOrderPath,
55
} from "./apiPaths";
6-
import { GetOrdersResponse, CancelOrderResponse } from "./types";
6+
import {
7+
GetOrdersResponse,
8+
CancelOrderResponse,
9+
GetOrderByHashResponse,
10+
} from "./types";
711
import {
812
FulfillmentDataResponse,
913
OrderAPIOptions,
@@ -72,16 +76,17 @@ export class OrdersAPI {
7276

7377
/**
7478
* Gets a single order by its order hash.
79+
* Returns the raw API response which can be either an Offer or Listing.
7580
*/
7681
async getOrderByHash(
7782
orderHash: string,
7883
protocolAddress: string,
7984
chain: Chain = this.chain,
80-
): Promise<OrderV2> {
85+
): Promise<GetOrderByHashResponse> {
8186
const response = await this.fetcher.get<{
82-
order: OrdersQueryResponse["orders"][0];
87+
order: GetOrderByHashResponse;
8388
}>(getOrderByHashPath(chain, protocolAddress, orderHash));
84-
return deserializeOrder(response.order);
89+
return response.order;
8590
}
8691

8792
/**

src/api/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,13 @@ export type GetBestOfferResponse = Offer | CollectionOffer;
243243
*/
244244
export type GetBestListingResponse = Listing;
245245

246+
/**
247+
* Response from OpenSea API for fetching an order by hash.
248+
* Can be either an Offer or a Listing.
249+
* @category API Response Types
250+
*/
251+
export type GetOrderByHashResponse = Offer | Listing;
252+
246253
/**
247254
* Response from OpenSea API for offchain canceling an order.
248255
* @category API Response Types

src/sdk/cancellation.ts

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { OrderComponents } from "@opensea/seaport-js/lib/types";
22
import { Overrides, Signer } from "ethers";
3+
import { Offer, Listing } from "../api/types";
34
import { OrderV2 } from "../orders/types";
45
import { DEFAULT_SEAPORT_CONTRACT_ADDRESS } from "../orders/utils";
56
import { Chain, EventType } from "../types";
@@ -55,37 +56,44 @@ export class CancellationManager {
5556
// Check account availability after parameter validation
5657
await this.context.requireAccountIsAvailable(accountAddress);
5758

58-
let orderToCancel: OrderV2;
59+
let orderComponents: OrderComponents;
60+
let effectiveProtocolAddress: string;
5961

6062
if (order) {
6163
// Using OrderV2 object directly
6264
requireValidProtocol(order.protocolAddress);
63-
orderToCancel = order;
65+
effectiveProtocolAddress = order.protocolAddress;
66+
orderComponents = order.protocolData.parameters;
67+
this.context.dispatch(EventType.CancelOrder, {
68+
orderV2: order,
69+
accountAddress,
70+
});
6471
} else if (orderHash) {
6572
// Fetch order from API using order hash
6673
requireValidProtocol(protocolAddress);
67-
orderToCancel = await this.context.api.getOrderByHash(
74+
const fetchedOrder = await this.context.api.getOrderByHash(
6875
orderHash,
6976
protocolAddress,
7077
this.context.chain,
7178
);
72-
requireValidProtocol(orderToCancel.protocolAddress);
79+
requireValidProtocol(fetchedOrder.protocol_address);
80+
effectiveProtocolAddress = fetchedOrder.protocol_address;
81+
orderComponents = fetchedOrder.protocol_data.parameters;
82+
this.context.dispatch(EventType.CancelOrder, {
83+
order: fetchedOrder,
84+
accountAddress,
85+
});
7386
} else {
7487
// Should never reach here due to earlier validation
7588
throw new Error("Invalid input");
7689
}
7790

78-
this.context.dispatch(EventType.CancelOrder, {
79-
orderV2: orderToCancel,
80-
accountAddress,
81-
});
82-
8391
// Transact and get the transaction hash
8492
const transactionHash = await this.cancelSeaportOrders({
85-
orders: [orderToCancel.protocolData.parameters],
93+
orders: [orderComponents],
8694
accountAddress,
8795
domain,
88-
protocolAddress: orderToCancel.protocolAddress,
96+
protocolAddress: effectiveProtocolAddress,
8997
});
9098

9199
// Await transaction confirmation
@@ -156,17 +164,16 @@ export class CancellationManager {
156164

157165
let orderComponents: OrderComponents[];
158166
let effectiveProtocolAddress = protocolAddress;
159-
let firstOrderV2: OrderV2 | undefined;
160167

161168
if (orders) {
162169
// Extract OrderComponents from either OrderV2 objects or use OrderComponents directly
170+
let firstOrderV2: OrderV2 | undefined;
163171
orderComponents = orders.map((order) => {
164172
if ("protocolData" in order) {
165173
// It's an OrderV2 object
166174
const orderV2 = order as OrderV2;
167175
requireValidProtocol(orderV2.protocolAddress);
168176
effectiveProtocolAddress = orderV2.protocolAddress;
169-
// Save the first OrderV2 for event dispatching
170177
if (!firstOrderV2) {
171178
firstOrderV2 = orderV2;
172179
}
@@ -176,40 +183,44 @@ export class CancellationManager {
176183
return order as OrderComponents;
177184
}
178185
});
186+
// Dispatch event for the first OrderV2 if available
187+
if (firstOrderV2) {
188+
this.context.dispatch(EventType.CancelOrder, {
189+
orderV2: firstOrderV2,
190+
accountAddress,
191+
});
192+
}
179193
} else if (orderHashes) {
180194
// Fetch orders from the API using order hashes
181-
const fetchedOrders: OrderV2[] = [];
182-
for (const orderHash of orderHashes) {
183-
const order = await this.context.api.getOrderByHash(
184-
orderHash,
195+
const fetchedOrders: (Offer | Listing)[] = [];
196+
for (const hash of orderHashes) {
197+
const fetched = await this.context.api.getOrderByHash(
198+
hash,
185199
protocolAddress,
186200
this.context.chain,
187201
);
188-
fetchedOrders.push(order);
202+
fetchedOrders.push(fetched);
189203
}
190204

191205
// Extract OrderComponents from the fetched orders
192-
orderComponents = fetchedOrders.map((order) => {
193-
requireValidProtocol(order.protocolAddress);
194-
effectiveProtocolAddress = order.protocolAddress;
195-
return order.protocolData.parameters;
206+
orderComponents = fetchedOrders.map((fetched) => {
207+
requireValidProtocol(fetched.protocol_address);
208+
effectiveProtocolAddress = fetched.protocol_address;
209+
return fetched.protocol_data.parameters;
196210
});
197211

198-
// Save the first order for event dispatching
199-
firstOrderV2 = fetchedOrders[0];
212+
// Dispatch event for the first fetched order
213+
if (fetchedOrders.length > 0) {
214+
this.context.dispatch(EventType.CancelOrder, {
215+
order: fetchedOrders[0],
216+
accountAddress,
217+
});
218+
}
200219
} else {
201220
// Should never reach here due to earlier validation
202221
throw new Error("Invalid input");
203222
}
204223

205-
// Dispatch event for the first order if available (for backwards compatibility with cancelOrder)
206-
if (firstOrderV2) {
207-
this.context.dispatch(EventType.CancelOrder, {
208-
orderV2: firstOrderV2,
209-
accountAddress,
210-
});
211-
}
212-
213224
// Transact and get the transaction hash
214225
const transactionHash = await this.cancelSeaportOrders({
215226
orders: orderComponents,

src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { BigNumberish } from "ethers";
2+
import type { Offer, Listing } from "./api/types";
23
import type { OrderV2 } from "./orders/types";
34

45
/**
@@ -83,6 +84,10 @@ export interface EventData {
8384
* The {@link OrderV2} object.
8485
*/
8586
orderV2?: OrderV2;
87+
/**
88+
* The order as returned by the API ({@link Offer} or {@link Listing}).
89+
*/
90+
order?: Offer | Listing;
8691
/**
8792
* Array of assets for bulk transfer and batch approval operations.
8893
*/

0 commit comments

Comments
 (0)