@ledgerhq/coin-sui 0.9.0 → 0.10.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/.unimportedrc.json +1 -1
- package/CHANGELOG.md +26 -0
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.integration.test.js +21 -2
- package/lib/api/index.integration.test.js.map +1 -1
- package/lib/api/index.js +2 -0
- package/lib/api/index.js.map +1 -1
- package/lib/api/index.test.js +37 -0
- package/lib/api/index.test.js.map +1 -1
- package/lib/bridge/buildTransaction.d.ts +1 -3
- package/lib/bridge/buildTransaction.d.ts.map +1 -1
- package/lib/bridge/buildTransaction.integration.test.js +17 -35
- package/lib/bridge/buildTransaction.integration.test.js.map +1 -1
- package/lib/bridge/buildTransaction.js +10 -21
- package/lib/bridge/buildTransaction.js.map +1 -1
- package/lib/bridge/buildTransaction.test.js +33 -130
- package/lib/bridge/buildTransaction.test.js.map +1 -1
- package/lib/bridge/getFeesForTransaction.d.ts.map +1 -1
- package/lib/bridge/getFeesForTransaction.js +5 -1
- package/lib/bridge/getFeesForTransaction.js.map +1 -1
- package/lib/logic/craftTransaction.d.ts +2 -2
- package/lib/logic/craftTransaction.d.ts.map +1 -1
- package/lib/logic/craftTransaction.integration.test.d.ts +2 -0
- package/lib/logic/craftTransaction.integration.test.d.ts.map +1 -0
- package/lib/logic/craftTransaction.integration.test.js +56 -0
- package/lib/logic/craftTransaction.integration.test.js.map +1 -0
- package/lib/logic/craftTransaction.js +2 -2
- package/lib/logic/craftTransaction.js.map +1 -1
- package/lib/logic/estimateFees.d.ts +1 -1
- package/lib/logic/estimateFees.d.ts.map +1 -1
- package/lib/logic/estimateFees.integration.test.d.ts +2 -0
- package/lib/logic/estimateFees.integration.test.d.ts.map +1 -0
- package/lib/logic/estimateFees.integration.test.js +79 -0
- package/lib/logic/estimateFees.integration.test.js.map +1 -0
- package/lib/logic/estimateFees.js +7 -2
- package/lib/logic/estimateFees.js.map +1 -1
- package/lib/logic/getBalance.d.ts.map +1 -1
- package/lib/logic/getBalance.integration.test.d.ts +2 -0
- package/lib/logic/getBalance.integration.test.d.ts.map +1 -0
- package/lib/logic/getBalance.integration.test.js +56 -0
- package/lib/logic/getBalance.integration.test.js.map +1 -0
- package/lib/logic/getBalance.js +18 -7
- package/lib/logic/getBalance.js.map +1 -1
- package/lib/logic/getBalance.test.js +49 -7
- package/lib/logic/getBalance.test.js.map +1 -1
- package/lib/logic/index.d.ts +1 -0
- package/lib/logic/index.d.ts.map +1 -1
- package/lib/logic/index.js +4 -1
- package/lib/logic/index.js.map +1 -1
- package/lib/logic/staking.d.ts +4 -0
- package/lib/logic/staking.d.ts.map +1 -0
- package/lib/logic/staking.js +36 -0
- package/lib/logic/staking.js.map +1 -0
- package/lib/network/index.d.ts +6 -6
- package/lib/network/index.d.ts.map +1 -1
- package/lib/network/index.js +9 -3
- package/lib/network/index.js.map +1 -1
- package/lib/network/sdk.d.ts +27 -19
- package/lib/network/sdk.d.ts.map +1 -1
- package/lib/network/sdk.integration.test.js +21 -22
- package/lib/network/sdk.integration.test.js.map +1 -1
- package/lib/network/sdk.js +113 -68
- package/lib/network/sdk.js.map +1 -1
- package/lib/network/sdk.test.js +148 -65
- package/lib/network/sdk.test.js.map +1 -1
- package/lib/test/testUtils.d.ts +2 -0
- package/lib/test/testUtils.d.ts.map +1 -0
- package/lib/test/testUtils.js +35 -0
- package/lib/test/testUtils.js.map +1 -0
- package/lib-es/api/index.d.ts.map +1 -1
- package/lib-es/api/index.integration.test.js +21 -2
- package/lib-es/api/index.integration.test.js.map +1 -1
- package/lib-es/api/index.js +3 -1
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/api/index.test.js +37 -0
- package/lib-es/api/index.test.js.map +1 -1
- package/lib-es/bridge/buildTransaction.d.ts +1 -3
- package/lib-es/bridge/buildTransaction.d.ts.map +1 -1
- package/lib-es/bridge/buildTransaction.integration.test.js +13 -31
- package/lib-es/bridge/buildTransaction.integration.test.js.map +1 -1
- package/lib-es/bridge/buildTransaction.js +9 -16
- package/lib-es/bridge/buildTransaction.js.map +1 -1
- package/lib-es/bridge/buildTransaction.test.js +34 -131
- package/lib-es/bridge/buildTransaction.test.js.map +1 -1
- package/lib-es/bridge/getFeesForTransaction.d.ts.map +1 -1
- package/lib-es/bridge/getFeesForTransaction.js +5 -1
- package/lib-es/bridge/getFeesForTransaction.js.map +1 -1
- package/lib-es/logic/craftTransaction.d.ts +2 -2
- package/lib-es/logic/craftTransaction.d.ts.map +1 -1
- package/lib-es/logic/craftTransaction.integration.test.d.ts +2 -0
- package/lib-es/logic/craftTransaction.integration.test.d.ts.map +1 -0
- package/lib-es/logic/craftTransaction.integration.test.js +51 -0
- package/lib-es/logic/craftTransaction.integration.test.js.map +1 -0
- package/lib-es/logic/craftTransaction.js +2 -2
- package/lib-es/logic/craftTransaction.js.map +1 -1
- package/lib-es/logic/estimateFees.d.ts +1 -1
- package/lib-es/logic/estimateFees.d.ts.map +1 -1
- package/lib-es/logic/estimateFees.integration.test.d.ts +2 -0
- package/lib-es/logic/estimateFees.integration.test.d.ts.map +1 -0
- package/lib-es/logic/estimateFees.integration.test.js +74 -0
- package/lib-es/logic/estimateFees.integration.test.js.map +1 -0
- package/lib-es/logic/estimateFees.js +7 -2
- package/lib-es/logic/estimateFees.js.map +1 -1
- package/lib-es/logic/getBalance.d.ts.map +1 -1
- package/lib-es/logic/getBalance.integration.test.d.ts +2 -0
- package/lib-es/logic/getBalance.integration.test.d.ts.map +1 -0
- package/lib-es/logic/getBalance.integration.test.js +51 -0
- package/lib-es/logic/getBalance.integration.test.js.map +1 -0
- package/lib-es/logic/getBalance.js +19 -8
- package/lib-es/logic/getBalance.js.map +1 -1
- package/lib-es/logic/getBalance.test.js +50 -8
- package/lib-es/logic/getBalance.test.js.map +1 -1
- package/lib-es/logic/index.d.ts +1 -0
- package/lib-es/logic/index.d.ts.map +1 -1
- package/lib-es/logic/index.js +1 -0
- package/lib-es/logic/index.js.map +1 -1
- package/lib-es/logic/staking.d.ts +4 -0
- package/lib-es/logic/staking.d.ts.map +1 -0
- package/lib-es/logic/staking.js +8 -0
- package/lib-es/logic/staking.js.map +1 -0
- package/lib-es/network/index.d.ts +6 -6
- package/lib-es/network/index.d.ts.map +1 -1
- package/lib-es/network/index.js +6 -3
- package/lib-es/network/index.js.map +1 -1
- package/lib-es/network/sdk.d.ts +27 -19
- package/lib-es/network/sdk.d.ts.map +1 -1
- package/lib-es/network/sdk.integration.test.js +22 -23
- package/lib-es/network/sdk.integration.test.js.map +1 -1
- package/lib-es/network/sdk.js +106 -64
- package/lib-es/network/sdk.js.map +1 -1
- package/lib-es/network/sdk.test.js +148 -65
- package/lib-es/network/sdk.test.js.map +1 -1
- package/lib-es/test/testUtils.d.ts +2 -0
- package/lib-es/test/testUtils.d.ts.map +1 -0
- package/lib-es/test/testUtils.js +31 -0
- package/lib-es/test/testUtils.js.map +1 -0
- package/package.json +7 -7
- package/src/api/index.integration.test.ts +24 -2
- package/src/api/index.test.ts +40 -0
- package/src/api/index.ts +4 -0
- package/src/bridge/buildTransaction.integration.test.ts +14 -39
- package/src/bridge/buildTransaction.test.ts +37 -160
- package/src/bridge/buildTransaction.ts +12 -21
- package/src/bridge/getFeesForTransaction.ts +6 -1
- package/src/logic/craftTransaction.integration.test.ts +63 -0
- package/src/logic/craftTransaction.ts +4 -4
- package/src/logic/estimateFees.integration.test.ts +89 -0
- package/src/logic/estimateFees.ts +7 -1
- package/src/logic/getBalance.integration.test.ts +66 -0
- package/src/logic/getBalance.test.ts +58 -8
- package/src/logic/getBalance.ts +24 -8
- package/src/logic/index.ts +1 -0
- package/src/logic/staking.ts +10 -0
- package/src/network/index.ts +12 -3
- package/src/network/sdk.integration.test.ts +25 -22
- package/src/network/sdk.test.ts +186 -77
- package/src/network/sdk.ts +149 -93
- package/src/test/testUtils.ts +38 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BigNumber } from "bignumber.js";
|
|
2
|
-
import { buildTransaction
|
|
2
|
+
import { buildTransaction } from "./buildTransaction";
|
|
3
3
|
import type { SuiAccount, Transaction } from "../types";
|
|
4
|
+
import { createFixtureAccount } from "../types/bridge.fixture";
|
|
4
5
|
|
|
5
6
|
// Mock the craftTransaction function
|
|
6
7
|
jest.mock("../logic", () => ({
|
|
@@ -64,7 +65,7 @@ describe("buildTransaction", () => {
|
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
describe("buildTransaction", () => {
|
|
67
|
-
it("should call craftTransaction with correct parameters", async () => {
|
|
68
|
+
it("should call craftTransaction with correct parameters for native asset", async () => {
|
|
68
69
|
// WHEN
|
|
69
70
|
await buildTransaction(mockAccount, mockTransaction);
|
|
70
71
|
|
|
@@ -78,6 +79,40 @@ describe("buildTransaction", () => {
|
|
|
78
79
|
});
|
|
79
80
|
});
|
|
80
81
|
|
|
82
|
+
it("should call craftTransaction with correct parameters for token asset", async () => {
|
|
83
|
+
const account = createFixtureAccount({
|
|
84
|
+
id: "parentAccountId",
|
|
85
|
+
balance: BigNumber(0),
|
|
86
|
+
spendableBalance: BigNumber(0),
|
|
87
|
+
subAccounts: [
|
|
88
|
+
createFixtureAccount({
|
|
89
|
+
id: "subAccountId",
|
|
90
|
+
parentId: "parentAccountId",
|
|
91
|
+
type: "TokenAccount",
|
|
92
|
+
token: {
|
|
93
|
+
contractAddress: "0x3::usdt::USDT",
|
|
94
|
+
},
|
|
95
|
+
}),
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// WHEN
|
|
100
|
+
await buildTransaction(account, {
|
|
101
|
+
...mockTransaction,
|
|
102
|
+
subAccountId: "subAccountId",
|
|
103
|
+
coinType: "0x3::usdt::USDT",
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// THEN
|
|
107
|
+
expect(craftTransaction).toHaveBeenCalledWith({
|
|
108
|
+
sender: account.freshAddress,
|
|
109
|
+
recipient: mockTransaction.recipient,
|
|
110
|
+
type: mockTransaction.mode,
|
|
111
|
+
amount: BigInt(mockTransaction.amount!.toString()),
|
|
112
|
+
asset: { type: "token", assetReference: "0x3::usdt::USDT" },
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
81
116
|
it("should return the result from craftTransaction", async () => {
|
|
82
117
|
const expectedResult = {
|
|
83
118
|
unsigned: new Uint8Array([1, 2, 3, 4, 5]),
|
|
@@ -207,164 +242,6 @@ describe("buildTransaction", () => {
|
|
|
207
242
|
});
|
|
208
243
|
});
|
|
209
244
|
|
|
210
|
-
describe("extractExtrinsicArg", () => {
|
|
211
|
-
it("should extract correct fields from transaction", () => {
|
|
212
|
-
const transaction: Transaction = {
|
|
213
|
-
...mockTransaction,
|
|
214
|
-
useAllAmount: true,
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
// WHEN
|
|
218
|
-
const result = extractExtrinsicArg(transaction);
|
|
219
|
-
|
|
220
|
-
// THEN
|
|
221
|
-
expect(result).toEqual({
|
|
222
|
-
mode: "send",
|
|
223
|
-
coinType: "0x2::sui::SUI",
|
|
224
|
-
amount: new BigNumber("100000000"),
|
|
225
|
-
recipient: "0xabcdef1234567890",
|
|
226
|
-
useAllAmount: true,
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it("should handle transaction without useAllAmount", () => {
|
|
231
|
-
const transaction: Transaction = {
|
|
232
|
-
...mockTransaction,
|
|
233
|
-
useAllAmount: false,
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
// WHEN
|
|
237
|
-
const result = extractExtrinsicArg(transaction);
|
|
238
|
-
|
|
239
|
-
// THEN
|
|
240
|
-
expect(result).toEqual({
|
|
241
|
-
mode: "send",
|
|
242
|
-
coinType: "0x2::sui::SUI",
|
|
243
|
-
amount: new BigNumber("100000000"),
|
|
244
|
-
recipient: "0xabcdef1234567890",
|
|
245
|
-
useAllAmount: false,
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it("should handle transaction with undefined useAllAmount", () => {
|
|
250
|
-
const transaction = {
|
|
251
|
-
...mockTransaction,
|
|
252
|
-
useAllAmount: undefined,
|
|
253
|
-
} as any;
|
|
254
|
-
|
|
255
|
-
// WHEN
|
|
256
|
-
const result = extractExtrinsicArg(transaction);
|
|
257
|
-
|
|
258
|
-
// THEN
|
|
259
|
-
expect(result).toEqual({
|
|
260
|
-
mode: "send",
|
|
261
|
-
coinType: "0x2::sui::SUI",
|
|
262
|
-
amount: new BigNumber("100000000"),
|
|
263
|
-
recipient: "0xabcdef1234567890",
|
|
264
|
-
useAllAmount: undefined,
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it("should handle different transaction modes", () => {
|
|
269
|
-
const transaction: Transaction = {
|
|
270
|
-
...mockTransaction,
|
|
271
|
-
mode: "send",
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
// WHEN
|
|
275
|
-
const result = extractExtrinsicArg(transaction);
|
|
276
|
-
|
|
277
|
-
// THEN
|
|
278
|
-
expect(result.mode).toBe("send");
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it("should handle different amounts", () => {
|
|
282
|
-
const transaction: Transaction = {
|
|
283
|
-
...mockTransaction,
|
|
284
|
-
amount: new BigNumber("500000000"),
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
// WHEN
|
|
288
|
-
const result = extractExtrinsicArg(transaction);
|
|
289
|
-
|
|
290
|
-
// THEN
|
|
291
|
-
expect(result.amount).toEqual(new BigNumber("500000000"));
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
it("should handle different recipients", () => {
|
|
295
|
-
const transaction: Transaction = {
|
|
296
|
-
...mockTransaction,
|
|
297
|
-
recipient: "0x9876543210fedcba",
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
// WHEN
|
|
301
|
-
const result = extractExtrinsicArg(transaction);
|
|
302
|
-
|
|
303
|
-
// THEN
|
|
304
|
-
expect(result.recipient).toBe("0x9876543210fedcba");
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it("should not include other transaction fields", () => {
|
|
308
|
-
const transaction: Transaction = {
|
|
309
|
-
...mockTransaction,
|
|
310
|
-
fees: new BigNumber("1000000"),
|
|
311
|
-
errors: { someError: new Error("test") },
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
// WHEN
|
|
315
|
-
const result = extractExtrinsicArg(transaction);
|
|
316
|
-
|
|
317
|
-
// THEN
|
|
318
|
-
expect(result).not.toHaveProperty("fees");
|
|
319
|
-
expect(result).not.toHaveProperty("errors");
|
|
320
|
-
expect(result).not.toHaveProperty("family");
|
|
321
|
-
expect(result).not.toHaveProperty("id");
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
it("should handle zero amount", () => {
|
|
325
|
-
const transaction: Transaction = {
|
|
326
|
-
...mockTransaction,
|
|
327
|
-
amount: new BigNumber("0"),
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
// WHEN
|
|
331
|
-
const result = extractExtrinsicArg(transaction);
|
|
332
|
-
|
|
333
|
-
// THEN
|
|
334
|
-
expect(result.amount).toEqual(new BigNumber("0"));
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe("Integration between extractExtrinsicArg and buildTransaction", () => {
|
|
339
|
-
it("should work together correctly", async () => {
|
|
340
|
-
const transaction: Transaction = {
|
|
341
|
-
...mockTransaction,
|
|
342
|
-
useAllAmount: true,
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
// Extract extrinsic arg
|
|
346
|
-
const extrinsicArg = extractExtrinsicArg(transaction);
|
|
347
|
-
|
|
348
|
-
// Build transaction
|
|
349
|
-
await buildTransaction(mockAccount, transaction);
|
|
350
|
-
|
|
351
|
-
// Verify that the extracted arg contains the expected fields
|
|
352
|
-
expect(extrinsicArg).toHaveProperty("mode", "send");
|
|
353
|
-
expect(extrinsicArg).toHaveProperty("amount");
|
|
354
|
-
expect(extrinsicArg).toHaveProperty("recipient");
|
|
355
|
-
expect(extrinsicArg).toHaveProperty("useAllAmount", true);
|
|
356
|
-
|
|
357
|
-
// Verify that buildTransaction was called with correct parameters
|
|
358
|
-
expect(craftTransaction).toHaveBeenCalledWith({
|
|
359
|
-
sender: mockAccount.freshAddress,
|
|
360
|
-
recipient: transaction.recipient,
|
|
361
|
-
type: transaction.mode,
|
|
362
|
-
amount: BigInt(transaction.amount!.toString()),
|
|
363
|
-
asset: { type: "native" },
|
|
364
|
-
});
|
|
365
|
-
});
|
|
366
|
-
});
|
|
367
|
-
|
|
368
245
|
describe("Edge Cases", () => {
|
|
369
246
|
it("should handle empty recipient string", async () => {
|
|
370
247
|
const transactionWithEmptyRecipient: Transaction = {
|
|
@@ -1,34 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { findSubAccountById } from "@ledgerhq/coin-framework/account/helpers";
|
|
2
2
|
import type { SuiAccount, Transaction } from "../types";
|
|
3
|
-
import { craftTransaction
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export const extractExtrinsicArg = (transaction: Transaction): CreateExtrinsicArg =>
|
|
7
|
-
pick(transaction, ["mode", "amount", "recipient", "useAllAmount", "coinType"]);
|
|
3
|
+
import { craftTransaction } from "../logic";
|
|
4
|
+
import { DEFAULT_COIN_TYPE, toSuiAsset } from "../network/sdk";
|
|
8
5
|
|
|
9
6
|
/**
|
|
10
7
|
* @param {Account} account
|
|
11
8
|
* @param {Transaction} transaction
|
|
12
9
|
*/
|
|
13
10
|
export const buildTransaction = async (
|
|
14
|
-
|
|
15
|
-
{
|
|
11
|
+
account: SuiAccount,
|
|
12
|
+
{ amount, mode, recipient, subAccountId }: Transaction,
|
|
16
13
|
) => {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (coinType !== NATIVE_COIN_TYPE) {
|
|
22
|
-
asset = {
|
|
23
|
-
type: "token",
|
|
24
|
-
assetReference: coinType,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
14
|
+
const { freshAddress } = account;
|
|
15
|
+
const subAccount = findSubAccountById(account, subAccountId ?? "");
|
|
16
|
+
const asset = toSuiAsset(subAccount?.token.contractAddress ?? DEFAULT_COIN_TYPE);
|
|
17
|
+
|
|
27
18
|
return craftTransaction({
|
|
28
|
-
sender: freshAddress,
|
|
29
|
-
recipient,
|
|
30
|
-
type: mode,
|
|
31
19
|
amount: BigInt(amount.toString()),
|
|
32
20
|
asset,
|
|
21
|
+
recipient,
|
|
22
|
+
sender: freshAddress,
|
|
23
|
+
type: mode,
|
|
33
24
|
});
|
|
34
25
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { findSubAccountById } from "@ledgerhq/coin-framework/account/helpers";
|
|
1
2
|
import { BigNumber } from "bignumber.js";
|
|
2
3
|
import { getAbandonSeedAddress } from "@ledgerhq/cryptoassets";
|
|
3
4
|
import type { SuiAccount, Transaction } from "../types";
|
|
4
5
|
import { calculateAmount } from "./utils";
|
|
5
6
|
import { estimateFees } from "../logic";
|
|
7
|
+
import { DEFAULT_COIN_TYPE, toSuiAsset } from "../network/sdk";
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Fetch the transaction fees for a transaction
|
|
@@ -32,12 +34,15 @@ export default async function getEstimatedFees({
|
|
|
32
34
|
}), // Remove fees if present since we are fetching fees
|
|
33
35
|
};
|
|
34
36
|
|
|
37
|
+
const subAccount = findSubAccountById(account, transaction.subAccountId ?? "");
|
|
38
|
+
const asset = toSuiAsset(subAccount?.token.contractAddress ?? DEFAULT_COIN_TYPE);
|
|
39
|
+
|
|
35
40
|
const fees = await estimateFees({
|
|
36
41
|
recipient: getAbandonSeedAddress(account.currency.id),
|
|
37
42
|
sender: account.freshAddress,
|
|
38
43
|
amount: BigInt(t.amount.toString()),
|
|
39
44
|
type: "send",
|
|
40
|
-
asset
|
|
45
|
+
asset,
|
|
41
46
|
});
|
|
42
47
|
return new BigNumber(fees.toString());
|
|
43
48
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { TransactionIntent } from "@ledgerhq/coin-framework/api/index";
|
|
2
|
+
import { getFullnodeUrl } from "@mysten/sui/client";
|
|
3
|
+
import coinConfig from "../config";
|
|
4
|
+
import { extractCoinTypeFromUnsignedTx } from "../test/testUtils";
|
|
5
|
+
import { craftTransaction } from "./craftTransaction";
|
|
6
|
+
|
|
7
|
+
const SENDER = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
8
|
+
const RECIPIENT = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
9
|
+
|
|
10
|
+
describe("craftTransaction", () => {
|
|
11
|
+
beforeAll(() => {
|
|
12
|
+
coinConfig.setCoinConfig(() => ({
|
|
13
|
+
status: {
|
|
14
|
+
type: "active",
|
|
15
|
+
},
|
|
16
|
+
node: {
|
|
17
|
+
url: getFullnodeUrl("mainnet"),
|
|
18
|
+
},
|
|
19
|
+
}));
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should craft a native SUI send transaction", async () => {
|
|
23
|
+
const transactionIntent: TransactionIntent = {
|
|
24
|
+
sender: SENDER,
|
|
25
|
+
recipient: RECIPIENT,
|
|
26
|
+
amount: BigInt(1000),
|
|
27
|
+
type: "send",
|
|
28
|
+
asset: { type: "native" },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const result = await craftTransaction(transactionIntent);
|
|
32
|
+
|
|
33
|
+
expect(result).toBeDefined();
|
|
34
|
+
expect(result.unsigned).toBeInstanceOf(Uint8Array);
|
|
35
|
+
|
|
36
|
+
const resultCoinTypes = await extractCoinTypeFromUnsignedTx(result.unsigned);
|
|
37
|
+
expect(resultCoinTypes).toEqual(expect.arrayContaining([expect.stringContaining("sui")]));
|
|
38
|
+
}, 15000);
|
|
39
|
+
|
|
40
|
+
it("should craft a token send transaction", async () => {
|
|
41
|
+
const coinType =
|
|
42
|
+
"0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT";
|
|
43
|
+
|
|
44
|
+
const transactionIntent: TransactionIntent = {
|
|
45
|
+
sender: SENDER,
|
|
46
|
+
recipient: RECIPIENT,
|
|
47
|
+
amount: BigInt(1000),
|
|
48
|
+
type: "send",
|
|
49
|
+
asset: {
|
|
50
|
+
type: "token",
|
|
51
|
+
assetReference: coinType,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const result = await craftTransaction(transactionIntent);
|
|
56
|
+
|
|
57
|
+
expect(result).toBeDefined();
|
|
58
|
+
expect(result.unsigned).toBeInstanceOf(Uint8Array);
|
|
59
|
+
|
|
60
|
+
const resultCoinTypes = await extractCoinTypeFromUnsignedTx(result.unsigned);
|
|
61
|
+
expect(resultCoinTypes).toEqual(expect.arrayContaining([expect.stringContaining("usdt")]));
|
|
62
|
+
}, 15000);
|
|
63
|
+
});
|
|
@@ -5,18 +5,18 @@ import suiAPI from "../network";
|
|
|
5
5
|
import { DEFAULT_COIN_TYPE } from "../network/sdk";
|
|
6
6
|
|
|
7
7
|
export type CreateExtrinsicArg = {
|
|
8
|
-
mode: SuiTransactionMode;
|
|
9
8
|
amount: BigNumber;
|
|
10
9
|
coinType: string;
|
|
10
|
+
mode: SuiTransactionMode;
|
|
11
11
|
recipient: string;
|
|
12
12
|
useAllAmount?: boolean | undefined;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
export async function craftTransaction({
|
|
16
|
-
sender,
|
|
17
16
|
amount,
|
|
18
|
-
recipient,
|
|
19
17
|
asset,
|
|
18
|
+
recipient,
|
|
19
|
+
sender,
|
|
20
20
|
type,
|
|
21
21
|
}: TransactionIntent): Promise<CoreTransaction> {
|
|
22
22
|
let coinType = DEFAULT_COIN_TYPE;
|
|
@@ -25,9 +25,9 @@ export async function craftTransaction({
|
|
|
25
25
|
}
|
|
26
26
|
const unsigned = await suiAPI.createTransaction(sender, {
|
|
27
27
|
amount: BigNumber(amount.toString()),
|
|
28
|
-
recipient,
|
|
29
28
|
coinType,
|
|
30
29
|
mode: type as SuiTransactionMode,
|
|
30
|
+
recipient,
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
return { unsigned };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { TransactionIntent } from "@ledgerhq/coin-framework/api/index";
|
|
2
|
+
import { getFullnodeUrl } from "@mysten/sui/client";
|
|
3
|
+
import coinConfig from "../config";
|
|
4
|
+
import { estimateFees } from "./estimateFees";
|
|
5
|
+
|
|
6
|
+
const SENDER = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
|
|
7
|
+
const RECIPIENT = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
8
|
+
|
|
9
|
+
describe("estimateFees", () => {
|
|
10
|
+
beforeAll(() => {
|
|
11
|
+
coinConfig.setCoinConfig(() => ({
|
|
12
|
+
status: {
|
|
13
|
+
type: "active",
|
|
14
|
+
},
|
|
15
|
+
node: {
|
|
16
|
+
url: getFullnodeUrl("mainnet"),
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should estimate fees for native SUI transaction", async () => {
|
|
22
|
+
const transactionIntent: TransactionIntent = {
|
|
23
|
+
sender: SENDER,
|
|
24
|
+
recipient: RECIPIENT,
|
|
25
|
+
amount: BigInt(1000),
|
|
26
|
+
type: "send",
|
|
27
|
+
asset: { type: "native" },
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const estimatedFees = await estimateFees(transactionIntent);
|
|
31
|
+
|
|
32
|
+
expect(typeof estimatedFees).toBe("bigint");
|
|
33
|
+
expect(estimatedFees).toBeGreaterThan(1000n);
|
|
34
|
+
expect(estimatedFees).toBeLessThan(10000000n);
|
|
35
|
+
}, 25000);
|
|
36
|
+
|
|
37
|
+
it("should estimate fees for token transaction", async () => {
|
|
38
|
+
const coinType =
|
|
39
|
+
"0x375f70cf2ae4c00bf37117d0c85a2c71545e6ee05c4a5c7d282cd66a4504b068::usdt::USDT";
|
|
40
|
+
|
|
41
|
+
const transactionIntent: TransactionIntent = {
|
|
42
|
+
sender: SENDER,
|
|
43
|
+
recipient: RECIPIENT,
|
|
44
|
+
amount: BigInt(1000),
|
|
45
|
+
type: "send",
|
|
46
|
+
asset: {
|
|
47
|
+
type: "token",
|
|
48
|
+
assetReference: coinType,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const estimatedFees = await estimateFees(transactionIntent);
|
|
53
|
+
|
|
54
|
+
expect(typeof estimatedFees).toBe("bigint");
|
|
55
|
+
expect(estimatedFees).toBeGreaterThan(1000n);
|
|
56
|
+
expect(estimatedFees).toBeLessThan(10000000n);
|
|
57
|
+
}, 25000);
|
|
58
|
+
|
|
59
|
+
it("should handle concurrent fee estimations", async () => {
|
|
60
|
+
const transactionIntent: TransactionIntent = {
|
|
61
|
+
sender: SENDER,
|
|
62
|
+
recipient: RECIPIENT,
|
|
63
|
+
amount: BigInt(1000),
|
|
64
|
+
type: "send",
|
|
65
|
+
asset: { type: "native" },
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Run multiple concurrent estimations
|
|
69
|
+
const promises = Array(5)
|
|
70
|
+
.fill(0)
|
|
71
|
+
.map(() => estimateFees(transactionIntent));
|
|
72
|
+
const results = await Promise.all(promises);
|
|
73
|
+
|
|
74
|
+
// All results should be valid
|
|
75
|
+
results.forEach(fees => {
|
|
76
|
+
expect(typeof fees).toBe("bigint");
|
|
77
|
+
expect(fees).toBeGreaterThan(1000n);
|
|
78
|
+
expect(fees).toBeLessThan(10000000n);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Results should be similar (may have slight variations)
|
|
82
|
+
const values = results.map(r => Number(r));
|
|
83
|
+
const minValue = Math.min(...values);
|
|
84
|
+
const maxValue = Math.max(...values);
|
|
85
|
+
|
|
86
|
+
// Should not vary by more than 50% under concurrent load
|
|
87
|
+
expect((maxValue - minValue) / minValue).toBeLessThan(0.5);
|
|
88
|
+
}, 25000);
|
|
89
|
+
});
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import suiAPI from "../network";
|
|
2
2
|
import { BigNumber } from "bignumber.js";
|
|
3
3
|
import type { TransactionIntent } from "@ledgerhq/coin-framework/api/index";
|
|
4
|
+
import { DEFAULT_COIN_TYPE } from "../network/sdk";
|
|
4
5
|
|
|
5
6
|
export async function estimateFees({
|
|
6
7
|
recipient,
|
|
7
8
|
amount,
|
|
8
9
|
sender,
|
|
10
|
+
asset,
|
|
9
11
|
}: TransactionIntent): Promise<bigint> {
|
|
12
|
+
let coinType = DEFAULT_COIN_TYPE;
|
|
13
|
+
if (asset.type === "token" && asset.assetReference) {
|
|
14
|
+
coinType = asset.assetReference;
|
|
15
|
+
}
|
|
10
16
|
const { gasBudget } = await suiAPI.paymentInfo(sender, {
|
|
11
17
|
mode: "send",
|
|
12
18
|
family: "sui",
|
|
13
19
|
recipient,
|
|
14
20
|
amount: BigNumber(amount.toString()),
|
|
15
21
|
errors: {},
|
|
16
|
-
coinType
|
|
22
|
+
coinType,
|
|
17
23
|
});
|
|
18
24
|
return BigInt(gasBudget);
|
|
19
25
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { getFullnodeUrl } from "@mysten/sui/client";
|
|
2
|
+
import coinConfig from "../config";
|
|
3
|
+
import { getBalance } from "./getBalance";
|
|
4
|
+
|
|
5
|
+
const SENDER = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
6
|
+
|
|
7
|
+
describe("getBalance", () => {
|
|
8
|
+
beforeAll(() => {
|
|
9
|
+
coinConfig.setCoinConfig(() => ({
|
|
10
|
+
status: {
|
|
11
|
+
type: "active",
|
|
12
|
+
},
|
|
13
|
+
node: {
|
|
14
|
+
url: getFullnodeUrl("testnet"),
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should fetch native SUI balance", async () => {
|
|
20
|
+
const balances = await getBalance(SENDER);
|
|
21
|
+
|
|
22
|
+
expect(balances.length).toBeGreaterThanOrEqual(1);
|
|
23
|
+
expect(balances[0]).toMatchObject({
|
|
24
|
+
asset: { type: "native" },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect(typeof balances[0].value).toBe("bigint");
|
|
28
|
+
expect(balances[0].value).toBeGreaterThanOrEqual(0n);
|
|
29
|
+
}, 10000);
|
|
30
|
+
|
|
31
|
+
it("should fetch token balances", async () => {
|
|
32
|
+
const balances = await getBalance(SENDER);
|
|
33
|
+
|
|
34
|
+
expect(balances.length).toBeGreaterThanOrEqual(1);
|
|
35
|
+
|
|
36
|
+
const tokenBalances = balances.filter(balance => balance.asset.type === "token");
|
|
37
|
+
tokenBalances.forEach(balance => {
|
|
38
|
+
expect(balance.asset.type).toBe("token");
|
|
39
|
+
if (balance.asset.type === "token") {
|
|
40
|
+
expect(balance.asset.assetReference).toMatch(
|
|
41
|
+
/^0x[a-fA-F0-9]+::[a-zA-Z0-9_]+::[a-zA-Z0-9_]+$/,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
expect(typeof balance.value).toBe("bigint");
|
|
45
|
+
expect(balance.value).toBeGreaterThanOrEqual(0n);
|
|
46
|
+
});
|
|
47
|
+
}, 15000);
|
|
48
|
+
|
|
49
|
+
it("should properly parse token asset reference", async () => {
|
|
50
|
+
const balances = await getBalance(SENDER);
|
|
51
|
+
|
|
52
|
+
const usdTokens = balances.filter(
|
|
53
|
+
balance =>
|
|
54
|
+
balance.asset.type === "token" &&
|
|
55
|
+
balance.asset.assetReference?.toLowerCase().includes("usd"),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
usdTokens.forEach(balance => {
|
|
59
|
+
expect(balance.asset.type).toBe("token");
|
|
60
|
+
if (balance.asset.type === "token") {
|
|
61
|
+
expect(balance.asset.assetReference).toBeTruthy();
|
|
62
|
+
}
|
|
63
|
+
expect(typeof balance.value).toBe("bigint");
|
|
64
|
+
});
|
|
65
|
+
}, 15000);
|
|
66
|
+
});
|
|
@@ -1,24 +1,74 @@
|
|
|
1
1
|
import { getBalance } from "./getBalance";
|
|
2
|
-
import {
|
|
2
|
+
import { getAllBalancesCached, getStakes } from "../network";
|
|
3
|
+
import type { Stake } from "@ledgerhq/coin-framework/api/types";
|
|
3
4
|
|
|
4
|
-
// Mock the getAccount function
|
|
5
5
|
jest.mock("../network", () => ({
|
|
6
|
-
|
|
6
|
+
getAllBalancesCached: jest.fn().mockResolvedValue([
|
|
7
|
+
{ coinType: "0x2::sui::SUI", totalBalance: 1000000000 },
|
|
8
|
+
{ coinType: "0x3::usdt::USDT", totalBalance: 500000000 },
|
|
9
|
+
]),
|
|
10
|
+
getStakes: jest.fn().mockResolvedValue([]),
|
|
7
11
|
}));
|
|
8
12
|
|
|
13
|
+
const mockedGetStakes = jest.mocked(getStakes);
|
|
14
|
+
|
|
9
15
|
describe("getBalance", () => {
|
|
10
16
|
beforeEach(() => {
|
|
11
17
|
jest.clearAllMocks();
|
|
12
18
|
});
|
|
13
19
|
|
|
14
|
-
it("should return the correct
|
|
15
|
-
|
|
16
|
-
const
|
|
20
|
+
it("should return the correct native SUI balance", async () => {
|
|
21
|
+
const address = "0x123";
|
|
22
|
+
const result = await getBalance(address);
|
|
17
23
|
|
|
24
|
+
expect(result[0]).toMatchObject({
|
|
25
|
+
value: BigInt(1000000000),
|
|
26
|
+
asset: { type: "native" },
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should return the correct USDT token balance", async () => {
|
|
18
31
|
const address = "0x123";
|
|
19
32
|
const result = await getBalance(address);
|
|
20
33
|
|
|
21
|
-
expect(
|
|
22
|
-
|
|
34
|
+
expect(result[1]).toMatchObject({
|
|
35
|
+
value: BigInt(500000000),
|
|
36
|
+
asset: { type: "token", assetReference: "0x3::usdt::USDT" },
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should return staking balances when stakes are available", async () => {
|
|
41
|
+
const mockStakes: Stake[] = [
|
|
42
|
+
{
|
|
43
|
+
uid: "stake_1",
|
|
44
|
+
address: "0x123",
|
|
45
|
+
delegate: "0xvalidator1",
|
|
46
|
+
state: "active",
|
|
47
|
+
asset: { type: "native" },
|
|
48
|
+
amount: BigInt(2000000000),
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
mockedGetStakes.mockResolvedValueOnce(mockStakes);
|
|
53
|
+
|
|
54
|
+
const address = "0x123";
|
|
55
|
+
const result = await getBalance(address);
|
|
56
|
+
|
|
57
|
+
expect(getAllBalancesCached).toHaveBeenCalledWith(address);
|
|
58
|
+
expect(getStakes).toHaveBeenCalledWith(address);
|
|
59
|
+
expect(result).toHaveLength(3);
|
|
60
|
+
|
|
61
|
+
expect(result[2]).toMatchObject({
|
|
62
|
+
value: BigInt(2000000000),
|
|
63
|
+
asset: { type: "native" },
|
|
64
|
+
stake: {
|
|
65
|
+
uid: "stake_1",
|
|
66
|
+
address: "0x123",
|
|
67
|
+
delegate: "0xvalidator1",
|
|
68
|
+
state: "active",
|
|
69
|
+
asset: { type: "native" },
|
|
70
|
+
amount: BigInt(2000000000),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
23
73
|
});
|
|
24
74
|
});
|