@tradeport/sui-trading-sdk 0.4.39 → 0.4.41

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 (32) hide show
  1. package/dist/index.d.mts +14 -0
  2. package/dist/index.d.ts +14 -0
  3. package/dist/index.js +534 -134
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +518 -125
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +6 -2
  8. package/src/SuiTradingClient.ts +15 -0
  9. package/src/bigNumberConfig.ts +10 -0
  10. package/src/constants.ts +17 -1
  11. package/src/graphql/queries/fetchNftCollectionChainState.ts +12 -0
  12. package/src/helpers/calculateRoyaltyFee.ts +12 -7
  13. package/src/helpers/isExpiredListing.ts +9 -0
  14. package/src/helpers/kiosk/preProcessSharedBulkBuyingData.ts +9 -8
  15. package/src/helpers/swap.ts +197 -0
  16. package/src/helpers/validateMinFloorPrice.ts +22 -0
  17. package/src/methods/buyListings/addBuyListingTxs.ts +111 -5
  18. package/src/methods/buyLocks/buyLocks.ts +2 -2
  19. package/src/methods/createLongLocks/createLongLocks.ts +2 -2
  20. package/src/methods/createShortLocks/createShortLocks.ts +3 -3
  21. package/src/methods/listNfts/addListTxs.ts +17 -37
  22. package/src/methods/listNfts/addRelistTxs.ts +26 -17
  23. package/src/methods/listNfts/listNfts.ts +27 -16
  24. package/src/methods/placeNftBids/addPlaceNftBidTxs.ts +1 -1
  25. package/src/methods/relistNft/relistNft.ts +19 -28
  26. package/src/methods/sponsorNftListing/addSponsorNftListingTx.ts +71 -0
  27. package/src/methods/sponsorNftListing/sponsorNftListing.ts +62 -0
  28. package/src/methods/unlistListings/addUnlistListingTxs.ts +68 -5
  29. package/src/methods/unlistListings/unlistListings.ts +2 -6
  30. package/src/tests/SuiWallet.ts +4 -1
  31. package/src/utils/printTxBlockTxs.ts +7 -1
  32. package/src/utils/pureValues.ts +13 -0
@@ -1,14 +1,13 @@
1
1
  import {
2
2
  ORIGIN_BYTE_NFT_TYPES_MISSING_ORDERBOOK,
3
3
  TRADEPORT_BENEFICIARY_ADDRESS,
4
- TRADEPORT_KIOSK_LISTING_STORE,
5
- TRADEPORT_LISTING_STORE,
4
+ TRADEPORT_LISTINGS_PACKAGE,
5
+ TRADEPORT_LISTINGS_STORE,
6
6
  } from '../../constants';
7
7
  import { getMarketFeePrice } from '../../helpers/getMarketFeePrice';
8
8
  import { getSharedObjects } from '../../helpers/getSharedObjects';
9
9
  import { hasNativeKioskTransferPolicyRules } from '../../helpers/hasTransferPolicyRules';
10
10
  import { assertNftInSharedKiosk } from '../../helpers/kiosk/assertNftInSharedKiosk';
11
- import { getNativeKioskTransferPolicies } from '../../helpers/kiosk/getNativeKioskTransferPolicies';
12
11
  import { kioskTxWrapper } from '../../helpers/kiosk/kioskTxWrapper';
13
12
  import { takeAndBorrowNftFromKiosk } from '../../helpers/kiosk/takeAndBorrowNftFromKiosk';
14
13
  import { depositItemIntoOBKiosk } from '../../helpers/originByte/depositNftIntoOBKiosk';
@@ -16,6 +15,7 @@ import { getOrCreateOBKiosk } from '../../helpers/originByte/getOrCreateOBKiosk'
16
15
  import { isOriginByteCollection } from '../../helpers/originByte/isOriginByteCollection';
17
16
  import { shareOriginByteKiosk } from '../../helpers/originByte/shareOriginByteKiosk';
18
17
  import { normalizedNftType } from '../../utils/normalizeNftType';
18
+ import { validateMinFloorPrice } from '../../helpers/validateMinFloorPrice';
19
19
  import { type ListNftTx } from './listNfts';
20
20
 
21
21
  export async function addOriginByteListTx({
@@ -79,66 +79,44 @@ export function addTradePortListTx({
79
79
  nftTokenId,
80
80
  borrowedItem,
81
81
  nftType,
82
- collectionId,
83
82
  listPrice,
84
83
  }: ListNftTx) {
85
- const marketFeePrice = getMarketFeePrice({ price: listPrice, collectionId });
86
-
87
84
  tx.moveCall({
88
- target: '0xb42dbb7413b79394e1a0175af6ae22b69a5c7cc5df259cd78072b6818217c027::listings::list',
85
+ target: `${TRADEPORT_LISTINGS_PACKAGE}::tradeport_listings::create_listing_without_transfer_policy`,
89
86
  arguments: [
90
- tx.object(TRADEPORT_LISTING_STORE),
87
+ tx.object(TRADEPORT_LISTINGS_STORE),
91
88
  borrowedItem ? tx.object(borrowedItem) : tx.object(nftTokenId),
92
89
  tx.pure.u64(listPrice),
93
- tx.pure.u64(marketFeePrice),
94
- tx.pure.address(TRADEPORT_BENEFICIARY_ADDRESS),
95
90
  ],
96
91
  typeArguments: [nftType],
97
92
  });
98
93
  }
99
94
 
100
- export async function addTradePortKioskListTx({
95
+ export async function addKioskTradePortListTx({
101
96
  tx,
102
97
  kioskTx,
103
98
  transferPolicies,
104
99
  nftTokenId,
105
100
  nftType,
106
- collectionId,
107
101
  listPrice,
108
102
  }: ListNftTx) {
109
- const transferPolicy = getNativeKioskTransferPolicies(transferPolicies)?.at(0);
110
- const minFloorPrice = transferPolicy?.rules?.filter(
111
- (rule: any) => rule?.type === 'floor_price_rule',
112
- )?.[0]?.floor_price;
113
-
114
- if (minFloorPrice) {
115
- if (listPrice < minFloorPrice) {
116
- const formattedMinFloorPrice = Number(minFloorPrice) / 1000000000;
117
- throw new Error(
118
- `NFT Transfer Policy has a miminum floor price rule. Item cannot be listed for less than ${formattedMinFloorPrice} SUI`,
119
- );
120
- }
121
- }
122
-
123
- const marketFeePrice = getMarketFeePrice({ price: listPrice, collectionId });
103
+ validateMinFloorPrice({ transferPolicies, listPrice });
124
104
 
125
105
  tx.moveCall({
126
- target:
127
- '0x475e98e9c436ec118909f3b9e241d86bcbbc2cf9fba05e99a934823fefb375b7::kiosk_listings::list',
106
+ target: `${TRADEPORT_LISTINGS_PACKAGE}::tradeport_listings::create_listing_with_transfer_policy`,
128
107
  arguments: [
129
- tx.object(TRADEPORT_KIOSK_LISTING_STORE),
108
+ tx.object(TRADEPORT_LISTINGS_STORE),
130
109
  tx.object(kioskTx.kiosk.value ?? kioskTx.kiosk),
131
110
  tx.object(kioskTx.kioskCap.value ?? kioskTx.kioskCap),
132
- tx.pure.address(nftTokenId),
133
- tx.pure.u64(listPrice + marketFeePrice),
134
- tx.pure.u64(marketFeePrice),
135
- tx.pure.address(TRADEPORT_BENEFICIARY_ADDRESS),
111
+ tx.pure.id(nftTokenId),
112
+ tx.pure.u64(listPrice),
136
113
  ],
137
114
  typeArguments: [nftType],
138
115
  });
139
116
  }
140
117
 
141
118
  export async function addTradePortListTxHandler(txData: ListNftTx) {
119
+ // If NFT is an Origin Byte collection, create an Origin Byte listing
142
120
  if (
143
121
  isOriginByteCollection(txData?.transferPolicies) &&
144
122
  !ORIGIN_BYTE_NFT_TYPES_MISSING_ORDERBOOK?.includes(normalizedNftType(txData?.nftType))
@@ -181,6 +159,7 @@ export async function addTradePortListTxHandler(txData: ListNftTx) {
181
159
  });
182
160
  }
183
161
 
162
+ // If NFT is in a kiosk, create a kiosk listing
184
163
  if (txData?.sellerKiosk) {
185
164
  return kioskTxWrapper({
186
165
  tx: txData?.tx,
@@ -191,7 +170,7 @@ export async function addTradePortListTxHandler(txData: ListNftTx) {
191
170
  sharedKioskState: txData?.sharedKioskState,
192
171
  shouldUseSharedKioskTx: false,
193
172
  async runCommands(kioskTx) {
194
- await addTradePortKioskListTx({
173
+ await addKioskTradePortListTx({
195
174
  ...txData,
196
175
  kioskTx,
197
176
  });
@@ -199,7 +178,7 @@ export async function addTradePortListTxHandler(txData: ListNftTx) {
199
178
  });
200
179
  }
201
180
 
202
- // If NFT not in a kiosk, but nft type has a transfer policy rule, create kiosk and place NFT in kiosk first
181
+ // If NFT is not in a kiosk, but nft type has a transfer policy rule, create kiosk and place NFT in kiosk first
203
182
  if (!txData?.sellerKiosk && hasNativeKioskTransferPolicyRules(txData?.transferPolicies)) {
204
183
  return kioskTxWrapper({
205
184
  tx: txData?.tx,
@@ -213,7 +192,7 @@ export async function addTradePortListTxHandler(txData: ListNftTx) {
213
192
  item: txData?.nftTokenId,
214
193
  itemType: txData?.nftType,
215
194
  });
216
- await addTradePortKioskListTx({
195
+ await addKioskTradePortListTx({
217
196
  ...txData,
218
197
  kioskTx,
219
198
  });
@@ -221,5 +200,6 @@ export async function addTradePortListTxHandler(txData: ListNftTx) {
221
200
  });
222
201
  }
223
202
 
203
+ // Fallback to non-kiosk listing
224
204
  addTradePortListTx(txData);
225
205
  }
@@ -3,10 +3,9 @@ import { type Transaction, type TransactionObjectArgument } from '@mysten/sui/tr
3
3
  import {
4
4
  BLUEMOVE_MARKET_CONFIG_OBJECT,
5
5
  TOCEN_MARKETPLACE_OBJECT,
6
- TRADEPORT_BENEFICIARY_ADDRESS,
7
- TRADEPORT_LISTING_STORE,
6
+ TRADEPORT_LISTINGS_PACKAGE,
7
+ TRADEPORT_LISTINGS_STORE,
8
8
  } from '../../constants';
9
- import { getMarketFeePrice } from '../../helpers/getMarketFeePrice';
10
9
  import { addTradePortListTx } from './addListTxs';
11
10
  import { type SuiClient } from '@mysten/sui/client';
12
11
 
@@ -26,30 +25,40 @@ export type RelistNftTx = {
26
25
  sellerKiosk: string;
27
26
  };
28
27
 
29
- export function addTradePortRelistTx({
28
+ export function addTradePortRelistTx({ tx, nftTokenId, nftType, listPrice }: RelistNftTx) {
29
+ tx.moveCall({
30
+ target: `${TRADEPORT_LISTINGS_PACKAGE}::tradeport_listings::relist_listing_without_transfer_policy`,
31
+ arguments: [
32
+ tx.object(TRADEPORT_LISTINGS_STORE),
33
+ tx.pure.id(nftTokenId),
34
+ tx.pure.u64(listPrice),
35
+ ],
36
+ typeArguments: [nftType],
37
+ });
38
+ }
39
+
40
+ export async function addKioskTradePortRelistTx({
30
41
  tx,
42
+ kioskTx,
43
+ nftTokenId,
31
44
  nftType,
32
- collectionId,
33
- listingNonce,
34
45
  listPrice,
35
46
  }: RelistNftTx) {
36
- const marketFeePrice = getMarketFeePrice({ price: listPrice, collectionId });
37
-
38
47
  tx.moveCall({
39
- target: '0xb42dbb7413b79394e1a0175af6ae22b69a5c7cc5df259cd78072b6818217c027::listings::relist',
48
+ target: `${TRADEPORT_LISTINGS_PACKAGE}::tradeport_listings::relist_listing_with_transfer_policy`,
40
49
  arguments: [
41
- tx.object(TRADEPORT_LISTING_STORE),
42
- tx.pure.address(listingNonce),
50
+ tx.object(TRADEPORT_LISTINGS_STORE),
51
+ tx.object(kioskTx.kiosk.value ?? kioskTx.kiosk),
52
+ tx.object(kioskTx.kioskCap.value ?? kioskTx.kioskCap),
53
+ tx.pure.id(nftTokenId),
43
54
  tx.pure.u64(listPrice),
44
- tx.pure.u64(marketFeePrice),
45
- tx.pure.address(TRADEPORT_BENEFICIARY_ADDRESS),
46
55
  ],
47
56
  typeArguments: [nftType],
48
57
  });
49
58
  }
50
59
 
51
60
  export function addBlueMoveRelistTx(txData: RelistNftTx) {
52
- const { tx, nftTokenId, nftType, listPrice, suiClient } = txData;
61
+ const { tx, nftTokenId, nftType, listPrice } = txData;
53
62
 
54
63
  const borrowedItem = tx.moveCall({
55
64
  target:
@@ -58,11 +67,11 @@ export function addBlueMoveRelistTx(txData: RelistNftTx) {
58
67
  typeArguments: [nftType, nftType],
59
68
  }) as TransactionObjectArgument;
60
69
 
61
- addTradePortListTx({ ...txData, listPrice, borrowedItem, suiClient });
70
+ addTradePortListTx({ ...txData, listPrice, borrowedItem });
62
71
  }
63
72
 
64
73
  export function addTocenRelistTx(txData: RelistNftTx) {
65
- const { tx, nftTokenId, nftType, listPrice, suiClient } = txData;
74
+ const { tx, nftTokenId, nftType, listPrice } = txData;
66
75
 
67
76
  const borrowedItem = tx.moveCall({
68
77
  target:
@@ -71,5 +80,5 @@ export function addTocenRelistTx(txData: RelistNftTx) {
71
80
  typeArguments: [nftType],
72
81
  }) as any;
73
82
 
74
- addTradePortListTx({ ...txData, listPrice, borrowedItem, suiClient });
83
+ addTradePortListTx({ ...txData, listPrice, borrowedItem });
75
84
  }
@@ -1,7 +1,6 @@
1
1
  import { type KioskClient } from '@mysten/kiosk';
2
2
  import { type SuiClient } from '@mysten/sui/client';
3
3
  import { Transaction, type TransactionObjectInput } from '@mysten/sui/transactions';
4
- import { normalizeSuiAddress } from '@mysten/sui/utils';
5
4
  import { type RequestContext } from '../../SuiTradingClient';
6
5
  import {
7
6
  DELOREAN_TOKEN_IDS_TO_DISABLE,
@@ -13,6 +12,10 @@ import { getNftType } from '../../helpers/getNftType';
13
12
  import { type SharedKioskState } from '../../helpers/kiosk/sharedKioskState.type';
14
13
  import { relistNft } from '../relistNft/relistNft';
15
14
  import { addTradePortListTxHandler } from './addListTxs';
15
+ import { isOriginByteCollection } from '../../helpers/originByte/isOriginByteCollection';
16
+ import { addSponsorListingTx } from '../sponsorNftListing/addSponsorNftListingTx';
17
+ import { type SponsorNftListingOptions } from '../sponsorNftListing/sponsorNftListing';
18
+ import { isExpiredListing } from '../../helpers/isExpiredListing';
16
19
 
17
20
  export type ListNftTx = {
18
21
  tx: Transaction;
@@ -31,16 +34,11 @@ export type ListNftTx = {
31
34
  sharedKioskState?: SharedKioskState;
32
35
  };
33
36
 
34
- export type ListNft = {
35
- nftId: string;
36
- listPriceInMist: number;
37
- walletAddress: string;
38
- };
39
-
40
37
  export type ListNfts = {
41
38
  nfts: Array<{
42
39
  id: string;
43
40
  listPriceInMist: number;
41
+ sponsorOptions?: SponsorNftListingOptions;
44
42
  }>;
45
43
  walletAddress: string;
46
44
  };
@@ -67,6 +65,8 @@ export const listNfts = async (
67
65
  };
68
66
 
69
67
  for (const nft of res.nfts) {
68
+ const inputNft = nfts?.find((n) => n.id === nft?.id);
69
+
70
70
  if (DELOREAN_TOKEN_IDS_TO_DISABLE?.includes(nft?.token_id)) {
71
71
  throw new Error(DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE);
72
72
  }
@@ -79,14 +79,14 @@ export const listNfts = async (
79
79
 
80
80
  const transferPolicies = nft?.collection?.chain_state?.transfer_policies;
81
81
 
82
- // The NFT owner can also relist expired bids
82
+ if (inputNft?.sponsorOptions?.shouldSponsor && isOriginByteCollection(transferPolicies)) {
83
+ throw new Error(`You cannot sponsor an Origin Byte NFT. Nft Token Id: ${nft?.token_id}`);
84
+ }
85
+
83
86
  if (
84
87
  nft?.listed ||
85
- nft.listings.some(
86
- (listing: { nonce?: string; seller?: string }) =>
87
- listing.nonce &&
88
- listing.seller &&
89
- normalizeSuiAddress(listing.seller) === normalizeSuiAddress(walletAddress),
88
+ nft.listings.some((listing: { nonce?: string; seller?: string }) =>
89
+ isExpiredListing(listing, walletAddress),
90
90
  )
91
91
  ) {
92
92
  await relistNft({
@@ -96,7 +96,7 @@ export const listNfts = async (
96
96
  sharedKioskState,
97
97
  transferPolicies,
98
98
  nft,
99
- listPrice: nfts?.find((n) => n.id === nft?.id)?.listPriceInMist,
99
+ listPrice: inputNft?.listPriceInMist,
100
100
  walletAddress,
101
101
  });
102
102
  } else {
@@ -110,18 +110,29 @@ export const listNfts = async (
110
110
  collectionId: nft?.collection_id,
111
111
  nftTokenId: nft?.token_id,
112
112
  nftType,
113
- listPrice: nfts?.find((n) => n.id === nft?.id)?.listPriceInMist,
113
+ listPrice: inputNft?.listPriceInMist,
114
114
  sellerKiosk: nft?.chain_state?.kiosk_id,
115
115
  };
116
116
 
117
117
  await addTradePortListTxHandler(listTxData);
118
118
  }
119
119
 
120
+ if (inputNft?.sponsorOptions?.shouldSponsor) {
121
+ await addSponsorListingTx({
122
+ tx,
123
+ suiClient: context.suiClient,
124
+ nftTokenId: nft?.token_id,
125
+ nftType,
126
+ walletAddress,
127
+ sponsorOptions: inputNft?.sponsorOptions,
128
+ });
129
+ }
130
+
120
131
  nftsForTracking.push({
121
132
  walletAddress,
122
133
  nftType,
123
134
  collectionId: nft?.collection_id,
124
- listPrice: nfts?.find((n) => n.id === nft?.id)?.listPriceInMist,
135
+ listPrice: inputNft?.listPriceInMist,
125
136
  isRelist: nft?.listed,
126
137
  marketRelistedFrom: nft?.listings?.[0]?.market_name,
127
138
  });
@@ -105,7 +105,7 @@ export async function addTradePortPlaceNftBidTxHandler(txData: PlaceNftBidTx) {
105
105
  }
106
106
 
107
107
  const [coin] = tx.splitCoins(coinToSplit ? coinToSplit : tx.gas, [
108
- multiBidChainId ? 0n : price + fee + royalty,
108
+ multiBidChainId ? 0n : price + fee + royalty,
109
109
  ]);
110
110
  tx.moveCall({
111
111
  target: `${TRADEPORT_MULTI_BID_PACKAGE}::tradeport_biddings::create_bid_with${transferPolicy ? '' : 'out'}_transfer_policy`,
@@ -3,21 +3,20 @@ import { type SuiClient } from '@mysten/sui/client';
3
3
  import { type Transaction } from '@mysten/sui/transactions';
4
4
  import { ORIGIN_BYTE_NFT_TYPES_MISSING_ORDERBOOK } from '../../constants';
5
5
  import { getNftType } from '../../helpers/getNftType';
6
- import { isNonKioskListing } from '../../helpers/isNonKioskListing';
7
6
  import { kioskTxWrapper } from '../../helpers/kiosk/kioskTxWrapper';
8
7
  import { isOriginByteCollection } from '../../helpers/originByte/isOriginByteCollection';
9
8
  import { normalizedNftType } from '../../utils/normalizeNftType';
10
- import { addTradePortKioskListTx, addTradePortListTxHandler } from '../listNfts/addListTxs';
9
+ import { addTradePortListTxHandler } from '../listNfts/addListTxs';
11
10
  import {
12
11
  addBlueMoveRelistTx,
13
12
  addTocenRelistTx,
14
13
  addTradePortRelistTx,
14
+ addKioskTradePortRelistTx,
15
15
  } from '../listNfts/addRelistTxs';
16
16
  import {
17
17
  addBluemoveUnlistTxHandler,
18
18
  addClutchyUnlistTxHandler,
19
19
  addHyperspaceUnlistTxHandler,
20
- addTradePortKioskUnlistTx,
21
20
  addTradePortUnlistTxHandler,
22
21
  } from '../unlistListings/addUnlistListingTxs';
23
22
  import { type UnlistListingTx } from '../unlistListings/unlistListings';
@@ -73,30 +72,24 @@ export async function relistNft({
73
72
  switch (firstListedOrExpiredListing.market_name) {
74
73
  case 'tradeport':
75
74
  if (
76
- (!isOriginByteCollection(txData?.transferPolicies) ||
77
- ORIGIN_BYTE_NFT_TYPES_MISSING_ORDERBOOK?.includes(normalizedNftType(txData?.nftType))) &&
78
75
  txData?.listingNonce &&
79
- (await isNonKioskListing({
80
- suiClient: txData?.suiClient,
81
- listingNonce: txData?.listingNonce,
82
- }))
76
+ isOriginByteCollection(txData?.transferPolicies) &&
77
+ !ORIGIN_BYTE_NFT_TYPES_MISSING_ORDERBOOK?.includes(normalizedNftType(txData?.nftType))
83
78
  ) {
84
- addTradePortRelistTx({ ...txData, listPrice });
85
- } else {
86
- if (
87
- txData?.listingNonce &&
88
- isOriginByteCollection(txData?.transferPolicies) &&
89
- !ORIGIN_BYTE_NFT_TYPES_MISSING_ORDERBOOK?.includes(normalizedNftType(txData?.nftType))
90
- ) {
91
- await addTradePortUnlistTxHandler(txData);
92
- await addTradePortListTxHandler({
93
- ...txData,
94
- listPrice,
95
- });
79
+ await addTradePortUnlistTxHandler(txData);
80
+ await addTradePortListTxHandler({
81
+ ...txData,
82
+ listPrice,
83
+ });
84
+ return;
85
+ }
96
86
 
97
- return;
98
- }
87
+ if (txData?.listingNonce?.startsWith('0::')) {
88
+ addTradePortRelistTx({ ...txData, listPrice });
89
+ return;
90
+ }
99
91
 
92
+ if (txData?.listingNonce?.startsWith('1::')) {
100
93
  return kioskTxWrapper({
101
94
  tx: txData?.tx,
102
95
  kioskClient: txData?.kioskClient,
@@ -106,11 +99,7 @@ export async function relistNft({
106
99
  sharedKioskState: txData?.sharedKioskState,
107
100
  shouldUseSharedKioskTx: false,
108
101
  async runCommands(kioskTx) {
109
- await addTradePortKioskUnlistTx({
110
- ...txData,
111
- kioskTx,
112
- });
113
- await addTradePortKioskListTx({
102
+ await addKioskTradePortRelistTx({
114
103
  ...txData,
115
104
  kioskTx,
116
105
  listPrice,
@@ -119,6 +108,8 @@ export async function relistNft({
119
108
  });
120
109
  }
121
110
 
111
+ await addTradePortUnlistTxHandler({ ...txData, isPartOfRelist: true });
112
+ await addTradePortListTxHandler({ ...txData, listPrice });
122
113
  break;
123
114
  case 'hyperspace':
124
115
  await addHyperspaceUnlistTxHandler(txData);
@@ -0,0 +1,71 @@
1
+ import type { Transaction } from '@mysten/sui/transactions';
2
+ import {
3
+ calculateSwapInputAmountWithSlippage,
4
+ createSwapTransaction,
5
+ transferBackExtraSwappedCoin,
6
+ } from '../../helpers/swap';
7
+ import { TRADEPORT_SPONSOR_USDC_FEE_AMOUNT_PER_PERIOD, USDC_COIN_TYPE } from '../../constants';
8
+ import type { SuiClient } from '@mysten/sui/client';
9
+ import { SUI_CLOCK_OBJECT_ID } from '@mysten/sui.js/utils';
10
+ import { TRADEPORT_LISTINGS_PACKAGE, TRADEPORT_LISTINGS_STORE } from '../../constants';
11
+ import { type SponsorNftListingOptions } from './sponsorNftListing';
12
+ import BigNumber from '../../bigNumberConfig';
13
+
14
+ export const addSponsorListingTx = async ({
15
+ tx,
16
+ nftTokenId,
17
+ nftType,
18
+ suiClient,
19
+ walletAddress,
20
+ sponsorOptions,
21
+ }: {
22
+ tx: Transaction;
23
+ nftTokenId: string;
24
+ nftType: string;
25
+ suiClient: SuiClient;
26
+ walletAddress: string;
27
+ sponsorOptions: SponsorNftListingOptions;
28
+ }) => {
29
+ const coinInAmount = await calculateSwapInputAmountWithSlippage({
30
+ coinInType: sponsorOptions?.coinInType,
31
+ coinOutType: USDC_COIN_TYPE,
32
+ coinOutAmount: new BigNumber(TRADEPORT_SPONSOR_USDC_FEE_AMOUNT_PER_PERIOD)
33
+ ?.times(sponsorOptions?.numOfPeriods)
34
+ .toString(),
35
+ slippage: sponsorOptions?.slippage,
36
+ });
37
+
38
+ const { coinOut } = await createSwapTransaction({
39
+ suiClient,
40
+ walletAddress,
41
+ options: {
42
+ transaction: tx,
43
+ coinInType: sponsorOptions?.coinInType,
44
+ coinInAmount,
45
+ coinOutType: USDC_COIN_TYPE,
46
+ slippage: sponsorOptions?.slippage,
47
+ },
48
+ });
49
+
50
+ const [sponsorFeeCoin] = tx.splitCoins(coinOut, [
51
+ tx.pure.u64(
52
+ new BigNumber(TRADEPORT_SPONSOR_USDC_FEE_AMOUNT_PER_PERIOD)
53
+ ?.times(sponsorOptions?.numOfPeriods)
54
+ .toString(),
55
+ ),
56
+ ]);
57
+
58
+ tx.moveCall({
59
+ target: `${TRADEPORT_LISTINGS_PACKAGE}::tradeport_listings::add_sponsored_listing`,
60
+ arguments: [
61
+ tx.object(TRADEPORT_LISTINGS_STORE),
62
+ tx.object(SUI_CLOCK_OBJECT_ID),
63
+ tx.pure.id(nftTokenId),
64
+ tx.pure.u64(sponsorOptions?.numOfPeriods),
65
+ tx.object(sponsorFeeCoin),
66
+ ],
67
+ typeArguments: [nftType],
68
+ });
69
+
70
+ transferBackExtraSwappedCoin(tx, coinOut, walletAddress);
71
+ };
@@ -0,0 +1,62 @@
1
+ import { Transaction } from '@mysten/sui/transactions';
2
+ import { gqlChainRequest } from '../../graphql/gqlChainRequest';
3
+ import { fetchNftCollectionChainState } from '../../graphql/queries/fetchNftCollectionChainState';
4
+ import { isOriginByteCollection } from '../../helpers/originByte/isOriginByteCollection';
5
+ import type { RequestContext } from '../../SuiTradingClient';
6
+ import { addSponsorListingTx } from './addSponsorNftListingTx';
7
+ import { getNftType } from '../../helpers/getNftType';
8
+
9
+ export type SponsorNftListingOptions = {
10
+ shouldSponsor?: boolean;
11
+ numOfPeriods?: number;
12
+ slippage?: number;
13
+ coinInType?: string;
14
+ };
15
+
16
+ export type SponsorNftListing = {
17
+ nftTokenId: string;
18
+ walletAddress: string;
19
+ options: SponsorNftListingOptions;
20
+ };
21
+
22
+ export const sponsorNftListing = async (
23
+ { nftTokenId, walletAddress, options }: SponsorNftListing,
24
+ context: RequestContext,
25
+ ): Promise<Transaction> => {
26
+ const res = await gqlChainRequest({
27
+ chain: 'sui',
28
+ query: fetchNftCollectionChainState,
29
+ variables: { nftTokenId },
30
+ });
31
+
32
+ if (res?.nfts?.length === 0) {
33
+ throw new Error(`No nft found with token id ${nftTokenId}`);
34
+ }
35
+
36
+ const nft = res?.nfts?.[0];
37
+
38
+ const nftType = getNftType({
39
+ collectionId: nft?.collection?.id,
40
+ collectionChainState: nft?.collection?.chain_state,
41
+ nft,
42
+ });
43
+
44
+ const transferPolicies = nft?.collection?.chain_state?.transfer_policies;
45
+
46
+ if (isOriginByteCollection(transferPolicies)) {
47
+ throw new Error(`You cannot sponsor an Origin Byte NFT. Nft Token Id: ${nftTokenId}`);
48
+ }
49
+
50
+ const tx = new Transaction();
51
+
52
+ await addSponsorListingTx({
53
+ tx,
54
+ suiClient: context.suiClient,
55
+ nftTokenId,
56
+ nftType,
57
+ walletAddress,
58
+ sponsorOptions: options,
59
+ });
60
+
61
+ return Transaction.from(tx);
62
+ };