@opensea/sdk 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -0
- package/README.md +70 -0
- package/lib/api/accounts.d.ts +27 -0
- package/lib/api/accounts.js +46 -0
- package/lib/api/accounts.js.map +1 -0
- package/lib/api/api.d.ts +489 -0
- package/lib/api/api.js +754 -0
- package/lib/api/api.js.map +1 -0
- package/lib/api/apiPaths.d.ts +46 -0
- package/lib/api/apiPaths.js +176 -0
- package/lib/api/apiPaths.js.map +1 -0
- package/lib/api/chains.d.ts +13 -0
- package/lib/api/chains.js +22 -0
- package/lib/api/chains.js.map +1 -0
- package/lib/api/collections.d.ts +34 -0
- package/lib/api/collections.js +80 -0
- package/lib/api/collections.js.map +1 -0
- package/lib/api/drops.d.ts +21 -0
- package/lib/api/drops.js +39 -0
- package/lib/api/drops.js.map +1 -0
- package/lib/api/events.d.ts +26 -0
- package/lib/api/events.js +43 -0
- package/lib/api/events.js.map +1 -0
- package/lib/api/fetcher.d.ts +24 -0
- package/lib/api/fetcher.js +3 -0
- package/lib/api/fetcher.js.map +1 -0
- package/lib/api/index.d.ts +2 -0
- package/lib/api/index.js +19 -0
- package/lib/api/index.js.map +1 -0
- package/lib/api/listings.d.ts +44 -0
- package/lib/api/listings.js +88 -0
- package/lib/api/listings.js.map +1 -0
- package/lib/api/nfts.d.ts +39 -0
- package/lib/api/nfts.js +79 -0
- package/lib/api/nfts.js.map +1 -0
- package/lib/api/offers.d.ts +54 -0
- package/lib/api/offers.js +124 -0
- package/lib/api/offers.js.map +1 -0
- package/lib/api/orders.d.ts +50 -0
- package/lib/api/orders.js +153 -0
- package/lib/api/orders.js.map +1 -0
- package/lib/api/search.d.ts +13 -0
- package/lib/api/search.js +22 -0
- package/lib/api/search.js.map +1 -0
- package/lib/api/tokens.d.ts +25 -0
- package/lib/api/tokens.js +43 -0
- package/lib/api/tokens.js.map +1 -0
- package/lib/api/types.d.ts +1113 -0
- package/lib/api/types.js +65 -0
- package/lib/api/types.js.map +1 -0
- package/lib/constants.d.ts +22 -0
- package/lib/constants.js +52 -0
- package/lib/constants.js.map +1 -0
- package/lib/index.d.ts +18 -0
- package/lib/index.js +24 -0
- package/lib/index.js.map +1 -0
- package/lib/orders/privateListings.d.ts +12 -0
- package/lib/orders/privateListings.js +130 -0
- package/lib/orders/privateListings.js.map +1 -0
- package/lib/orders/types.d.ts +160 -0
- package/lib/orders/types.js +10 -0
- package/lib/orders/types.js.map +1 -0
- package/lib/orders/utils.d.ts +89 -0
- package/lib/orders/utils.js +177 -0
- package/lib/orders/utils.js.map +1 -0
- package/lib/sdk/assets.d.ts +104 -0
- package/lib/sdk/assets.js +398 -0
- package/lib/sdk/assets.js.map +1 -0
- package/lib/sdk/cancellation.d.ts +97 -0
- package/lib/sdk/cancellation.js +235 -0
- package/lib/sdk/cancellation.js.map +1 -0
- package/lib/sdk/context.d.ts +28 -0
- package/lib/sdk/context.js +3 -0
- package/lib/sdk/context.js.map +1 -0
- package/lib/sdk/fulfillment.d.ts +153 -0
- package/lib/sdk/fulfillment.js +298 -0
- package/lib/sdk/fulfillment.js.map +1 -0
- package/lib/sdk/orders.d.ts +253 -0
- package/lib/sdk/orders.js +679 -0
- package/lib/sdk/orders.js.map +1 -0
- package/lib/sdk/tokens.d.ts +31 -0
- package/lib/sdk/tokens.js +65 -0
- package/lib/sdk/tokens.js.map +1 -0
- package/lib/sdk.d.ts +560 -0
- package/lib/sdk.js +693 -0
- package/lib/sdk.js.map +1 -0
- package/lib/src/api/accounts.d.ts +18 -0
- package/lib/src/api/accounts.js +30 -0
- package/lib/src/api/accounts.js.map +1 -0
- package/lib/src/api/api.d.ts +429 -0
- package/lib/src/api/api.js +652 -0
- package/lib/src/api/api.js.map +1 -0
- package/lib/src/api/apiPaths.d.ts +37 -0
- package/lib/src/api/apiPaths.js +140 -0
- package/lib/src/api/apiPaths.js.map +1 -0
- package/lib/src/api/collections.d.ts +26 -0
- package/lib/src/api/collections.js +57 -0
- package/lib/src/api/collections.js.map +1 -0
- package/lib/src/api/events.d.ts +26 -0
- package/lib/src/api/events.js +42 -0
- package/lib/src/api/events.js.map +1 -0
- package/lib/src/api/fetcher.d.ts +24 -0
- package/lib/src/api/fetcher.js +3 -0
- package/lib/src/api/fetcher.js.map +1 -0
- package/lib/src/api/index.d.ts +2 -0
- package/lib/src/api/index.js +19 -0
- package/lib/src/api/index.js.map +1 -0
- package/lib/src/api/listings.d.ts +44 -0
- package/lib/src/api/listings.js +86 -0
- package/lib/src/api/listings.js.map +1 -0
- package/lib/src/api/nfts.d.ts +35 -0
- package/lib/src/api/nfts.js +66 -0
- package/lib/src/api/nfts.js.map +1 -0
- package/lib/src/api/offers.d.ts +54 -0
- package/lib/src/api/offers.js +122 -0
- package/lib/src/api/offers.js.map +1 -0
- package/lib/src/api/orders.d.ts +50 -0
- package/lib/src/api/orders.js +151 -0
- package/lib/src/api/orders.js.map +1 -0
- package/lib/src/api/search.d.ts +13 -0
- package/lib/src/api/search.js +21 -0
- package/lib/src/api/search.js.map +1 -0
- package/lib/src/api/tokens.d.ts +25 -0
- package/lib/src/api/tokens.js +42 -0
- package/lib/src/api/tokens.js.map +1 -0
- package/lib/src/api/types.d.ts +840 -0
- package/lib/src/api/types.js +65 -0
- package/lib/src/api/types.js.map +1 -0
- package/lib/src/constants.d.ts +22 -0
- package/lib/src/constants.js +52 -0
- package/lib/src/constants.js.map +1 -0
- package/lib/src/index.d.ts +18 -0
- package/lib/src/index.js +24 -0
- package/lib/src/index.js.map +1 -0
- package/lib/src/orders/privateListings.d.ts +12 -0
- package/lib/src/orders/privateListings.js +130 -0
- package/lib/src/orders/privateListings.js.map +1 -0
- package/lib/src/orders/types.d.ts +160 -0
- package/lib/src/orders/types.js +10 -0
- package/lib/src/orders/types.js.map +1 -0
- package/lib/src/orders/utils.d.ts +89 -0
- package/lib/src/orders/utils.js +177 -0
- package/lib/src/orders/utils.js.map +1 -0
- package/lib/src/sdk/assets.d.ts +104 -0
- package/lib/src/sdk/assets.js +397 -0
- package/lib/src/sdk/assets.js.map +1 -0
- package/lib/src/sdk/cancellation.d.ts +97 -0
- package/lib/src/sdk/cancellation.js +234 -0
- package/lib/src/sdk/cancellation.js.map +1 -0
- package/lib/src/sdk/context.d.ts +28 -0
- package/lib/src/sdk/context.js +3 -0
- package/lib/src/sdk/context.js.map +1 -0
- package/lib/src/sdk/fulfillment.d.ts +153 -0
- package/lib/src/sdk/fulfillment.js +296 -0
- package/lib/src/sdk/fulfillment.js.map +1 -0
- package/lib/src/sdk/orders.d.ts +253 -0
- package/lib/src/sdk/orders.js +677 -0
- package/lib/src/sdk/orders.js.map +1 -0
- package/lib/src/sdk/tokens.d.ts +31 -0
- package/lib/src/sdk/tokens.js +64 -0
- package/lib/src/sdk/tokens.js.map +1 -0
- package/lib/src/sdk.d.ts +560 -0
- package/lib/src/sdk.js +675 -0
- package/lib/src/sdk.js.map +1 -0
- package/lib/src/typechain/contracts/ERC1155.d.ts +236 -0
- package/lib/src/typechain/contracts/ERC1155.js +3 -0
- package/lib/src/typechain/contracts/ERC1155.js.map +1 -0
- package/lib/src/typechain/contracts/ERC20.d.ts +141 -0
- package/lib/src/typechain/contracts/ERC20.js +3 -0
- package/lib/src/typechain/contracts/ERC20.js.map +1 -0
- package/lib/src/typechain/contracts/ERC721.d.ts +213 -0
- package/lib/src/typechain/contracts/ERC721.js +3 -0
- package/lib/src/typechain/contracts/ERC721.js.map +1 -0
- package/lib/src/typechain/contracts/Multicall3.d.ts +57 -0
- package/lib/src/typechain/contracts/Multicall3.js +3 -0
- package/lib/src/typechain/contracts/Multicall3.js.map +1 -0
- package/lib/src/typechain/contracts/TransferHelper.d.ts +55 -0
- package/lib/src/typechain/contracts/TransferHelper.js +3 -0
- package/lib/src/typechain/contracts/TransferHelper.js.map +1 -0
- package/lib/src/typechain/contracts/common.d.ts +50 -0
- package/lib/src/typechain/contracts/common.js +3 -0
- package/lib/src/typechain/contracts/common.js.map +1 -0
- package/lib/src/typechain/contracts/factories/ERC1155__factory.d.ts +250 -0
- package/lib/src/typechain/contracts/factories/ERC1155__factory.js +332 -0
- package/lib/src/typechain/contracts/factories/ERC1155__factory.js.map +1 -0
- package/lib/src/typechain/contracts/factories/ERC20__factory.d.ts +174 -0
- package/lib/src/typechain/contracts/factories/ERC20__factory.js +240 -0
- package/lib/src/typechain/contracts/factories/ERC20__factory.js.map +1 -0
- package/lib/src/typechain/contracts/factories/ERC721__factory.d.ts +268 -0
- package/lib/src/typechain/contracts/factories/ERC721__factory.js +351 -0
- package/lib/src/typechain/contracts/factories/ERC721__factory.js.map +1 -0
- package/lib/src/typechain/contracts/factories/Multicall3__factory.d.ts +43 -0
- package/lib/src/typechain/contracts/factories/Multicall3__factory.js +68 -0
- package/lib/src/typechain/contracts/factories/Multicall3__factory.js.map +1 -0
- package/lib/src/typechain/contracts/factories/TransferHelper__factory.d.ts +46 -0
- package/lib/src/typechain/contracts/factories/TransferHelper__factory.js +71 -0
- package/lib/src/typechain/contracts/factories/TransferHelper__factory.js.map +1 -0
- package/lib/src/typechain/contracts/factories/index.d.ts +5 -0
- package/lib/src/typechain/contracts/factories/index.js +17 -0
- package/lib/src/typechain/contracts/factories/index.js.map +1 -0
- package/lib/src/typechain/contracts/index.d.ts +11 -0
- package/lib/src/typechain/contracts/index.js +48 -0
- package/lib/src/typechain/contracts/index.js.map +1 -0
- package/lib/src/types.d.ts +387 -0
- package/lib/src/types.js +127 -0
- package/lib/src/types.js.map +1 -0
- package/lib/src/utils/chain.d.ts +60 -0
- package/lib/src/utils/chain.js +248 -0
- package/lib/src/utils/chain.js.map +1 -0
- package/lib/src/utils/converters.d.ts +37 -0
- package/lib/src/utils/converters.js +137 -0
- package/lib/src/utils/converters.js.map +1 -0
- package/lib/src/utils/dateHelper.d.ts +38 -0
- package/lib/src/utils/dateHelper.js +52 -0
- package/lib/src/utils/dateHelper.js.map +1 -0
- package/lib/src/utils/fees.d.ts +13 -0
- package/lib/src/utils/fees.js +29 -0
- package/lib/src/utils/fees.js.map +1 -0
- package/lib/src/utils/index.d.ts +2 -0
- package/lib/src/utils/index.js +19 -0
- package/lib/src/utils/index.js.map +1 -0
- package/lib/src/utils/protocol.d.ts +75 -0
- package/lib/src/utils/protocol.js +161 -0
- package/lib/src/utils/protocol.js.map +1 -0
- package/lib/src/utils/rateLimit.d.ts +34 -0
- package/lib/src/utils/rateLimit.js +97 -0
- package/lib/src/utils/rateLimit.js.map +1 -0
- package/lib/src/utils/stringHelper.d.ts +18 -0
- package/lib/src/utils/stringHelper.js +24 -0
- package/lib/src/utils/stringHelper.js.map +1 -0
- package/lib/src/utils/utils.d.ts +18 -0
- package/lib/src/utils/utils.js +45 -0
- package/lib/src/utils/utils.js.map +1 -0
- package/lib/typechain/contracts/ERC1155.d.ts +236 -0
- package/lib/typechain/contracts/ERC1155.js +3 -0
- package/lib/typechain/contracts/ERC1155.js.map +1 -0
- package/lib/typechain/contracts/ERC20.d.ts +141 -0
- package/lib/typechain/contracts/ERC20.js +3 -0
- package/lib/typechain/contracts/ERC20.js.map +1 -0
- package/lib/typechain/contracts/ERC721.d.ts +213 -0
- package/lib/typechain/contracts/ERC721.js +3 -0
- package/lib/typechain/contracts/ERC721.js.map +1 -0
- package/lib/typechain/contracts/Multicall3.d.ts +57 -0
- package/lib/typechain/contracts/Multicall3.js +3 -0
- package/lib/typechain/contracts/Multicall3.js.map +1 -0
- package/lib/typechain/contracts/TransferHelper.d.ts +55 -0
- package/lib/typechain/contracts/TransferHelper.js +3 -0
- package/lib/typechain/contracts/TransferHelper.js.map +1 -0
- package/lib/typechain/contracts/common.d.ts +50 -0
- package/lib/typechain/contracts/common.js +3 -0
- package/lib/typechain/contracts/common.js.map +1 -0
- package/lib/typechain/contracts/factories/ERC1155__factory.d.ts +250 -0
- package/lib/typechain/contracts/factories/ERC1155__factory.js +332 -0
- package/lib/typechain/contracts/factories/ERC1155__factory.js.map +1 -0
- package/lib/typechain/contracts/factories/ERC20__factory.d.ts +174 -0
- package/lib/typechain/contracts/factories/ERC20__factory.js +240 -0
- package/lib/typechain/contracts/factories/ERC20__factory.js.map +1 -0
- package/lib/typechain/contracts/factories/ERC721__factory.d.ts +268 -0
- package/lib/typechain/contracts/factories/ERC721__factory.js +351 -0
- package/lib/typechain/contracts/factories/ERC721__factory.js.map +1 -0
- package/lib/typechain/contracts/factories/Multicall3__factory.d.ts +43 -0
- package/lib/typechain/contracts/factories/Multicall3__factory.js +68 -0
- package/lib/typechain/contracts/factories/Multicall3__factory.js.map +1 -0
- package/lib/typechain/contracts/factories/TransferHelper__factory.d.ts +46 -0
- package/lib/typechain/contracts/factories/TransferHelper__factory.js +71 -0
- package/lib/typechain/contracts/factories/TransferHelper__factory.js.map +1 -0
- package/lib/typechain/contracts/factories/index.d.ts +5 -0
- package/lib/typechain/contracts/factories/index.js +17 -0
- package/lib/typechain/contracts/factories/index.js.map +1 -0
- package/lib/typechain/contracts/index.d.ts +11 -0
- package/lib/typechain/contracts/index.js +48 -0
- package/lib/typechain/contracts/index.js.map +1 -0
- package/lib/types.d.ts +389 -0
- package/lib/types.js +129 -0
- package/lib/types.js.map +1 -0
- package/lib/utils/chain.d.ts +64 -0
- package/lib/utils/chain.js +211 -0
- package/lib/utils/chain.js.map +1 -0
- package/lib/utils/chainIds.generated.d.ts +7 -0
- package/lib/utils/chainIds.generated.js +37 -0
- package/lib/utils/chainIds.generated.js.map +1 -0
- package/lib/utils/converters.d.ts +37 -0
- package/lib/utils/converters.js +137 -0
- package/lib/utils/converters.js.map +1 -0
- package/lib/utils/dateHelper.d.ts +38 -0
- package/lib/utils/dateHelper.js +52 -0
- package/lib/utils/dateHelper.js.map +1 -0
- package/lib/utils/fees.d.ts +13 -0
- package/lib/utils/fees.js +29 -0
- package/lib/utils/fees.js.map +1 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.js +19 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/protocol.d.ts +75 -0
- package/lib/utils/protocol.js +161 -0
- package/lib/utils/protocol.js.map +1 -0
- package/lib/utils/rateLimit.d.ts +34 -0
- package/lib/utils/rateLimit.js +97 -0
- package/lib/utils/rateLimit.js.map +1 -0
- package/lib/utils/stringHelper.d.ts +18 -0
- package/lib/utils/stringHelper.js +24 -0
- package/lib/utils/stringHelper.js.map +1 -0
- package/lib/utils/utils.d.ts +18 -0
- package/lib/utils/utils.js +45 -0
- package/lib/utils/utils.js.map +1 -0
- package/package.json +72 -0
- package/src/abi/ERC1155.json +314 -0
- package/src/abi/ERC20.json +222 -0
- package/src/abi/ERC721.json +333 -0
- package/src/abi/Multicall3.json +50 -0
- package/src/abi/TransferHelper.json +53 -0
- package/src/api/accounts.ts +69 -0
- package/src/api/api.ts +1152 -0
- package/src/api/apiPaths.ts +208 -0
- package/src/api/chains.ts +18 -0
- package/src/api/collections.ts +120 -0
- package/src/api/drops.ts +49 -0
- package/src/api/events.ts +71 -0
- package/src/api/fetcher.ts +31 -0
- package/src/api/index.ts +2 -0
- package/src/api/listings.ts +126 -0
- package/src/api/nfts.ts +144 -0
- package/src/api/offers.ts +242 -0
- package/src/api/orders.ts +283 -0
- package/src/api/search.ts +21 -0
- package/src/api/tokens.ts +67 -0
- package/src/api/types.ts +1210 -0
- package/src/constants.ts +90 -0
- package/src/index.ts +22 -0
- package/src/orders/privateListings.ts +173 -0
- package/src/orders/types.ts +191 -0
- package/src/orders/utils.ts +253 -0
- package/src/sdk/assets.ts +591 -0
- package/src/sdk/cancellation.ts +346 -0
- package/src/sdk/context.ts +33 -0
- package/src/sdk/fulfillment.ts +478 -0
- package/src/sdk/orders.ts +1149 -0
- package/src/sdk/tokens.ts +95 -0
- package/src/sdk.ts +1051 -0
- package/src/typechain/contracts/ERC1155.ts +440 -0
- package/src/typechain/contracts/ERC20.ts +286 -0
- package/src/typechain/contracts/ERC721.ts +412 -0
- package/src/typechain/contracts/Multicall3.ts +117 -0
- package/src/typechain/contracts/TransferHelper.ts +122 -0
- package/src/typechain/contracts/common.ts +131 -0
- package/src/typechain/contracts/factories/ERC1155__factory.ts +331 -0
- package/src/typechain/contracts/factories/ERC20__factory.ts +239 -0
- package/src/typechain/contracts/factories/ERC721__factory.ts +350 -0
- package/src/typechain/contracts/factories/Multicall3__factory.ts +67 -0
- package/src/typechain/contracts/factories/TransferHelper__factory.ts +76 -0
- package/src/typechain/contracts/factories/index.ts +8 -0
- package/src/typechain/contracts/index.ts +14 -0
- package/src/types.ts +413 -0
- package/src/utils/chain.ts +224 -0
- package/src/utils/chainIds.generated.ts +34 -0
- package/src/utils/converters.ts +145 -0
- package/src/utils/dateHelper.ts +48 -0
- package/src/utils/fees.ts +31 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/protocol.ts +185 -0
- package/src/utils/rateLimit.ts +147 -0
- package/src/utils/stringHelper.ts +25 -0
- package/src/utils/utils.ts +36 -0
|
@@ -0,0 +1,1149 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ConsiderationInputItem,
|
|
3
|
+
CreateInputItem,
|
|
4
|
+
OrderComponents,
|
|
5
|
+
} from "@opensea/seaport-js/lib/types"
|
|
6
|
+
import { type BigNumberish, ZeroAddress } from "ethers"
|
|
7
|
+
import type { CollectionOffer, NFT } from "../api/types"
|
|
8
|
+
import { INVERSE_BASIS_POINT } from "../constants"
|
|
9
|
+
import type { OrderV2, ProtocolData } from "../orders/types"
|
|
10
|
+
import {
|
|
11
|
+
type AssetWithTokenId,
|
|
12
|
+
type Fee,
|
|
13
|
+
type OpenSeaCollection,
|
|
14
|
+
OrderSide,
|
|
15
|
+
type TokenStandard,
|
|
16
|
+
} from "../types"
|
|
17
|
+
import { oneMonthFromNowInSeconds } from "../utils/dateHelper"
|
|
18
|
+
import { pluralize } from "../utils/stringHelper"
|
|
19
|
+
import {
|
|
20
|
+
basisPointsForFee,
|
|
21
|
+
getAssetItemType,
|
|
22
|
+
getFeeRecipient,
|
|
23
|
+
getListingPaymentToken,
|
|
24
|
+
getOfferPaymentToken,
|
|
25
|
+
getSignedZone,
|
|
26
|
+
remapSharedStorefrontAddress,
|
|
27
|
+
totalBasisPointsForFees,
|
|
28
|
+
} from "../utils/utils"
|
|
29
|
+
import type { SDKContext } from "./context"
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Result type for bulk operations that may partially succeed.
|
|
33
|
+
* Contains successfully submitted orders and any failures with error information.
|
|
34
|
+
*/
|
|
35
|
+
export interface BulkOrderResult {
|
|
36
|
+
/** Successfully submitted orders */
|
|
37
|
+
successful: OrderV2[]
|
|
38
|
+
/** Failed order submissions with error information */
|
|
39
|
+
failed: Array<{
|
|
40
|
+
/** Index of the failed order in the original input array */
|
|
41
|
+
index: number
|
|
42
|
+
/** The signed order that failed to submit (undefined if order creation failed before signing) */
|
|
43
|
+
order?: ProtocolData
|
|
44
|
+
/** The error that occurred during submission */
|
|
45
|
+
error: Error
|
|
46
|
+
}>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Manager for order building and creation operations.
|
|
51
|
+
* Handles listing creation, offer creation, and collection offers.
|
|
52
|
+
*/
|
|
53
|
+
export class OrdersManager {
|
|
54
|
+
constructor(
|
|
55
|
+
private context: SDKContext,
|
|
56
|
+
private getPriceParametersCallback: (
|
|
57
|
+
orderSide: OrderSide,
|
|
58
|
+
tokenAddress: string,
|
|
59
|
+
amount: BigNumberish,
|
|
60
|
+
) => Promise<{ basePrice: bigint }>,
|
|
61
|
+
) {}
|
|
62
|
+
|
|
63
|
+
private getAmountWithBasisPointsApplied(
|
|
64
|
+
amount: bigint,
|
|
65
|
+
basisPoints: bigint,
|
|
66
|
+
): string {
|
|
67
|
+
return ((amount * basisPoints) / INVERSE_BASIS_POINT).toString()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private isNotMarketplaceFee(fee: Fee): boolean {
|
|
71
|
+
return (
|
|
72
|
+
fee.recipient.toLowerCase() !==
|
|
73
|
+
getFeeRecipient(this.context.chain).toLowerCase()
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private getNFTItems(
|
|
78
|
+
nfts: NFT[],
|
|
79
|
+
quantities: bigint[] = [],
|
|
80
|
+
): CreateInputItem[] {
|
|
81
|
+
return nfts.map((nft, index) => ({
|
|
82
|
+
itemType: getAssetItemType(
|
|
83
|
+
nft.token_standard.toUpperCase() as TokenStandard,
|
|
84
|
+
),
|
|
85
|
+
token: remapSharedStorefrontAddress(nft.contract),
|
|
86
|
+
identifier: nft.identifier ?? undefined,
|
|
87
|
+
amount: quantities[index]?.toString() ?? "1",
|
|
88
|
+
}))
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private async getFees({
|
|
92
|
+
collection,
|
|
93
|
+
seller,
|
|
94
|
+
paymentTokenAddress,
|
|
95
|
+
amount,
|
|
96
|
+
includeOptionalCreatorFees = false,
|
|
97
|
+
isPrivateListing = false,
|
|
98
|
+
}: {
|
|
99
|
+
collection: OpenSeaCollection
|
|
100
|
+
seller?: string
|
|
101
|
+
paymentTokenAddress: string
|
|
102
|
+
amount: bigint
|
|
103
|
+
includeOptionalCreatorFees?: boolean
|
|
104
|
+
isPrivateListing?: boolean
|
|
105
|
+
}): Promise<ConsiderationInputItem[]> {
|
|
106
|
+
let collectionFees = includeOptionalCreatorFees
|
|
107
|
+
? collection.fees
|
|
108
|
+
: collection.fees.filter(fee => fee.required)
|
|
109
|
+
if (isPrivateListing) {
|
|
110
|
+
collectionFees = collectionFees.filter(fee =>
|
|
111
|
+
this.isNotMarketplaceFee(fee),
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
const collectionFeesBasisPoints = totalBasisPointsForFees(collectionFees)
|
|
115
|
+
const sellerBasisPoints = INVERSE_BASIS_POINT - collectionFeesBasisPoints
|
|
116
|
+
|
|
117
|
+
const getConsiderationItem = (basisPoints: bigint, recipient?: string) => {
|
|
118
|
+
return {
|
|
119
|
+
token: paymentTokenAddress,
|
|
120
|
+
amount: this.getAmountWithBasisPointsApplied(amount, basisPoints),
|
|
121
|
+
recipient,
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const considerationItems: ConsiderationInputItem[] = []
|
|
126
|
+
|
|
127
|
+
if (seller) {
|
|
128
|
+
considerationItems.push(getConsiderationItem(sellerBasisPoints, seller))
|
|
129
|
+
}
|
|
130
|
+
if (collectionFeesBasisPoints > 0) {
|
|
131
|
+
for (const fee of collectionFees) {
|
|
132
|
+
considerationItems.push(
|
|
133
|
+
getConsiderationItem(basisPointsForFee(fee), fee.recipient),
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return considerationItems
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Build listing order without submitting to API
|
|
142
|
+
* @param options Listing parameters
|
|
143
|
+
* @returns OrderWithCounter ready for API submission or onchain validation
|
|
144
|
+
*/
|
|
145
|
+
private async _buildListingOrder({
|
|
146
|
+
asset,
|
|
147
|
+
accountAddress,
|
|
148
|
+
amount,
|
|
149
|
+
quantity = 1,
|
|
150
|
+
domain,
|
|
151
|
+
salt,
|
|
152
|
+
listingTime,
|
|
153
|
+
expirationTime,
|
|
154
|
+
buyerAddress,
|
|
155
|
+
includeOptionalCreatorFees = false,
|
|
156
|
+
zone = ZeroAddress,
|
|
157
|
+
}: {
|
|
158
|
+
asset: AssetWithTokenId
|
|
159
|
+
accountAddress: string
|
|
160
|
+
amount: BigNumberish
|
|
161
|
+
quantity?: BigNumberish
|
|
162
|
+
domain?: string
|
|
163
|
+
salt?: BigNumberish
|
|
164
|
+
listingTime?: number
|
|
165
|
+
expirationTime?: number
|
|
166
|
+
buyerAddress?: string
|
|
167
|
+
includeOptionalCreatorFees?: boolean
|
|
168
|
+
zone?: string
|
|
169
|
+
}) {
|
|
170
|
+
await this.context.requireAccountIsAvailable(accountAddress)
|
|
171
|
+
|
|
172
|
+
const { nft } = await this.context.api.getNFT(
|
|
173
|
+
asset.tokenAddress,
|
|
174
|
+
asset.tokenId,
|
|
175
|
+
)
|
|
176
|
+
const offerAssetItems = this.getNFTItems([nft], [BigInt(quantity ?? 1)])
|
|
177
|
+
|
|
178
|
+
const collection = await this.context.api.getCollection(nft.collection)
|
|
179
|
+
|
|
180
|
+
const paymentTokenAddress =
|
|
181
|
+
collection.pricingCurrencies?.listingCurrency?.address ??
|
|
182
|
+
getListingPaymentToken(this.context.chain)
|
|
183
|
+
|
|
184
|
+
const { basePrice } = await this.getPriceParametersCallback(
|
|
185
|
+
OrderSide.LISTING,
|
|
186
|
+
paymentTokenAddress,
|
|
187
|
+
amount,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
const considerationFeeItems = await this.getFees({
|
|
191
|
+
collection,
|
|
192
|
+
seller: accountAddress,
|
|
193
|
+
paymentTokenAddress,
|
|
194
|
+
amount: basePrice,
|
|
195
|
+
includeOptionalCreatorFees,
|
|
196
|
+
isPrivateListing: !!buyerAddress,
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
if (buyerAddress) {
|
|
200
|
+
const { getPrivateListingConsiderations } = await import(
|
|
201
|
+
"../orders/privateListings"
|
|
202
|
+
)
|
|
203
|
+
considerationFeeItems.push(
|
|
204
|
+
...getPrivateListingConsiderations(offerAssetItems, buyerAddress),
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (collection.requiredZone) {
|
|
209
|
+
zone = collection.requiredZone
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const { executeAllActions } = await this.context.seaport.createOrder(
|
|
213
|
+
{
|
|
214
|
+
offer: offerAssetItems,
|
|
215
|
+
consideration: considerationFeeItems,
|
|
216
|
+
startTime: listingTime?.toString(),
|
|
217
|
+
endTime:
|
|
218
|
+
expirationTime?.toString() ?? oneMonthFromNowInSeconds().toString(),
|
|
219
|
+
zone,
|
|
220
|
+
domain,
|
|
221
|
+
salt: BigInt(salt ?? 0).toString(),
|
|
222
|
+
restrictedByZone: zone !== ZeroAddress,
|
|
223
|
+
allowPartialFills: true,
|
|
224
|
+
},
|
|
225
|
+
accountAddress,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
return executeAllActions()
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Build listing order components without submitting to API
|
|
233
|
+
* @param options Listing parameters
|
|
234
|
+
* @returns OrderComponents ready for onchain validation
|
|
235
|
+
*/
|
|
236
|
+
async buildListingOrderComponents({
|
|
237
|
+
asset,
|
|
238
|
+
accountAddress,
|
|
239
|
+
amount,
|
|
240
|
+
quantity = 1,
|
|
241
|
+
domain,
|
|
242
|
+
salt,
|
|
243
|
+
listingTime,
|
|
244
|
+
expirationTime,
|
|
245
|
+
buyerAddress,
|
|
246
|
+
includeOptionalCreatorFees = false,
|
|
247
|
+
zone = ZeroAddress,
|
|
248
|
+
}: {
|
|
249
|
+
asset: AssetWithTokenId
|
|
250
|
+
accountAddress: string
|
|
251
|
+
amount: BigNumberish
|
|
252
|
+
quantity?: BigNumberish
|
|
253
|
+
domain?: string
|
|
254
|
+
salt?: BigNumberish
|
|
255
|
+
listingTime?: number
|
|
256
|
+
expirationTime?: number
|
|
257
|
+
buyerAddress?: string
|
|
258
|
+
includeOptionalCreatorFees?: boolean
|
|
259
|
+
zone?: string
|
|
260
|
+
}): Promise<OrderComponents> {
|
|
261
|
+
const order = await this._buildListingOrder({
|
|
262
|
+
asset,
|
|
263
|
+
accountAddress,
|
|
264
|
+
amount,
|
|
265
|
+
quantity,
|
|
266
|
+
domain,
|
|
267
|
+
salt,
|
|
268
|
+
listingTime,
|
|
269
|
+
expirationTime,
|
|
270
|
+
buyerAddress,
|
|
271
|
+
includeOptionalCreatorFees,
|
|
272
|
+
zone,
|
|
273
|
+
})
|
|
274
|
+
return order.parameters
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Build offer order without submitting to API
|
|
279
|
+
* @param options Offer parameters
|
|
280
|
+
* @returns OrderWithCounter ready for API submission or onchain validation
|
|
281
|
+
*/
|
|
282
|
+
private async _buildOfferOrder({
|
|
283
|
+
asset,
|
|
284
|
+
accountAddress,
|
|
285
|
+
amount,
|
|
286
|
+
quantity = 1,
|
|
287
|
+
domain,
|
|
288
|
+
salt,
|
|
289
|
+
expirationTime,
|
|
290
|
+
zone = getSignedZone(this.context.chain),
|
|
291
|
+
}: {
|
|
292
|
+
asset: AssetWithTokenId
|
|
293
|
+
accountAddress: string
|
|
294
|
+
amount: BigNumberish
|
|
295
|
+
quantity?: BigNumberish
|
|
296
|
+
domain?: string
|
|
297
|
+
salt?: BigNumberish
|
|
298
|
+
expirationTime?: BigNumberish
|
|
299
|
+
zone?: string
|
|
300
|
+
}) {
|
|
301
|
+
await this.context.requireAccountIsAvailable(accountAddress)
|
|
302
|
+
|
|
303
|
+
const { nft } = await this.context.api.getNFT(
|
|
304
|
+
asset.tokenAddress,
|
|
305
|
+
asset.tokenId,
|
|
306
|
+
)
|
|
307
|
+
const considerationAssetItems = this.getNFTItems(
|
|
308
|
+
[nft],
|
|
309
|
+
[BigInt(quantity ?? 1)],
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
const collection = await this.context.api.getCollection(nft.collection)
|
|
313
|
+
|
|
314
|
+
const paymentTokenAddress =
|
|
315
|
+
collection.pricingCurrencies?.offerCurrency?.address ??
|
|
316
|
+
getOfferPaymentToken(this.context.chain)
|
|
317
|
+
|
|
318
|
+
const { basePrice } = await this.getPriceParametersCallback(
|
|
319
|
+
OrderSide.OFFER,
|
|
320
|
+
paymentTokenAddress,
|
|
321
|
+
amount,
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
const considerationFeeItems = await this.getFees({
|
|
325
|
+
collection,
|
|
326
|
+
paymentTokenAddress,
|
|
327
|
+
amount: basePrice,
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
if (collection.requiredZone) {
|
|
331
|
+
zone = collection.requiredZone
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const { executeAllActions } = await this.context.seaport.createOrder(
|
|
335
|
+
{
|
|
336
|
+
offer: [
|
|
337
|
+
{
|
|
338
|
+
token: paymentTokenAddress,
|
|
339
|
+
amount: basePrice.toString(),
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
consideration: [...considerationAssetItems, ...considerationFeeItems],
|
|
343
|
+
endTime:
|
|
344
|
+
expirationTime !== undefined
|
|
345
|
+
? BigInt(expirationTime).toString()
|
|
346
|
+
: oneMonthFromNowInSeconds().toString(),
|
|
347
|
+
zone,
|
|
348
|
+
domain,
|
|
349
|
+
salt: BigInt(salt ?? 0).toString(),
|
|
350
|
+
restrictedByZone: zone !== ZeroAddress,
|
|
351
|
+
allowPartialFills: true,
|
|
352
|
+
},
|
|
353
|
+
accountAddress,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
return executeAllActions()
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Build offer order components without submitting to API
|
|
361
|
+
* @param options Offer parameters
|
|
362
|
+
* @returns OrderComponents ready for onchain validation
|
|
363
|
+
*/
|
|
364
|
+
async buildOfferOrderComponents({
|
|
365
|
+
asset,
|
|
366
|
+
accountAddress,
|
|
367
|
+
amount,
|
|
368
|
+
quantity = 1,
|
|
369
|
+
domain,
|
|
370
|
+
salt,
|
|
371
|
+
expirationTime,
|
|
372
|
+
zone = getSignedZone(this.context.chain),
|
|
373
|
+
}: {
|
|
374
|
+
asset: AssetWithTokenId
|
|
375
|
+
accountAddress: string
|
|
376
|
+
amount: BigNumberish
|
|
377
|
+
quantity?: BigNumberish
|
|
378
|
+
domain?: string
|
|
379
|
+
salt?: BigNumberish
|
|
380
|
+
expirationTime?: BigNumberish
|
|
381
|
+
zone?: string
|
|
382
|
+
}): Promise<OrderComponents> {
|
|
383
|
+
const order = await this._buildOfferOrder({
|
|
384
|
+
asset,
|
|
385
|
+
accountAddress,
|
|
386
|
+
amount,
|
|
387
|
+
quantity,
|
|
388
|
+
domain,
|
|
389
|
+
salt,
|
|
390
|
+
expirationTime,
|
|
391
|
+
zone,
|
|
392
|
+
})
|
|
393
|
+
return order.parameters
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Create and submit an offer on an asset.
|
|
398
|
+
* @param options
|
|
399
|
+
* @param options.asset The asset to trade. tokenAddress and tokenId must be defined.
|
|
400
|
+
* @param options.accountAddress Address of the wallet making the offer.
|
|
401
|
+
* @param options.amount Amount in decimal format (e.g., "1.5" for 1.5 ETH, not wei). Automatically converted to base units.
|
|
402
|
+
* @param options.quantity Number of assets to bid for. Defaults to 1.
|
|
403
|
+
* @param options.domain Optional domain for onchain attribution. Hashed and included in salt.
|
|
404
|
+
* @param options.salt Arbitrary salt. Auto-generated if not provided.
|
|
405
|
+
* @param options.expirationTime Expiration time for the order, in UTC seconds
|
|
406
|
+
* @param options.zone Zone for order protection. Defaults to chain's signed zone.
|
|
407
|
+
*
|
|
408
|
+
* @returns The {@link OrderV2} that was created.
|
|
409
|
+
*
|
|
410
|
+
* @throws Error if the asset does not contain a token id.
|
|
411
|
+
* @throws Error if the accountAddress is not available through wallet or provider.
|
|
412
|
+
* @throws Error if the amount is not greater than 0.
|
|
413
|
+
*/
|
|
414
|
+
async createOffer({
|
|
415
|
+
asset,
|
|
416
|
+
accountAddress,
|
|
417
|
+
amount,
|
|
418
|
+
quantity = 1,
|
|
419
|
+
domain,
|
|
420
|
+
salt,
|
|
421
|
+
expirationTime,
|
|
422
|
+
zone = getSignedZone(this.context.chain),
|
|
423
|
+
}: {
|
|
424
|
+
asset: AssetWithTokenId
|
|
425
|
+
accountAddress: string
|
|
426
|
+
amount: BigNumberish
|
|
427
|
+
quantity?: BigNumberish
|
|
428
|
+
domain?: string
|
|
429
|
+
salt?: BigNumberish
|
|
430
|
+
expirationTime?: BigNumberish
|
|
431
|
+
zone?: string
|
|
432
|
+
}): Promise<OrderV2> {
|
|
433
|
+
const order = await this._buildOfferOrder({
|
|
434
|
+
asset,
|
|
435
|
+
accountAddress,
|
|
436
|
+
amount,
|
|
437
|
+
quantity,
|
|
438
|
+
domain,
|
|
439
|
+
salt,
|
|
440
|
+
expirationTime,
|
|
441
|
+
zone,
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
return this.context.api.postOrder(order, {
|
|
445
|
+
protocol: "seaport",
|
|
446
|
+
protocolAddress: this.context.seaport.contract.target as string,
|
|
447
|
+
side: OrderSide.OFFER,
|
|
448
|
+
})
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Create and submit a listing for an asset.
|
|
453
|
+
* @param options
|
|
454
|
+
* @param options.asset The asset to trade. tokenAddress and tokenId must be defined.
|
|
455
|
+
* @param options.accountAddress Address of the wallet making the listing
|
|
456
|
+
* @param options.amount Amount in decimal format (e.g., "1.5" for 1.5 ETH, not wei). Automatically converted to base units.
|
|
457
|
+
* @param options.quantity Number of assets to list. Defaults to 1.
|
|
458
|
+
* @param options.domain Optional domain for onchain attribution. Hashed and included in salt. This can be used for onchain order attribution to assist with analytics.
|
|
459
|
+
* @param options.salt Arbitrary salt. Auto-generated if not provided.
|
|
460
|
+
* @param options.listingTime Optional time when the order will become fulfillable, in UTC seconds. Undefined means it will start now.
|
|
461
|
+
* @param options.expirationTime Expiration time for the order, in UTC seconds.
|
|
462
|
+
* @param options.buyerAddress Optional address that's allowed to purchase this item. If specified, no other address will be able to take the order, unless its value is the null address.
|
|
463
|
+
* @param options.includeOptionalCreatorFees If true, optional creator fees will be included in the listing. Default: false.
|
|
464
|
+
* @param options.zone Zone for order protection. Defaults to no zone.
|
|
465
|
+
* @returns The {@link OrderV2} that was created.
|
|
466
|
+
*
|
|
467
|
+
* @throws Error if the asset does not contain a token id.
|
|
468
|
+
* @throws Error if the accountAddress is not available through wallet or provider.
|
|
469
|
+
* @throws Error if the amount is not greater than 0.
|
|
470
|
+
*/
|
|
471
|
+
async createListing({
|
|
472
|
+
asset,
|
|
473
|
+
accountAddress,
|
|
474
|
+
amount,
|
|
475
|
+
quantity = 1,
|
|
476
|
+
domain,
|
|
477
|
+
salt,
|
|
478
|
+
listingTime,
|
|
479
|
+
expirationTime,
|
|
480
|
+
buyerAddress,
|
|
481
|
+
includeOptionalCreatorFees = false,
|
|
482
|
+
zone = ZeroAddress,
|
|
483
|
+
}: {
|
|
484
|
+
asset: AssetWithTokenId
|
|
485
|
+
accountAddress: string
|
|
486
|
+
amount: BigNumberish
|
|
487
|
+
quantity?: BigNumberish
|
|
488
|
+
domain?: string
|
|
489
|
+
salt?: BigNumberish
|
|
490
|
+
listingTime?: number
|
|
491
|
+
expirationTime?: number
|
|
492
|
+
buyerAddress?: string
|
|
493
|
+
includeOptionalCreatorFees?: boolean
|
|
494
|
+
zone?: string
|
|
495
|
+
}): Promise<OrderV2> {
|
|
496
|
+
const order = await this._buildListingOrder({
|
|
497
|
+
asset,
|
|
498
|
+
accountAddress,
|
|
499
|
+
amount,
|
|
500
|
+
quantity,
|
|
501
|
+
domain,
|
|
502
|
+
salt,
|
|
503
|
+
listingTime,
|
|
504
|
+
expirationTime,
|
|
505
|
+
buyerAddress,
|
|
506
|
+
includeOptionalCreatorFees,
|
|
507
|
+
zone,
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
return this.context.api.postOrder(order, {
|
|
511
|
+
protocol: "seaport",
|
|
512
|
+
protocolAddress: this.context.seaport.contract.target as string,
|
|
513
|
+
side: OrderSide.LISTING,
|
|
514
|
+
})
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Create and submit multiple listings using Seaport's bulk order creation.
|
|
519
|
+
* This method uses a single signature for all listings and submits them individually to the OpenSea API with rate limit handling.
|
|
520
|
+
* All listings must be from the same account address.
|
|
521
|
+
*
|
|
522
|
+
* Note: If only one listing is provided, this method will use a normal order signature instead of a bulk signature,
|
|
523
|
+
* as bulk signatures are more expensive to decode onchain due to the merkle proof verification.
|
|
524
|
+
*
|
|
525
|
+
* @param options
|
|
526
|
+
* @param options.listings Array of listing parameters. Each listing requires asset, amount, and optionally other listing parameters.
|
|
527
|
+
* @param options.accountAddress Address of the wallet making the listings
|
|
528
|
+
* @param options.continueOnError If true, continue submitting remaining listings even if some fail. Default: false (throw on first error).
|
|
529
|
+
* @param options.onProgress Optional callback for progress updates. Called after each listing is submitted (successfully or not).
|
|
530
|
+
* @returns {@link BulkOrderResult} containing successful orders and any failures.
|
|
531
|
+
*
|
|
532
|
+
* @throws Error if listings array is empty
|
|
533
|
+
* @throws Error if the accountAddress is not available through wallet or provider.
|
|
534
|
+
* @throws Error if any asset does not contain a token id.
|
|
535
|
+
* @throws Error if continueOnError is false and any submission fails.
|
|
536
|
+
*/
|
|
537
|
+
async createBulkListings({
|
|
538
|
+
listings,
|
|
539
|
+
accountAddress,
|
|
540
|
+
continueOnError = false,
|
|
541
|
+
onProgress,
|
|
542
|
+
}: {
|
|
543
|
+
listings: Array<{
|
|
544
|
+
asset: AssetWithTokenId
|
|
545
|
+
amount: BigNumberish
|
|
546
|
+
quantity?: BigNumberish
|
|
547
|
+
domain?: string
|
|
548
|
+
salt?: BigNumberish
|
|
549
|
+
listingTime?: number
|
|
550
|
+
expirationTime?: number
|
|
551
|
+
buyerAddress?: string
|
|
552
|
+
includeOptionalCreatorFees?: boolean
|
|
553
|
+
zone?: string
|
|
554
|
+
}>
|
|
555
|
+
accountAddress: string
|
|
556
|
+
continueOnError?: boolean
|
|
557
|
+
onProgress?: (completed: number, total: number) => void
|
|
558
|
+
}): Promise<BulkOrderResult> {
|
|
559
|
+
if (listings.length === 0) {
|
|
560
|
+
throw new Error("Listings array cannot be empty")
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// If only one listing, use normal signature to avoid bulk signature overhead
|
|
564
|
+
if (listings.length === 1) {
|
|
565
|
+
try {
|
|
566
|
+
const order = await this.createListing({
|
|
567
|
+
...listings[0],
|
|
568
|
+
accountAddress,
|
|
569
|
+
})
|
|
570
|
+
return {
|
|
571
|
+
successful: [order],
|
|
572
|
+
failed: [],
|
|
573
|
+
}
|
|
574
|
+
} catch (error) {
|
|
575
|
+
if (continueOnError) {
|
|
576
|
+
return {
|
|
577
|
+
successful: [],
|
|
578
|
+
failed: [
|
|
579
|
+
{
|
|
580
|
+
index: 0,
|
|
581
|
+
order: {} as ProtocolData, // Order wasn't created
|
|
582
|
+
error: error as Error,
|
|
583
|
+
},
|
|
584
|
+
],
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
throw error
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
await this.context.requireAccountIsAvailable(accountAddress)
|
|
592
|
+
|
|
593
|
+
// Build metadata array for each listing
|
|
594
|
+
const listingMetadata: Array<{
|
|
595
|
+
nft: NFT
|
|
596
|
+
collection: OpenSeaCollection
|
|
597
|
+
paymentTokenAddress: string
|
|
598
|
+
zone: string
|
|
599
|
+
domain?: string
|
|
600
|
+
salt?: BigNumberish
|
|
601
|
+
listingTime?: number
|
|
602
|
+
expirationTime?: number
|
|
603
|
+
}> = []
|
|
604
|
+
|
|
605
|
+
// Build all order inputs
|
|
606
|
+
for (const listing of listings) {
|
|
607
|
+
const {
|
|
608
|
+
asset,
|
|
609
|
+
amount,
|
|
610
|
+
quantity = 1,
|
|
611
|
+
domain,
|
|
612
|
+
salt,
|
|
613
|
+
listingTime,
|
|
614
|
+
expirationTime,
|
|
615
|
+
buyerAddress,
|
|
616
|
+
includeOptionalCreatorFees = false,
|
|
617
|
+
zone = ZeroAddress,
|
|
618
|
+
} = listing
|
|
619
|
+
|
|
620
|
+
// Fetch NFT and collection data
|
|
621
|
+
const { nft } = await this.context.api.getNFT(
|
|
622
|
+
asset.tokenAddress,
|
|
623
|
+
asset.tokenId,
|
|
624
|
+
)
|
|
625
|
+
const collection = await this.context.api.getCollection(nft.collection)
|
|
626
|
+
|
|
627
|
+
const paymentTokenAddress =
|
|
628
|
+
collection.pricingCurrencies?.listingCurrency?.address ??
|
|
629
|
+
getListingPaymentToken(this.context.chain)
|
|
630
|
+
|
|
631
|
+
const offerAssetItems = this.getNFTItems([nft], [BigInt(quantity ?? 1)])
|
|
632
|
+
|
|
633
|
+
const { basePrice } = await this.getPriceParametersCallback(
|
|
634
|
+
OrderSide.LISTING,
|
|
635
|
+
paymentTokenAddress,
|
|
636
|
+
amount,
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
const considerationFeeItems = await this.getFees({
|
|
640
|
+
collection,
|
|
641
|
+
seller: accountAddress,
|
|
642
|
+
paymentTokenAddress,
|
|
643
|
+
amount: basePrice,
|
|
644
|
+
includeOptionalCreatorFees,
|
|
645
|
+
isPrivateListing: !!buyerAddress,
|
|
646
|
+
})
|
|
647
|
+
|
|
648
|
+
if (buyerAddress) {
|
|
649
|
+
const { getPrivateListingConsiderations } = await import(
|
|
650
|
+
"../orders/privateListings"
|
|
651
|
+
)
|
|
652
|
+
considerationFeeItems.push(
|
|
653
|
+
...getPrivateListingConsiderations(offerAssetItems, buyerAddress),
|
|
654
|
+
)
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
let finalZone = zone
|
|
658
|
+
if (collection.requiredZone) {
|
|
659
|
+
finalZone = collection.requiredZone
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
listingMetadata.push({
|
|
663
|
+
nft,
|
|
664
|
+
collection,
|
|
665
|
+
paymentTokenAddress,
|
|
666
|
+
zone: finalZone,
|
|
667
|
+
domain,
|
|
668
|
+
salt,
|
|
669
|
+
listingTime,
|
|
670
|
+
expirationTime,
|
|
671
|
+
})
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Create the bulk orders using seaport's createBulkOrders method
|
|
675
|
+
const createOrderInputsForSeaport = listings.map((listing, index) => {
|
|
676
|
+
const {
|
|
677
|
+
amount,
|
|
678
|
+
quantity = 1,
|
|
679
|
+
listingTime,
|
|
680
|
+
expirationTime,
|
|
681
|
+
buyerAddress,
|
|
682
|
+
includeOptionalCreatorFees = false,
|
|
683
|
+
} = listing
|
|
684
|
+
|
|
685
|
+
const metadata = listingMetadata[index]
|
|
686
|
+
const offerAssetItems = this.getNFTItems(
|
|
687
|
+
[metadata.nft],
|
|
688
|
+
[BigInt(quantity ?? 1)],
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
return this.getPriceParametersCallback(
|
|
692
|
+
OrderSide.LISTING,
|
|
693
|
+
metadata.paymentTokenAddress,
|
|
694
|
+
amount,
|
|
695
|
+
).then(async ({ basePrice }) => {
|
|
696
|
+
const considerationFeeItems = await this.getFees({
|
|
697
|
+
collection: metadata.collection,
|
|
698
|
+
seller: accountAddress,
|
|
699
|
+
paymentTokenAddress: metadata.paymentTokenAddress,
|
|
700
|
+
amount: basePrice,
|
|
701
|
+
includeOptionalCreatorFees,
|
|
702
|
+
isPrivateListing: !!buyerAddress,
|
|
703
|
+
})
|
|
704
|
+
|
|
705
|
+
if (buyerAddress) {
|
|
706
|
+
const { getPrivateListingConsiderations } = await import(
|
|
707
|
+
"../orders/privateListings"
|
|
708
|
+
)
|
|
709
|
+
considerationFeeItems.push(
|
|
710
|
+
...getPrivateListingConsiderations(offerAssetItems, buyerAddress),
|
|
711
|
+
)
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return {
|
|
715
|
+
offer: offerAssetItems,
|
|
716
|
+
consideration: considerationFeeItems,
|
|
717
|
+
startTime: listingTime?.toString(),
|
|
718
|
+
endTime:
|
|
719
|
+
expirationTime?.toString() ?? oneMonthFromNowInSeconds().toString(),
|
|
720
|
+
zone: metadata.zone,
|
|
721
|
+
domain: metadata.domain,
|
|
722
|
+
salt: metadata.salt
|
|
723
|
+
? BigInt(metadata.salt ?? 0).toString()
|
|
724
|
+
: undefined,
|
|
725
|
+
restrictedByZone: metadata.zone !== ZeroAddress,
|
|
726
|
+
allowPartialFills: true,
|
|
727
|
+
}
|
|
728
|
+
})
|
|
729
|
+
})
|
|
730
|
+
|
|
731
|
+
const resolvedInputs = await Promise.all(createOrderInputsForSeaport)
|
|
732
|
+
|
|
733
|
+
const { executeAllActions } = await this.context.seaport.createBulkOrders(
|
|
734
|
+
resolvedInputs,
|
|
735
|
+
accountAddress,
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
const orders = await executeAllActions()
|
|
739
|
+
|
|
740
|
+
// Submit each order individually to the OpenSea API
|
|
741
|
+
// Rate limiting is handled automatically by the API client
|
|
742
|
+
this.context.logger(
|
|
743
|
+
`Starting submission of ${orders.length} bulk-signed ${pluralize(orders.length, "listing")} to OpenSea API...`,
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
const submittedOrders: OrderV2[] = []
|
|
747
|
+
const failedOrders: BulkOrderResult["failed"] = []
|
|
748
|
+
|
|
749
|
+
for (let i = 0; i < orders.length; i++) {
|
|
750
|
+
this.context.logger(`Submitting listing ${i + 1}/${orders.length}...`)
|
|
751
|
+
try {
|
|
752
|
+
const submittedOrder = await this.context.api.postOrder(orders[i], {
|
|
753
|
+
protocol: "seaport",
|
|
754
|
+
protocolAddress: this.context.seaport.contract.target as string,
|
|
755
|
+
side: OrderSide.LISTING,
|
|
756
|
+
})
|
|
757
|
+
submittedOrders.push(submittedOrder)
|
|
758
|
+
this.context.logger(`Completed listing ${i + 1}/${orders.length}`)
|
|
759
|
+
} catch (error) {
|
|
760
|
+
const errorMessage = (error as Error).message
|
|
761
|
+
this.context.logger(
|
|
762
|
+
`Failed listing ${i + 1}/${orders.length}: ${errorMessage}`,
|
|
763
|
+
)
|
|
764
|
+
failedOrders.push({
|
|
765
|
+
index: i,
|
|
766
|
+
order: orders[i],
|
|
767
|
+
error: error as Error,
|
|
768
|
+
})
|
|
769
|
+
|
|
770
|
+
// If not continuing on error, throw immediately
|
|
771
|
+
if (!continueOnError) {
|
|
772
|
+
throw error
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Call progress callback after each listing (successful or failed)
|
|
777
|
+
onProgress?.(i + 1, orders.length)
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
if (submittedOrders.length > 0) {
|
|
781
|
+
this.context.logger(
|
|
782
|
+
`Successfully submitted ${submittedOrders.length}/${orders.length} ${pluralize(submittedOrders.length, "listing")}`,
|
|
783
|
+
)
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
if (failedOrders.length > 0) {
|
|
787
|
+
this.context.logger(
|
|
788
|
+
`Failed to submit ${failedOrders.length}/${orders.length} ${pluralize(failedOrders.length, "listing")}`,
|
|
789
|
+
)
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
return {
|
|
793
|
+
successful: submittedOrders,
|
|
794
|
+
failed: failedOrders,
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Create and submit multiple offers using Seaport's bulk order creation.
|
|
800
|
+
* This method uses a single signature for all offers and submits them individually to the OpenSea API with rate limit handling.
|
|
801
|
+
* All offers must be from the same account address.
|
|
802
|
+
*
|
|
803
|
+
* Note: If only one offer is provided, this method will use a normal order signature instead of a bulk signature,
|
|
804
|
+
* as bulk signatures are more expensive to decode onchain due to the merkle proof verification.
|
|
805
|
+
*
|
|
806
|
+
* @param options
|
|
807
|
+
* @param options.offers Array of offer parameters. Each offer requires asset, amount, and optionally other offer parameters.
|
|
808
|
+
* @param options.accountAddress Address of the wallet making the offers
|
|
809
|
+
* @param options.continueOnError If true, continue submitting remaining offers even if some fail. Default: false (throw on first error).
|
|
810
|
+
* @param options.onProgress Optional callback for progress updates. Called after each offer is submitted (successfully or not).
|
|
811
|
+
* @returns {@link BulkOrderResult} containing successful orders and any failures.
|
|
812
|
+
*
|
|
813
|
+
* @throws Error if offers array is empty
|
|
814
|
+
* @throws Error if the accountAddress is not available through wallet or provider.
|
|
815
|
+
* @throws Error if any asset does not contain a token id.
|
|
816
|
+
* @throws Error if continueOnError is false and any submission fails.
|
|
817
|
+
*/
|
|
818
|
+
async createBulkOffers({
|
|
819
|
+
offers,
|
|
820
|
+
accountAddress,
|
|
821
|
+
continueOnError = false,
|
|
822
|
+
onProgress,
|
|
823
|
+
}: {
|
|
824
|
+
offers: Array<{
|
|
825
|
+
asset: AssetWithTokenId
|
|
826
|
+
amount: BigNumberish
|
|
827
|
+
quantity?: BigNumberish
|
|
828
|
+
domain?: string
|
|
829
|
+
salt?: BigNumberish
|
|
830
|
+
expirationTime?: BigNumberish
|
|
831
|
+
zone?: string
|
|
832
|
+
}>
|
|
833
|
+
accountAddress: string
|
|
834
|
+
continueOnError?: boolean
|
|
835
|
+
onProgress?: (completed: number, total: number) => void
|
|
836
|
+
}): Promise<BulkOrderResult> {
|
|
837
|
+
if (offers.length === 0) {
|
|
838
|
+
throw new Error("Offers array cannot be empty")
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// If only one offer, use normal signature to avoid bulk signature overhead
|
|
842
|
+
if (offers.length === 1) {
|
|
843
|
+
try {
|
|
844
|
+
const order = await this.createOffer({
|
|
845
|
+
...offers[0],
|
|
846
|
+
accountAddress,
|
|
847
|
+
})
|
|
848
|
+
return {
|
|
849
|
+
successful: [order],
|
|
850
|
+
failed: [],
|
|
851
|
+
}
|
|
852
|
+
} catch (error) {
|
|
853
|
+
if (continueOnError) {
|
|
854
|
+
return {
|
|
855
|
+
successful: [],
|
|
856
|
+
failed: [
|
|
857
|
+
{
|
|
858
|
+
index: 0,
|
|
859
|
+
order: {} as ProtocolData, // Order wasn't created
|
|
860
|
+
error: error as Error,
|
|
861
|
+
},
|
|
862
|
+
],
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
throw error
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
await this.context.requireAccountIsAvailable(accountAddress)
|
|
870
|
+
|
|
871
|
+
// Build metadata array for each offer
|
|
872
|
+
const offerMetadata: Array<{
|
|
873
|
+
nft: NFT
|
|
874
|
+
collection: OpenSeaCollection
|
|
875
|
+
paymentTokenAddress: string
|
|
876
|
+
zone: string
|
|
877
|
+
domain?: string
|
|
878
|
+
salt?: BigNumberish
|
|
879
|
+
expirationTime?: BigNumberish
|
|
880
|
+
}> = []
|
|
881
|
+
|
|
882
|
+
// Build all order inputs
|
|
883
|
+
for (const offer of offers) {
|
|
884
|
+
const {
|
|
885
|
+
asset,
|
|
886
|
+
domain,
|
|
887
|
+
salt,
|
|
888
|
+
expirationTime,
|
|
889
|
+
zone = getSignedZone(this.context.chain),
|
|
890
|
+
} = offer
|
|
891
|
+
|
|
892
|
+
// Fetch NFT and collection data
|
|
893
|
+
const { nft } = await this.context.api.getNFT(
|
|
894
|
+
asset.tokenAddress,
|
|
895
|
+
asset.tokenId,
|
|
896
|
+
)
|
|
897
|
+
const collection = await this.context.api.getCollection(nft.collection)
|
|
898
|
+
|
|
899
|
+
const paymentTokenAddress =
|
|
900
|
+
collection.pricingCurrencies?.offerCurrency?.address ??
|
|
901
|
+
getOfferPaymentToken(this.context.chain)
|
|
902
|
+
|
|
903
|
+
let finalZone = zone
|
|
904
|
+
if (collection.requiredZone) {
|
|
905
|
+
finalZone = collection.requiredZone
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
offerMetadata.push({
|
|
909
|
+
nft,
|
|
910
|
+
collection,
|
|
911
|
+
paymentTokenAddress,
|
|
912
|
+
zone: finalZone,
|
|
913
|
+
domain,
|
|
914
|
+
salt,
|
|
915
|
+
expirationTime,
|
|
916
|
+
})
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// Create the bulk orders using seaport's createBulkOrders method
|
|
920
|
+
const createOrderInputsForSeaport = offers.map((offer, index) => {
|
|
921
|
+
const { amount, quantity = 1 } = offer
|
|
922
|
+
|
|
923
|
+
const metadata = offerMetadata[index]
|
|
924
|
+
const considerationAssetItems = this.getNFTItems(
|
|
925
|
+
[metadata.nft],
|
|
926
|
+
[BigInt(quantity ?? 1)],
|
|
927
|
+
)
|
|
928
|
+
|
|
929
|
+
return this.getPriceParametersCallback(
|
|
930
|
+
OrderSide.OFFER,
|
|
931
|
+
metadata.paymentTokenAddress,
|
|
932
|
+
amount,
|
|
933
|
+
).then(async ({ basePrice }) => {
|
|
934
|
+
const considerationFeeItems = await this.getFees({
|
|
935
|
+
collection: metadata.collection,
|
|
936
|
+
paymentTokenAddress: metadata.paymentTokenAddress,
|
|
937
|
+
amount: basePrice,
|
|
938
|
+
})
|
|
939
|
+
|
|
940
|
+
return {
|
|
941
|
+
offer: [
|
|
942
|
+
{
|
|
943
|
+
token: metadata.paymentTokenAddress,
|
|
944
|
+
amount: basePrice.toString(),
|
|
945
|
+
},
|
|
946
|
+
],
|
|
947
|
+
consideration: [...considerationAssetItems, ...considerationFeeItems],
|
|
948
|
+
endTime:
|
|
949
|
+
metadata.expirationTime !== undefined
|
|
950
|
+
? BigInt(metadata.expirationTime).toString()
|
|
951
|
+
: oneMonthFromNowInSeconds().toString(),
|
|
952
|
+
zone: metadata.zone,
|
|
953
|
+
domain: metadata.domain,
|
|
954
|
+
salt: metadata.salt
|
|
955
|
+
? BigInt(metadata.salt ?? 0).toString()
|
|
956
|
+
: undefined,
|
|
957
|
+
restrictedByZone: metadata.zone !== ZeroAddress,
|
|
958
|
+
allowPartialFills: true,
|
|
959
|
+
}
|
|
960
|
+
})
|
|
961
|
+
})
|
|
962
|
+
|
|
963
|
+
const resolvedInputs = await Promise.all(createOrderInputsForSeaport)
|
|
964
|
+
|
|
965
|
+
const { executeAllActions } = await this.context.seaport.createBulkOrders(
|
|
966
|
+
resolvedInputs,
|
|
967
|
+
accountAddress,
|
|
968
|
+
)
|
|
969
|
+
|
|
970
|
+
const orders = await executeAllActions()
|
|
971
|
+
|
|
972
|
+
// Submit each order individually to the OpenSea API
|
|
973
|
+
// Rate limiting is handled automatically by the API client
|
|
974
|
+
this.context.logger(
|
|
975
|
+
`Starting submission of ${orders.length} bulk-signed ${pluralize(orders.length, "offer")} to OpenSea API...`,
|
|
976
|
+
)
|
|
977
|
+
|
|
978
|
+
const submittedOrders: OrderV2[] = []
|
|
979
|
+
const failedOrders: BulkOrderResult["failed"] = []
|
|
980
|
+
|
|
981
|
+
for (let i = 0; i < orders.length; i++) {
|
|
982
|
+
this.context.logger(`Submitting offer ${i + 1}/${orders.length}...`)
|
|
983
|
+
try {
|
|
984
|
+
const submittedOrder = await this.context.api.postOrder(orders[i], {
|
|
985
|
+
protocol: "seaport",
|
|
986
|
+
protocolAddress: this.context.seaport.contract.target as string,
|
|
987
|
+
side: OrderSide.OFFER,
|
|
988
|
+
})
|
|
989
|
+
submittedOrders.push(submittedOrder)
|
|
990
|
+
this.context.logger(`Completed offer ${i + 1}/${orders.length}`)
|
|
991
|
+
} catch (error) {
|
|
992
|
+
const errorMessage = (error as Error).message
|
|
993
|
+
this.context.logger(
|
|
994
|
+
`Failed offer ${i + 1}/${orders.length}: ${errorMessage}`,
|
|
995
|
+
)
|
|
996
|
+
failedOrders.push({
|
|
997
|
+
index: i,
|
|
998
|
+
order: orders[i],
|
|
999
|
+
error: error as Error,
|
|
1000
|
+
})
|
|
1001
|
+
|
|
1002
|
+
// If not continuing on error, throw immediately
|
|
1003
|
+
if (!continueOnError) {
|
|
1004
|
+
throw error
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// Call progress callback after each offer (successful or failed)
|
|
1009
|
+
onProgress?.(i + 1, orders.length)
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
if (submittedOrders.length > 0) {
|
|
1013
|
+
this.context.logger(
|
|
1014
|
+
`Successfully submitted ${submittedOrders.length}/${orders.length} ${pluralize(submittedOrders.length, "offer")}`,
|
|
1015
|
+
)
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
if (failedOrders.length > 0) {
|
|
1019
|
+
this.context.logger(
|
|
1020
|
+
`Failed to submit ${failedOrders.length}/${orders.length} ${pluralize(failedOrders.length, "offer")}`,
|
|
1021
|
+
)
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
return {
|
|
1025
|
+
successful: submittedOrders,
|
|
1026
|
+
failed: failedOrders,
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* Create and submit a collection offer.
|
|
1032
|
+
* @param options
|
|
1033
|
+
* @param options.collectionSlug Identifier for the collection.
|
|
1034
|
+
* @param options.accountAddress Address of the wallet making the offer.
|
|
1035
|
+
* @param options.amount Amount in decimal format (e.g., "1.5" for 1.5 ETH, not wei). Automatically converted to base units.
|
|
1036
|
+
* @param options.quantity Number of assets to bid for.
|
|
1037
|
+
* @param options.domain Optional domain for onchain attribution. Hashed and included in salt. This can be used for onchain order attribution to assist with analytics.
|
|
1038
|
+
* @param options.salt Arbitrary salt. Auto-generated if not provided.
|
|
1039
|
+
* @param options.expirationTime Expiration time for the order, in UTC seconds.
|
|
1040
|
+
* @param options.offerProtectionEnabled Use signed zone for protection against disabled items. Default: true.
|
|
1041
|
+
* @param options.traitType If defined, the trait name to create the collection offer for.
|
|
1042
|
+
* @param options.traitValue If defined, the trait value to create the collection offer for.
|
|
1043
|
+
* @param options.traits If defined, an array of traits to create the multi-trait collection offer for.
|
|
1044
|
+
* @param options.numericTraits If defined, an array of numeric trait criteria with min/max ranges.
|
|
1045
|
+
* @returns The {@link CollectionOffer} that was created.
|
|
1046
|
+
*/
|
|
1047
|
+
async createCollectionOffer({
|
|
1048
|
+
collectionSlug,
|
|
1049
|
+
accountAddress,
|
|
1050
|
+
amount,
|
|
1051
|
+
quantity,
|
|
1052
|
+
domain,
|
|
1053
|
+
salt,
|
|
1054
|
+
expirationTime,
|
|
1055
|
+
offerProtectionEnabled = true,
|
|
1056
|
+
traitType,
|
|
1057
|
+
traitValue,
|
|
1058
|
+
traits,
|
|
1059
|
+
numericTraits,
|
|
1060
|
+
}: {
|
|
1061
|
+
collectionSlug: string
|
|
1062
|
+
accountAddress: string
|
|
1063
|
+
amount: BigNumberish
|
|
1064
|
+
quantity: number
|
|
1065
|
+
domain?: string
|
|
1066
|
+
salt?: BigNumberish
|
|
1067
|
+
expirationTime?: number | string
|
|
1068
|
+
offerProtectionEnabled?: boolean
|
|
1069
|
+
traitType?: string
|
|
1070
|
+
traitValue?: string
|
|
1071
|
+
traits?: Array<{ type: string; value: string }>
|
|
1072
|
+
numericTraits?: Array<{ type: string; min?: number; max?: number }>
|
|
1073
|
+
}): Promise<CollectionOffer | null> {
|
|
1074
|
+
await this.context.requireAccountIsAvailable(accountAddress)
|
|
1075
|
+
|
|
1076
|
+
const collection = await this.context.api.getCollection(collectionSlug)
|
|
1077
|
+
|
|
1078
|
+
const paymentTokenAddress =
|
|
1079
|
+
collection.pricingCurrencies?.offerCurrency?.address ??
|
|
1080
|
+
getOfferPaymentToken(this.context.chain)
|
|
1081
|
+
|
|
1082
|
+
const buildOfferResult = await this.context.api.buildOffer(
|
|
1083
|
+
accountAddress,
|
|
1084
|
+
quantity,
|
|
1085
|
+
collectionSlug,
|
|
1086
|
+
offerProtectionEnabled,
|
|
1087
|
+
traitType,
|
|
1088
|
+
traitValue,
|
|
1089
|
+
traits,
|
|
1090
|
+
numericTraits,
|
|
1091
|
+
)
|
|
1092
|
+
const item = buildOfferResult.partialParameters.consideration[0]
|
|
1093
|
+
const convertedConsiderationItem = {
|
|
1094
|
+
itemType: item.itemType,
|
|
1095
|
+
token: item.token,
|
|
1096
|
+
identifier: item.identifierOrCriteria,
|
|
1097
|
+
amount: item.startAmount,
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
const { basePrice } = await this.getPriceParametersCallback(
|
|
1101
|
+
OrderSide.OFFER,
|
|
1102
|
+
paymentTokenAddress,
|
|
1103
|
+
amount,
|
|
1104
|
+
)
|
|
1105
|
+
const considerationFeeItems = await this.getFees({
|
|
1106
|
+
collection,
|
|
1107
|
+
paymentTokenAddress,
|
|
1108
|
+
amount: basePrice,
|
|
1109
|
+
})
|
|
1110
|
+
|
|
1111
|
+
const considerationItems = [
|
|
1112
|
+
convertedConsiderationItem,
|
|
1113
|
+
...considerationFeeItems,
|
|
1114
|
+
]
|
|
1115
|
+
|
|
1116
|
+
const payload = {
|
|
1117
|
+
offerer: accountAddress,
|
|
1118
|
+
offer: [
|
|
1119
|
+
{
|
|
1120
|
+
token: paymentTokenAddress,
|
|
1121
|
+
amount: basePrice.toString(),
|
|
1122
|
+
},
|
|
1123
|
+
],
|
|
1124
|
+
consideration: considerationItems,
|
|
1125
|
+
endTime:
|
|
1126
|
+
expirationTime?.toString() ?? oneMonthFromNowInSeconds().toString(),
|
|
1127
|
+
zone: buildOfferResult.partialParameters.zone,
|
|
1128
|
+
domain,
|
|
1129
|
+
salt: BigInt(salt ?? 0).toString(),
|
|
1130
|
+
restrictedByZone: true,
|
|
1131
|
+
allowPartialFills: true,
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
const { executeAllActions } = await this.context.seaport.createOrder(
|
|
1135
|
+
payload,
|
|
1136
|
+
accountAddress,
|
|
1137
|
+
)
|
|
1138
|
+
const order = await executeAllActions()
|
|
1139
|
+
|
|
1140
|
+
return this.context.api.postCollectionOffer(
|
|
1141
|
+
order,
|
|
1142
|
+
collectionSlug,
|
|
1143
|
+
traitType,
|
|
1144
|
+
traitValue,
|
|
1145
|
+
traits,
|
|
1146
|
+
numericTraits,
|
|
1147
|
+
)
|
|
1148
|
+
}
|
|
1149
|
+
}
|