@ledgerhq/coin-sui 0.14.0 → 0.15.0-nightly.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +16 -0
- package/lib/api/index.integration.test.js +9 -0
- package/lib/api/index.integration.test.js.map +1 -1
- package/lib/api/index.js +7 -2
- package/lib/api/index.js.map +1 -1
- package/lib/api/index.test.js +1 -1
- package/lib/api/index.test.js.map +1 -1
- package/lib/logic/craftTransaction.d.ts +1 -1
- package/lib/logic/craftTransaction.d.ts.map +1 -1
- package/lib/logic/craftTransaction.integration.test.js +38 -0
- package/lib/logic/craftTransaction.integration.test.js.map +1 -1
- package/lib/logic/craftTransaction.js +3 -4
- package/lib/logic/craftTransaction.js.map +1 -1
- package/lib/logic/craftTransaction.test.js +5 -5
- package/lib/logic/craftTransaction.test.js.map +1 -1
- package/lib/logic/estimateFees.integration.test.js +1 -1
- package/lib/network/index.d.ts +1 -1
- package/lib/network/sdk.d.ts +20 -9
- package/lib/network/sdk.d.ts.map +1 -1
- package/lib/network/sdk.integration.test.js +2 -2
- package/lib/network/sdk.integration.test.js.map +1 -1
- package/lib/network/sdk.js +70 -40
- package/lib/network/sdk.js.map +1 -1
- package/lib/types/model.d.ts +3 -0
- package/lib/types/model.d.ts.map +1 -1
- package/lib-es/api/index.integration.test.js +9 -0
- package/lib-es/api/index.integration.test.js.map +1 -1
- package/lib-es/api/index.js +7 -2
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/api/index.test.js +1 -1
- package/lib-es/api/index.test.js.map +1 -1
- package/lib-es/logic/craftTransaction.d.ts +1 -1
- package/lib-es/logic/craftTransaction.d.ts.map +1 -1
- package/lib-es/logic/craftTransaction.integration.test.js +38 -0
- package/lib-es/logic/craftTransaction.integration.test.js.map +1 -1
- package/lib-es/logic/craftTransaction.js +3 -4
- package/lib-es/logic/craftTransaction.js.map +1 -1
- package/lib-es/logic/craftTransaction.test.js +5 -5
- package/lib-es/logic/craftTransaction.test.js.map +1 -1
- package/lib-es/logic/estimateFees.integration.test.js +1 -1
- package/lib-es/network/index.d.ts +1 -1
- package/lib-es/network/sdk.d.ts +20 -9
- package/lib-es/network/sdk.d.ts.map +1 -1
- package/lib-es/network/sdk.integration.test.js +2 -2
- package/lib-es/network/sdk.integration.test.js.map +1 -1
- package/lib-es/network/sdk.js +68 -39
- package/lib-es/network/sdk.js.map +1 -1
- package/lib-es/types/model.d.ts +3 -0
- package/lib-es/types/model.d.ts.map +1 -1
- package/package.json +8 -9
- package/src/api/index.integration.test.ts +16 -0
- package/src/api/index.test.ts +1 -1
- package/src/api/index.ts +7 -2
- package/src/logic/craftTransaction.integration.test.ts +48 -0
- package/src/logic/craftTransaction.test.ts +41 -25
- package/src/logic/craftTransaction.ts +25 -20
- package/src/logic/estimateFees.integration.test.ts +1 -1
- package/src/network/sdk.integration.test.ts +2 -2
- package/src/network/sdk.ts +90 -48
- package/src/types/model.ts +4 -0
- package/index.d.ts +0 -0
|
@@ -32,6 +32,7 @@ describe("craftTransaction", () => {
|
|
|
32
32
|
|
|
33
33
|
expect(result).toBeDefined();
|
|
34
34
|
expect(result.unsigned).toBeInstanceOf(Uint8Array);
|
|
35
|
+
expect(result.objects).toBeUndefined();
|
|
35
36
|
|
|
36
37
|
const resultCoinTypes = await extractCoinTypeFromUnsignedTx(result.unsigned);
|
|
37
38
|
expect(resultCoinTypes).toEqual(expect.arrayContaining([expect.stringContaining("sui")]));
|
|
@@ -56,6 +57,53 @@ describe("craftTransaction", () => {
|
|
|
56
57
|
|
|
57
58
|
expect(result).toBeDefined();
|
|
58
59
|
expect(result.unsigned).toBeInstanceOf(Uint8Array);
|
|
60
|
+
expect(result.objects).toBeUndefined();
|
|
61
|
+
|
|
62
|
+
const resultCoinTypes = await extractCoinTypeFromUnsignedTx(result.unsigned);
|
|
63
|
+
expect(resultCoinTypes).toEqual(expect.arrayContaining([expect.stringContaining("usdt")]));
|
|
64
|
+
}, 15000);
|
|
65
|
+
|
|
66
|
+
it("should craft a native SUI send transaction, returning serialized objects when requested", async () => {
|
|
67
|
+
const transactionIntent: TransactionIntent = {
|
|
68
|
+
sender: SENDER,
|
|
69
|
+
recipient: RECIPIENT,
|
|
70
|
+
amount: BigInt(1000),
|
|
71
|
+
type: "send",
|
|
72
|
+
asset: { type: "native" },
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const result = await craftTransaction(transactionIntent, true);
|
|
76
|
+
|
|
77
|
+
expect(result).toBeDefined();
|
|
78
|
+
expect(result.unsigned).toBeInstanceOf(Uint8Array);
|
|
79
|
+
expect(result.objects).toBeDefined();
|
|
80
|
+
expect(result.objects?.length).toBeGreaterThan(0);
|
|
81
|
+
|
|
82
|
+
const resultCoinTypes = await extractCoinTypeFromUnsignedTx(result.unsigned);
|
|
83
|
+
expect(resultCoinTypes).toEqual(expect.arrayContaining([expect.stringContaining("sui")]));
|
|
84
|
+
}, 15000);
|
|
85
|
+
|
|
86
|
+
it("should craft a token send transaction, returning serialized objects when requested", async () => {
|
|
87
|
+
const coinType =
|
|
88
|
+
"0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT";
|
|
89
|
+
|
|
90
|
+
const transactionIntent: TransactionIntent = {
|
|
91
|
+
sender: SENDER,
|
|
92
|
+
recipient: RECIPIENT,
|
|
93
|
+
amount: BigInt(1000),
|
|
94
|
+
type: "send",
|
|
95
|
+
asset: {
|
|
96
|
+
type: "token",
|
|
97
|
+
assetReference: coinType,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const result = await craftTransaction(transactionIntent, true);
|
|
102
|
+
|
|
103
|
+
expect(result).toBeDefined();
|
|
104
|
+
expect(result.unsigned).toBeInstanceOf(Uint8Array);
|
|
105
|
+
expect(result.objects).toBeDefined();
|
|
106
|
+
expect(result.objects?.length).toBeGreaterThan(0);
|
|
59
107
|
|
|
60
108
|
const resultCoinTypes = await extractCoinTypeFromUnsignedTx(result.unsigned);
|
|
61
109
|
expect(resultCoinTypes).toEqual(expect.arrayContaining([expect.stringContaining("usdt")]));
|
|
@@ -10,7 +10,7 @@ describe("craftTransaction", () => {
|
|
|
10
10
|
|
|
11
11
|
beforeEach(() => {
|
|
12
12
|
jest.clearAllMocks();
|
|
13
|
-
mockCreateTransaction.mockResolvedValue(mockUnsignedTx);
|
|
13
|
+
mockCreateTransaction.mockResolvedValue({ unsigned: mockUnsignedTx });
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
it("should create a transaction with correct parameters", async () => {
|
|
@@ -27,12 +27,16 @@ describe("craftTransaction", () => {
|
|
|
27
27
|
asset: { type: "native" },
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
expect(mockCreateTransaction).toHaveBeenCalledWith(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
expect(mockCreateTransaction).toHaveBeenCalledWith(
|
|
31
|
+
sender,
|
|
32
|
+
{
|
|
33
|
+
amount: new BigNumber(amount.toString()),
|
|
34
|
+
recipient,
|
|
35
|
+
mode: type,
|
|
36
|
+
coinType: "0x2::sui::SUI",
|
|
37
|
+
},
|
|
38
|
+
false,
|
|
39
|
+
);
|
|
36
40
|
expect(result).toEqual({ unsigned: mockUnsignedTx });
|
|
37
41
|
});
|
|
38
42
|
|
|
@@ -50,12 +54,16 @@ describe("craftTransaction", () => {
|
|
|
50
54
|
asset: { type: "native" },
|
|
51
55
|
});
|
|
52
56
|
|
|
53
|
-
expect(mockCreateTransaction).toHaveBeenCalledWith(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
expect(mockCreateTransaction).toHaveBeenCalledWith(
|
|
58
|
+
sender,
|
|
59
|
+
{
|
|
60
|
+
amount: new BigNumber(amount.toString()),
|
|
61
|
+
recipient,
|
|
62
|
+
mode: type,
|
|
63
|
+
coinType: "0x2::sui::SUI",
|
|
64
|
+
},
|
|
65
|
+
false,
|
|
66
|
+
);
|
|
59
67
|
expect(result).toEqual({ unsigned: mockUnsignedTx });
|
|
60
68
|
});
|
|
61
69
|
|
|
@@ -73,12 +81,16 @@ describe("craftTransaction", () => {
|
|
|
73
81
|
asset: { type: "native" },
|
|
74
82
|
});
|
|
75
83
|
|
|
76
|
-
expect(mockCreateTransaction).toHaveBeenCalledWith(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
expect(mockCreateTransaction).toHaveBeenCalledWith(
|
|
85
|
+
sender,
|
|
86
|
+
{
|
|
87
|
+
amount: new BigNumber(amount.toString()),
|
|
88
|
+
recipient,
|
|
89
|
+
mode: type,
|
|
90
|
+
coinType: "0x2::sui::SUI",
|
|
91
|
+
},
|
|
92
|
+
false,
|
|
93
|
+
);
|
|
82
94
|
expect(result).toEqual({ unsigned: mockUnsignedTx });
|
|
83
95
|
});
|
|
84
96
|
|
|
@@ -96,12 +108,16 @@ describe("craftTransaction", () => {
|
|
|
96
108
|
asset: { type: "native" },
|
|
97
109
|
});
|
|
98
110
|
|
|
99
|
-
expect(mockCreateTransaction).toHaveBeenCalledWith(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
expect(mockCreateTransaction).toHaveBeenCalledWith(
|
|
112
|
+
sender,
|
|
113
|
+
{
|
|
114
|
+
amount: new BigNumber(amount.toString()),
|
|
115
|
+
recipient,
|
|
116
|
+
mode: type,
|
|
117
|
+
coinType: "0x2::sui::SUI",
|
|
118
|
+
},
|
|
119
|
+
false,
|
|
120
|
+
);
|
|
105
121
|
expect(result).toEqual({ unsigned: mockUnsignedTx });
|
|
106
122
|
});
|
|
107
123
|
|
|
@@ -4,28 +4,33 @@ import type { SuiTransactionMode, CoreTransaction } from "../types";
|
|
|
4
4
|
import suiAPI from "../network";
|
|
5
5
|
import { DEFAULT_COIN_TYPE } from "../network/sdk";
|
|
6
6
|
|
|
7
|
-
export async function craftTransaction(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
export async function craftTransaction(
|
|
8
|
+
{
|
|
9
|
+
amount,
|
|
10
|
+
asset,
|
|
11
|
+
recipient,
|
|
12
|
+
sender,
|
|
13
|
+
type,
|
|
14
|
+
...extra
|
|
15
|
+
}: TransactionIntent & {
|
|
16
|
+
useAllAmount?: boolean;
|
|
17
|
+
stakedSuiId?: string;
|
|
18
|
+
},
|
|
19
|
+
withObjects: boolean = false,
|
|
20
|
+
): Promise<CoreTransaction> {
|
|
18
21
|
let coinType = DEFAULT_COIN_TYPE;
|
|
19
22
|
if (asset.type === "token" && asset.assetReference) {
|
|
20
23
|
coinType = asset.assetReference;
|
|
21
24
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
return suiAPI.createTransaction(
|
|
26
|
+
sender,
|
|
27
|
+
{
|
|
28
|
+
amount: BigNumber(amount.toString()),
|
|
29
|
+
coinType,
|
|
30
|
+
mode: type as SuiTransactionMode,
|
|
31
|
+
recipient,
|
|
32
|
+
...extra,
|
|
33
|
+
},
|
|
34
|
+
withObjects,
|
|
35
|
+
);
|
|
31
36
|
}
|
|
@@ -3,7 +3,7 @@ import { getFullnodeUrl } from "@mysten/sui/client";
|
|
|
3
3
|
import coinConfig from "../config";
|
|
4
4
|
import { estimateFees } from "./estimateFees";
|
|
5
5
|
|
|
6
|
-
const SENDER = "
|
|
6
|
+
const SENDER = "0xad79719ac7edb44f6e253f1f771e8291e281a6aaf1e4789b52bf85336f525e8e";
|
|
7
7
|
const RECIPIENT = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
8
8
|
|
|
9
9
|
describe("estimateFees", () => {
|
|
@@ -155,14 +155,14 @@ describe("SUI SDK Integration tests", () => {
|
|
|
155
155
|
recipient: "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164",
|
|
156
156
|
errors: {},
|
|
157
157
|
};
|
|
158
|
-
const tx = await createTransaction(address, transaction);
|
|
158
|
+
const { unsigned: tx } = await createTransaction(address, transaction);
|
|
159
159
|
expect(tx).toBeInstanceOf(Uint8Array);
|
|
160
160
|
});
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
describe("paymentInfo", () => {
|
|
164
164
|
test("paymentInfo should return gas budget and fees", async () => {
|
|
165
|
-
const sender = "
|
|
165
|
+
const sender = "0xad79719ac7edb44f6e253f1f771e8291e281a6aaf1e4789b52bf85336f525e8e";
|
|
166
166
|
const fakeTransaction = {
|
|
167
167
|
mode: "send" as const,
|
|
168
168
|
family: "sui" as const,
|
package/src/network/sdk.ts
CHANGED
|
@@ -34,14 +34,19 @@ import uniqBy from "lodash/unionBy";
|
|
|
34
34
|
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
35
35
|
import { log } from "@ledgerhq/logs";
|
|
36
36
|
import { makeLRUCache, minutes } from "@ledgerhq/live-network/cache";
|
|
37
|
-
import type {
|
|
37
|
+
import type {
|
|
38
|
+
Transaction as TransactionType,
|
|
39
|
+
SuiValidator,
|
|
40
|
+
CreateExtrinsicArg,
|
|
41
|
+
CoreTransaction,
|
|
42
|
+
} from "../types";
|
|
38
43
|
import { ensureAddressFormat } from "../utils";
|
|
39
44
|
import coinConfig from "../config";
|
|
40
45
|
import { getEnv } from "@ledgerhq/live-env";
|
|
41
46
|
import { SUI_SYSTEM_STATE_OBJECT_ID } from "@mysten/sui/utils";
|
|
42
47
|
import { getCurrentSuiPreloadData } from "../bridge/preload";
|
|
43
48
|
import { ONE_SUI } from "../constants";
|
|
44
|
-
import
|
|
49
|
+
import { getInputObjects } from "@mysten/signers/ledger";
|
|
45
50
|
|
|
46
51
|
const apiMap: Record<string, SuiClient> = {};
|
|
47
52
|
type AsyncApiFunction<T> = (api: SuiClient) => Promise<T>;
|
|
@@ -528,21 +533,6 @@ function convertApiOrderToSdkOrder(order: "asc" | "desc"): "ascending" | "descen
|
|
|
528
533
|
return order === "asc" ? "ascending" : "descending";
|
|
529
534
|
}
|
|
530
535
|
|
|
531
|
-
type Cursor = {
|
|
532
|
-
out?: string;
|
|
533
|
-
in?: string;
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
function serializeCursor(cursor: Cursor): string | undefined {
|
|
537
|
-
return cursor.in || cursor.out ? bs58.encode(Buffer.from(JSON.stringify(cursor))) : undefined;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
function deserializeCursor(b58cursor: string | undefined): Cursor {
|
|
541
|
-
return b58cursor
|
|
542
|
-
? (JSON.parse(Buffer.from(bs58.decode(b58cursor)).toString()) as Cursor)
|
|
543
|
-
: ({} as Cursor);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
536
|
function toSdkCursor(cursor: string | undefined): QueryTransactionBlocksParams["cursor"] {
|
|
547
537
|
const ret: QueryTransactionBlocksParams["cursor"] = cursor;
|
|
548
538
|
return ret;
|
|
@@ -553,20 +543,6 @@ function toSdkCursor(cursor: string | undefined): QueryTransactionBlocksParams["
|
|
|
553
543
|
* It fetches separately the "OUT" and "IN" operations and then merge them.
|
|
554
544
|
* The cursor is composed of the last "OUT" and "IN" operation cursors.
|
|
555
545
|
*
|
|
556
|
-
* Warning:
|
|
557
|
-
* Some IN operations are also OUT operations because the sender receive a new version of the coin objects,
|
|
558
|
-
* and the complexity of this function don't go that far to detect it.
|
|
559
|
-
* IN calls and OUT calls are not disjoint
|
|
560
|
-
* Consequence: 2 successive calls of this function when passing cursor may return an operation we already saw in previous calls,
|
|
561
|
-
* fetched as an OUT operation.
|
|
562
|
-
*
|
|
563
|
-
* Note: I think it's possible to detect duplicated IN oprations:
|
|
564
|
-
* - if the address is the sender of the tx
|
|
565
|
-
* - and there is some transfer to other address
|
|
566
|
-
* - and the address is the single only owner of mutated or deleted object
|
|
567
|
-
* when all that conditions are met, the transaction will be fetched as an OUT operation,
|
|
568
|
-
* and it can be filtered out from the IN operations results.
|
|
569
|
-
*
|
|
570
546
|
* @returns the operations.
|
|
571
547
|
*
|
|
572
548
|
*/
|
|
@@ -578,43 +554,95 @@ export const getListOperations = async (
|
|
|
578
554
|
): Promise<Page<Op>> =>
|
|
579
555
|
withApiImpl(async api => {
|
|
580
556
|
const rpcOrder = convertApiOrderToSdkOrder(order);
|
|
581
|
-
const { out: outCursor, in: inCursor } = deserializeCursor(cursor);
|
|
582
557
|
|
|
583
558
|
const [opsOut, opsIn] = await Promise.all([
|
|
584
559
|
queryTransactions({
|
|
585
560
|
api,
|
|
586
561
|
addr,
|
|
587
562
|
type: "OUT",
|
|
588
|
-
cursor: toSdkCursor(
|
|
563
|
+
cursor: toSdkCursor(cursor),
|
|
589
564
|
order: rpcOrder,
|
|
590
565
|
}),
|
|
591
566
|
queryTransactions({
|
|
592
567
|
api,
|
|
593
568
|
addr,
|
|
594
569
|
type: "IN",
|
|
595
|
-
cursor: toSdkCursor(
|
|
570
|
+
cursor: toSdkCursor(cursor),
|
|
596
571
|
order: rpcOrder,
|
|
597
572
|
}),
|
|
598
573
|
]);
|
|
599
574
|
|
|
600
|
-
const ops =
|
|
575
|
+
const ops = dedupOperations(opsOut, opsIn, order);
|
|
576
|
+
|
|
577
|
+
const operations = ops.operations
|
|
601
578
|
.sort((a, b) => Number(b.timestampMs) - Number(a.timestampMs))
|
|
602
579
|
.map(t => transactionToOp(addr, t));
|
|
603
580
|
|
|
604
|
-
const nextCursor: Cursor = {};
|
|
605
|
-
if (opsOut.hasNextPage && opsOut.nextCursor) {
|
|
606
|
-
nextCursor.out = opsOut.nextCursor;
|
|
607
|
-
}
|
|
608
|
-
if (opsIn.hasNextPage && opsIn.nextCursor) {
|
|
609
|
-
nextCursor.in = opsIn.nextCursor;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
581
|
return {
|
|
613
|
-
items:
|
|
614
|
-
next:
|
|
582
|
+
items: operations,
|
|
583
|
+
next: ops.cursor ?? "",
|
|
615
584
|
};
|
|
616
585
|
});
|
|
617
586
|
|
|
587
|
+
const oldestOpTime = (ops: PaginatedTransactionResponse) =>
|
|
588
|
+
Number(ops.data[ops.data.length - 1].timestampMs ?? 0);
|
|
589
|
+
const newestOpTime = (ops: PaginatedTransactionResponse) => Number(ops.data[0].timestampMs ?? 0);
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Some IN operations are also OUT operations because the sender receive a new version of the coin objects,
|
|
593
|
+
* So IN operations and OUT operations are not disjoint
|
|
594
|
+
* This function will takes the logical lowest operation of the two lists (according so sort order)
|
|
595
|
+
* and remove any higher operation of the other list.
|
|
596
|
+
*
|
|
597
|
+
* Most of the logic have been duplicated from filterOperations (used by bridge).
|
|
598
|
+
*
|
|
599
|
+
* Warning:
|
|
600
|
+
* This function removes some results, so it's not very efficient
|
|
601
|
+
* What we want is the FromOrToAddress filter from SUI RPC, but it's not supported yet
|
|
602
|
+
*
|
|
603
|
+
* Note: I think it's possible to detect duplicated IN oprations:
|
|
604
|
+
* - if the address is the sender of the tx
|
|
605
|
+
* - and there is some transfer to other address
|
|
606
|
+
* - and the address is the single only owner of mutated or deleted object
|
|
607
|
+
* when all that conditions are met, the transaction will be fetched as an OUT operation,
|
|
608
|
+
* and it can be filtered out from the IN operations results.
|
|
609
|
+
*
|
|
610
|
+
* @returns a chronologically sorted list of operations without duplicates and
|
|
611
|
+
* a cursor that guarantee to not return any operation that was already returned in previous calls
|
|
612
|
+
*
|
|
613
|
+
*/
|
|
614
|
+
export const dedupOperations = (
|
|
615
|
+
outOps: PaginatedTransactionResponse,
|
|
616
|
+
inOps: PaginatedTransactionResponse,
|
|
617
|
+
order: "asc" | "desc",
|
|
618
|
+
): LoadOperationResponse => {
|
|
619
|
+
// in asc order, the operations are sorted by timestamp in ascending order
|
|
620
|
+
// in desc order, the operations are sorted by timestamp in descending order
|
|
621
|
+
|
|
622
|
+
let lastOpTime: number = 0;
|
|
623
|
+
let nextCursor: string | null | undefined = undefined;
|
|
624
|
+
const findLastOpTime = order === "asc" ? newestOpTime : oldestOpTime;
|
|
625
|
+
|
|
626
|
+
// When we've reached the limit for either sent or received operations,
|
|
627
|
+
// we filter out extra operations to maintain correct chronological order
|
|
628
|
+
if (outOps.hasNextPage || inOps.hasNextPage) {
|
|
629
|
+
const lastOut = findLastOpTime(outOps);
|
|
630
|
+
const lastIn = findLastOpTime(inOps);
|
|
631
|
+
if (lastOut >= lastIn) {
|
|
632
|
+
nextCursor = outOps.nextCursor;
|
|
633
|
+
lastOpTime = lastOut;
|
|
634
|
+
} else {
|
|
635
|
+
nextCursor = inOps.nextCursor;
|
|
636
|
+
lastOpTime = lastIn;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
const operations = [...outOps.data, ...inOps.data]
|
|
640
|
+
.sort((a, b) => Number(b.timestampMs) - Number(a.timestampMs))
|
|
641
|
+
.filter(op => Number(op.timestampMs) >= lastOpTime);
|
|
642
|
+
|
|
643
|
+
return { operations: uniqBy(operations, tx => tx.digest), cursor: nextCursor };
|
|
644
|
+
};
|
|
645
|
+
|
|
618
646
|
/**
|
|
619
647
|
* Get a checkpoint (a.k.a, a block) metadata.
|
|
620
648
|
*
|
|
@@ -710,10 +738,15 @@ export const getCoinsForAmount = async (
|
|
|
710
738
|
*
|
|
711
739
|
* @param address - The sender's address
|
|
712
740
|
* @param transaction - The transaction details including recipient, amount, and coin type
|
|
741
|
+
* @param withObjects - Return serialized input objects used in the transaction
|
|
713
742
|
* @returns Promise<TransactionBlock> - A built transaction block ready for execution
|
|
714
743
|
*
|
|
715
744
|
*/
|
|
716
|
-
export const createTransaction = async (
|
|
745
|
+
export const createTransaction = async (
|
|
746
|
+
address: string,
|
|
747
|
+
transaction: CreateExtrinsicArg,
|
|
748
|
+
withObjects: boolean = false,
|
|
749
|
+
): Promise<CoreTransaction> =>
|
|
717
750
|
withApi(async api => {
|
|
718
751
|
const tx = new Transaction();
|
|
719
752
|
tx.setSender(ensureAddressFormat(address));
|
|
@@ -778,7 +811,14 @@ export const createTransaction = async (address: string, transaction: CreateExtr
|
|
|
778
811
|
}
|
|
779
812
|
}
|
|
780
813
|
|
|
781
|
-
|
|
814
|
+
const serialized = await tx.build({ client: api });
|
|
815
|
+
|
|
816
|
+
if (withObjects) {
|
|
817
|
+
const { bcsObjects } = await getInputObjects(tx, api);
|
|
818
|
+
return { unsigned: serialized, objects: bcsObjects as Uint8Array[] };
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
return { unsigned: serialized };
|
|
782
822
|
});
|
|
783
823
|
|
|
784
824
|
/**
|
|
@@ -786,7 +826,7 @@ export const createTransaction = async (address: string, transaction: CreateExtr
|
|
|
786
826
|
*/
|
|
787
827
|
export const paymentInfo = async (sender: string, fakeTransaction: TransactionType) =>
|
|
788
828
|
withApi(async api => {
|
|
789
|
-
const txb = await createTransaction(sender, fakeTransaction);
|
|
829
|
+
const { unsigned: txb } = await createTransaction(sender, fakeTransaction);
|
|
790
830
|
const dryRunTxResponse = await api.dryRunTransactionBlock({ transactionBlock: txb });
|
|
791
831
|
const fees = getTotalGasUsed(dryRunTxResponse.effects);
|
|
792
832
|
|
|
@@ -865,6 +905,8 @@ export const queryTransactions = async (params: {
|
|
|
865
905
|
cursor?: QueryTransactionBlocksParams["cursor"];
|
|
866
906
|
}): Promise<PaginatedTransactionResponse> => {
|
|
867
907
|
const { api, addr, type, cursor, order } = params;
|
|
908
|
+
// what we really want is te FromOrToAddress filter, but it's not supported yet
|
|
909
|
+
// it would relieve a lot of complexity (see dedupOperations)
|
|
868
910
|
const filter: QueryTransactionBlocksParams["filter"] =
|
|
869
911
|
type === "IN" ? { ToAddress: addr } : { FromAddress: addr };
|
|
870
912
|
|
package/src/types/model.ts
CHANGED
|
@@ -3,5 +3,9 @@ export type SuiOperationMode = "send";
|
|
|
3
3
|
export type AccountInfoResponse = Record<string, string>;
|
|
4
4
|
|
|
5
5
|
export type CoreTransaction = {
|
|
6
|
+
/** The transaction in a serialized format, ready to be signed. */
|
|
6
7
|
unsigned: Uint8Array;
|
|
8
|
+
|
|
9
|
+
/** The input objects referenced in the transaction, in serialized form.. */
|
|
10
|
+
objects?: Uint8Array[];
|
|
7
11
|
};
|
package/index.d.ts
DELETED
|
File without changes
|