@tradeport/sui-trading-sdk 0.5.3 → 0.5.5

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,73 @@
1
+ import { type KioskClient, type KioskTransaction, type TransferPolicy } from '@mysten/kiosk';
2
+ import { type SuiGrpcClient } from '@mysten/sui/grpc';
3
+ import { type Transaction } from '@mysten/sui/transactions';
4
+ import { getNativeKioskTransferPolicies } from './getNativeKioskTransferPolicies';
5
+ import { resolveTransferPolicies } from './resolveTransferPolicies';
6
+
7
+ interface TakeLockedNftFromKioskProps {
8
+ tx: Transaction;
9
+ transferPolicies: TransferPolicy[];
10
+ suiClient: SuiGrpcClient;
11
+ kioskTx: KioskTransaction;
12
+ kioskClient: KioskClient;
13
+ nftTokenId: string;
14
+ nftType: string;
15
+ kioskOwner: string;
16
+ }
17
+
18
+ export const takeLockedNftFromKiosk = async ({
19
+ tx,
20
+ transferPolicies,
21
+ suiClient,
22
+ kioskTx,
23
+ kioskClient,
24
+ nftTokenId,
25
+ nftType,
26
+ kioskOwner,
27
+ }: TakeLockedNftFromKioskProps) => {
28
+ const transferPolicy = getNativeKioskTransferPolicies(transferPolicies)?.at(0);
29
+ const hasFloorPriceRule = transferPolicy?.rules?.some(
30
+ (rule: any) => rule.type === 'floor_price_rule',
31
+ );
32
+ if (hasFloorPriceRule) {
33
+ throw new Error('Cannot take locked NFT from kiosk with a minimum floor price rule');
34
+ }
35
+
36
+ const [purchase_cap] = tx.moveCall({
37
+ target: '0x2::kiosk::list_with_purchase_cap',
38
+ arguments: [
39
+ tx.object(kioskTx.kiosk),
40
+ tx.object(kioskTx.kioskCap),
41
+ tx.pure.address(nftTokenId),
42
+ tx.pure.u64(0),
43
+ ],
44
+ typeArguments: [nftType],
45
+ });
46
+
47
+ const [zeroCoin] = tx.moveCall({
48
+ target: '0x2::coin::zero',
49
+ arguments: [],
50
+ typeArguments: ['0x2::sui::SUI'],
51
+ });
52
+
53
+ const [nft, transferRequest] = tx.moveCall({
54
+ target: '0x2::kiosk::purchase_with_cap',
55
+ arguments: [tx.object(kioskTx.kiosk), purchase_cap, zeroCoin],
56
+ typeArguments: [nftType],
57
+ });
58
+
59
+ await resolveTransferPolicies({
60
+ tx,
61
+ transferPolicies,
62
+ suiClient,
63
+ walletAddress: kioskOwner,
64
+ kioskTx,
65
+ kioskClient,
66
+ nftType,
67
+ price: '0',
68
+ transferRequest,
69
+ shouldSkipKioskLocking: true,
70
+ });
71
+
72
+ return nft;
73
+ };
@@ -0,0 +1,17 @@
1
+ import { normalizeSuiAddress } from '@mysten/sui/utils';
2
+
3
+ // @mysten/kiosk's mainnet rule defaults still point at v1 of the kiosk rules
4
+ // package. The package has since been upgraded; newer collections (e.g. suirocks)
5
+ // have linkage constraints that require the upgraded version, so calling v1
6
+ // fails with InvalidLinkage. Remap the original packageId to the upgraded one
7
+ // when it shows up in rule lookups.
8
+ const KIOSK_RULES_ORIGINAL_PACKAGE_ID = normalizeSuiAddress(
9
+ '0x434b5bd8f6a7b05fede0ff46c6e511d71ea326ed38056e3bcd681d2d7c2a7879',
10
+ );
11
+ const KIOSK_RULES_UPGRADED_PACKAGE_ID =
12
+ '0xdfb4f1d4e43e0c3ad834dcd369f0d39005c872e118c9dc1c5da9765bb93ee5f3';
13
+
14
+ export const upgradeKioskRulesPackageId = (packageId: string): string =>
15
+ normalizeSuiAddress(packageId) === KIOSK_RULES_ORIGINAL_PACKAGE_ID
16
+ ? KIOSK_RULES_UPGRADED_PACKAGE_ID
17
+ : packageId;
@@ -0,0 +1,33 @@
1
+ import { type Transaction } from '@mysten/sui/transactions';
2
+
3
+ type Args = {
4
+ tx: Transaction;
5
+ sharedObjects: any;
6
+ transferRequest: any;
7
+ nftType: string;
8
+ };
9
+
10
+ export const confirmOBTranfer = ({ tx, sharedObjects, transferRequest, nftType }: Args) => {
11
+ tx.moveCall({
12
+ target:
13
+ '0x6f42ec2355fcda5ebeee2399d901ae9f71cb214e640a45a0007f1f1cdf9f7b5e::transfer_allowlist::confirm_transfer',
14
+ arguments: [tx.object(sharedObjects?.allowList), tx.object(transferRequest)],
15
+ typeArguments: [nftType],
16
+ });
17
+
18
+ if (sharedObjects?.royaltyStrategy) {
19
+ tx.moveCall({
20
+ target:
21
+ '0x6f42ec2355fcda5ebeee2399d901ae9f71cb214e640a45a0007f1f1cdf9f7b5e::royalty_strategy_bps::confirm_transfer',
22
+ arguments: [tx.object(sharedObjects?.royaltyStrategy), tx.object(transferRequest)],
23
+ typeArguments: [nftType, '0x2::sui::SUI'],
24
+ });
25
+ }
26
+
27
+ tx.moveCall({
28
+ target:
29
+ '0xadf32ebafc587cc86e1e56e59f7b17c7e8cbeb3315193be63c6f73157d4e88b9::transfer_request::confirm',
30
+ arguments: [tx.object(transferRequest), tx.object(sharedObjects?.transferPolicy)],
31
+ typeArguments: [nftType, '0x2::sui::SUI'],
32
+ });
33
+ };
@@ -0,0 +1,14 @@
1
+ type Args = {
2
+ tx: any;
3
+ createMethod?: string;
4
+ };
5
+
6
+ export const createOBKiosk = async ({ tx, createMethod = 'new' }: Args) => {
7
+ const [kiosk] = tx.moveCall({
8
+ target: `0x2678c98fe23173eebea384509464eb81b1f3035a57419cb46d025000c337451a::ob_kiosk::${createMethod}`,
9
+ arguments: [],
10
+ typeArguments: [],
11
+ });
12
+
13
+ return [kiosk];
14
+ };
@@ -0,0 +1,16 @@
1
+ import { type Transaction } from '@mysten/sui/transactions';
2
+
3
+ type Args = {
4
+ tx: Transaction;
5
+ kiosk: string;
6
+ nftTokenId: string;
7
+ nftType: string;
8
+ };
9
+
10
+ export const depositItemIntoOBKiosk = ({ tx, kiosk, nftTokenId, nftType }: Args) => {
11
+ tx.moveCall({
12
+ target: '0x2678c98fe23173eebea384509464eb81b1f3035a57419cb46d025000c337451a::ob_kiosk::deposit',
13
+ arguments: [tx.object(kiosk), tx.object(nftTokenId)],
14
+ typeArguments: [nftType],
15
+ });
16
+ };
@@ -0,0 +1,12 @@
1
+ import { type SuiGrpcClient } from '@mysten/sui/grpc';
2
+
3
+ export const getOBBidderKiosk = async ({
4
+ suiClient,
5
+ bidNonce,
6
+ }: {
7
+ suiClient: SuiGrpcClient;
8
+ bidNonce: string;
9
+ }) => {
10
+ const bidObject = await suiClient.getObject({ objectId: bidNonce, include: { json: true } });
11
+ return (bidObject.object?.json as any)?.kiosk;
12
+ };
@@ -0,0 +1,24 @@
1
+ import { gqlChainRequest } from '../../graphql/gqlChainRequest';
2
+ import { fetchWalletKiosks } from '../../graphql/queries/fetchWalletKiosks';
3
+ import { addLeadingZerosAfter0x } from '../../utils/addLeadingZerosAfter0x';
4
+ import { type SharedKioskState } from '../kiosk/sharedKioskState.type';
5
+
6
+ export const getOBKiosk = async ({
7
+ wallet,
8
+ sharedKioskState,
9
+ }: {
10
+ wallet: string;
11
+ sharedKioskState?: SharedKioskState;
12
+ }): Promise<any> => {
13
+ const res = await gqlChainRequest({
14
+ chain: 'sui',
15
+ query: fetchWalletKiosks,
16
+ variables: { wallet: addLeadingZerosAfter0x(wallet) },
17
+ });
18
+
19
+ if (sharedKioskState && !sharedKioskState?.ownerKiosks) {
20
+ sharedKioskState.ownerKiosks = res?.kiosks;
21
+ }
22
+
23
+ return res?.kiosks?.filter((kiosk: any) => kiosk?.is_origin_byte && kiosk?.is_shared)?.[0]?.id;
24
+ };
@@ -0,0 +1,42 @@
1
+ import { type SharedKioskState } from '../kiosk/sharedKioskState.type';
2
+ import { createOBKiosk } from './createOBKiosk';
3
+ import { getOBKiosk } from './getOBKiosk';
4
+
5
+ type Args = {
6
+ tx: any;
7
+ address: string;
8
+ kioskToUseIfExists?: string;
9
+ createMethod?: string;
10
+ sharedKioskState?: SharedKioskState;
11
+ };
12
+
13
+ export const getOrCreateOBKiosk = async ({
14
+ tx,
15
+ address,
16
+ kioskToUseIfExists,
17
+ createMethod,
18
+ sharedKioskState,
19
+ }: Args) => {
20
+ if (kioskToUseIfExists) {
21
+ return {
22
+ kiosk: kioskToUseIfExists,
23
+ isNewKiosk: false,
24
+ };
25
+ }
26
+
27
+ if (!sharedKioskState?.ownerKiosks) {
28
+ const existingKiosk = await getOBKiosk({ wallet: address, sharedKioskState });
29
+ if (existingKiosk) {
30
+ return {
31
+ kiosk: existingKiosk,
32
+ isNewKiosk: false,
33
+ };
34
+ }
35
+ }
36
+
37
+ const [newKiosk] = await createOBKiosk({ tx, createMethod });
38
+ return {
39
+ kiosk: newKiosk,
40
+ isNewKiosk: true,
41
+ };
42
+ };
@@ -0,0 +1,13 @@
1
+ import { gqlChainRequest } from '../../graphql/gqlChainRequest';
2
+ import { fetchAccountKiosks } from '../../graphql/queries/fetchAccountKiosks';
3
+ import { addLeadingZerosAfter0x } from '../../utils/addLeadingZerosAfter0x';
4
+
5
+ export const isOBKiosk = async (accountAddress: string, kiosk: any): Promise<boolean> => {
6
+ const res = await gqlChainRequest({
7
+ chain: 'sui',
8
+ query: fetchAccountKiosks,
9
+ variables: { accountAddress: addLeadingZerosAfter0x(accountAddress) },
10
+ });
11
+
12
+ return res?.kiosks?.filter((k: any) => k?.id === kiosk)?.[0]?.is_origin_byte;
13
+ };
@@ -0,0 +1,30 @@
1
+ import { normalizeStructTag } from '@mysten/sui/utils';
2
+ import { ORIGIN_BYTE_BID_NONCE_TYPE } from '../../constants';
3
+
4
+ // The gRPC client returns Move types with fully-padded addresses
5
+ // (e.g. `0x0000…0002::kiosk::Kiosk`), while the JSON-RPC client used the
6
+ // abbreviated form (`0x2::kiosk::Kiosk`). Normalize both sides so the
7
+ // comparison is independent of address format / type-argument padding.
8
+ const safeNormalizeStructTag = (type: string): string => {
9
+ try {
10
+ return normalizeStructTag(type);
11
+ } catch {
12
+ return type;
13
+ }
14
+ };
15
+
16
+ // Precomputed once. `normalizeStructTag` preserves module-name casing, so the
17
+ // legacy capitalized `Kiosk` variant is kept alongside the canonical lowercase one.
18
+ const ORIGIN_BYTE_BID_TYPES = new Set(
19
+ [ORIGIN_BYTE_BID_NONCE_TYPE, '0x2::kiosk::Kiosk', '0x2::Kiosk::Kiosk'].map(
20
+ safeNormalizeStructTag,
21
+ ),
22
+ );
23
+
24
+ export const isOriginByteBid = (bidType: string): boolean => {
25
+ if (!bidType) {
26
+ return false;
27
+ }
28
+
29
+ return ORIGIN_BYTE_BID_TYPES.has(safeNormalizeStructTag(bidType));
30
+ };
@@ -0,0 +1,11 @@
1
+ export const isOriginByteCollection = (transferPolicies: any): boolean => {
2
+ const hasOriginBytePolicies =
3
+ transferPolicies?.filter((policy: any) => policy?.is_origin_byte && !policy?.is_disabled)
4
+ ?.length > 0;
5
+
6
+ const hasNonOriginBytePoliciesWithRules = transferPolicies
7
+ ?.filter((policy: any) => !policy?.is_origin_byte && !policy?.is_disabled)
8
+ ?.some((policy: any) => policy?.rules?.length > 0);
9
+
10
+ return Boolean(hasOriginBytePolicies && !hasNonOriginBytePoliciesWithRules);
11
+ };
@@ -0,0 +1,14 @@
1
+ import { type Transaction } from '@mysten/sui/transactions';
2
+
3
+ type Args = {
4
+ tx: Transaction;
5
+ kiosk: string;
6
+ };
7
+
8
+ export const shareOriginByteKiosk = ({ tx, kiosk }: Args) => {
9
+ tx.moveCall({
10
+ target: '0x2::transfer::public_share_object',
11
+ arguments: [tx.object(kiosk)],
12
+ typeArguments: ['0x2::kiosk::Kiosk'],
13
+ });
14
+ };
@@ -0,0 +1,18 @@
1
+ import { type SuiGrpcClient } from '@mysten/sui/grpc';
2
+ import { addLeadingZerosAfter0x } from '../../utils/addLeadingZerosAfter0x';
3
+
4
+ type Args = {
5
+ suiClient: SuiGrpcClient;
6
+ owner: string;
7
+ };
8
+
9
+ export const getAccountBalance = async ({ suiClient, owner }: Args): Promise<number> => {
10
+ try {
11
+ const res = await suiClient.getBalance({
12
+ owner: addLeadingZerosAfter0x(owner),
13
+ });
14
+ return Number(res?.balance?.balance);
15
+ } catch (err) {
16
+ return 0;
17
+ }
18
+ };
@@ -0,0 +1,25 @@
1
+ import { type SuiGrpcClient } from '@mysten/sui/grpc';
2
+ import { isValidSuiObjectId } from '@mysten/sui/utils';
3
+ import { addLeadingZerosAfter0x } from '../../utils/addLeadingZerosAfter0x';
4
+
5
+ export const getObjectType = async ({
6
+ suiClient,
7
+ objectId,
8
+ }: {
9
+ suiClient: SuiGrpcClient;
10
+ objectId: string;
11
+ }): Promise<string> => {
12
+ const normalizedObjectId = objectId.startsWith('0x')
13
+ ? addLeadingZerosAfter0x(objectId)
14
+ : objectId;
15
+ if (isValidSuiObjectId(normalizedObjectId)) {
16
+ try {
17
+ const res = await suiClient.getObject({ objectId: normalizedObjectId, include: {} });
18
+ return res.object?.type ?? '';
19
+ } catch {
20
+ return '';
21
+ }
22
+ }
23
+
24
+ return '';
25
+ };
@@ -0,0 +1,12 @@
1
+ import { type Transaction } from '@mysten/sui/transactions';
2
+
3
+ type Args = {
4
+ tx: Transaction;
5
+ amounts: any;
6
+ };
7
+
8
+ export const splitCoins = ({ tx, amounts }: Args) => {
9
+ const res = tx.splitCoins(tx.gas, amounts);
10
+
11
+ return res;
12
+ };
@@ -0,0 +1,20 @@
1
+ interface TrackMethodCallArgs {
2
+ apiUser: string;
3
+ apiKey: string;
4
+ event: string;
5
+ items?: any[];
6
+ }
7
+
8
+ export const trackMethodCall = ({ apiUser, apiKey, event, items }: TrackMethodCallArgs) => {
9
+ // analytics.track({
10
+ // userId: apiUser,
11
+ // event,
12
+ // properties: {
13
+ // chain: 'sui',
14
+ // apiUser,
15
+ // apiKey,
16
+ // items,
17
+ // },
18
+ // });
19
+ // void analytics.flush();
20
+ };
@@ -0,0 +1,22 @@
1
+ import { getNativeKioskTransferPolicies } from './kiosk/getNativeKioskTransferPolicies';
2
+
3
+ interface ValidateMinFloorPriceArgs {
4
+ transferPolicies: any;
5
+ listPrice: number;
6
+ }
7
+
8
+ export function validateMinFloorPrice({ transferPolicies, listPrice }: ValidateMinFloorPriceArgs) {
9
+ const transferPolicy = getNativeKioskTransferPolicies(transferPolicies)?.at(0);
10
+ const minFloorPrice = transferPolicy?.rules?.filter(
11
+ (rule: any) => rule?.type === 'floor_price_rule',
12
+ )?.[0]?.floor_price;
13
+
14
+ if (minFloorPrice) {
15
+ if (listPrice < minFloorPrice) {
16
+ const formattedMinFloorPrice = Number(minFloorPrice) / 1000000000;
17
+ throw new Error(
18
+ `NFT Transfer Policy has a miminum floor price rule. Item cannot be listed for less than ${formattedMinFloorPrice} SUI`,
19
+ );
20
+ }
21
+ }
22
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ import SuiTradingClient from './SuiTradingClient';
2
+ export { SuiTradingClient };
@@ -0,0 +1,189 @@
1
+ import type { KioskClient, KioskTransaction } 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 {
6
+ DELOREAN_TOKEN_IDS_TO_DISABLE,
7
+ DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE,
8
+ } from '../../constants';
9
+ import { gqlChainRequest } from '../../graphql/gqlChainRequest';
10
+ import { fetchNftById } from '../../graphql/queries/fetchNftsById';
11
+ import { getNftType } from '../../helpers/getNftType';
12
+ import { getSharedObjects } from '../../helpers/getSharedObjects';
13
+ import { type SharedKioskState } from '../../helpers/kiosk/sharedKioskState.type';
14
+ import {
15
+ addBluemoveAcceptCollectionBidTxHandler,
16
+ addOriginByteAcceptCollectionBidTx,
17
+ addTocenAcceptCollectionBidTxHandler,
18
+ addTradePortAcceptCollectionBidTxHandler,
19
+ } from './addAcceptCollectionBIdTxs';
20
+
21
+ export type AcceptCollectionBidTx = {
22
+ tx: Transaction;
23
+ suiClient: SuiGrpcClient;
24
+ kioskClient: KioskClient;
25
+ kioskTx?: any;
26
+ sharedObjects?: any;
27
+ transferPolicies: any;
28
+ sharedKioskState?: SharedKioskState;
29
+ bidNonce: string;
30
+ nftType: string;
31
+ nftTokenId: string;
32
+ listingPrice: number;
33
+ listingNonce: string;
34
+ itemOwner: string;
35
+ bidAmount: number;
36
+ bidder: string;
37
+ seller: string;
38
+ sellerKiosk: string;
39
+ collectionId: string;
40
+ isListedOnBluemove: boolean;
41
+ bidMarketName: string;
42
+ itemTakenOutOfNativeKiosk?: any;
43
+ royaltyRulePackageId?: string;
44
+ royaltyRuleModule?: string;
45
+ shouldSplitRoyaltyFromUserGasCoins?: boolean;
46
+ multiBidId?: string;
47
+ beforeResolveKioskTransferRequest?: (coin: any, transferRequest: any) => void | Promise<void>;
48
+ };
49
+
50
+ export type AcceptCollectionBid = {
51
+ bidId: string;
52
+ nftId: string;
53
+ walletAddress: string;
54
+ };
55
+
56
+ export type InternalAcceptCollectionBid = {
57
+ bid: any;
58
+ nftId: string;
59
+ walletAddress: string;
60
+ tx?: Transaction;
61
+ kioskTx?: KioskTransaction;
62
+ shouldSplitRoyaltyFromUserGasCoins?: boolean;
63
+ beforeResolveKioskTransferRequest?: (coin: any, transferRequest: any) => void | Promise<void>;
64
+ };
65
+
66
+ const ERROR_UNLIST_FIRST =
67
+ 'Item must be unlisted first before you can accept a collection bid with it';
68
+
69
+ export const acceptCollectionBid = async (
70
+ {
71
+ bid,
72
+ nftId,
73
+ walletAddress,
74
+ tx: existingTx,
75
+ kioskTx,
76
+ shouldSplitRoyaltyFromUserGasCoins,
77
+ beforeResolveKioskTransferRequest,
78
+ }: InternalAcceptCollectionBid,
79
+ context: RequestContext,
80
+ ): Promise<Transaction> => {
81
+ const nftRes = await gqlChainRequest({
82
+ chain: 'sui',
83
+ query: fetchNftById,
84
+ variables: { nftId },
85
+ });
86
+ const nft = nftRes?.nfts?.[0];
87
+
88
+ if (!nft) {
89
+ throw new Error('No nft found');
90
+ }
91
+
92
+ if (DELOREAN_TOKEN_IDS_TO_DISABLE?.includes(nft?.token_id)) {
93
+ throw new Error(DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE);
94
+ }
95
+
96
+ const bidsForTracking = [];
97
+ const tx = existingTx ?? new Transaction();
98
+
99
+ const sharedKioskState: SharedKioskState = {
100
+ kioskTx: kioskTx ?? undefined,
101
+ };
102
+
103
+ const nftType = getNftType({
104
+ collectionId: nft?.collection_id,
105
+ collectionChainState: nft?.collection?.chain_state,
106
+ nft,
107
+ });
108
+
109
+ const transferPolicies = nft?.collection?.chain_state?.transfer_policies;
110
+
111
+ const txData: AcceptCollectionBidTx = {
112
+ tx,
113
+ kioskTx,
114
+ transferPolicies,
115
+ suiClient: context.suiClient,
116
+ kioskClient: context.kioskClient,
117
+ sharedKioskState,
118
+ bidNonce: bid?.nonce,
119
+ nftType,
120
+ nftTokenId: nft?.token_id,
121
+ itemOwner: nft?.owner,
122
+ listingPrice: nft?.listings?.[0]?.price,
123
+ listingNonce: nft?.listings?.[0]?.nonce,
124
+ bidAmount: bid?.price,
125
+ bidder: bid?.bidder,
126
+ seller: walletAddress,
127
+ sellerKiosk: nft?.chain_state?.kiosk_id,
128
+ collectionId: nft?.collection_id,
129
+ isListedOnBluemove: nft?.listings?.[0]?.market_name === 'bluemove',
130
+ bidMarketName: bid?.market_contract?.name,
131
+ multiBidId: bid.multi_bid_id,
132
+ shouldSplitRoyaltyFromUserGasCoins,
133
+ beforeResolveKioskTransferRequest,
134
+ };
135
+
136
+ switch (txData.bidMarketName) {
137
+ case 'tradeport':
138
+ if (txData?.listingPrice && txData?.listingPrice > 0) {
139
+ throw new Error(ERROR_UNLIST_FIRST);
140
+ }
141
+
142
+ await addTradePortAcceptCollectionBidTxHandler(txData);
143
+ break;
144
+ case 'clutchy': {
145
+ const sharedObjects = await getSharedObjects(txData?.nftType);
146
+ await addOriginByteAcceptCollectionBidTx({ ...txData, sharedObjects });
147
+ break;
148
+ }
149
+
150
+ case 'bluemove':
151
+ if (txData?.listingPrice && txData?.listingPrice > 0 && !txData?.isListedOnBluemove) {
152
+ throw new Error(ERROR_UNLIST_FIRST);
153
+ }
154
+
155
+ await addBluemoveAcceptCollectionBidTxHandler(txData);
156
+ break;
157
+ case 'tocen':
158
+ if (txData?.listingPrice && txData?.listingPrice > 0) {
159
+ throw new Error(ERROR_UNLIST_FIRST);
160
+ }
161
+
162
+ addTocenAcceptCollectionBidTxHandler(txData);
163
+ break;
164
+ default:
165
+ throw new Error('Marketplace not supported');
166
+ }
167
+
168
+ bidsForTracking.push({
169
+ nftType,
170
+ collectionId: nft?.collection_id,
171
+ bidAmount: bid?.price,
172
+ bidMarketName: bid?.market_contract?.name,
173
+ itemOwner: nft?.owner,
174
+ bidder: bid?.bidder,
175
+ });
176
+
177
+ sharedKioskState?.kioskTx?.finalize();
178
+
179
+ // if (process.env.ENABLE_SEGMENT_TRACKING === 'true' && bidsForTracking.length > 0) {
180
+ // trackMethodCall({
181
+ // apiUser: context.apiUser,
182
+ // apiKey: context.apiKey,
183
+ // event: 'ACCEPT_COLLECTION_BID',
184
+ // items: bidsForTracking,
185
+ // });
186
+ // }
187
+
188
+ return Transaction.from(tx);
189
+ };