Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/sdk/cancellation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ export class CancellationManager {
throw new Error("At least one order hash must be provided")
}

// Cancellation is a single transaction to one Seaport contract, so every
// order must live on the same protocol. Mixing protocol addresses would
// send the others to the wrong contract and silently leave them live.
if (orders) {
const protocols = new Set(
orders
.filter(order => "protocolData" in order)
.map(order => (order as OrderV2).protocolAddress.toLowerCase()),
)
if (protocols.size > 1) {
throw new Error(
"All orders must use the same protocolAddress to be cancelled in one call. " +
"Cancel orders from different protocols separately.",
)
}
}

requireValidProtocol(protocolAddress)

// Check account availability after parameter validation
Expand Down
38 changes: 38 additions & 0 deletions test/sdk/cancelOrders.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { OrderComponents } from "@opensea/seaport-js/lib/types"
import { ethers } from "ethers"
import { describe, expect, test } from "vitest"
import { ALTERNATE_SEAPORT_V1_6_ADDRESS } from "../../src/constants"
import type { OrderV2 } from "../../src/orders/types"
import { DEFAULT_SEAPORT_CONTRACT_ADDRESS } from "../../src/orders/utils"
import { sdk } from "../utils/sdk"
Expand Down Expand Up @@ -84,6 +85,43 @@ describe("SDK: cancelOrders", () => {
}
})

test("Should throw when orders span different protocol addresses", async () => {
const mockOrderComponents: OrderComponents = {
offerer: "0x0000000000000000000000000000000000000001",
zone: "0x0000000000000000000000000000000000000000",
offer: [],
consideration: [],
orderType: 0,
startTime: "0",
endTime: "0",
zoneHash:
"0x0000000000000000000000000000000000000000000000000000000000000000",
salt: "0",
conduitKey:
"0x0000000000000000000000000000000000000000000000000000000000000000",
totalOriginalConsiderationItems: 0,
counter: 0,
}
const makeOrderV2 = (protocolAddress: string) =>
({
protocolData: { parameters: mockOrderComponents },
protocolAddress,
}) as unknown as OrderV2

try {
await sdk.cancelOrders({
orders: [
makeOrderV2(DEFAULT_SEAPORT_CONTRACT_ADDRESS),
makeOrderV2(ALTERNATE_SEAPORT_V1_6_ADDRESS),
],
accountAddress,
})
throw new Error("should have thrown")
} catch (e) {
expect((e as Error).message).toContain("same protocolAddress")
}
})

test("Should attempt to fetch orders from API when using orderHashes", async () => {
try {
await sdk.cancelOrders({
Expand Down