@tradeport/sui-trading-sdk 0.5.3 → 0.5.4

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.
Files changed (153) hide show
  1. package/.babel.config.js +3 -0
  2. package/.claude/settings.json +5 -0
  3. package/.claude/settings.local.json +5 -0
  4. package/.env.demo +5 -0
  5. package/.eslintrc.json +46 -0
  6. package/.prettierignore +4 -0
  7. package/.prettierrc.json +7 -0
  8. package/.vscode/launch.json +23 -0
  9. package/CHANGELOG.md +746 -0
  10. package/jest.config.js +12 -0
  11. package/package.json +66 -71
  12. package/src/SuiTradingClient.ts +442 -0
  13. package/src/apiClients/createKioskClient.ts +10 -0
  14. package/src/apiClients/createSuiClient.ts +5 -0
  15. package/src/apiClients/graphqlClient.ts +17 -0
  16. package/src/bigNumberConfig.ts +10 -0
  17. package/src/constants.ts +1052 -0
  18. package/src/graphql/createChainGQLQuery.ts +27 -0
  19. package/src/graphql/gqlChainRequest.ts +21 -0
  20. package/src/graphql/queries/fetchAccountKiosks.ts +12 -0
  21. package/src/graphql/queries/fetchActiveLockStateByNftId.ts +15 -0
  22. package/src/graphql/queries/fetchBidsById.ts +36 -0
  23. package/src/graphql/queries/fetchCollectionBidById.ts +21 -0
  24. package/src/graphql/queries/fetchCollectionBidsAtSamePrice.ts +29 -0
  25. package/src/graphql/queries/fetchCollectionChainState.ts +17 -0
  26. package/src/graphql/queries/fetchCollectionFloorListingForMarket.ts +28 -0
  27. package/src/graphql/queries/fetchCollectionFloorListings.ts +15 -0
  28. package/src/graphql/queries/fetchCollectionsById.ts +39 -0
  29. package/src/graphql/queries/fetchCommissionByListingId.ts +13 -0
  30. package/src/graphql/queries/fetchCryptoToUsdRate.ts +13 -0
  31. package/src/graphql/queries/fetchKiosksByOwner.ts +14 -0
  32. package/src/graphql/queries/fetchListingsById.ts +29 -0
  33. package/src/graphql/queries/fetchListingsByNftId.ts +23 -0
  34. package/src/graphql/queries/fetchLockById.ts +23 -0
  35. package/src/graphql/queries/fetchMultibidById.ts +34 -0
  36. package/src/graphql/queries/fetchNftCollectionChainState.ts +12 -0
  37. package/src/graphql/queries/fetchNftsById.ts +75 -0
  38. package/src/graphql/queries/fetchNftsByKioskId.ts +45 -0
  39. package/src/graphql/queries/fetchOwnerCapByKiosk.ts +10 -0
  40. package/src/graphql/queries/fetchPersonalCapByKiosk.ts +10 -0
  41. package/src/graphql/queries/fetchSharedObjectsByType.ts +12 -0
  42. package/src/graphql/queries/fetchTransferPoliciesByType.ts +12 -0
  43. package/src/graphql/queries/fetchWalletKiosks.ts +14 -0
  44. package/src/graphql/queries/getCommissionByListingId.ts +15 -0
  45. package/src/helpers/addOneDollarFee.ts +17 -0
  46. package/src/helpers/addThirdPartyTxFee.ts +17 -0
  47. package/src/helpers/calculatePremium.ts +9 -0
  48. package/src/helpers/calculateRoyaltyFee.ts +28 -0
  49. package/src/helpers/destroyZeroCoin.ts +14 -0
  50. package/src/helpers/getActiveLockStateByNftId.ts +15 -0
  51. package/src/helpers/getCollectionChainState.ts +31 -0
  52. package/src/helpers/getCollectionFloorPrice.ts +12 -0
  53. package/src/helpers/getLockById.ts +29 -0
  54. package/src/helpers/getMarketFeePrice.ts +82 -0
  55. package/src/helpers/getNftType.ts +38 -0
  56. package/src/helpers/getRoyaltyRuleModule.ts +7 -0
  57. package/src/helpers/getSharedObjects.ts +119 -0
  58. package/src/helpers/getSuiToUsdRate.ts +14 -0
  59. package/src/helpers/getTradeportBiddingContractBidAmount.ts +31 -0
  60. package/src/helpers/getTransferPolicyRuleNamesFromSuiObject.ts +24 -0
  61. package/src/helpers/hasPersonalKioskRule.ts +7 -0
  62. package/src/helpers/hasRoyaltyRule.ts +7 -0
  63. package/src/helpers/hasTransferPolicyRules.ts +6 -0
  64. package/src/helpers/isExpiredListing.ts +9 -0
  65. package/src/helpers/isNonKioskListing.ts +14 -0
  66. package/src/helpers/isSIngleBid.ts +13 -0
  67. package/src/helpers/kiosk/assertNftInSharedKiosk.ts +31 -0
  68. package/src/helpers/kiosk/getKioskCollectionRoyaltyFeeAmount.ts +71 -0
  69. package/src/helpers/kiosk/getKioskIdFromKioskTx.ts +29 -0
  70. package/src/helpers/kiosk/getKioskPlaceBidCoin.ts +59 -0
  71. package/src/helpers/kiosk/getNativeKioskTransferPolicies.ts +29 -0
  72. package/src/helpers/kiosk/getNativeKioskTransferPoliciesByNftType.ts +21 -0
  73. package/src/helpers/kiosk/getRulePackageId.ts +59 -0
  74. package/src/helpers/kiosk/getTransferPoliciesToResolve.ts +154 -0
  75. package/src/helpers/kiosk/isBluemoveKioskBid.ts +1 -0
  76. package/src/helpers/kiosk/isTradePortKioskBid.ts +4 -0
  77. package/src/helpers/kiosk/kioskListingBcs.ts +19 -0
  78. package/src/helpers/kiosk/kioskTxWrapper.ts +152 -0
  79. package/src/helpers/kiosk/lockNftInsideKioskIfNotLocked.ts +100 -0
  80. package/src/helpers/kiosk/preProcessSharedBulkBuyingData.ts +171 -0
  81. package/src/helpers/kiosk/resolveCustomTransferPolicyRules.ts +75 -0
  82. package/src/helpers/kiosk/resolveFloorPriceRule.ts +21 -0
  83. package/src/helpers/kiosk/resolveKioskLockRule.ts +47 -0
  84. package/src/helpers/kiosk/resolvePersonalKioskRule.ts +23 -0
  85. package/src/helpers/kiosk/resolveRoyaltyRule.ts +57 -0
  86. package/src/helpers/kiosk/resolveTableAllowlistRule.ts +34 -0
  87. package/src/helpers/kiosk/resolveTransferPolicies.ts +158 -0
  88. package/src/helpers/kiosk/sharedKioskState.type.ts +11 -0
  89. package/src/helpers/kiosk/takeAndBorrowNftFromKiosk.ts +50 -0
  90. package/src/helpers/kiosk/takeLockedNftFromKiosk.ts +73 -0
  91. package/src/helpers/kiosk/upgradeKioskRulesPackageId.ts +17 -0
  92. package/src/helpers/originByte/confirmOBTranfer.ts +33 -0
  93. package/src/helpers/originByte/createOBKiosk.ts +14 -0
  94. package/src/helpers/originByte/depositNftIntoOBKiosk.ts +16 -0
  95. package/src/helpers/originByte/getOBBidderKiosk.ts +12 -0
  96. package/src/helpers/originByte/getOBKiosk.ts +24 -0
  97. package/src/helpers/originByte/getOrCreateOBKiosk.ts +42 -0
  98. package/src/helpers/originByte/isOBKiosk.ts +13 -0
  99. package/src/helpers/originByte/isOriginByteBid.ts +30 -0
  100. package/src/helpers/originByte/isOriginByteCollection.ts +11 -0
  101. package/src/helpers/originByte/shareOriginByteKiosk.ts +14 -0
  102. package/src/helpers/rpc/getAcountBalance.ts +18 -0
  103. package/src/helpers/rpc/getObjectType.ts +25 -0
  104. package/src/helpers/splitCoins.ts +12 -0
  105. package/src/helpers/track.ts +20 -0
  106. package/src/helpers/validateMinFloorPrice.ts +22 -0
  107. package/src/index.ts +2 -0
  108. package/src/methods/acceptCollectionBid/acceptCollectionBid.ts +189 -0
  109. package/src/methods/acceptCollectionBid/addAcceptCollectionBIdTxs.ts +398 -0
  110. package/src/methods/acceptNftBids/acceptNftBids.ts +174 -0
  111. package/src/methods/acceptNftBids/addAcceptNftBidTxs.ts +438 -0
  112. package/src/methods/applyFtStrategy/applyFtStrategy.ts +55 -0
  113. package/src/methods/applyNftStrategy/applyNftStrategy.ts +90 -0
  114. package/src/methods/buyListings/addBuyListingTxs.ts +806 -0
  115. package/src/methods/buyListings/buyListings.ts +230 -0
  116. package/src/methods/cancelMultiBid/cancelMultiBid.ts +51 -0
  117. package/src/methods/cancelNftTransfers/addCancelNftTransfersTx.ts +20 -0
  118. package/src/methods/cancelNftTransfers/cancelNftTransfers.ts +118 -0
  119. package/src/methods/claimNfts/addClaimNftsTxs.ts +247 -0
  120. package/src/methods/claimNfts/claimNfts.ts +270 -0
  121. package/src/methods/createMultiBid/createMultiBid.ts +36 -0
  122. package/src/methods/listNfts/addListTxs.ts +210 -0
  123. package/src/methods/listNfts/addRelistTxs.ts +87 -0
  124. package/src/methods/listNfts/listNfts.ts +152 -0
  125. package/src/methods/migrateNftsFromUnsharedToSharedKiosks/migrateNftsFromUnsharedToSharedKiosks.ts +226 -0
  126. package/src/methods/placeCollectionBids/addPlaceCollectionBidTxs.ts +149 -0
  127. package/src/methods/placeCollectionBids/placeCollectionBids.ts +153 -0
  128. package/src/methods/placeNftBids/addPlaceNftBidTxs.ts +154 -0
  129. package/src/methods/placeNftBids/placeNftBids.ts +111 -0
  130. package/src/methods/relistNft/relistNft.ts +153 -0
  131. package/src/methods/removeCollectionBids/addRemoveCollectionBidsTxs.ts +132 -0
  132. package/src/methods/removeCollectionBids/removeCollectionBids.ts +117 -0
  133. package/src/methods/removeNftBids/addRemoveNftBidTxs.ts +122 -0
  134. package/src/methods/removeNftBids/removeNftBids.ts +116 -0
  135. package/src/methods/sponsorNftListing/addSponsorNftListingTx.ts +40 -0
  136. package/src/methods/sponsorNftListing/sponsorNftListing.ts +60 -0
  137. package/src/methods/transferNfts/addTransferNftTx.ts +220 -0
  138. package/src/methods/transferNfts/transferNfts.ts +216 -0
  139. package/src/methods/unlistListings/addUnlistListingTxs.ts +399 -0
  140. package/src/methods/unlistListings/unlistListings.ts +158 -0
  141. package/src/methods/updateMultiBid/updateMultiBid.ts +66 -0
  142. package/src/methods/withdrawProfitsFromKiosks/withdrawProfitsFromKiosks.ts +100 -0
  143. package/src/tests/SuiWallet.ts +83 -0
  144. package/src/utils/addHexPrefix.ts +7 -0
  145. package/src/utils/addLeadingZerosAfter0x.ts +9 -0
  146. package/src/utils/normalizeNftType.ts +7 -0
  147. package/src/utils/printTxBlockTxs.ts +11 -0
  148. package/src/utils/pureValues.ts +13 -0
  149. package/src/utils/toUint8Array.ts +12 -0
  150. package/tsconfig.json +16 -0
  151. package/dist/index.d.ts +0 -194
  152. package/dist/index.js +0 -7419
  153. package/dist/index.js.map +0 -1
@@ -0,0 +1,152 @@
1
+ import { type KioskClient } from '@mysten/kiosk';
2
+ import { type SuiGrpcClient } from '@mysten/sui/grpc';
3
+ import { Transaction, type TransactionObjectInput } from '@mysten/sui/transactions';
4
+ import { type RequestContext } from '../../SuiTradingClient';
5
+ import {
6
+ DELOREAN_TOKEN_IDS_TO_DISABLE,
7
+ DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE,
8
+ } from '../../constants';
9
+ import { gqlChainRequest } from '../../graphql/gqlChainRequest';
10
+ import { fetchNftsWithListingsById } from '../../graphql/queries/fetchNftsById';
11
+ import { getNftType } from '../../helpers/getNftType';
12
+ import { isExpiredListing } from '../../helpers/isExpiredListing';
13
+ import { type SharedKioskState } from '../../helpers/kiosk/sharedKioskState.type';
14
+ import { isOriginByteCollection } from '../../helpers/originByte/isOriginByteCollection';
15
+ import { relistNft } from '../relistNft/relistNft';
16
+ import { addSponsorListingTx } from '../sponsorNftListing/addSponsorNftListingTx';
17
+ import { type SponsorNftListingOptions } from '../sponsorNftListing/sponsorNftListing';
18
+ import { addTradePortListTxHandler } from './addListTxs';
19
+
20
+ export type ListNftTx = {
21
+ tx: Transaction;
22
+ suiClient: SuiGrpcClient;
23
+ kioskClient: KioskClient;
24
+ kioskTx?: any;
25
+ sharedObjects?: any;
26
+ transferPolicies: any;
27
+ seller: string;
28
+ collectionId: string;
29
+ nftTokenId?: string;
30
+ borrowedItem?: TransactionObjectInput;
31
+ nftType: string;
32
+ listPrice: number;
33
+ sellerKiosk: string;
34
+ sharedKioskState?: SharedKioskState;
35
+ };
36
+
37
+ export type ListNfts = {
38
+ nfts: Array<{
39
+ id: string;
40
+ listPriceInMist: number;
41
+ sponsorOptions?: SponsorNftListingOptions;
42
+ }>;
43
+ walletAddress: string;
44
+ tx?: Transaction;
45
+ };
46
+
47
+ export const listNfts = async (
48
+ { nfts, walletAddress, tx: existingTx }: ListNfts,
49
+ context: RequestContext,
50
+ ): Promise<Transaction> => {
51
+ const res = await gqlChainRequest({
52
+ chain: 'sui',
53
+ query: fetchNftsWithListingsById,
54
+ variables: { nftIds: nfts.map((nft) => nft.id) },
55
+ });
56
+
57
+ if (res?.nfts?.length === 0) {
58
+ throw new Error('No nfts found');
59
+ }
60
+
61
+ const nftsForTracking = [];
62
+ const tx = existingTx ?? new Transaction();
63
+
64
+ const sharedKioskState: SharedKioskState = {
65
+ kioskTx: undefined,
66
+ };
67
+
68
+ for (const nft of res.nfts) {
69
+ const inputNft = nfts?.find((n) => n.id === nft?.id);
70
+
71
+ if (DELOREAN_TOKEN_IDS_TO_DISABLE?.includes(nft?.token_id)) {
72
+ throw new Error(DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE);
73
+ }
74
+
75
+ const nftType = getNftType({
76
+ collectionId: nft?.collection?.id,
77
+ collectionChainState: nft?.collection?.chain_state,
78
+ nft,
79
+ });
80
+
81
+ const transferPolicies = nft?.collection?.chain_state?.transfer_policies;
82
+
83
+ if (inputNft?.sponsorOptions?.shouldSponsor && isOriginByteCollection(transferPolicies)) {
84
+ throw new Error(`You cannot sponsor an Origin Byte NFT. Nft Token Id: ${nft?.token_id}`);
85
+ }
86
+
87
+ if (
88
+ nft?.listed ||
89
+ nft.listings.some((listing: { nonce?: string; seller?: string }) =>
90
+ isExpiredListing(listing, walletAddress),
91
+ )
92
+ ) {
93
+ await relistNft({
94
+ tx,
95
+ suiClient: context.suiClient,
96
+ kioskClient: context.kioskClient,
97
+ sharedKioskState,
98
+ transferPolicies,
99
+ nft,
100
+ listPrice: inputNft?.listPriceInMist,
101
+ walletAddress,
102
+ });
103
+ } else {
104
+ const listTxData: ListNftTx = {
105
+ tx,
106
+ suiClient: context.suiClient,
107
+ kioskClient: context.kioskClient,
108
+ sharedKioskState,
109
+ transferPolicies,
110
+ seller: walletAddress,
111
+ collectionId: nft?.collection_id,
112
+ nftTokenId: nft?.token_id,
113
+ nftType,
114
+ listPrice: inputNft?.listPriceInMist,
115
+ sellerKiosk: nft?.chain_state?.kiosk_id,
116
+ };
117
+
118
+ await addTradePortListTxHandler(listTxData);
119
+ }
120
+
121
+ if (inputNft?.sponsorOptions?.shouldSponsor) {
122
+ await addSponsorListingTx({
123
+ tx,
124
+ nftTokenId: nft?.token_id,
125
+ nftType,
126
+ sponsorOptions: inputNft?.sponsorOptions,
127
+ });
128
+ }
129
+
130
+ nftsForTracking.push({
131
+ walletAddress,
132
+ nftType,
133
+ collectionId: nft?.collection_id,
134
+ listPrice: inputNft?.listPriceInMist,
135
+ isRelist: nft?.listed,
136
+ marketRelistedFrom: nft?.listings?.[0]?.market_name,
137
+ });
138
+ }
139
+
140
+ sharedKioskState?.kioskTx?.finalize();
141
+
142
+ // if (process.env.ENABLE_SEGMENT_TRACKING === 'true' && nftsForTracking.length > 0) {
143
+ // trackMethodCall({
144
+ // apiUser: context.apiUser,
145
+ // apiKey: context.apiKey,
146
+ // event: 'LIST_NFTS',
147
+ // items: nftsForTracking,
148
+ // });
149
+ // }
150
+
151
+ return tx;
152
+ };
@@ -0,0 +1,226 @@
1
+ import { Transaction } from '@mysten/sui/transactions';
2
+ import { type RequestContext } from '../../SuiTradingClient';
3
+ import { gqlChainRequest } from '../../graphql/gqlChainRequest';
4
+ import { fetchKiosksByOwner } from '../../graphql/queries/fetchKiosksByOwner';
5
+ import {
6
+ fetchBulkNftsByKioskId,
7
+ fetchNftsByKioskId,
8
+ } from '../../graphql/queries/fetchNftsByKioskId';
9
+ import { getNftType } from '../../helpers/getNftType';
10
+ import { getNativeKioskTransferPoliciesByNftType } from '../../helpers/kiosk/getNativeKioskTransferPoliciesByNftType';
11
+ import { kioskTxWrapper } from '../../helpers/kiosk/kioskTxWrapper';
12
+ import { type SharedKioskState } from '../../helpers/kiosk/sharedKioskState.type';
13
+ import { addLeadingZerosAfter0x } from '../../utils/addLeadingZerosAfter0x';
14
+ import { addClaimTransferredNftWithPurchaseCapTx } from '../claimNfts/addClaimNftsTxs';
15
+ import { addTradeportKioskTransferTx } from '../transferNfts/addTransferNftTx';
16
+
17
+ export type MigrateNftsFromUnsharedToSharedKiosks = {
18
+ walletAddress: string;
19
+ max?: number;
20
+ };
21
+
22
+ export async function migrateNftsFromUnsharedToSharedKiosks(
23
+ { walletAddress, max = 50 }: MigrateNftsFromUnsharedToSharedKiosks,
24
+ context: RequestContext,
25
+ ): Promise<Transaction> {
26
+ const tx = new Transaction();
27
+
28
+ const res = await gqlChainRequest({
29
+ chain: 'sui',
30
+ query: fetchKiosksByOwner,
31
+ variables: { ownerAddress: addLeadingZerosAfter0x(walletAddress) },
32
+ });
33
+
34
+ const unsharedOBKiosks = res?.kiosks
35
+ ?.filter((k: any) => !k.is_shared && k.is_origin_byte)
36
+ ?.map((k: any) => k.id);
37
+
38
+ let currentMigrationCount = 0;
39
+
40
+ const sharedOBKiosk = res?.kiosks?.filter((k: any) => k.is_shared && k.is_origin_byte)?.[0]?.id;
41
+
42
+ for (const unsharedOBKiosk of unsharedOBKiosks) {
43
+ if (currentMigrationCount >= max) {
44
+ continue;
45
+ }
46
+
47
+ const res = await gqlChainRequest({
48
+ chain: 'sui',
49
+ query: fetchNftsByKioskId,
50
+ variables: { jsonFilter: { kiosk_id: unsharedOBKiosk } },
51
+ });
52
+
53
+ const nfts = res?.nfts;
54
+
55
+ if (nfts.length > 0) {
56
+ currentMigrationCount++;
57
+ }
58
+
59
+ for (const nft of nfts) {
60
+ if (nft?.chain_state?.claimable_trade_id) {
61
+ // origin byte trade hold, so they are stuck and cannot be migrated
62
+ continue;
63
+ }
64
+
65
+ const nftType = getNftType({
66
+ collectionId: nft?.collection?.id,
67
+ collectionChainState: nft?.collection?.chain_state,
68
+ nft,
69
+ });
70
+
71
+ const nftTokenId = nft?.token_id;
72
+
73
+ if (sharedOBKiosk) {
74
+ tx.moveCall({
75
+ target:
76
+ '0x2678c98fe23173eebea384509464eb81b1f3035a57419cb46d025000c337451a::ob_kiosk::p2p_transfer',
77
+ arguments: [
78
+ tx.object(unsharedOBKiosk),
79
+ tx.object(sharedOBKiosk),
80
+ tx.pure.address(nftTokenId),
81
+ ],
82
+ typeArguments: [nftType],
83
+ });
84
+ } else {
85
+ tx.moveCall({
86
+ target:
87
+ '0x2678c98fe23173eebea384509464eb81b1f3035a57419cb46d025000c337451a::ob_kiosk::p2p_transfer_and_create_target_kiosk',
88
+ arguments: [
89
+ tx.object(unsharedOBKiosk),
90
+ tx.pure.address(addLeadingZerosAfter0x(walletAddress)),
91
+ tx.pure.address(nftTokenId),
92
+ ],
93
+ typeArguments: [nftType],
94
+ });
95
+ }
96
+ }
97
+ }
98
+
99
+ const unsharedNativeKiosks = res?.kiosks
100
+ ?.filter((k: any) => !k.is_shared && !k.is_origin_byte)
101
+ ?.map((k: any) => k.id);
102
+
103
+ const allNfts = await gqlChainRequest({
104
+ chain: 'sui',
105
+ query: fetchBulkNftsByKioskId,
106
+ variables: {
107
+ where: {
108
+ _or: unsharedNativeKiosks.map((nk: any) => ({
109
+ chain_state: { _contains: { kiosk_id: nk } },
110
+ })),
111
+ },
112
+ },
113
+ });
114
+
115
+ const formatted: any = {};
116
+ allNfts.nfts.forEach((e: any) => {
117
+ if (formatted[e.chain_state.kiosk_id]) {
118
+ formatted[e.chain_state.kiosk_id]?.push(e);
119
+ } else {
120
+ formatted[e.chain_state.kiosk_id] = [e];
121
+ }
122
+ });
123
+
124
+ const allNftTypes = allNfts.nfts.reduce((acc: any[], curr: any) => {
125
+ const type = getNftType({
126
+ collectionId: curr?.collection?.id,
127
+ collectionChainState: curr?.collection?.chain_state,
128
+ nft: curr,
129
+ });
130
+ if (!acc.includes(type)) acc.push(type);
131
+ return acc;
132
+ }, []);
133
+
134
+ const transferPolicies = await Promise.all(
135
+ allNftTypes.map(async (type: string) => getNativeKioskTransferPoliciesByNftType(type)),
136
+ );
137
+
138
+ const mappedTrasferPolicies: Record<string, any> = {};
139
+ transferPolicies.forEach((tp: any) => {
140
+ mappedTrasferPolicies[tp?.[0]?.type] = tp;
141
+ });
142
+
143
+ const sharedKioskState: SharedKioskState = {
144
+ kioskTx: undefined,
145
+ };
146
+
147
+ for (const unsharedNativeKiosk of unsharedNativeKiosks) {
148
+ if (currentMigrationCount >= max) {
149
+ continue;
150
+ }
151
+
152
+ const nfts = formatted[unsharedNativeKiosk] ?? [];
153
+ if (nfts?.length > 0) {
154
+ currentMigrationCount++;
155
+ }
156
+
157
+ for (const nft of nfts) {
158
+ let existingKioskTx;
159
+ if (nft?.claimable_reason === 'offer-transfer') {
160
+ // native kiosk kiosk_transfers transfer hold. Transfer needs to be cancelled first in order to be migrated
161
+ continue;
162
+ }
163
+
164
+ const nftType = getNftType({
165
+ collectionId: nft?.collection?.id,
166
+ collectionChainState: nft?.collection?.chain_state,
167
+ nft,
168
+ });
169
+ const nftTokenId = nft?.token_id;
170
+ await kioskTxWrapper({
171
+ tx,
172
+ kioskClient: context?.kioskClient,
173
+ kioskOwner: walletAddress,
174
+ kiosk: unsharedNativeKiosk,
175
+ shouldAllowNftUnsharedKiosk: true,
176
+ sharedKioskState,
177
+ shouldUseSharedKioskTx: false,
178
+ async runCommands(kioskTx) {
179
+ await addTradeportKioskTransferTx({
180
+ tx,
181
+ kioskTx,
182
+ kioskClient: context?.kioskClient,
183
+ suiClient: context?.suiClient,
184
+ senderKiosk: unsharedNativeKiosk,
185
+ senderAddress: walletAddress,
186
+ recipientAddress: walletAddress,
187
+ nftTokenId,
188
+ nftType,
189
+ transferPolicies: mappedTrasferPolicies[nftType],
190
+ transferPolicy: mappedTrasferPolicies[nftType]?.[0],
191
+ });
192
+ },
193
+ });
194
+ await kioskTxWrapper({
195
+ tx,
196
+ kioskClient: context.kioskClient,
197
+ kioskOwner: walletAddress,
198
+ kiosk: unsharedNativeKiosk,
199
+ kioskStrategy: 'exclude',
200
+ shouldConvertToPersonalKiosk: true,
201
+ sharedKioskState,
202
+ shouldUseSharedKioskTx: false,
203
+ async runCommands(kioskTx) {
204
+ await addClaimTransferredNftWithPurchaseCapTx({
205
+ tx,
206
+ kioskTx,
207
+ sharedObjects: [],
208
+ claimer: walletAddress,
209
+ kioskClient: context.kioskClient,
210
+ suiClient: context.suiClient,
211
+ nftTokenId,
212
+ nftType,
213
+ sellerKiosk: unsharedNativeKiosk,
214
+ seller: nft?.owner,
215
+ transferPolicies: mappedTrasferPolicies[nftType],
216
+ preloadedTransferPolicyId: mappedTrasferPolicies[nftType]?.[0]?.id,
217
+ });
218
+ },
219
+ });
220
+ }
221
+ }
222
+
223
+ sharedKioskState?.kioskTx?.finalize();
224
+
225
+ return Transaction.from(tx);
226
+ }
@@ -0,0 +1,149 @@
1
+ import {
2
+ TRADEPORT_BENEFICIARY_ADDRESS,
3
+ TRADEPORT_BIDDING_STORE,
4
+ TRADEPORT_KIOSK_BIDDING_STORE,
5
+ } from '../../constants';
6
+ import { destroyZeroCoin } from '../../helpers/destroyZeroCoin';
7
+ import { getCollectionFloorPrice } from '../../helpers/getCollectionFloorPrice';
8
+ import { getMarketFeePrice } from '../../helpers/getMarketFeePrice';
9
+ import { getRoyaltyRuleModule } from '../../helpers/getRoyaltyRuleModule';
10
+ import { getTradeportBiddingContractBidAmount } from '../../helpers/getTradeportBiddingContractBidAmount';
11
+ import { hasRoyaltyRule } from '../../helpers/hasRoyaltyRule';
12
+ import { getKioskPlaceBidCoin } from '../../helpers/kiosk/getKioskPlaceBidCoin';
13
+ import { getNativeKioskTransferPolicies } from '../../helpers/kiosk/getNativeKioskTransferPolicies';
14
+ import { getRulePackageId } from '../../helpers/kiosk/getRulePackageId';
15
+ import { splitCoins } from '../../helpers/splitCoins';
16
+ import { type PlaceCollectionBidTx } from './placeCollectionBids';
17
+
18
+ export function addTradePortCollectionBidTx({
19
+ tx,
20
+ collectionId,
21
+ nftType,
22
+ bidAmount,
23
+ }: PlaceCollectionBidTx) {
24
+ const amountToBid = getTradeportBiddingContractBidAmount({ bidAmount, collectionId });
25
+ const marketFeePrice = getMarketFeePrice({ price: bidAmount, collectionId });
26
+
27
+ const [coin] = splitCoins({ tx, amounts: [tx.pure.u64(amountToBid + marketFeePrice)] });
28
+
29
+ tx.moveCall({
30
+ target:
31
+ '0xb42dbb7413b79394e1a0175af6ae22b69a5c7cc5df259cd78072b6818217c027::biddings::collection_bid',
32
+ arguments: [
33
+ tx.object(TRADEPORT_BIDDING_STORE),
34
+ tx.pure.u64(amountToBid),
35
+ tx.object(coin),
36
+ tx.pure.u64(marketFeePrice),
37
+ tx.pure.address(TRADEPORT_BENEFICIARY_ADDRESS),
38
+ ],
39
+ typeArguments: [nftType],
40
+ });
41
+
42
+ destroyZeroCoin({ tx, coin });
43
+ }
44
+
45
+ export async function addTradePortKioskCollectionBidTx({
46
+ tx,
47
+ suiClient,
48
+ bidder,
49
+ collectionId,
50
+ nftType,
51
+ bidAmount,
52
+ royaltyRulePackageId,
53
+ royaltyRuleModule,
54
+ transferPolicies,
55
+ }: PlaceCollectionBidTx) {
56
+ const transferPolicyId = getNativeKioskTransferPolicies(transferPolicies)?.at(0)?.id;
57
+
58
+ const marketFeePrice = getMarketFeePrice({
59
+ price: bidAmount,
60
+ collectionId,
61
+ });
62
+
63
+ const coin = await getKioskPlaceBidCoin({
64
+ tx,
65
+ suiClient,
66
+ bidder,
67
+ nftType,
68
+ bidAmount,
69
+ marketFeePrice,
70
+ royaltyRulePackageId,
71
+ royaltyRuleModule,
72
+ transferPolicyId,
73
+ });
74
+
75
+ tx.moveCall({
76
+ target:
77
+ '0x475e98e9c436ec118909f3b9e241d86bcbbc2cf9fba05e99a934823fefb375b7::kiosk_biddings::collection_bid',
78
+ arguments: [
79
+ tx.object(TRADEPORT_KIOSK_BIDDING_STORE),
80
+ tx.pure.u64(bidAmount),
81
+ tx.object(coin),
82
+ tx.pure.u64(marketFeePrice),
83
+ tx.pure.address(TRADEPORT_BENEFICIARY_ADDRESS),
84
+ ],
85
+ typeArguments: [nftType],
86
+ });
87
+
88
+ destroyZeroCoin({ tx, coin });
89
+ }
90
+
91
+ export async function addOriginByteCollectionBidTx({
92
+ tx,
93
+ collectionId,
94
+ nftType,
95
+ bidAmount,
96
+ sharedObjects,
97
+ bidderKiosk,
98
+ coinToSplit,
99
+ }: PlaceCollectionBidTx) {
100
+ const collectionFloorPrice = await getCollectionFloorPrice(collectionId);
101
+ if (
102
+ collectionFloorPrice &&
103
+ collectionFloorPrice > 0 &&
104
+ Number(bidAmount) > Number(collectionFloorPrice)
105
+ ) {
106
+ throw new Error('Bid amount must be less than the collection floor price');
107
+ }
108
+
109
+ const { orderbook } = sharedObjects;
110
+
111
+ const marketFeePrice = getMarketFeePrice({ price: bidAmount, collectionId });
112
+
113
+ const [coin] = tx.splitCoins(coinToSplit ? coinToSplit : tx.gas, [
114
+ tx.pure.u64(bidAmount + marketFeePrice),
115
+ ]);
116
+
117
+ tx.moveCall({
118
+ target:
119
+ '0x8534e4cdfd28709c94330a9783c3d5fe6f5daba0bffb69102ce303c5b38aed5a::orderbook::create_bid_with_commission',
120
+ arguments: [
121
+ tx.object(orderbook),
122
+ tx.object(bidderKiosk),
123
+ tx.pure.u64(bidAmount),
124
+ tx.pure.address(TRADEPORT_BENEFICIARY_ADDRESS),
125
+ tx.pure.u64(marketFeePrice),
126
+ tx.object(coin),
127
+ ],
128
+ typeArguments: [nftType, '0x2::sui::SUI'],
129
+ });
130
+
131
+ destroyZeroCoin({ tx, coin });
132
+ }
133
+
134
+ export async function addTradePortPlaceCollectionBidTxHandler(txData: PlaceCollectionBidTx) {
135
+ if (hasRoyaltyRule(txData?.transferPolicies)) {
136
+ const royaltyRuleModule = getRoyaltyRuleModule(txData?.nftType);
137
+ const royaltyRulePackageId = await getRulePackageId({
138
+ transferPolicies: txData?.transferPolicies,
139
+ suiClient: txData?.suiClient,
140
+ nftType: txData.nftType,
141
+ ruleType: getRoyaltyRuleModule(txData?.collectionId),
142
+ kioskClient: txData?.kioskClient,
143
+ });
144
+ await addTradePortKioskCollectionBidTx({ ...txData, royaltyRulePackageId, royaltyRuleModule });
145
+ return;
146
+ }
147
+
148
+ addTradePortCollectionBidTx(txData);
149
+ }
@@ -0,0 +1,153 @@
1
+ import { type KioskClient } from '@mysten/kiosk';
2
+ import { type SuiGrpcClient } from '@mysten/sui/grpc';
3
+ import { Transaction } from '@mysten/sui/transactions';
4
+ import { type RequestContext } from '../../SuiTradingClient';
5
+ import { ORIGIN_BYTE_NFT_TYPES_MISSING_ORDERBOOK } from '../../constants';
6
+ import { gqlChainRequest } from '../../graphql/gqlChainRequest';
7
+ import { fetchCollectionsByIdWithOneNft } from '../../graphql/queries/fetchCollectionsById';
8
+ import { getNftType } from '../../helpers/getNftType';
9
+ import { getSharedObjects } from '../../helpers/getSharedObjects';
10
+ import { getOrCreateOBKiosk } from '../../helpers/originByte/getOrCreateOBKiosk';
11
+ import { isOriginByteCollection } from '../../helpers/originByte/isOriginByteCollection';
12
+ import { shareOriginByteKiosk } from '../../helpers/originByte/shareOriginByteKiosk';
13
+ import { normalizedNftType } from '../../utils/normalizeNftType';
14
+ import { addTradePortPlaceNftBidTxHandler } from '../placeNftBids/addPlaceNftBidTxs';
15
+ import { addOriginByteCollectionBidTx } from './addPlaceCollectionBidTxs';
16
+
17
+ export type PlaceCollectionBidTx = {
18
+ tx: Transaction;
19
+ suiClient: SuiGrpcClient;
20
+ kioskClient: KioskClient;
21
+ sharedObjects?: any;
22
+ transferPolicies: any;
23
+ bidder: string;
24
+ collectionId: string;
25
+ nftType: string;
26
+ bidAmount: number;
27
+ bidderKiosk?: string;
28
+ royaltyRulePackageId?: string;
29
+ royaltyRuleModule?: string;
30
+ multiBidId?: string;
31
+ multiBidChainId?: any;
32
+ expireAt?: Date;
33
+ coinToSplit?: any;
34
+ };
35
+
36
+ export type PlaceCollectionBid = {
37
+ collectionId: string;
38
+ bidAmountInMist: number;
39
+ numOfBids: number;
40
+ walletAddress: string;
41
+ multiBidId?: string;
42
+ multiBidChainId?: any;
43
+ expireAt?: Date;
44
+ tx?: Transaction;
45
+ };
46
+
47
+ export type PlaceCollectionBids = {
48
+ collections: Array<{
49
+ id: string;
50
+ bidAmountInMist: number;
51
+ numOfBids: number;
52
+ expireAt?: Date;
53
+ }>;
54
+ walletAddress: string;
55
+ multiBidId?: string;
56
+ multiBidChainId?: any;
57
+ tx?: Transaction;
58
+ coinToSplit?: any;
59
+ };
60
+
61
+ export const placeCollectionBids = async (
62
+ {
63
+ collections,
64
+ walletAddress,
65
+ multiBidId,
66
+ multiBidChainId,
67
+ tx: existingTx,
68
+ coinToSplit,
69
+ }: PlaceCollectionBids,
70
+ context: RequestContext,
71
+ ): Promise<Transaction> => {
72
+ const res = await gqlChainRequest({
73
+ chain: 'sui',
74
+ query: fetchCollectionsByIdWithOneNft,
75
+ variables: { collectionIds: collections.map((collection) => collection.id) },
76
+ });
77
+
78
+ if (res?.collections?.length === 0) {
79
+ throw new Error('No collection found');
80
+ }
81
+
82
+ const collectionsForTracking = [];
83
+ const tx = existingTx ?? new Transaction();
84
+
85
+ for (const collection of res.collections) {
86
+ const nftType = getNftType({
87
+ collectionId: collection?.id,
88
+ collectionChainState: collection?.chain_state,
89
+ nft: collection?.nfts?.[0],
90
+ });
91
+
92
+ const transferPolicies = collection?.chain_state?.transfer_policies;
93
+
94
+ const txData: PlaceCollectionBidTx = {
95
+ tx,
96
+ suiClient: context.suiClient,
97
+ kioskClient: context.kioskClient,
98
+ transferPolicies,
99
+ bidder: walletAddress,
100
+ collectionId: collection?.id,
101
+ nftType,
102
+ bidAmount: collections?.find((c) => c.id === collection?.id)?.bidAmountInMist,
103
+ multiBidId,
104
+ multiBidChainId,
105
+ expireAt: collections?.find((c) => c.id === collection?.id)?.expireAt,
106
+ coinToSplit,
107
+ };
108
+
109
+ const numOfBids = collections?.find((c) => c.id === collection?.id)?.numOfBids;
110
+
111
+ if (
112
+ isOriginByteCollection(txData?.transferPolicies) &&
113
+ !ORIGIN_BYTE_NFT_TYPES_MISSING_ORDERBOOK?.includes(normalizedNftType(txData?.nftType))
114
+ ) {
115
+ const sharedObjects = await getSharedObjects(txData?.nftType);
116
+
117
+ const { kiosk: bidderKiosk, isNewKiosk: isNewBidderKiosk } = await getOrCreateOBKiosk({
118
+ tx,
119
+ address: txData.bidder,
120
+ });
121
+
122
+ for (let i = 0; i < numOfBids; i++) {
123
+ await addOriginByteCollectionBidTx({ ...txData, bidderKiosk, sharedObjects });
124
+ }
125
+
126
+ if (isNewBidderKiosk) {
127
+ shareOriginByteKiosk({ tx, kiosk: bidderKiosk });
128
+ }
129
+ } else {
130
+ for (let i = 0; i < numOfBids; i++) {
131
+ await addTradePortPlaceNftBidTxHandler({ ...txData, bidAmount: BigInt(txData.bidAmount) });
132
+ }
133
+ }
134
+
135
+ collectionsForTracking.push({
136
+ nftType,
137
+ collectionId: collection?.id,
138
+ bidAmount: collections?.find((c) => c.id === collection?.id)?.bidAmountInMist,
139
+ bidder: walletAddress,
140
+ });
141
+ }
142
+
143
+ // if (process.env.ENABLE_SEGMENT_TRACKING === 'true' && collectionsForTracking.length > 0) {
144
+ // trackMethodCall({
145
+ // apiUser: context.apiUser,
146
+ // apiKey: context.apiKey,
147
+ // event: 'PLACE_COLLECTION_BIDS',
148
+ // items: collectionsForTracking,
149
+ // });
150
+ // }
151
+
152
+ return tx;
153
+ };