@tradeport/sui-trading-sdk 0.2.2 → 0.3.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tradeport/sui-trading-sdk",
3
3
  "license": "MIT",
4
- "version": "0.2.2",
4
+ "version": "0.3.1",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
@@ -5,7 +5,7 @@ import createKioskClient from './apiClients/createKioskClient';
5
5
  import createSuiClient from './apiClients/createSuiClient';
6
6
  import { getGraphqlClient, setGraphqlClient } from './apiClients/graphqlClient';
7
7
  import { gqlChainRequest } from './graphql/gqlChainRequest';
8
- import { fetchCollectionBidById } from './graphql/queries/fetchCollectionBidById';
8
+ import { fetchCollectionBidsById } from './graphql/queries/fetchCollectionBidById';
9
9
  import { fetchCollectionBidsAtSamePrice } from './graphql/queries/fetchCollectionBidsAtSamePrice';
10
10
  import {
11
11
  acceptCollectionBid,
@@ -52,9 +52,9 @@ import {
52
52
  } from './methods/placeCollectionBids/placeCollectionBids';
53
53
  import { placeNftBids, type PlaceNftBids } from './methods/placeNftBids/placeNftBids';
54
54
  import {
55
- removeCollectionBid,
56
- type RemoveCollectionBid,
57
- } from './methods/removeCollectionBid/removeCollectionBid';
55
+ removeCollectionBids,
56
+ type RemoveCollectionBids,
57
+ } from './methods/removeCollectionBids/removeCollectionBids';
58
58
  import { removeNftBids, type RemoveNftBids } from './methods/removeNftBids/removeNftBids';
59
59
  import { transferNfts, type TransferNfts } from './methods/transferNfts/transferNfts';
60
60
  import { unlistListings, type UnlistListings } from './methods/unlistListings/unlistListings';
@@ -146,7 +146,7 @@ class SuiTradingClient {
146
146
  return placeNftBids({ nfts, walletAddress }, context);
147
147
  }
148
148
 
149
- public async removeNftBids({ bidIds }: RemoveNftBids) {
149
+ public async removeNftBids({ bidIds, tx }: RemoveNftBids) {
150
150
  const context: RequestContext = {
151
151
  apiUser: this.apiUser,
152
152
  apiKey: this.apiKey,
@@ -154,7 +154,7 @@ class SuiTradingClient {
154
154
  kioskClient: this.kioskClient,
155
155
  };
156
156
 
157
- return removeNftBids({ bidIds }, context);
157
+ return removeNftBids({ bidIds, tx }, context);
158
158
  }
159
159
 
160
160
  public async acceptNftBids({ bidIds }: AcceptNftBids) {
@@ -206,8 +206,8 @@ class SuiTradingClient {
206
206
 
207
207
  const collectionBidRes = await gqlChainRequest({
208
208
  chain: 'sui',
209
- query: fetchCollectionBidById,
210
- variables: { bidId },
209
+ query: fetchCollectionBidsById,
210
+ variables: { bidIds: [bidId] },
211
211
  });
212
212
  const bid = collectionBidRes?.bids?.[0];
213
213
 
@@ -283,7 +283,7 @@ class SuiTradingClient {
283
283
  }
284
284
  }
285
285
 
286
- public async removeCollectionBid({ bidId }: RemoveCollectionBid) {
286
+ public async removeCollectionBids({ bidIds, tx }: RemoveCollectionBids) {
287
287
  const context: RequestContext = {
288
288
  apiUser: this.apiUser,
289
289
  apiKey: this.apiKey,
@@ -291,7 +291,7 @@ class SuiTradingClient {
291
291
  kioskClient: this.kioskClient,
292
292
  };
293
293
 
294
- return removeCollectionBid({ bidId }, context);
294
+ return removeCollectionBids({ bidIds, tx }, context);
295
295
  }
296
296
 
297
297
  public async transferNfts({ nftIds, recipientAddress, walletAddress }: TransferNfts) {
@@ -1,8 +1,8 @@
1
1
  import { gql } from 'graphql-request';
2
2
 
3
- export const fetchCollectionBidById = gql`
4
- query fetchCollectionBidById($bidId: uuid!) {
5
- bids(where: { id: { _eq: $bidId } }) {
3
+ export const fetchCollectionBidsById = gql`
4
+ query fetchCollectionBidsById($bidIds: [uuid!]) {
5
+ bids(where: { id: { _in: $bidIds } }) {
6
6
  nonce
7
7
  price
8
8
  bidder
@@ -3,13 +3,14 @@ import {
3
3
  BLUEMOVE_OFFER_COLLECTION_DATA_OBJECT,
4
4
  TRADEPORT_BIDDING_STORE,
5
5
  } from '../../constants';
6
+ import { getSharedObjects } from '../../helpers/getSharedObjects';
6
7
  import { isBluemoveKioskBid } from '../../helpers/kiosk/isBluemoveKioskBid';
7
8
  import { isTradePortKioskBid } from '../../helpers/kiosk/isTradePortKioskBid';
8
9
  import { isOriginByteBid } from '../../helpers/originByte/isOriginByteBid';
9
10
  import { getObjectType } from '../../helpers/rpc/getObjectType';
10
11
  import { addLeadingZerosAfter0x } from '../../utils/addLeadingZerosAfter0x';
11
12
  import { addTradeportKioskRemoveNftBidTx } from '../removeNftBids/addRemoveNftBidTxs';
12
- import { type RemoveCollectionBidTx } from './removeCollectionBid';
13
+ import { type RemoveCollectionBidTx } from './removeCollectionBids';
13
14
 
14
15
  export function addTradeportRemoveCollectionBidTx({
15
16
  tx,
@@ -82,7 +83,8 @@ export async function addTradePortRemoveCollectionBidTxHandler(txData: RemoveCol
82
83
  });
83
84
 
84
85
  if (isOriginByteBid(bidType)) {
85
- addOriginByteRemoveCollectionBidTx(txData);
86
+ const sharedObjects = await getSharedObjects(txData?.nftType);
87
+ addOriginByteRemoveCollectionBidTx({ ...txData, sharedObjects });
86
88
  return;
87
89
  }
88
90
 
@@ -98,7 +100,8 @@ export async function addBluemoveRemoveCollectionBidTxHandler(txData: RemoveColl
98
100
  const bidType = await getObjectType({ suiClient: txData?.suiClient, objectId: txData?.bidNonce });
99
101
 
100
102
  if (isOriginByteBid(bidType)) {
101
- addOriginByteRemoveCollectionBidTx(txData);
103
+ const sharedObjects = await getSharedObjects(txData?.nftType);
104
+ addOriginByteRemoveCollectionBidTx({ ...txData, sharedObjects });
102
105
  return;
103
106
  }
104
107
 
@@ -111,5 +114,6 @@ export async function addBluemoveRemoveCollectionBidTxHandler(txData: RemoveColl
111
114
  }
112
115
 
113
116
  export async function addClutchyRemoveCollectionBidTxHandler(txData: RemoveCollectionBidTx) {
114
- addOriginByteRemoveCollectionBidTx(txData);
117
+ const sharedObjects = await getSharedObjects(txData?.nftType);
118
+ addOriginByteRemoveCollectionBidTx({ ...txData, sharedObjects });
115
119
  }
@@ -1,25 +1,24 @@
1
1
  import type { SuiClient } from '@mysten/sui/client';
2
2
  import { Transaction } from '@mysten/sui/transactions';
3
3
  import { type RequestContext } from '../../SuiTradingClient';
4
+ import {
5
+ DELOREAN_TOKEN_IDS_TO_DISABLE,
6
+ DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE,
7
+ } from '../../constants';
4
8
  import { gqlChainRequest } from '../../graphql/gqlChainRequest';
5
- import { fetchCollectionBidById } from '../../graphql/queries/fetchCollectionBidById';
9
+ import { fetchCollectionBidsById } from '../../graphql/queries/fetchCollectionBidById';
6
10
  import { fetchCollectionsByIdWithOneNft } from '../../graphql/queries/fetchCollectionsById';
7
11
  import { getNftType } from '../../helpers/getNftType';
8
- import { getSharedObjects } from '../../helpers/getSharedObjects';
9
12
  import {
10
13
  addBluemoveRemoveCollectionBidTxHandler,
11
14
  addClutchyRemoveCollectionBidTxHandler,
12
15
  addTradePortRemoveCollectionBidTxHandler,
13
- } from './addRemoveCollectionBidTxs';
14
- import {
15
- DELOREAN_TOKEN_IDS_TO_DISABLE,
16
- DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE,
17
- } from '../../constants';
16
+ } from './addRemoveCollectionBidsTxs';
18
17
 
19
18
  export type RemoveCollectionBidTx = {
20
19
  tx: Transaction;
21
20
  suiClient: SuiClient;
22
- sharedObjects: any;
21
+ sharedObjects?: any;
23
22
  bidNonce: string;
24
23
  bidder: string;
25
24
  nftType: string;
@@ -29,18 +28,19 @@ export type RemoveCollectionBidTx = {
29
28
  bidMarketName: string;
30
29
  };
31
30
 
32
- export type RemoveCollectionBid = {
33
- bidId: string;
31
+ export type RemoveCollectionBids = {
32
+ bidIds: string[];
33
+ tx?: Transaction;
34
34
  };
35
35
 
36
- export const removeCollectionBid = async (
37
- { bidId }: RemoveCollectionBid,
36
+ export const removeCollectionBids = async (
37
+ { bidIds, tx: existingTx }: RemoveCollectionBids,
38
38
  context: RequestContext,
39
39
  ): Promise<Transaction> => {
40
40
  const res = await gqlChainRequest({
41
41
  chain: 'sui',
42
- query: fetchCollectionBidById,
43
- variables: { bidId },
42
+ query: fetchCollectionBidsById,
43
+ variables: { bidIds },
44
44
  });
45
45
 
46
46
  if (res?.bids?.length === 0) {
@@ -48,7 +48,7 @@ export const removeCollectionBid = async (
48
48
  }
49
49
 
50
50
  const bidsForTracking = [];
51
- const tx = new Transaction();
51
+ const tx = existingTx ?? new Transaction();
52
52
 
53
53
  for (const bid of res.bids) {
54
54
  if (DELOREAN_TOKEN_IDS_TO_DISABLE?.includes(bid?.nft?.token_id)) {
@@ -67,12 +67,9 @@ export const removeCollectionBid = async (
67
67
  nft: collectionWithOneNftRes?.collections?.[0]?.nfts?.[0],
68
68
  });
69
69
 
70
- const sharedObjects = await getSharedObjects(nftType);
71
-
72
70
  const txData: RemoveCollectionBidTx = {
73
71
  tx,
74
72
  suiClient: context.suiClient,
75
- sharedObjects,
76
73
  bidNonce: bid?.nonce,
77
74
  bidder: bid?.bidder,
78
75
  nftType,
@@ -1,25 +1,24 @@
1
1
  import type { SuiClient } from '@mysten/sui/client';
2
2
  import { Transaction } from '@mysten/sui/transactions';
3
3
  import { type RequestContext } from '../../SuiTradingClient';
4
+ import {
5
+ DELOREAN_TOKEN_IDS_TO_DISABLE,
6
+ DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE,
7
+ } from '../../constants';
4
8
  import { gqlChainRequest } from '../../graphql/gqlChainRequest';
5
9
  import { fetchBidsById } from '../../graphql/queries/fetchBidsById';
6
10
  import { getNftType } from '../../helpers/getNftType';
7
- import { getSharedObjects } from '../../helpers/getSharedObjects';
8
11
  import {
9
12
  addBluemoveRemoveNftBidTx,
10
13
  addOriginByteRemoveNftBidTx,
11
14
  addTocenRemoveNftBidTx,
12
15
  addTradePortRemoveNftBidTxHandler,
13
16
  } from './addRemoveNftBidTxs';
14
- import {
15
- DELOREAN_TOKEN_IDS_TO_DISABLE,
16
- DELOREAN_TOKEN_IDS_TO_DISABLE_MESSAGE,
17
- } from '../../constants';
18
17
 
19
18
  export type RemoveNftBidTx = {
20
19
  tx: Transaction;
21
20
  suiClient: SuiClient;
22
- sharedObjects: any;
21
+ sharedObjects?: any;
23
22
  bidNonce: string;
24
23
  nftType: string;
25
24
  nftTokenId: string;
@@ -34,10 +33,11 @@ export type RemoveNftBid = {
34
33
 
35
34
  export type RemoveNftBids = {
36
35
  bidIds: string[];
36
+ tx?: Transaction;
37
37
  };
38
38
 
39
39
  export const removeNftBids = async (
40
- { bidIds }: RemoveNftBids,
40
+ { bidIds, tx: existingTx }: RemoveNftBids,
41
41
  context: RequestContext,
42
42
  ): Promise<Transaction> => {
43
43
  const res = await gqlChainRequest({
@@ -51,7 +51,7 @@ export const removeNftBids = async (
51
51
  }
52
52
 
53
53
  const bidsForTracking = [];
54
- const tx = new Transaction();
54
+ const tx = existingTx ?? new Transaction();
55
55
 
56
56
  for (const bid of res.bids) {
57
57
  if (DELOREAN_TOKEN_IDS_TO_DISABLE?.includes(bid?.nft?.token_id)) {
@@ -64,12 +64,9 @@ export const removeNftBids = async (
64
64
  nft: bid?.nft,
65
65
  });
66
66
 
67
- const sharedObjects = await getSharedObjects(nftType);
68
-
69
67
  const txData: RemoveNftBidTx = {
70
68
  tx,
71
69
  suiClient: context.suiClient,
72
- sharedObjects,
73
70
  bidNonce: bid?.nonce,
74
71
  nftType,
75
72
  nftTokenId: bid?.nft?.token_id,
@@ -1,9 +1,23 @@
1
+ import { type Transaction } from '@mysten/sui/dist/cjs/transactions';
1
2
  import { TRADEPORT_KIOSK_TRANSFERS_STORE } from '../../constants';
3
+ import { destroyZeroCoin } from '../../helpers/destroyZeroCoin';
4
+ import { getNftType } from '../../helpers/getNftType';
2
5
  import { assertNftInSharedKiosk } from '../../helpers/kiosk/assertNftInSharedKiosk';
3
6
  import { getKioskTransferPolicies } from '../../helpers/kiosk/getKioskTransferPolicies';
7
+ import { kioskTxWrapper } from '../../helpers/kiosk/kioskTxWrapper';
4
8
  import { getOBKiosk } from '../../helpers/originByte/getOBKiosk';
5
9
  import { addLeadingZerosAfter0x } from '../../utils/addLeadingZerosAfter0x';
6
10
  import { type TransferNftTx } from './transferNfts';
11
+ import { type KioskClient } from '@mysten/kiosk';
12
+
13
+ type CollectionChainState = {
14
+ transfer_policies: TransferPolicy[];
15
+ };
16
+ type TransferPolicy = {
17
+ id: string;
18
+ rules: Array<{ type: string; min_amount?: string }>;
19
+ is_origin_byte: boolean;
20
+ };
7
21
 
8
22
  export async function addOriginByteTransferNftTx({
9
23
  tx,
@@ -69,3 +83,97 @@ export async function addTradeportKioskTransferTx({
69
83
  typeArguments: [nftType],
70
84
  });
71
85
  }
86
+
87
+ export async function addTradeportKioskDirectTransferTx(
88
+ txData: {
89
+ tx: Transaction;
90
+ recipientAddress: string;
91
+ kioskClient: KioskClient;
92
+ senderAddress: string;
93
+ },
94
+ nfts: any[],
95
+ ) {
96
+ const { tx, recipientAddress, kioskClient, senderAddress } = txData;
97
+ if (nfts.length === 0) {
98
+ return;
99
+ }
100
+
101
+ const [receiverKiosk, receiverKioskCap] = tx.moveCall({
102
+ target: '0x2::kiosk::new',
103
+ arguments: [],
104
+ });
105
+ const recipientAddressWithPrefix = addLeadingZerosAfter0x(recipientAddress);
106
+ tx.moveCall({
107
+ target: '0x2::kiosk::set_owner_custom',
108
+ arguments: [
109
+ tx.object(receiverKiosk),
110
+ tx.object(receiverKioskCap),
111
+ tx.pure.address(recipientAddressWithPrefix),
112
+ ],
113
+ });
114
+ const totalRoyaltyAmount = nfts.reduce(
115
+ (sum: bigint, nft) =>
116
+ sum +
117
+ BigInt(
118
+ getTransferPolicyForDirectTransfer(nft.collection.chain_state)?.rules?.find(
119
+ (rule) => rule.type === 'royalty_rule',
120
+ )?.min_amount ?? 0n,
121
+ ),
122
+ 0n,
123
+ );
124
+ const [royaltyCoin] = tx.splitCoins(tx.gas, [tx.pure.u64(totalRoyaltyAmount)]);
125
+ for (const nft of nfts) {
126
+ const nftType = getNftType({
127
+ collectionId: nft?.collection?.id,
128
+ collectionChainState: nft?.collection?.chain_state,
129
+ nft,
130
+ });
131
+
132
+ await kioskTxWrapper({
133
+ tx,
134
+ kioskClient,
135
+ kioskOwner: senderAddress,
136
+ kiosk: nft?.chain_state?.kiosk_id,
137
+ async runCommands(kioskTx) {
138
+ tx.moveCall({
139
+ target:
140
+ '0xd0ad5bf7ac7d372cdcfee5273d5e487dabad724040e089c626cba2a01127ccd6::kiosk_transfers::direct_transfer',
141
+ arguments: [
142
+ tx.object(kioskTx.getKiosk() as any),
143
+ tx.object(kioskTx.getKioskCap() as any),
144
+ tx.object(receiverKiosk),
145
+ tx.object(receiverKioskCap),
146
+ tx.pure.id(nft.token_id),
147
+ tx.object(getTransferPolicyForDirectTransfer(nft.collection.chain_state).id),
148
+ royaltyCoin,
149
+ ],
150
+ typeArguments: [nftType],
151
+ });
152
+ },
153
+ });
154
+ }
155
+
156
+ tx.transferObjects([receiverKioskCap], tx.pure.address(recipientAddressWithPrefix));
157
+ tx.moveCall({
158
+ target: '0x2::transfer::public_share_object',
159
+ arguments: [receiverKiosk],
160
+ typeArguments: ['0x2::kiosk::Kiosk'],
161
+ });
162
+ destroyZeroCoin({ tx, coin: royaltyCoin });
163
+ }
164
+
165
+ export function canBeTransferedDirectly(collectionChainState?: CollectionChainState) {
166
+ return getTransferPolicyForDirectTransfer(collectionChainState) !== undefined;
167
+ }
168
+
169
+ export function getTransferPolicyForDirectTransfer(
170
+ collectionChainState?: CollectionChainState,
171
+ ): TransferPolicy | undefined {
172
+ return collectionChainState?.transfer_policies?.find(
173
+ (policy) =>
174
+ !policy.is_origin_byte &&
175
+ policy.rules?.filter(
176
+ (rule) => rule.type !== 'kiosk_lock_rule' && rule.type !== 'royalty_rule',
177
+ ).length === 0,
178
+ );
179
+ }
@@ -13,7 +13,12 @@ import { kioskTxWrapper } from '../../helpers/kiosk/kioskTxWrapper';
13
13
  import { isOBKiosk } from '../../helpers/originByte/isOBKiosk';
14
14
  import { getAccountBalance } from '../../helpers/rpc/getAcountBalance';
15
15
  import { addLeadingZerosAfter0x } from '../../utils/addLeadingZerosAfter0x';
16
- import { addOriginByteTransferNftTx, addTradeportKioskTransferTx } from './addTransferNftTx';
16
+ import {
17
+ addOriginByteTransferNftTx,
18
+ addTradeportKioskDirectTransferTx,
19
+ addTradeportKioskTransferTx,
20
+ canBeTransferedDirectly,
21
+ } from './addTransferNftTx';
17
22
 
18
23
  export type TransferNftTx = {
19
24
  tx: Transaction;
@@ -66,6 +71,7 @@ export const transferNfts = async (
66
71
  }
67
72
 
68
73
  const nftsForTracking = [];
74
+ const nftsToTransferDirectly = [];
69
75
  const tx = new Transaction();
70
76
 
71
77
  for (const nft of res.nfts) {
@@ -115,16 +121,22 @@ export const transferNfts = async (
115
121
  }
116
122
 
117
123
  // If NFT is inside native kiosk
118
- await kioskTxWrapper({
119
- tx: txData?.tx,
120
- kioskClient: txData?.kioskClient,
121
- kioskOwner: txData?.senderAddress,
122
- kiosk: txData?.senderKiosk,
123
- shouldAssertNftInSharedKiosk: true,
124
- async runCommands(kioskTx) {
125
- await addTradeportKioskTransferTx({ ...txData, kioskTx });
126
- },
127
- });
124
+
125
+ // If NFT can be transfered directly by creating new kiosk for receiver
126
+ if (canBeTransferedDirectly(nft?.collection?.chain_state)) {
127
+ nftsToTransferDirectly.push(nft);
128
+ } else {
129
+ await kioskTxWrapper({
130
+ tx: txData?.tx,
131
+ kioskClient: txData?.kioskClient,
132
+ kioskOwner: txData?.senderAddress,
133
+ kiosk: txData?.senderKiosk,
134
+ shouldAssertNftInSharedKiosk: true,
135
+ async runCommands(kioskTx) {
136
+ await addTradeportKioskTransferTx({ ...txData, kioskTx });
137
+ },
138
+ });
139
+ }
128
140
 
129
141
  nftsForTracking.push({
130
142
  nftType,
@@ -133,6 +145,11 @@ export const transferNfts = async (
133
145
  });
134
146
  }
135
147
 
148
+ await addTradeportKioskDirectTransferTx(
149
+ { tx, kioskClient: context.kioskClient, senderAddress: walletAddress, recipientAddress },
150
+ nftsToTransferDirectly,
151
+ );
152
+
136
153
  // currently turned off $1 bulk transfer fee
137
154
  // if (res?.nfts?.length > 1) {
138
155
  // await addOneDollarFee(tx);
@@ -28,7 +28,7 @@ export class SuiWallet {
28
28
  }
29
29
 
30
30
  async simulateCall(tx: Transaction): Promise<any> {
31
- tx.setSenderIfNotSet('0x645e9f833ddc10e73e8c8aad0cf7abf2f48ad92b45c80ef33f68a56488effaf0');
31
+ tx.setSenderIfNotSet('0x7cb678cc0446b986bab45d612a25946b2a63763d2252b1e554d1763eb788f660');
32
32
  const rawTransaction = await tx.build({ client: this.suiClient });
33
33
  const result = await this.suiClient.dryRunTransactionBlock({
34
34
  transactionBlock: rawTransaction,