@ledgerhq/coin-sui 0.16.0 → 0.16.1-nightly.0
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/.unimportedrc.json +2 -1
- package/CHANGELOG.md +9 -0
- package/lib/logic/estimateFees.d.ts +4 -1
- package/lib/logic/estimateFees.d.ts.map +1 -1
- package/lib/logic/estimateFees.js +2 -1
- package/lib/logic/estimateFees.js.map +1 -1
- package/lib/network/sdk.d.ts.map +1 -1
- package/lib/network/sdk.js +18 -13
- package/lib/network/sdk.js.map +1 -1
- package/lib/{bridge/bridge.integration.test.d.ts → test/bridge.dataset.d.ts} +1 -1
- package/lib/test/bridge.dataset.d.ts.map +1 -0
- package/lib/{bridge/bridge.integration.test.js → test/bridge.dataset.js} +2 -2
- package/lib/test/bridge.dataset.js.map +1 -0
- package/lib-es/logic/estimateFees.d.ts +4 -1
- package/lib-es/logic/estimateFees.d.ts.map +1 -1
- package/lib-es/logic/estimateFees.js +2 -1
- package/lib-es/logic/estimateFees.js.map +1 -1
- package/lib-es/network/sdk.d.ts.map +1 -1
- package/lib-es/network/sdk.js +18 -13
- package/lib-es/network/sdk.js.map +1 -1
- package/lib-es/{bridge/bridge.integration.test.d.ts → test/bridge.dataset.d.ts} +1 -1
- package/lib-es/test/bridge.dataset.d.ts.map +1 -0
- package/lib-es/{bridge/bridge.integration.test.js → test/bridge.dataset.js} +2 -2
- package/lib-es/test/bridge.dataset.js.map +1 -0
- package/package.json +5 -9
- package/src/api/index.integration.test.ts +44 -7
- package/src/logic/estimateFees.test.ts +22 -16
- package/src/logic/estimateFees.ts +6 -1
- package/src/network/sdk.test.ts +44 -4
- package/src/network/sdk.ts +21 -13
- package/src/{bridge/bridge.integration.test.ts → test/bridge.dataset.ts} +1 -1
- package/lib/api/index.integration.test.d.ts +0 -2
- package/lib/api/index.integration.test.d.ts.map +0 -1
- package/lib/api/index.integration.test.js +0 -173
- package/lib/api/index.integration.test.js.map +0 -1
- package/lib/api/index.test.d.ts +0 -2
- package/lib/api/index.test.d.ts.map +0 -1
- package/lib/api/index.test.js +0 -173
- package/lib/api/index.test.js.map +0 -1
- package/lib/bridge/bridge.integration.test.d.ts.map +0 -1
- package/lib/bridge/bridge.integration.test.js.map +0 -1
- package/lib/bridge/broadcast.test.d.ts +0 -2
- package/lib/bridge/broadcast.test.d.ts.map +0 -1
- package/lib/bridge/broadcast.test.js +0 -48
- package/lib/bridge/broadcast.test.js.map +0 -1
- package/lib/bridge/buildOptimisticOperation.test.d.ts +0 -2
- package/lib/bridge/buildOptimisticOperation.test.d.ts.map +0 -1
- package/lib/bridge/buildOptimisticOperation.test.js +0 -52
- package/lib/bridge/buildOptimisticOperation.test.js.map +0 -1
- package/lib/bridge/buildTransaction.integration.test.d.ts +0 -2
- package/lib/bridge/buildTransaction.integration.test.d.ts.map +0 -1
- package/lib/bridge/buildTransaction.integration.test.js +0 -72
- package/lib/bridge/buildTransaction.integration.test.js.map +0 -1
- package/lib/bridge/buildTransaction.test.d.ts +0 -2
- package/lib/bridge/buildTransaction.test.d.ts.map +0 -1
- package/lib/bridge/buildTransaction.test.js +0 -231
- package/lib/bridge/buildTransaction.test.js.map +0 -1
- package/lib/bridge/estimateMaxSpendable.test.d.ts +0 -2
- package/lib/bridge/estimateMaxSpendable.test.d.ts.map +0 -1
- package/lib/bridge/estimateMaxSpendable.test.js +0 -52
- package/lib/bridge/estimateMaxSpendable.test.js.map +0 -1
- package/lib/bridge/formatters.test.d.ts +0 -2
- package/lib/bridge/formatters.test.d.ts.map +0 -1
- package/lib/bridge/formatters.test.js +0 -18
- package/lib/bridge/formatters.test.js.map +0 -1
- package/lib/bridge/getFeesForTransaction.test.d.ts +0 -2
- package/lib/bridge/getFeesForTransaction.test.d.ts.map +0 -1
- package/lib/bridge/getFeesForTransaction.test.js +0 -35
- package/lib/bridge/getFeesForTransaction.test.js.map +0 -1
- package/lib/bridge/getTransactionStatus.test.d.ts +0 -2
- package/lib/bridge/getTransactionStatus.test.d.ts.map +0 -1
- package/lib/bridge/getTransactionStatus.test.js +0 -69
- package/lib/bridge/getTransactionStatus.test.js.map +0 -1
- package/lib/bridge/index.test.d.ts +0 -2
- package/lib/bridge/index.test.d.ts.map +0 -1
- package/lib/bridge/index.test.js +0 -265
- package/lib/bridge/index.test.js.map +0 -1
- package/lib/bridge/preload.test.d.ts +0 -2
- package/lib/bridge/preload.test.d.ts.map +0 -1
- package/lib/bridge/preload.test.js +0 -52
- package/lib/bridge/preload.test.js.map +0 -1
- package/lib/bridge/prepareTransaction.test.d.ts +0 -2
- package/lib/bridge/prepareTransaction.test.d.ts.map +0 -1
- package/lib/bridge/prepareTransaction.test.js +0 -97
- package/lib/bridge/prepareTransaction.test.js.map +0 -1
- package/lib/bridge/serialization.test.d.ts +0 -2
- package/lib/bridge/serialization.test.d.ts.map +0 -1
- package/lib/bridge/serialization.test.js +0 -131
- package/lib/bridge/serialization.test.js.map +0 -1
- package/lib/bridge/signOperation.integration.test.d.ts +0 -2
- package/lib/bridge/signOperation.integration.test.d.ts.map +0 -1
- package/lib/bridge/signOperation.integration.test.js +0 -80
- package/lib/bridge/signOperation.integration.test.js.map +0 -1
- package/lib/bridge/signOperation.test.d.ts +0 -2
- package/lib/bridge/signOperation.test.d.ts.map +0 -1
- package/lib/bridge/signOperation.test.js +0 -445
- package/lib/bridge/signOperation.test.js.map +0 -1
- package/lib/bridge/synchronisation.test.d.ts +0 -2
- package/lib/bridge/synchronisation.test.d.ts.map +0 -1
- package/lib/bridge/synchronisation.test.js +0 -505
- package/lib/bridge/synchronisation.test.js.map +0 -1
- package/lib/bridge/transaction.test.d.ts +0 -2
- package/lib/bridge/transaction.test.d.ts.map +0 -1
- package/lib/bridge/transaction.test.js +0 -68
- package/lib/bridge/transaction.test.js.map +0 -1
- package/lib/logic/broadcast.test.d.ts +0 -2
- package/lib/logic/broadcast.test.d.ts.map +0 -1
- package/lib/logic/broadcast.test.js +0 -62
- package/lib/logic/broadcast.test.js.map +0 -1
- package/lib/logic/combine.test.d.ts +0 -2
- package/lib/logic/combine.test.d.ts.map +0 -1
- package/lib/logic/combine.test.js +0 -37
- package/lib/logic/combine.test.js.map +0 -1
- package/lib/logic/craftTransaction.integration.test.d.ts +0 -2
- package/lib/logic/craftTransaction.integration.test.d.ts.map +0 -1
- package/lib/logic/craftTransaction.integration.test.js +0 -98
- package/lib/logic/craftTransaction.integration.test.js.map +0 -1
- package/lib/logic/craftTransaction.test.d.ts +0 -2
- package/lib/logic/craftTransaction.test.d.ts.map +0 -1
- package/lib/logic/craftTransaction.test.js +0 -127
- package/lib/logic/craftTransaction.test.js.map +0 -1
- package/lib/logic/estimateFees.integration.test.d.ts +0 -2
- package/lib/logic/estimateFees.integration.test.d.ts.map +0 -1
- package/lib/logic/estimateFees.integration.test.js +0 -82
- package/lib/logic/estimateFees.integration.test.js.map +0 -1
- package/lib/logic/estimateFees.test.d.ts +0 -2
- package/lib/logic/estimateFees.test.d.ts.map +0 -1
- package/lib/logic/estimateFees.test.js +0 -70
- package/lib/logic/estimateFees.test.js.map +0 -1
- package/lib/logic/getBalance.integration.test.d.ts +0 -2
- package/lib/logic/getBalance.integration.test.d.ts.map +0 -1
- package/lib/logic/getBalance.integration.test.js +0 -56
- package/lib/logic/getBalance.integration.test.js.map +0 -1
- package/lib/logic/getBalance.test.d.ts +0 -2
- package/lib/logic/getBalance.test.d.ts.map +0 -1
- package/lib/logic/getBalance.test.js +0 -64
- package/lib/logic/getBalance.test.js.map +0 -1
- package/lib/logic/lastBlock.test.d.ts +0 -2
- package/lib/logic/lastBlock.test.d.ts.map +0 -1
- package/lib/logic/lastBlock.test.js +0 -27
- package/lib/logic/lastBlock.test.js.map +0 -1
- package/lib/logic/listOperations.test.d.ts +0 -2
- package/lib/logic/listOperations.test.d.ts.map +0 -1
- package/lib/logic/listOperations.test.js +0 -79
- package/lib/logic/listOperations.test.js.map +0 -1
- package/lib/network/sdk.integration.test.d.ts +0 -2
- package/lib/network/sdk.integration.test.d.ts.map +0 -1
- package/lib/network/sdk.integration.test.js +0 -215
- package/lib/network/sdk.integration.test.js.map +0 -1
- package/lib/network/sdk.test.d.ts +0 -2
- package/lib/network/sdk.test.d.ts.map +0 -1
- package/lib/network/sdk.test.js +0 -1784
- package/lib/network/sdk.test.js.map +0 -1
- package/lib/signer/getAddress.test.d.ts +0 -2
- package/lib/signer/getAddress.test.d.ts.map +0 -1
- package/lib/signer/getAddress.test.js +0 -106
- package/lib/signer/getAddress.test.js.map +0 -1
- package/lib/test/config.test.d.ts +0 -2
- package/lib/test/config.test.d.ts.map +0 -1
- package/lib/test/config.test.js +0 -44
- package/lib/test/config.test.js.map +0 -1
- package/lib-es/api/index.integration.test.d.ts +0 -2
- package/lib-es/api/index.integration.test.d.ts.map +0 -1
- package/lib-es/api/index.integration.test.js +0 -171
- package/lib-es/api/index.integration.test.js.map +0 -1
- package/lib-es/api/index.test.d.ts +0 -2
- package/lib-es/api/index.test.d.ts.map +0 -1
- package/lib-es/api/index.test.js +0 -148
- package/lib-es/api/index.test.js.map +0 -1
- package/lib-es/bridge/bridge.integration.test.d.ts.map +0 -1
- package/lib-es/bridge/bridge.integration.test.js.map +0 -1
- package/lib-es/bridge/broadcast.test.d.ts +0 -2
- package/lib-es/bridge/broadcast.test.d.ts.map +0 -1
- package/lib-es/bridge/broadcast.test.js +0 -46
- package/lib-es/bridge/broadcast.test.js.map +0 -1
- package/lib-es/bridge/buildOptimisticOperation.test.d.ts +0 -2
- package/lib-es/bridge/buildOptimisticOperation.test.d.ts.map +0 -1
- package/lib-es/bridge/buildOptimisticOperation.test.js +0 -47
- package/lib-es/bridge/buildOptimisticOperation.test.js.map +0 -1
- package/lib-es/bridge/buildTransaction.integration.test.d.ts +0 -2
- package/lib-es/bridge/buildTransaction.integration.test.d.ts.map +0 -1
- package/lib-es/bridge/buildTransaction.integration.test.js +0 -67
- package/lib-es/bridge/buildTransaction.integration.test.js.map +0 -1
- package/lib-es/bridge/buildTransaction.test.d.ts +0 -2
- package/lib-es/bridge/buildTransaction.test.d.ts.map +0 -1
- package/lib-es/bridge/buildTransaction.test.js +0 -229
- package/lib-es/bridge/buildTransaction.test.js.map +0 -1
- package/lib-es/bridge/estimateMaxSpendable.test.d.ts +0 -2
- package/lib-es/bridge/estimateMaxSpendable.test.d.ts.map +0 -1
- package/lib-es/bridge/estimateMaxSpendable.test.js +0 -50
- package/lib-es/bridge/estimateMaxSpendable.test.js.map +0 -1
- package/lib-es/bridge/formatters.test.d.ts +0 -2
- package/lib-es/bridge/formatters.test.d.ts.map +0 -1
- package/lib-es/bridge/formatters.test.js +0 -16
- package/lib-es/bridge/formatters.test.js.map +0 -1
- package/lib-es/bridge/getFeesForTransaction.test.d.ts +0 -2
- package/lib-es/bridge/getFeesForTransaction.test.d.ts.map +0 -1
- package/lib-es/bridge/getFeesForTransaction.test.js +0 -30
- package/lib-es/bridge/getFeesForTransaction.test.js.map +0 -1
- package/lib-es/bridge/getTransactionStatus.test.d.ts +0 -2
- package/lib-es/bridge/getTransactionStatus.test.d.ts.map +0 -1
- package/lib-es/bridge/getTransactionStatus.test.js +0 -64
- package/lib-es/bridge/getTransactionStatus.test.js.map +0 -1
- package/lib-es/bridge/index.test.d.ts +0 -2
- package/lib-es/bridge/index.test.d.ts.map +0 -1
- package/lib-es/bridge/index.test.js +0 -260
- package/lib-es/bridge/index.test.js.map +0 -1
- package/lib-es/bridge/preload.test.d.ts +0 -2
- package/lib-es/bridge/preload.test.d.ts.map +0 -1
- package/lib-es/bridge/preload.test.js +0 -50
- package/lib-es/bridge/preload.test.js.map +0 -1
- package/lib-es/bridge/prepareTransaction.test.d.ts +0 -2
- package/lib-es/bridge/prepareTransaction.test.d.ts.map +0 -1
- package/lib-es/bridge/prepareTransaction.test.js +0 -92
- package/lib-es/bridge/prepareTransaction.test.js.map +0 -1
- package/lib-es/bridge/serialization.test.d.ts +0 -2
- package/lib-es/bridge/serialization.test.d.ts.map +0 -1
- package/lib-es/bridge/serialization.test.js +0 -126
- package/lib-es/bridge/serialization.test.js.map +0 -1
- package/lib-es/bridge/signOperation.integration.test.d.ts +0 -2
- package/lib-es/bridge/signOperation.integration.test.d.ts.map +0 -1
- package/lib-es/bridge/signOperation.integration.test.js +0 -75
- package/lib-es/bridge/signOperation.integration.test.js.map +0 -1
- package/lib-es/bridge/signOperation.test.d.ts +0 -2
- package/lib-es/bridge/signOperation.test.d.ts.map +0 -1
- package/lib-es/bridge/signOperation.test.js +0 -440
- package/lib-es/bridge/signOperation.test.js.map +0 -1
- package/lib-es/bridge/synchronisation.test.d.ts +0 -2
- package/lib-es/bridge/synchronisation.test.d.ts.map +0 -1
- package/lib-es/bridge/synchronisation.test.js +0 -477
- package/lib-es/bridge/synchronisation.test.js.map +0 -1
- package/lib-es/bridge/transaction.test.d.ts +0 -2
- package/lib-es/bridge/transaction.test.d.ts.map +0 -1
- package/lib-es/bridge/transaction.test.js +0 -66
- package/lib-es/bridge/transaction.test.js.map +0 -1
- package/lib-es/logic/broadcast.test.d.ts +0 -2
- package/lib-es/logic/broadcast.test.d.ts.map +0 -1
- package/lib-es/logic/broadcast.test.js +0 -57
- package/lib-es/logic/broadcast.test.js.map +0 -1
- package/lib-es/logic/combine.test.d.ts +0 -2
- package/lib-es/logic/combine.test.d.ts.map +0 -1
- package/lib-es/logic/combine.test.js +0 -35
- package/lib-es/logic/combine.test.js.map +0 -1
- package/lib-es/logic/craftTransaction.integration.test.d.ts +0 -2
- package/lib-es/logic/craftTransaction.integration.test.d.ts.map +0 -1
- package/lib-es/logic/craftTransaction.integration.test.js +0 -93
- package/lib-es/logic/craftTransaction.integration.test.js.map +0 -1
- package/lib-es/logic/craftTransaction.test.d.ts +0 -2
- package/lib-es/logic/craftTransaction.test.d.ts.map +0 -1
- package/lib-es/logic/craftTransaction.test.js +0 -122
- package/lib-es/logic/craftTransaction.test.js.map +0 -1
- package/lib-es/logic/estimateFees.integration.test.d.ts +0 -2
- package/lib-es/logic/estimateFees.integration.test.d.ts.map +0 -1
- package/lib-es/logic/estimateFees.integration.test.js +0 -77
- package/lib-es/logic/estimateFees.integration.test.js.map +0 -1
- package/lib-es/logic/estimateFees.test.d.ts +0 -2
- package/lib-es/logic/estimateFees.test.d.ts.map +0 -1
- package/lib-es/logic/estimateFees.test.js +0 -65
- package/lib-es/logic/estimateFees.test.js.map +0 -1
- package/lib-es/logic/getBalance.integration.test.d.ts +0 -2
- package/lib-es/logic/getBalance.integration.test.d.ts.map +0 -1
- package/lib-es/logic/getBalance.integration.test.js +0 -51
- package/lib-es/logic/getBalance.integration.test.js.map +0 -1
- package/lib-es/logic/getBalance.test.d.ts +0 -2
- package/lib-es/logic/getBalance.test.d.ts.map +0 -1
- package/lib-es/logic/getBalance.test.js +0 -62
- package/lib-es/logic/getBalance.test.js.map +0 -1
- package/lib-es/logic/lastBlock.test.d.ts +0 -2
- package/lib-es/logic/lastBlock.test.d.ts.map +0 -1
- package/lib-es/logic/lastBlock.test.js +0 -25
- package/lib-es/logic/lastBlock.test.js.map +0 -1
- package/lib-es/logic/listOperations.test.d.ts +0 -2
- package/lib-es/logic/listOperations.test.d.ts.map +0 -1
- package/lib-es/logic/listOperations.test.js +0 -77
- package/lib-es/logic/listOperations.test.js.map +0 -1
- package/lib-es/network/sdk.integration.test.d.ts +0 -2
- package/lib-es/network/sdk.integration.test.d.ts.map +0 -1
- package/lib-es/network/sdk.integration.test.js +0 -210
- package/lib-es/network/sdk.integration.test.js.map +0 -1
- package/lib-es/network/sdk.test.d.ts +0 -2
- package/lib-es/network/sdk.test.d.ts.map +0 -1
- package/lib-es/network/sdk.test.js +0 -1756
- package/lib-es/network/sdk.test.js.map +0 -1
- package/lib-es/signer/getAddress.test.d.ts +0 -2
- package/lib-es/signer/getAddress.test.d.ts.map +0 -1
- package/lib-es/signer/getAddress.test.js +0 -101
- package/lib-es/signer/getAddress.test.js.map +0 -1
- package/lib-es/test/config.test.d.ts +0 -2
- package/lib-es/test/config.test.d.ts.map +0 -1
- package/lib-es/test/config.test.js +0 -39
- package/lib-es/test/config.test.js.map +0 -1
|
@@ -1,1756 +0,0 @@
|
|
|
1
|
-
import * as sdk from "./sdk";
|
|
2
|
-
import coinConfig from "../config";
|
|
3
|
-
import { BigNumber } from "bignumber.js";
|
|
4
|
-
import { SuiClient } from "@mysten/sui/client";
|
|
5
|
-
import assert from "assert";
|
|
6
|
-
// Mock SUI client for tests
|
|
7
|
-
jest.mock("@mysten/sui/client", () => {
|
|
8
|
-
return {
|
|
9
|
-
...jest.requireActual("@mysten/sui/client"),
|
|
10
|
-
SuiClient: jest.fn().mockImplementation(() => ({
|
|
11
|
-
getAllBalances: jest.fn().mockResolvedValue([
|
|
12
|
-
{ coinType: "0x2::sui::SUI", totalBalance: "1000000000" },
|
|
13
|
-
{ coinType: "0x123::test::TOKEN", totalBalance: "500000" },
|
|
14
|
-
]),
|
|
15
|
-
queryTransactionBlocks: jest.fn().mockResolvedValue({
|
|
16
|
-
data: [],
|
|
17
|
-
hasNextPage: false,
|
|
18
|
-
}),
|
|
19
|
-
dryRunTransactionBlock: jest.fn().mockResolvedValue({
|
|
20
|
-
effects: {
|
|
21
|
-
gasUsed: {
|
|
22
|
-
computationCost: "1000000",
|
|
23
|
-
storageCost: "500000",
|
|
24
|
-
storageRebate: "450000",
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
input: {
|
|
28
|
-
gasData: {
|
|
29
|
-
budget: "4000000",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
}),
|
|
33
|
-
getCoins: jest.fn().mockResolvedValue({
|
|
34
|
-
data: [{ coinObjectId: "0xtest_coin_object_id" }],
|
|
35
|
-
}),
|
|
36
|
-
executeTransactionBlock: jest.fn().mockResolvedValue({
|
|
37
|
-
digest: "transaction_digest_123",
|
|
38
|
-
effects: {
|
|
39
|
-
status: { status: "success" },
|
|
40
|
-
},
|
|
41
|
-
}),
|
|
42
|
-
getReferenceGasPrice: jest.fn().mockResolvedValue("1000"),
|
|
43
|
-
getTransactionBlock: jest.fn().mockResolvedValue({
|
|
44
|
-
transaction: {
|
|
45
|
-
data: {
|
|
46
|
-
transaction: {
|
|
47
|
-
kind: "ProgrammableTransaction",
|
|
48
|
-
inputs: [],
|
|
49
|
-
transactions: [],
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
effects: {
|
|
54
|
-
status: { status: "success" },
|
|
55
|
-
},
|
|
56
|
-
}),
|
|
57
|
-
})),
|
|
58
|
-
getFullnodeUrl: jest.fn().mockReturnValue("https://mockapi.sui.io"),
|
|
59
|
-
};
|
|
60
|
-
});
|
|
61
|
-
// Mock the Transaction class
|
|
62
|
-
jest.mock("@mysten/sui/transactions", () => {
|
|
63
|
-
const mockTxb = {
|
|
64
|
-
// This will be the built transaction block
|
|
65
|
-
transactionBlock: new Uint8Array(),
|
|
66
|
-
};
|
|
67
|
-
return {
|
|
68
|
-
...jest.requireActual("@mysten/sui/transactions"),
|
|
69
|
-
Transaction: jest.fn().mockImplementation(() => {
|
|
70
|
-
return {
|
|
71
|
-
gas: "0xmock_gas_object_id",
|
|
72
|
-
setSender: jest.fn(),
|
|
73
|
-
splitCoins: jest.fn().mockReturnValue(["0xmock_coin"]),
|
|
74
|
-
transferObjects: jest.fn(),
|
|
75
|
-
moveCall: jest.fn(),
|
|
76
|
-
object: jest.fn(),
|
|
77
|
-
pure: {
|
|
78
|
-
address: jest.fn(),
|
|
79
|
-
u64: jest.fn(),
|
|
80
|
-
},
|
|
81
|
-
build: jest.fn().mockResolvedValue(mockTxb),
|
|
82
|
-
setGasBudgetIfNotSet: jest.fn(),
|
|
83
|
-
};
|
|
84
|
-
}),
|
|
85
|
-
};
|
|
86
|
-
});
|
|
87
|
-
const mockTransaction = {
|
|
88
|
-
digest: "DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt",
|
|
89
|
-
transaction: {
|
|
90
|
-
data: {
|
|
91
|
-
messageVersion: "v1",
|
|
92
|
-
transaction: {
|
|
93
|
-
kind: "ProgrammableTransaction",
|
|
94
|
-
inputs: [
|
|
95
|
-
{
|
|
96
|
-
type: "pure",
|
|
97
|
-
valueType: "address",
|
|
98
|
-
value: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
transactions: [
|
|
102
|
-
{
|
|
103
|
-
TransferObjects: [["GasCoin"], { Input: 0 }],
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
},
|
|
107
|
-
sender: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
|
|
108
|
-
gasData: {
|
|
109
|
-
payment: [
|
|
110
|
-
{
|
|
111
|
-
objectId: "0x9d49c70b621b618c7918468a7ac286e71cffe6e30c4e4175a4385516b121cb0e",
|
|
112
|
-
version: "57",
|
|
113
|
-
digest: "2rPEonJQQUXmAmAegn3fVqBjpKrC5NadAZBetb5wJQm6",
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
owner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
|
|
117
|
-
price: "1000",
|
|
118
|
-
budget: "2988000",
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
txSignatures: [
|
|
122
|
-
"AJKFd5y+1y/ggTAKTZlrrQlvSWXoYCSU7ksxyBG6BI9FDjN/R8db5PNbw19Bs+Lp4VE0cu9BBzAc/gYDFwgYrQVgR+QnZSFg3qWm+IjLX2dEep/wlLje2lziXO+HmZApcQ==",
|
|
123
|
-
],
|
|
124
|
-
},
|
|
125
|
-
effects: {
|
|
126
|
-
messageVersion: "v1",
|
|
127
|
-
status: { status: "success" },
|
|
128
|
-
executedEpoch: "18",
|
|
129
|
-
gasUsed: {
|
|
130
|
-
computationCost: "1000000",
|
|
131
|
-
storageCost: "988000",
|
|
132
|
-
storageRebate: "978120",
|
|
133
|
-
nonRefundableStorageFee: "9880",
|
|
134
|
-
},
|
|
135
|
-
modifiedAtVersions: [
|
|
136
|
-
{
|
|
137
|
-
objectId: "0x9d49c70b621b618c7918468a7ac286e71cffe6e30c4e4175a4385516b121cb0e",
|
|
138
|
-
sequenceNumber: "57",
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
|
-
transactionDigest: "DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt",
|
|
142
|
-
mutated: [
|
|
143
|
-
{
|
|
144
|
-
owner: {
|
|
145
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
146
|
-
},
|
|
147
|
-
reference: {
|
|
148
|
-
objectId: "0x9d49c70b621b618c7918468a7ac286e71cffe6e30c4e4175a4385516b121cb0e",
|
|
149
|
-
version: "58",
|
|
150
|
-
digest: "82pvkMbymnBFQjhuDDaaW88BeATbNgWWcWH67DcLaPBi",
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
],
|
|
154
|
-
gasObject: {
|
|
155
|
-
owner: { AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0" },
|
|
156
|
-
reference: {
|
|
157
|
-
objectId: "0x9d49c70b621b618c7918468a7ac286e71cffe6e30c4e4175a4385516b121cb0e",
|
|
158
|
-
version: "58",
|
|
159
|
-
digest: "82pvkMbymnBFQjhuDDaaW88BeATbNgWWcWH67DcLaPBi",
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
dependencies: ["D8tHbu9JwGuoaH67PFXCoswqDUy2M4S6KVLWhCodt1a7"],
|
|
163
|
-
},
|
|
164
|
-
balanceChanges: [
|
|
165
|
-
{
|
|
166
|
-
owner: { AddressOwner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24" },
|
|
167
|
-
coinType: "0x2::sui::SUI",
|
|
168
|
-
amount: "-10000000000",
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
owner: { AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0" },
|
|
172
|
-
coinType: "0x2::sui::SUI",
|
|
173
|
-
amount: "9998990120",
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
owner: { AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0" },
|
|
177
|
-
coinType: "0x123::test::TOKEN",
|
|
178
|
-
amount: "500000",
|
|
179
|
-
},
|
|
180
|
-
],
|
|
181
|
-
timestampMs: "1742294454878",
|
|
182
|
-
checkpoint: "313024",
|
|
183
|
-
};
|
|
184
|
-
// Create a mock staking transaction
|
|
185
|
-
// amount must be a negative number
|
|
186
|
-
function mockStakingTx(address, amount) {
|
|
187
|
-
assert(new BigNumber(amount).lte(0), "amount must be a negative number");
|
|
188
|
-
return {
|
|
189
|
-
digest: "delegate_tx_digest_123",
|
|
190
|
-
transaction: {
|
|
191
|
-
data: {
|
|
192
|
-
sender: address,
|
|
193
|
-
transaction: {
|
|
194
|
-
kind: "ProgrammableTransaction",
|
|
195
|
-
inputs: [],
|
|
196
|
-
transactions: [
|
|
197
|
-
{
|
|
198
|
-
MoveCall: {
|
|
199
|
-
function: "request_add_stake",
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
],
|
|
203
|
-
},
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
effects: {
|
|
207
|
-
status: { status: "success" },
|
|
208
|
-
gasUsed: {
|
|
209
|
-
computationCost: "1000000",
|
|
210
|
-
storageCost: "500000",
|
|
211
|
-
storageRebate: "450000",
|
|
212
|
-
},
|
|
213
|
-
},
|
|
214
|
-
balanceChanges: [
|
|
215
|
-
{
|
|
216
|
-
owner: { AddressOwner: address },
|
|
217
|
-
coinType: "0x2::sui::SUI",
|
|
218
|
-
amount: amount.startsWith("-") ? amount : `-${amount}`,
|
|
219
|
-
},
|
|
220
|
-
],
|
|
221
|
-
timestampMs: "1742294454878",
|
|
222
|
-
checkpoint: "313024",
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
// amount must be a positive number
|
|
226
|
-
function mockUnstakingTx(address, amount) {
|
|
227
|
-
assert(new BigNumber(amount).gte(0), "amount must be a positive number");
|
|
228
|
-
return {
|
|
229
|
-
digest: "undelegate_tx_digest_456",
|
|
230
|
-
transaction: {
|
|
231
|
-
data: {
|
|
232
|
-
sender: address,
|
|
233
|
-
transaction: {
|
|
234
|
-
kind: "ProgrammableTransaction",
|
|
235
|
-
inputs: [],
|
|
236
|
-
transactions: [
|
|
237
|
-
{
|
|
238
|
-
MoveCall: {
|
|
239
|
-
function: "request_withdraw_stake",
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
],
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
effects: {
|
|
247
|
-
status: { status: "success" },
|
|
248
|
-
gasUsed: {
|
|
249
|
-
computationCost: "1000000",
|
|
250
|
-
storageCost: "500000",
|
|
251
|
-
storageRebate: "450000",
|
|
252
|
-
},
|
|
253
|
-
},
|
|
254
|
-
balanceChanges: [
|
|
255
|
-
{
|
|
256
|
-
owner: { AddressOwner: address },
|
|
257
|
-
coinType: "0x2::sui::SUI",
|
|
258
|
-
amount: amount,
|
|
259
|
-
},
|
|
260
|
-
],
|
|
261
|
-
timestampMs: "1742294454878",
|
|
262
|
-
checkpoint: "313024",
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
const mockApi = new SuiClient({ url: "mock" });
|
|
266
|
-
// Add getTransactionBlock method to mockApi
|
|
267
|
-
mockApi.getTransactionBlock = jest.fn();
|
|
268
|
-
// Helper function to generate mock coins from an array of balances
|
|
269
|
-
const createMockCoins = (balances) => {
|
|
270
|
-
return balances.map((balance, index) => ({
|
|
271
|
-
coinObjectId: `0xcoin${index + 1}`,
|
|
272
|
-
balance,
|
|
273
|
-
digest: `0xdigest${index + 1}`,
|
|
274
|
-
version: "1",
|
|
275
|
-
}));
|
|
276
|
-
};
|
|
277
|
-
beforeAll(() => {
|
|
278
|
-
coinConfig.setCoinConfig(() => ({
|
|
279
|
-
status: {
|
|
280
|
-
type: "active",
|
|
281
|
-
},
|
|
282
|
-
node: {
|
|
283
|
-
url: "https://mockapi.sui.io",
|
|
284
|
-
},
|
|
285
|
-
}));
|
|
286
|
-
});
|
|
287
|
-
beforeEach(() => {
|
|
288
|
-
mockApi.queryTransactionBlocks.mockReset();
|
|
289
|
-
});
|
|
290
|
-
describe("SDK Functions", () => {
|
|
291
|
-
test("getAccountBalances should return array of account balances", async () => {
|
|
292
|
-
// Patch getAllBalancesCached to return a valid array for this test
|
|
293
|
-
jest.spyOn(sdk, "getAllBalancesCached").mockResolvedValue([
|
|
294
|
-
{
|
|
295
|
-
coinType: "0x2::sui::SUI",
|
|
296
|
-
totalBalance: "1000000000",
|
|
297
|
-
coinObjectCount: 1,
|
|
298
|
-
lockedBalance: {},
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
coinType: "0x123::test::TOKEN",
|
|
302
|
-
totalBalance: "500000",
|
|
303
|
-
coinObjectCount: 1,
|
|
304
|
-
lockedBalance: {},
|
|
305
|
-
},
|
|
306
|
-
]);
|
|
307
|
-
const address = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
308
|
-
const balances = await sdk.getAccountBalances(address);
|
|
309
|
-
expect(Array.isArray(balances)).toBe(true);
|
|
310
|
-
expect(balances.length).toBeGreaterThan(0);
|
|
311
|
-
// Check structure of the first balance
|
|
312
|
-
const firstBalance = balances[0];
|
|
313
|
-
expect(firstBalance).toHaveProperty("coinType");
|
|
314
|
-
expect(firstBalance).toHaveProperty("blockHeight");
|
|
315
|
-
expect(firstBalance).toHaveProperty("balance");
|
|
316
|
-
expect(firstBalance.balance).toBeInstanceOf(BigNumber);
|
|
317
|
-
// Should include SUI and token balances
|
|
318
|
-
const coinTypes = balances.map(b => b.coinType);
|
|
319
|
-
expect(coinTypes).toContain(sdk.DEFAULT_COIN_TYPE);
|
|
320
|
-
});
|
|
321
|
-
test("getOperationType should return IN for incoming tx", () => {
|
|
322
|
-
const address = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
323
|
-
expect(sdk.getOperationType(address, mockTransaction)).toBe("IN");
|
|
324
|
-
});
|
|
325
|
-
test("getOperationType should return OUT for outgoing tx", () => {
|
|
326
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
327
|
-
expect(sdk.getOperationType(address, mockTransaction)).toBe("OUT");
|
|
328
|
-
});
|
|
329
|
-
test("getOperationSenders should return sender address", () => {
|
|
330
|
-
expect(sdk.getOperationSenders(mockTransaction.transaction?.data)).toEqual(["0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24"]);
|
|
331
|
-
});
|
|
332
|
-
test("getOperationRecipients should return recipient addresses", () => {
|
|
333
|
-
expect(sdk.getOperationRecipients(mockTransaction.transaction?.data)).toEqual(["0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0"]);
|
|
334
|
-
});
|
|
335
|
-
test("getOperationFee should calculate fee correctly", () => {
|
|
336
|
-
expect(sdk.getOperationFee(mockTransaction)).toEqual(new BigNumber(1009880));
|
|
337
|
-
});
|
|
338
|
-
test("getOperationDate should return correct date", () => {
|
|
339
|
-
const date = sdk.getOperationDate(mockTransaction);
|
|
340
|
-
expect(date).toBeDefined();
|
|
341
|
-
expect(date).toBeInstanceOf(Date);
|
|
342
|
-
});
|
|
343
|
-
test("getOperationCoinType should extract token coin type", () => {
|
|
344
|
-
// For a token transaction
|
|
345
|
-
const tokenTx = {
|
|
346
|
-
...mockTransaction,
|
|
347
|
-
balanceChanges: [
|
|
348
|
-
{
|
|
349
|
-
owner: {
|
|
350
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
351
|
-
},
|
|
352
|
-
coinType: "0x123::test::TOKEN",
|
|
353
|
-
amount: "500000",
|
|
354
|
-
},
|
|
355
|
-
{
|
|
356
|
-
owner: {
|
|
357
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
358
|
-
},
|
|
359
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
360
|
-
amount: "-1009880",
|
|
361
|
-
},
|
|
362
|
-
],
|
|
363
|
-
};
|
|
364
|
-
expect(sdk.getOperationCoinType(tokenTx)).toBe("0x123::test::TOKEN");
|
|
365
|
-
// For a SUI-only transaction
|
|
366
|
-
const suiTx = {
|
|
367
|
-
...mockTransaction,
|
|
368
|
-
balanceChanges: [
|
|
369
|
-
{
|
|
370
|
-
owner: {
|
|
371
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
372
|
-
},
|
|
373
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
374
|
-
amount: "9998990120",
|
|
375
|
-
},
|
|
376
|
-
],
|
|
377
|
-
};
|
|
378
|
-
expect(sdk.getOperationCoinType(suiTx)).toBe(sdk.DEFAULT_COIN_TYPE);
|
|
379
|
-
});
|
|
380
|
-
test("transactionToOperation should map transaction to operation", () => {
|
|
381
|
-
const accountId = "mockAccountId";
|
|
382
|
-
const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
|
|
383
|
-
// Create a SUI-only transaction for this test to avoid token detection
|
|
384
|
-
const suiTx = {
|
|
385
|
-
...mockTransaction,
|
|
386
|
-
balanceChanges: [
|
|
387
|
-
{
|
|
388
|
-
owner: {
|
|
389
|
-
AddressOwner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
|
|
390
|
-
},
|
|
391
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
392
|
-
amount: "-10000000000",
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
owner: {
|
|
396
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
397
|
-
},
|
|
398
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
399
|
-
amount: "9998990120",
|
|
400
|
-
},
|
|
401
|
-
],
|
|
402
|
-
};
|
|
403
|
-
// Instead of mocking, just directly verify the amount
|
|
404
|
-
const operation = sdk.transactionToOperation(accountId, address, suiTx);
|
|
405
|
-
expect(operation).toHaveProperty("id");
|
|
406
|
-
expect(operation).toHaveProperty("accountId", accountId);
|
|
407
|
-
expect(operation).toHaveProperty("extra");
|
|
408
|
-
expect(operation.extra.coinType).toBe(sdk.DEFAULT_COIN_TYPE);
|
|
409
|
-
// Directly calculate expected amount for SUI coin type
|
|
410
|
-
const expectedAmount = sdk.getOperationAmount(address, suiTx, sdk.DEFAULT_COIN_TYPE);
|
|
411
|
-
expect(expectedAmount.toString()).toBe("9998990120");
|
|
412
|
-
});
|
|
413
|
-
test("transactionToOperation should map token transaction to operation", () => {
|
|
414
|
-
const accountId = "mockAccountId";
|
|
415
|
-
const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
|
|
416
|
-
// Create a token transaction
|
|
417
|
-
const tokenTx = {
|
|
418
|
-
...mockTransaction,
|
|
419
|
-
balanceChanges: [
|
|
420
|
-
{
|
|
421
|
-
owner: {
|
|
422
|
-
AddressOwner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
|
|
423
|
-
},
|
|
424
|
-
coinType: "0x123::test::TOKEN",
|
|
425
|
-
amount: "-500000",
|
|
426
|
-
},
|
|
427
|
-
{
|
|
428
|
-
owner: {
|
|
429
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
430
|
-
},
|
|
431
|
-
coinType: "0x123::test::TOKEN",
|
|
432
|
-
amount: "500000",
|
|
433
|
-
},
|
|
434
|
-
{
|
|
435
|
-
owner: {
|
|
436
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
437
|
-
},
|
|
438
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
439
|
-
amount: "-1000000",
|
|
440
|
-
},
|
|
441
|
-
],
|
|
442
|
-
};
|
|
443
|
-
const operation = sdk.transactionToOperation(accountId, address, tokenTx);
|
|
444
|
-
expect(operation).toHaveProperty("id");
|
|
445
|
-
expect(operation).toHaveProperty("accountId", accountId);
|
|
446
|
-
expect(operation).toHaveProperty("extra");
|
|
447
|
-
expect(operation.extra.coinType).toBe("0x123::test::TOKEN");
|
|
448
|
-
expect(operation.value).toEqual(new BigNumber("500000"));
|
|
449
|
-
});
|
|
450
|
-
test("transactionToOp should map token transaction to operation", () => {
|
|
451
|
-
const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
|
|
452
|
-
// Create a token transaction
|
|
453
|
-
const tokenTx = {
|
|
454
|
-
...mockTransaction,
|
|
455
|
-
balanceChanges: [
|
|
456
|
-
{
|
|
457
|
-
owner: {
|
|
458
|
-
AddressOwner: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
|
|
459
|
-
},
|
|
460
|
-
coinType: "0x123::test::TOKEN",
|
|
461
|
-
amount: "-500000",
|
|
462
|
-
},
|
|
463
|
-
{
|
|
464
|
-
owner: {
|
|
465
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
466
|
-
},
|
|
467
|
-
coinType: "0x123::test::TOKEN",
|
|
468
|
-
amount: "500000",
|
|
469
|
-
},
|
|
470
|
-
{
|
|
471
|
-
owner: {
|
|
472
|
-
AddressOwner: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
473
|
-
},
|
|
474
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
475
|
-
amount: "-1000000",
|
|
476
|
-
},
|
|
477
|
-
],
|
|
478
|
-
};
|
|
479
|
-
const operation = sdk.alpacaTransactionToOp(address, tokenTx);
|
|
480
|
-
expect(operation.id).toEqual("DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt");
|
|
481
|
-
expect(operation.type).toEqual("IN");
|
|
482
|
-
expect(operation.senders).toEqual([
|
|
483
|
-
"0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
|
|
484
|
-
]);
|
|
485
|
-
expect(operation.recipients).toEqual([
|
|
486
|
-
"0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
487
|
-
]);
|
|
488
|
-
expect(operation.value).toEqual(500000n);
|
|
489
|
-
expect(operation.asset).toEqual({ type: "token", assetReference: "0x123::test::TOKEN" });
|
|
490
|
-
expect(operation.memo).toBeUndefined();
|
|
491
|
-
expect(operation.details).toBeUndefined();
|
|
492
|
-
expect(operation.tx.block.hash).toBeUndefined();
|
|
493
|
-
expect(operation.tx).toMatchObject({
|
|
494
|
-
hash: "DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt",
|
|
495
|
-
block: {},
|
|
496
|
-
fees: 1009880n,
|
|
497
|
-
date: new Date("2025-03-18T10:40:54.878Z"),
|
|
498
|
-
});
|
|
499
|
-
});
|
|
500
|
-
test("getOperations should fetch operations", async () => {
|
|
501
|
-
const accountId = "mockAccountId";
|
|
502
|
-
const addr = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
503
|
-
const operations = await sdk.getOperations(accountId, addr);
|
|
504
|
-
expect(Array.isArray(operations)).toBe(true);
|
|
505
|
-
});
|
|
506
|
-
test("paymentInfo should return gas budget and fees", async () => {
|
|
507
|
-
const sender = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
|
|
508
|
-
const fakeTransaction = {
|
|
509
|
-
mode: "send",
|
|
510
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
511
|
-
family: "sui",
|
|
512
|
-
amount: new BigNumber(100),
|
|
513
|
-
recipient: "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164",
|
|
514
|
-
errors: {},
|
|
515
|
-
};
|
|
516
|
-
const info = await sdk.paymentInfo(sender, fakeTransaction);
|
|
517
|
-
expect(info).toHaveProperty("gasBudget");
|
|
518
|
-
expect(info).toHaveProperty("totalGasUsed");
|
|
519
|
-
expect(info).toHaveProperty("fees");
|
|
520
|
-
});
|
|
521
|
-
test("createTransaction should build a transaction", async () => {
|
|
522
|
-
const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
|
|
523
|
-
const transaction = {
|
|
524
|
-
mode: "send",
|
|
525
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
526
|
-
amount: new BigNumber(100),
|
|
527
|
-
recipient: "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164",
|
|
528
|
-
};
|
|
529
|
-
const tx = await sdk.createTransaction(address, transaction);
|
|
530
|
-
expect(tx).toBeDefined();
|
|
531
|
-
});
|
|
532
|
-
test("executeTransactionBlock should execute a transaction", async () => {
|
|
533
|
-
const result = await sdk.executeTransactionBlock({
|
|
534
|
-
transactionBlock: new Uint8Array(),
|
|
535
|
-
signature: "mockSignature",
|
|
536
|
-
options: { showEffects: true },
|
|
537
|
-
});
|
|
538
|
-
expect(result).toHaveProperty("digest", "transaction_digest_123");
|
|
539
|
-
expect(result?.effects).toBeDefined();
|
|
540
|
-
if (result?.effects) {
|
|
541
|
-
expect(result.effects).toHaveProperty("status");
|
|
542
|
-
expect(result.effects.status).toHaveProperty("status", "success");
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
});
|
|
546
|
-
describe("Staking Operations", () => {
|
|
547
|
-
describe("Operation Type Detection", () => {
|
|
548
|
-
test("getOperationType should return DELEGATE for staking transaction", () => {
|
|
549
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
550
|
-
expect(sdk.getOperationType(address, mockStakingTx(address, "-1000000000"))).toBe("DELEGATE");
|
|
551
|
-
});
|
|
552
|
-
test("getOperationType should return UNDELEGATE for unstaking transaction", () => {
|
|
553
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
554
|
-
expect(sdk.getOperationType(address, mockUnstakingTx(address, "1000000000"))).toBe("UNDELEGATE");
|
|
555
|
-
});
|
|
556
|
-
});
|
|
557
|
-
describe("Operation Amount Calculation", () => {
|
|
558
|
-
const address = "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0";
|
|
559
|
-
function bridgeOperationAmount(mock, coinType = sdk.DEFAULT_COIN_TYPE) {
|
|
560
|
-
return sdk.getOperationAmount(address, mock, coinType);
|
|
561
|
-
}
|
|
562
|
-
test("getOperationAmount should calculate staking amount", () => expect(bridgeOperationAmount(mockStakingTx(address, "-1000000000"))).toEqual(new BigNumber("1000000000")));
|
|
563
|
-
test("getOperationAmount should calculate unstaking amount of 1000", () => expect(bridgeOperationAmount(mockUnstakingTx(address, "1000"))).toEqual(new BigNumber("-1000")));
|
|
564
|
-
test("getOperationAmount should calculate unstaking amount of 0", () => expect(bridgeOperationAmount(mockUnstakingTx(address, "0"))).toEqual(new BigNumber("0")));
|
|
565
|
-
test("getOperationAmount should calculate amount correctly for SUI", () => expect(bridgeOperationAmount(mockTransaction)).toEqual(new BigNumber("9998990120")));
|
|
566
|
-
test("getOperationAmount should calculate amount correctly for tokens", () => expect(bridgeOperationAmount(mockTransaction, "0x123::test::TOKEN")).toEqual(new BigNumber("500000")));
|
|
567
|
-
function alpacaOperationAmount(mock, coinType = sdk.DEFAULT_COIN_TYPE) {
|
|
568
|
-
return sdk.alpacaGetOperationAmount(address, mock, coinType);
|
|
569
|
-
}
|
|
570
|
-
test("alpaca getOperationAmount should calculate staking amount", () => expect(alpacaOperationAmount(mockStakingTx(address, "-1000000000"))).toEqual(new BigNumber("1000000000")));
|
|
571
|
-
test("alpaca getOperationAmount should calculate unstaking amount of 1000", () => expect(alpacaOperationAmount(mockUnstakingTx(address, "1000"))).toEqual(new BigNumber("1000")));
|
|
572
|
-
test("alpaca getOperationAmount should calculate unstaking amount of 0", () => expect(alpacaOperationAmount(mockUnstakingTx(address, "0"))).toEqual(new BigNumber("0")));
|
|
573
|
-
test("alpaca getOperationAmount should calculate amount correctly for SUI", () => expect(alpacaOperationAmount(mockTransaction)).toEqual(new BigNumber("9998990120")));
|
|
574
|
-
test("alpaca getOperationAmount should calculate amount correctly for tokens", () => expect(alpacaOperationAmount(mockTransaction, "0x123::test::TOKEN")).toEqual(new BigNumber("500000")));
|
|
575
|
-
});
|
|
576
|
-
describe("Operation Recipients", () => {
|
|
577
|
-
test("getOperationRecipients should return empty array for staking transaction", () => {
|
|
578
|
-
const recipients = sdk.getOperationRecipients(mockStakingTx("0xdeadbeef", "-1000000000").transaction?.data);
|
|
579
|
-
expect(recipients).toEqual([]);
|
|
580
|
-
});
|
|
581
|
-
test("getOperationRecipients should return empty array for unstaking transaction", () => {
|
|
582
|
-
const recipients = sdk.getOperationRecipients(mockUnstakingTx("0xdeadbeef", "1000000000").transaction?.data);
|
|
583
|
-
expect(recipients).toEqual([]);
|
|
584
|
-
});
|
|
585
|
-
});
|
|
586
|
-
describe("Transaction Creation", () => {
|
|
587
|
-
test("createTransaction should build delegate transaction", async () => {
|
|
588
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
589
|
-
const transaction = {
|
|
590
|
-
mode: "delegate",
|
|
591
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
592
|
-
amount: new BigNumber(1000000000), // 1 SUI
|
|
593
|
-
recipient: "0xvalidator_address_123",
|
|
594
|
-
};
|
|
595
|
-
const tx = await sdk.createTransaction(address, transaction);
|
|
596
|
-
expect(tx).toBeDefined();
|
|
597
|
-
});
|
|
598
|
-
test("createTransaction should build undelegate transaction with specific amount", async () => {
|
|
599
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
600
|
-
const transaction = {
|
|
601
|
-
mode: "undelegate",
|
|
602
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
603
|
-
amount: new BigNumber(500000000), // 0.5 SUI
|
|
604
|
-
stakedSuiId: "0xstaked_sui_object_123",
|
|
605
|
-
useAllAmount: false,
|
|
606
|
-
recipient: "0xvalidator_address_123", // Required by type but not used for undelegate
|
|
607
|
-
};
|
|
608
|
-
const tx = await sdk.createTransaction(address, transaction);
|
|
609
|
-
expect(tx).toBeDefined();
|
|
610
|
-
});
|
|
611
|
-
test("createTransaction should build undelegate transaction with all amount", async () => {
|
|
612
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
613
|
-
const transaction = {
|
|
614
|
-
mode: "undelegate",
|
|
615
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
616
|
-
amount: new BigNumber(0),
|
|
617
|
-
stakedSuiId: "0xstaked_sui_object_123",
|
|
618
|
-
useAllAmount: true,
|
|
619
|
-
recipient: "0xvalidator_address_123", // Required by type but not used for undelegate
|
|
620
|
-
};
|
|
621
|
-
const tx = await sdk.createTransaction(address, transaction);
|
|
622
|
-
expect(tx).toBeDefined();
|
|
623
|
-
});
|
|
624
|
-
});
|
|
625
|
-
describe("Payment Info for Staking", () => {
|
|
626
|
-
test("paymentInfo should return gas budget and fees for delegate transaction", async () => {
|
|
627
|
-
const sender = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
628
|
-
const fakeTransaction = {
|
|
629
|
-
mode: "delegate",
|
|
630
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
631
|
-
family: "sui",
|
|
632
|
-
amount: new BigNumber(1000000000), // 1 SUI
|
|
633
|
-
recipient: "0xvalidator_address_123",
|
|
634
|
-
errors: {},
|
|
635
|
-
};
|
|
636
|
-
const info = await sdk.paymentInfo(sender, fakeTransaction);
|
|
637
|
-
expect(info).toHaveProperty("gasBudget");
|
|
638
|
-
expect(info).toHaveProperty("totalGasUsed");
|
|
639
|
-
expect(info).toHaveProperty("fees");
|
|
640
|
-
});
|
|
641
|
-
test("paymentInfo should return gas budget and fees for undelegate transaction", async () => {
|
|
642
|
-
const sender = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
643
|
-
const fakeTransaction = {
|
|
644
|
-
mode: "undelegate",
|
|
645
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
646
|
-
family: "sui",
|
|
647
|
-
amount: new BigNumber(500000000), // 0.5 SUI
|
|
648
|
-
stakedSuiId: "0xstaked_sui_object_123",
|
|
649
|
-
useAllAmount: false,
|
|
650
|
-
recipient: "0xvalidator_address_123", // Required by type but not used for undelegate
|
|
651
|
-
errors: {},
|
|
652
|
-
};
|
|
653
|
-
const info = await sdk.paymentInfo(sender, fakeTransaction);
|
|
654
|
-
expect(info).toHaveProperty("gasBudget");
|
|
655
|
-
expect(info).toHaveProperty("totalGasUsed");
|
|
656
|
-
expect(info).toHaveProperty("fees");
|
|
657
|
-
});
|
|
658
|
-
});
|
|
659
|
-
describe("Transaction to Operation Mapping", () => {
|
|
660
|
-
test("transactionToOperation should map staking transaction correctly", () => {
|
|
661
|
-
const accountId = "mockAccountId";
|
|
662
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
663
|
-
const operation = sdk.transactionToOperation(accountId, address, mockStakingTx(address, "-1000000000"));
|
|
664
|
-
expect(operation).toHaveProperty("id");
|
|
665
|
-
expect(operation).toHaveProperty("accountId", accountId);
|
|
666
|
-
expect(operation).toHaveProperty("type", "DELEGATE");
|
|
667
|
-
expect(operation).toHaveProperty("hash", "delegate_tx_digest_123");
|
|
668
|
-
expect(operation).toHaveProperty("extra");
|
|
669
|
-
expect(operation.extra.coinType).toBe(sdk.DEFAULT_COIN_TYPE);
|
|
670
|
-
expect(operation.value).toEqual(new BigNumber("1000000000")); // The function returns minus of the balance change
|
|
671
|
-
expect(operation.recipients).toEqual([]);
|
|
672
|
-
expect(operation.senders).toEqual([address]);
|
|
673
|
-
});
|
|
674
|
-
test("transactionToOperation should map unstaking transaction correctly", () => {
|
|
675
|
-
const accountId = "mockAccountId";
|
|
676
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
677
|
-
const operation = sdk.transactionToOperation(accountId, address, mockUnstakingTx(address, "1000000000"));
|
|
678
|
-
expect(operation).toHaveProperty("id");
|
|
679
|
-
expect(operation).toHaveProperty("accountId", accountId);
|
|
680
|
-
expect(operation).toHaveProperty("type", "UNDELEGATE");
|
|
681
|
-
expect(operation).toHaveProperty("hash", "undelegate_tx_digest_456");
|
|
682
|
-
expect(operation).toHaveProperty("extra");
|
|
683
|
-
expect(operation.extra.coinType).toBe(sdk.DEFAULT_COIN_TYPE);
|
|
684
|
-
expect(operation.value).toEqual(new BigNumber("-1000000000"));
|
|
685
|
-
expect(operation.recipients).toEqual([]);
|
|
686
|
-
expect(operation.senders).toEqual([address]);
|
|
687
|
-
});
|
|
688
|
-
test("transactionToOp should map staking transaction correctly", () => {
|
|
689
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
690
|
-
const operation = sdk.alpacaTransactionToOp(address, mockStakingTx(address, "-1000000000"));
|
|
691
|
-
expect(operation.id).toEqual("delegate_tx_digest_123");
|
|
692
|
-
expect(operation.type).toEqual("DELEGATE");
|
|
693
|
-
expect(operation.senders).toEqual([address]);
|
|
694
|
-
expect(operation.recipients).toEqual([]);
|
|
695
|
-
expect(operation.value).toEqual(1000000000n); // The function returns minus of the balance change
|
|
696
|
-
expect(operation.asset).toEqual({ type: "native" });
|
|
697
|
-
expect(operation.tx.block.hash).toBeUndefined();
|
|
698
|
-
});
|
|
699
|
-
test("transactionToOp should map unstaking transaction correctly", () => {
|
|
700
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
701
|
-
const operation = sdk.alpacaTransactionToOp(address, mockUnstakingTx(address, "1000000000"));
|
|
702
|
-
expect(operation.id).toEqual("undelegate_tx_digest_456");
|
|
703
|
-
expect(operation.type).toEqual("UNDELEGATE");
|
|
704
|
-
expect(operation.senders).toEqual([address]);
|
|
705
|
-
expect(operation.recipients).toEqual([]);
|
|
706
|
-
expect(operation.value).toEqual(1000000000n);
|
|
707
|
-
expect(operation.asset).toEqual({ type: "native" });
|
|
708
|
-
expect(operation.tx.block.hash).toBeUndefined();
|
|
709
|
-
});
|
|
710
|
-
});
|
|
711
|
-
describe("Operation Extra Information", () => {
|
|
712
|
-
test("getOperationExtra should be a function", () => {
|
|
713
|
-
expect(typeof sdk.getOperationExtra).toBe("function");
|
|
714
|
-
});
|
|
715
|
-
test("getOperationExtra should return a Promise", () => {
|
|
716
|
-
const result = sdk.getOperationExtra("test_digest");
|
|
717
|
-
expect(result).toBeInstanceOf(Promise);
|
|
718
|
-
});
|
|
719
|
-
});
|
|
720
|
-
});
|
|
721
|
-
describe("queryTransactions", () => {
|
|
722
|
-
it("should call api.queryTransactionBlocks with correct params for IN", async () => {
|
|
723
|
-
mockApi.queryTransactionBlocks.mockResolvedValueOnce({
|
|
724
|
-
data: [{ digest: "tx1" }],
|
|
725
|
-
hasNextPage: false,
|
|
726
|
-
});
|
|
727
|
-
const result = await sdk.queryTransactions({
|
|
728
|
-
api: mockApi,
|
|
729
|
-
addr: "0xabc",
|
|
730
|
-
type: "IN",
|
|
731
|
-
order: "ascending",
|
|
732
|
-
});
|
|
733
|
-
expect(mockApi.queryTransactionBlocks).toHaveBeenCalledWith(expect.objectContaining({
|
|
734
|
-
filter: { ToAddress: "0xabc" },
|
|
735
|
-
}));
|
|
736
|
-
expect(result.data).toHaveLength(1);
|
|
737
|
-
});
|
|
738
|
-
it("should call api.queryTransactionBlocks with correct params for OUT", async () => {
|
|
739
|
-
mockApi.queryTransactionBlocks.mockResolvedValueOnce({
|
|
740
|
-
data: [{ digest: "tx2" }],
|
|
741
|
-
hasNextPage: false,
|
|
742
|
-
});
|
|
743
|
-
const result = await sdk.queryTransactions({
|
|
744
|
-
api: mockApi,
|
|
745
|
-
addr: "0xdef",
|
|
746
|
-
type: "OUT",
|
|
747
|
-
order: "ascending",
|
|
748
|
-
});
|
|
749
|
-
expect(mockApi.queryTransactionBlocks).toHaveBeenCalledWith(expect.objectContaining({
|
|
750
|
-
filter: { FromAddress: "0xdef" },
|
|
751
|
-
}));
|
|
752
|
-
expect(result.data).toHaveLength(1);
|
|
753
|
-
});
|
|
754
|
-
});
|
|
755
|
-
describe("loadOperations", () => {
|
|
756
|
-
it("should paginate and accumulate results", async () => {
|
|
757
|
-
const pageSize = sdk.TRANSACTIONS_LIMIT_PER_QUERY;
|
|
758
|
-
const firstPage = Array.from({ length: pageSize }, (_, i) => ({ digest: `tx${i + 1}` }));
|
|
759
|
-
mockApi.queryTransactionBlocks
|
|
760
|
-
.mockResolvedValueOnce({
|
|
761
|
-
data: firstPage,
|
|
762
|
-
hasNextPage: true,
|
|
763
|
-
nextCursor: "cursor1",
|
|
764
|
-
})
|
|
765
|
-
.mockResolvedValueOnce({
|
|
766
|
-
data: [{ digest: `tx${pageSize + 1}` }],
|
|
767
|
-
hasNextPage: false,
|
|
768
|
-
});
|
|
769
|
-
const result = await sdk.loadOperations({
|
|
770
|
-
api: mockApi,
|
|
771
|
-
addr: "0xabc",
|
|
772
|
-
type: "IN",
|
|
773
|
-
order: "ascending",
|
|
774
|
-
operations: [],
|
|
775
|
-
});
|
|
776
|
-
expect(result.operations).toHaveLength(pageSize + 1);
|
|
777
|
-
expect(result.operations.map(tx => tx.digest)).toEqual([
|
|
778
|
-
...firstPage.map(tx => tx.digest),
|
|
779
|
-
`tx${pageSize + 1}`,
|
|
780
|
-
]);
|
|
781
|
-
expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(2);
|
|
782
|
-
});
|
|
783
|
-
it("should stop if less than TRANSACTIONS_LIMIT_PER_QUERY returned", async () => {
|
|
784
|
-
// Create an array with length less than TRANSACTIONS_LIMIT_PER_QUERY
|
|
785
|
-
const txs = Array.from({ length: sdk.TRANSACTIONS_LIMIT_PER_QUERY - 1 }, (_, i) => ({
|
|
786
|
-
digest: `tx${i + 1}`,
|
|
787
|
-
}));
|
|
788
|
-
mockApi.queryTransactionBlocks.mockResolvedValueOnce({
|
|
789
|
-
data: txs,
|
|
790
|
-
hasNextPage: false, // Only one call should be made
|
|
791
|
-
});
|
|
792
|
-
const result = await sdk.loadOperations({
|
|
793
|
-
api: mockApi,
|
|
794
|
-
addr: "0xabc",
|
|
795
|
-
type: "OUT",
|
|
796
|
-
order: "ascending",
|
|
797
|
-
operations: [],
|
|
798
|
-
});
|
|
799
|
-
expect(result.operations).toHaveLength(sdk.TRANSACTIONS_LIMIT_PER_QUERY - 1);
|
|
800
|
-
expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(1);
|
|
801
|
-
});
|
|
802
|
-
it("should not exceed TRANSACTIONS_LIMIT", async () => {
|
|
803
|
-
const page = Array.from({ length: sdk.TRANSACTIONS_LIMIT_PER_QUERY }, (_, i) => ({
|
|
804
|
-
digest: `tx${i + 1}`,
|
|
805
|
-
}));
|
|
806
|
-
const expectedCalls = Math.ceil(sdk.TRANSACTIONS_LIMIT / sdk.TRANSACTIONS_LIMIT_PER_QUERY);
|
|
807
|
-
let callCount = 0;
|
|
808
|
-
mockApi.queryTransactionBlocks.mockImplementation(() => {
|
|
809
|
-
callCount++;
|
|
810
|
-
return Promise.resolve({
|
|
811
|
-
data: page,
|
|
812
|
-
hasNextPage: callCount < expectedCalls,
|
|
813
|
-
nextCursor: callCount < expectedCalls ? "cursor" : null,
|
|
814
|
-
});
|
|
815
|
-
});
|
|
816
|
-
const result = await sdk.loadOperations({
|
|
817
|
-
api: mockApi,
|
|
818
|
-
addr: "0xabc",
|
|
819
|
-
type: "IN",
|
|
820
|
-
order: "ascending",
|
|
821
|
-
operations: [],
|
|
822
|
-
});
|
|
823
|
-
expect(result.operations).toHaveLength(sdk.TRANSACTIONS_LIMIT);
|
|
824
|
-
expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(expectedCalls);
|
|
825
|
-
});
|
|
826
|
-
it("should retry without cursor when InvalidParams error occurs", async () => {
|
|
827
|
-
// Reset the mock for this test
|
|
828
|
-
mockApi.queryTransactionBlocks.mockReset();
|
|
829
|
-
// Call fails with InvalidParams
|
|
830
|
-
mockApi.queryTransactionBlocks.mockRejectedValueOnce({ type: "InvalidParams" });
|
|
831
|
-
const result = await sdk.loadOperations({
|
|
832
|
-
api: mockApi,
|
|
833
|
-
addr: "0xabc",
|
|
834
|
-
type: "IN",
|
|
835
|
-
cursor: "some-cursor",
|
|
836
|
-
order: "ascending",
|
|
837
|
-
operations: [],
|
|
838
|
-
});
|
|
839
|
-
// Should have been called once (no retry in actual implementation)
|
|
840
|
-
expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(1);
|
|
841
|
-
// Should have been called with the cursor
|
|
842
|
-
expect(mockApi.queryTransactionBlocks).toHaveBeenCalledWith(expect.objectContaining({
|
|
843
|
-
filter: { ToAddress: "0xabc" },
|
|
844
|
-
cursor: "some-cursor",
|
|
845
|
-
}));
|
|
846
|
-
// Result should be empty array (no retry, just return operations)
|
|
847
|
-
expect(result.operations).toHaveLength(0);
|
|
848
|
-
});
|
|
849
|
-
it("should should not retry after unexpected errors and return empty data", async () => {
|
|
850
|
-
mockApi.queryTransactionBlocks.mockRejectedValueOnce(new Error("unexpected"));
|
|
851
|
-
const result = await sdk.loadOperations({
|
|
852
|
-
api: mockApi,
|
|
853
|
-
addr: "0xerr",
|
|
854
|
-
type: "IN",
|
|
855
|
-
order: "ascending",
|
|
856
|
-
operations: [],
|
|
857
|
-
});
|
|
858
|
-
expect(result.operations).toEqual([]);
|
|
859
|
-
expect(mockApi.queryTransactionBlocks).toHaveBeenCalledTimes(1);
|
|
860
|
-
});
|
|
861
|
-
});
|
|
862
|
-
describe("getOperations filtering logic", () => {
|
|
863
|
-
const mockAccountId = "mockAccountId";
|
|
864
|
-
const mockAddr = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
865
|
-
// Mock loadOperations to return controlled test data
|
|
866
|
-
const mockLoadOperations = jest.spyOn(sdk, "loadOperations");
|
|
867
|
-
// Helper function to create mock transaction data
|
|
868
|
-
const createMockTransaction = (digest, timestampMs, sender = mockAddr, recipients = [], balanceChangeAmount) => {
|
|
869
|
-
// If sender is mockAddr (OUT), amount is negative; if sender is otherAddr (IN), amount is positive
|
|
870
|
-
const isOut = sender === mockAddr;
|
|
871
|
-
const amount = balanceChangeAmount ?? (isOut ? "-1000000" : "1000000");
|
|
872
|
-
return {
|
|
873
|
-
digest,
|
|
874
|
-
timestampMs,
|
|
875
|
-
effects: {
|
|
876
|
-
status: { status: "success" },
|
|
877
|
-
gasUsed: {
|
|
878
|
-
computationCost: "1000000",
|
|
879
|
-
storageCost: "500000",
|
|
880
|
-
storageRebate: "450000",
|
|
881
|
-
nonRefundableStorageFee: "0",
|
|
882
|
-
},
|
|
883
|
-
executedEpoch: "1",
|
|
884
|
-
gasObject: {
|
|
885
|
-
owner: { AddressOwner: sender },
|
|
886
|
-
reference: {
|
|
887
|
-
objectId: "0xgas",
|
|
888
|
-
version: "1",
|
|
889
|
-
digest: "gas-digest",
|
|
890
|
-
},
|
|
891
|
-
},
|
|
892
|
-
messageVersion: "v1",
|
|
893
|
-
transactionDigest: digest,
|
|
894
|
-
},
|
|
895
|
-
balanceChanges: [
|
|
896
|
-
{
|
|
897
|
-
owner: { AddressOwner: mockAddr },
|
|
898
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
899
|
-
amount,
|
|
900
|
-
},
|
|
901
|
-
],
|
|
902
|
-
transaction: {
|
|
903
|
-
data: {
|
|
904
|
-
sender,
|
|
905
|
-
transaction: {
|
|
906
|
-
kind: "ProgrammableTransaction",
|
|
907
|
-
inputs: recipients.map(r => ({ type: "pure", valueType: "address", value: r })),
|
|
908
|
-
transactions: [],
|
|
909
|
-
},
|
|
910
|
-
gasData: {
|
|
911
|
-
budget: "1000",
|
|
912
|
-
owner: sender,
|
|
913
|
-
payment: [],
|
|
914
|
-
price: "1",
|
|
915
|
-
},
|
|
916
|
-
messageVersion: "v1",
|
|
917
|
-
},
|
|
918
|
-
txSignatures: [],
|
|
919
|
-
},
|
|
920
|
-
};
|
|
921
|
-
};
|
|
922
|
-
const otherAddr = "0xotheraddress";
|
|
923
|
-
// OUT = sender is mockAddr, IN = sender is otherAddr
|
|
924
|
-
beforeEach(() => {
|
|
925
|
-
mockLoadOperations.mockReset();
|
|
926
|
-
// Mock loadOperations to return different data based on operation type
|
|
927
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
928
|
-
if (type === "OUT") {
|
|
929
|
-
return {
|
|
930
|
-
operations: [
|
|
931
|
-
createMockTransaction("sent1", "1000", mockAddr, []),
|
|
932
|
-
createMockTransaction("sent2", "2000", mockAddr, []),
|
|
933
|
-
],
|
|
934
|
-
cursor: null,
|
|
935
|
-
};
|
|
936
|
-
}
|
|
937
|
-
else if (type === "IN") {
|
|
938
|
-
return {
|
|
939
|
-
operations: [
|
|
940
|
-
createMockTransaction("received1", "1500", otherAddr, [mockAddr]),
|
|
941
|
-
createMockTransaction("received2", "2500", otherAddr, [mockAddr]),
|
|
942
|
-
],
|
|
943
|
-
cursor: null,
|
|
944
|
-
};
|
|
945
|
-
}
|
|
946
|
-
return { operations: [], cursor: null };
|
|
947
|
-
});
|
|
948
|
-
});
|
|
949
|
-
afterEach(() => {
|
|
950
|
-
// Remove mockRestore as it might interfere with the mock setup
|
|
951
|
-
});
|
|
952
|
-
test("should not apply timestamp filter when cursor is provided", async () => {
|
|
953
|
-
const cursor = "test-cursor";
|
|
954
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr, cursor);
|
|
955
|
-
// Should not filter by timestamp when cursor is provided
|
|
956
|
-
expect(operations).toHaveLength(4);
|
|
957
|
-
expect(operations.map(op => op.hash)).toEqual(["received2", "sent2", "received1", "sent1"]);
|
|
958
|
-
});
|
|
959
|
-
test("should not apply timestamp filter when operations don't reach limits", async () => {
|
|
960
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
961
|
-
// Should not filter by timestamp when limits aren't reached
|
|
962
|
-
expect(operations).toHaveLength(4);
|
|
963
|
-
expect(operations.map(op => op.hash)).toEqual(["received2", "sent2", "received1", "sent1"]);
|
|
964
|
-
});
|
|
965
|
-
test("should apply timestamp filter when sent operations reach limit", async () => {
|
|
966
|
-
// Mock to return enough sent operations to reach limit
|
|
967
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
968
|
-
if (type === "OUT") {
|
|
969
|
-
return {
|
|
970
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`sent${i + 1}`, String(1000 + i * 100), mockAddr, [])),
|
|
971
|
-
cursor: null,
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
else if (type === "IN") {
|
|
975
|
-
return {
|
|
976
|
-
operations: [
|
|
977
|
-
createMockTransaction("received1", "500", otherAddr, [mockAddr]),
|
|
978
|
-
createMockTransaction("received2", "1500", otherAddr, [mockAddr]),
|
|
979
|
-
],
|
|
980
|
-
cursor: null,
|
|
981
|
-
};
|
|
982
|
-
}
|
|
983
|
-
return { operations: [], cursor: null };
|
|
984
|
-
});
|
|
985
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
986
|
-
// Filter timestamp should be the maximum of the last timestamps from both arrays
|
|
987
|
-
// sent: last timestamp = 1000 + 299*100 = 30900
|
|
988
|
-
// received: last timestamp = 1500
|
|
989
|
-
// filter = max(30900, 1500) = 30900
|
|
990
|
-
// Only operations with timestamp >= 30900 should remain
|
|
991
|
-
expect(operations).toHaveLength(1); // Only sent300 (30900)
|
|
992
|
-
expect(operations.map(op => op.hash)).toEqual(["sent300"]);
|
|
993
|
-
});
|
|
994
|
-
test("should apply timestamp filter when received operations reach limit", async () => {
|
|
995
|
-
// Mock to return enough received operations to reach limit
|
|
996
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
997
|
-
if (type === "OUT") {
|
|
998
|
-
return {
|
|
999
|
-
operations: [
|
|
1000
|
-
createMockTransaction("sent1", "500", mockAddr, []),
|
|
1001
|
-
createMockTransaction("sent2", "1500", mockAddr, []),
|
|
1002
|
-
],
|
|
1003
|
-
cursor: null,
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
else if (type === "IN") {
|
|
1007
|
-
return {
|
|
1008
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`received${i + 1}`, String(1000 + i * 100), otherAddr, [
|
|
1009
|
-
mockAddr,
|
|
1010
|
-
])),
|
|
1011
|
-
cursor: null,
|
|
1012
|
-
};
|
|
1013
|
-
}
|
|
1014
|
-
return { operations: [], cursor: null };
|
|
1015
|
-
});
|
|
1016
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
1017
|
-
// Filter timestamp should be the maximum of the last timestamps from both arrays
|
|
1018
|
-
// sent: last timestamp = 1500
|
|
1019
|
-
// received: last timestamp = 1000 + 299*100 = 30900
|
|
1020
|
-
// filter = max(1500, 30900) = 30900
|
|
1021
|
-
// Only operations with timestamp >= 30900 should remain
|
|
1022
|
-
expect(operations).toHaveLength(1); // Only received300 (30900)
|
|
1023
|
-
expect(operations.map(op => op.hash)).toEqual(["received300"]);
|
|
1024
|
-
});
|
|
1025
|
-
test("should apply timestamp filter when both operations reach limit", async () => {
|
|
1026
|
-
// Mock to return enough operations to reach limit for both types
|
|
1027
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
1028
|
-
if (type === "OUT") {
|
|
1029
|
-
return {
|
|
1030
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`sent${i + 1}`, String(1000 + i * 100), mockAddr, [])),
|
|
1031
|
-
cursor: null,
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
else if (type === "IN") {
|
|
1035
|
-
return {
|
|
1036
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`received${i + 1}`, String(2000 + i * 100), otherAddr, [
|
|
1037
|
-
mockAddr,
|
|
1038
|
-
])),
|
|
1039
|
-
cursor: null,
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
return { operations: [], cursor: null };
|
|
1043
|
-
});
|
|
1044
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
1045
|
-
// Filter timestamp should be the maximum of the last timestamps from both arrays
|
|
1046
|
-
// sent: last timestamp = 1000 + 299*100 = 30900
|
|
1047
|
-
// received: last timestamp = 2000 + 299*100 = 31900
|
|
1048
|
-
// filter = max(30900, 31900) = 31900
|
|
1049
|
-
// Only operations with timestamp >= 31900 should remain
|
|
1050
|
-
expect(operations).toHaveLength(1); // Only received300 (31900)
|
|
1051
|
-
expect(operations.map(op => op.hash)).toEqual(["received300"]);
|
|
1052
|
-
});
|
|
1053
|
-
test("should handle null/undefined timestampMs values", async () => {
|
|
1054
|
-
// Mock to return operations with null timestamps and reach limit
|
|
1055
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
1056
|
-
if (type === "OUT") {
|
|
1057
|
-
return {
|
|
1058
|
-
operations: [
|
|
1059
|
-
createMockTransaction("sent1", "1000", mockAddr, []),
|
|
1060
|
-
createMockTransaction("sent2", null, mockAddr, []),
|
|
1061
|
-
createMockTransaction("sent3", "3000", mockAddr, []),
|
|
1062
|
-
...Array.from({ length: sdk.TRANSACTIONS_LIMIT - 3 }, (_, i) => createMockTransaction(`sent${i + 4}`, String(4000 + i * 100), mockAddr, [])),
|
|
1063
|
-
],
|
|
1064
|
-
cursor: null,
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
|
-
else if (type === "IN") {
|
|
1068
|
-
return {
|
|
1069
|
-
operations: [
|
|
1070
|
-
createMockTransaction("received1", null, otherAddr, [mockAddr]),
|
|
1071
|
-
createMockTransaction("received2", "2000", otherAddr, [mockAddr]),
|
|
1072
|
-
createMockTransaction("received3", "4000", otherAddr, [mockAddr]),
|
|
1073
|
-
],
|
|
1074
|
-
cursor: null,
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
return { operations: [], cursor: null };
|
|
1078
|
-
});
|
|
1079
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
1080
|
-
// Filter timestamp should be the timestamp of the last sent operation (4000 + 296*100 = 33600)
|
|
1081
|
-
// Only operations with timestamp >= 33600 should remain
|
|
1082
|
-
expect(operations).toHaveLength(1); // Only sent300 (33600)
|
|
1083
|
-
expect(operations.map(op => op.hash)).toEqual(["sent300"]);
|
|
1084
|
-
});
|
|
1085
|
-
test("should maintain chronological order after filtering", async () => {
|
|
1086
|
-
// Mock to return operations that reach limit
|
|
1087
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
1088
|
-
if (type === "OUT") {
|
|
1089
|
-
return {
|
|
1090
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`sent${i + 1}`, String(1000 + i * 10), mockAddr, [])),
|
|
1091
|
-
cursor: null,
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
else if (type === "IN") {
|
|
1095
|
-
return {
|
|
1096
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`received${i + 1}`, String(500 + i * 10), otherAddr, [mockAddr])),
|
|
1097
|
-
cursor: null,
|
|
1098
|
-
};
|
|
1099
|
-
}
|
|
1100
|
-
return { operations: [], cursor: null };
|
|
1101
|
-
});
|
|
1102
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
1103
|
-
// Should be sorted by timestamp in descending order
|
|
1104
|
-
const timestamps = operations.map(op => Number(op.date.getTime()));
|
|
1105
|
-
expect(timestamps).toEqual(timestamps.slice().sort((a, b) => b - a));
|
|
1106
|
-
});
|
|
1107
|
-
test("should handle empty operations arrays", async () => {
|
|
1108
|
-
// Mock to return empty arrays
|
|
1109
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
1110
|
-
return { operations: [], cursor: null };
|
|
1111
|
-
});
|
|
1112
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
1113
|
-
expect(operations).toHaveLength(0);
|
|
1114
|
-
});
|
|
1115
|
-
test("should handle mixed empty and non-empty operations", async () => {
|
|
1116
|
-
// Mock to return only OUT operations
|
|
1117
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
1118
|
-
if (type === "OUT") {
|
|
1119
|
-
return {
|
|
1120
|
-
operations: [
|
|
1121
|
-
createMockTransaction("sent1", "1000", mockAddr, []),
|
|
1122
|
-
createMockTransaction("sent2", "2000", mockAddr, []),
|
|
1123
|
-
],
|
|
1124
|
-
cursor: null,
|
|
1125
|
-
};
|
|
1126
|
-
}
|
|
1127
|
-
else if (type === "IN") {
|
|
1128
|
-
return { operations: [], cursor: null };
|
|
1129
|
-
}
|
|
1130
|
-
return { operations: [], cursor: null };
|
|
1131
|
-
});
|
|
1132
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
1133
|
-
expect(operations).toHaveLength(2);
|
|
1134
|
-
expect(operations.map(op => op.hash)).toEqual(["sent2", "sent1"]);
|
|
1135
|
-
});
|
|
1136
|
-
test("should handle operations with same timestamps", async () => {
|
|
1137
|
-
// Mock to return operations with same timestamps and reach limit
|
|
1138
|
-
mockLoadOperations.mockImplementation(async ({ type, ..._params }) => {
|
|
1139
|
-
if (type === "OUT") {
|
|
1140
|
-
return {
|
|
1141
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`sent${i + 1}`, "1000", mockAddr, [])),
|
|
1142
|
-
cursor: null,
|
|
1143
|
-
};
|
|
1144
|
-
}
|
|
1145
|
-
else if (type === "IN") {
|
|
1146
|
-
return {
|
|
1147
|
-
operations: [
|
|
1148
|
-
createMockTransaction("received1", "1000", otherAddr, [mockAddr]),
|
|
1149
|
-
createMockTransaction("received2", "1000", otherAddr, [mockAddr]),
|
|
1150
|
-
],
|
|
1151
|
-
cursor: null,
|
|
1152
|
-
};
|
|
1153
|
-
}
|
|
1154
|
-
return { operations: [], cursor: null };
|
|
1155
|
-
});
|
|
1156
|
-
const operations = await sdk.getOperations(mockAccountId, mockAddr);
|
|
1157
|
-
// Filter timestamp should be 1000 (the common timestamp)
|
|
1158
|
-
// All operations have timestamp 1000, so all should pass the filter
|
|
1159
|
-
expect(operations).toHaveLength(sdk.TRANSACTIONS_LIMIT + 2); // All 300 sent + 2 received
|
|
1160
|
-
expect(operations[0].hash).toBe("sent1"); // First one should be the first sent
|
|
1161
|
-
expect(operations[operations.length - 1].hash).toBe("received2"); // Last one should be the last received
|
|
1162
|
-
});
|
|
1163
|
-
});
|
|
1164
|
-
describe("filterOperations", () => {
|
|
1165
|
-
const createMockTransaction = (digest, timestampMs) => ({
|
|
1166
|
-
digest,
|
|
1167
|
-
timestampMs,
|
|
1168
|
-
effects: {
|
|
1169
|
-
status: { status: "success" },
|
|
1170
|
-
gasUsed: {
|
|
1171
|
-
computationCost: "1000000",
|
|
1172
|
-
storageCost: "500000",
|
|
1173
|
-
storageRebate: "450000",
|
|
1174
|
-
nonRefundableStorageFee: "0",
|
|
1175
|
-
},
|
|
1176
|
-
executedEpoch: "1",
|
|
1177
|
-
gasObject: {
|
|
1178
|
-
owner: { AddressOwner: "0x123" },
|
|
1179
|
-
reference: {
|
|
1180
|
-
objectId: "0xgas",
|
|
1181
|
-
version: "1",
|
|
1182
|
-
digest: "gas-digest",
|
|
1183
|
-
},
|
|
1184
|
-
},
|
|
1185
|
-
messageVersion: "v1",
|
|
1186
|
-
transactionDigest: digest,
|
|
1187
|
-
},
|
|
1188
|
-
transaction: {
|
|
1189
|
-
data: {
|
|
1190
|
-
sender: "0x123",
|
|
1191
|
-
transaction: {
|
|
1192
|
-
kind: "ProgrammableTransaction",
|
|
1193
|
-
inputs: [],
|
|
1194
|
-
transactions: [],
|
|
1195
|
-
},
|
|
1196
|
-
gasData: {
|
|
1197
|
-
budget: "1000",
|
|
1198
|
-
owner: "0x123",
|
|
1199
|
-
payment: [],
|
|
1200
|
-
price: "1",
|
|
1201
|
-
},
|
|
1202
|
-
messageVersion: "v1",
|
|
1203
|
-
},
|
|
1204
|
-
txSignatures: [],
|
|
1205
|
-
},
|
|
1206
|
-
balanceChanges: [],
|
|
1207
|
-
});
|
|
1208
|
-
describe("when cursor is provided", () => {
|
|
1209
|
-
test("should not apply timestamp filtering", () => {
|
|
1210
|
-
const operationList1 = {
|
|
1211
|
-
operations: [createMockTransaction("tx1", "1000"), createMockTransaction("tx2", "2000")],
|
|
1212
|
-
cursor: null,
|
|
1213
|
-
};
|
|
1214
|
-
const operationList2 = {
|
|
1215
|
-
operations: [createMockTransaction("tx3", "1500"), createMockTransaction("tx4", "2500")],
|
|
1216
|
-
cursor: null,
|
|
1217
|
-
};
|
|
1218
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1219
|
-
// Should return all operations sorted by timestamp in descending order
|
|
1220
|
-
expect(result.operations).toHaveLength(4);
|
|
1221
|
-
expect(result.operations.map(tx => tx.digest)).toEqual(["tx4", "tx2", "tx3", "tx1"]);
|
|
1222
|
-
});
|
|
1223
|
-
test("should handle null cursor", () => {
|
|
1224
|
-
const operationList1 = {
|
|
1225
|
-
operations: [createMockTransaction("tx1", "1000"), createMockTransaction("tx2", "2000")],
|
|
1226
|
-
cursor: null,
|
|
1227
|
-
};
|
|
1228
|
-
const operationList2 = {
|
|
1229
|
-
operations: [createMockTransaction("tx3", "1500"), createMockTransaction("tx4", "2500")],
|
|
1230
|
-
cursor: null,
|
|
1231
|
-
};
|
|
1232
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1233
|
-
// Should return all operations sorted by timestamp in descending order
|
|
1234
|
-
expect(result.operations).toHaveLength(4);
|
|
1235
|
-
expect(result.operations.map(tx => tx.digest)).toEqual(["tx4", "tx2", "tx3", "tx1"]);
|
|
1236
|
-
});
|
|
1237
|
-
test("should handle undefined cursor", () => {
|
|
1238
|
-
const operationList1 = {
|
|
1239
|
-
operations: [createMockTransaction("tx1", "1000"), createMockTransaction("tx2", "2000")],
|
|
1240
|
-
cursor: null,
|
|
1241
|
-
};
|
|
1242
|
-
const operationList2 = {
|
|
1243
|
-
operations: [createMockTransaction("tx3", "1500"), createMockTransaction("tx4", "2500")],
|
|
1244
|
-
cursor: null,
|
|
1245
|
-
};
|
|
1246
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1247
|
-
// Should return all operations sorted by timestamp in descending order
|
|
1248
|
-
expect(result.operations).toHaveLength(4);
|
|
1249
|
-
expect(result.operations.map(tx => tx.digest)).toEqual(["tx4", "tx2", "tx3", "tx1"]);
|
|
1250
|
-
});
|
|
1251
|
-
});
|
|
1252
|
-
describe("when cursor is not provided and operations reach limits", () => {
|
|
1253
|
-
test("should apply timestamp filtering when both lists reach limit", () => {
|
|
1254
|
-
const operationList1 = {
|
|
1255
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, String(1000 + i * 100))),
|
|
1256
|
-
cursor: null,
|
|
1257
|
-
};
|
|
1258
|
-
const operationList2 = {
|
|
1259
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx2_${i + 1}`, String(2000 + i * 100))),
|
|
1260
|
-
cursor: null,
|
|
1261
|
-
};
|
|
1262
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1263
|
-
// Filter timestamp should be max of last timestamps:
|
|
1264
|
-
// operationList1: 1000 + 299*100 = 30900
|
|
1265
|
-
// operationList2: 2000 + 299*100 = 31900
|
|
1266
|
-
// filter = max(30900, 31900) = 31900
|
|
1267
|
-
// Only operations with timestamp >= 31900 should remain
|
|
1268
|
-
const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 31900);
|
|
1269
|
-
expect(filteredOperations).toHaveLength(1);
|
|
1270
|
-
expect(filteredOperations[0].digest).toBe("tx2_300");
|
|
1271
|
-
});
|
|
1272
|
-
test("should apply timestamp filtering when only first list reaches limit", () => {
|
|
1273
|
-
const operationList1 = {
|
|
1274
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, String(1000 + i * 100))),
|
|
1275
|
-
cursor: null,
|
|
1276
|
-
};
|
|
1277
|
-
const operationList2 = {
|
|
1278
|
-
operations: [createMockTransaction("tx2_1", "500"), createMockTransaction("tx2_2", "1500")],
|
|
1279
|
-
cursor: null,
|
|
1280
|
-
};
|
|
1281
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1282
|
-
// Filter timestamp should be max of last timestamps:
|
|
1283
|
-
// operationList1: 1000 + 299*100 = 30900
|
|
1284
|
-
// operationList2: 1500
|
|
1285
|
-
// filter = max(30900, 1500) = 30900
|
|
1286
|
-
// Only operations with timestamp >= 30900 should remain
|
|
1287
|
-
const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 30900);
|
|
1288
|
-
expect(filteredOperations).toHaveLength(1);
|
|
1289
|
-
expect(filteredOperations[0].digest).toBe("tx1_300");
|
|
1290
|
-
});
|
|
1291
|
-
test("should apply timestamp filtering when only second list reaches limit", () => {
|
|
1292
|
-
const operationList1 = {
|
|
1293
|
-
operations: [createMockTransaction("tx1_1", "500"), createMockTransaction("tx1_2", "1500")],
|
|
1294
|
-
cursor: null,
|
|
1295
|
-
};
|
|
1296
|
-
const operationList2 = {
|
|
1297
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx2_${i + 1}`, String(2000 + i * 100))),
|
|
1298
|
-
cursor: null,
|
|
1299
|
-
};
|
|
1300
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1301
|
-
// Filter timestamp should be max of last timestamps:
|
|
1302
|
-
// operationList1: 1500
|
|
1303
|
-
// operationList2: 2000 + 299*100 = 31900
|
|
1304
|
-
// filter = max(1500, 31900) = 31900
|
|
1305
|
-
// Only operations with timestamp >= 31900 should remain
|
|
1306
|
-
const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 31900);
|
|
1307
|
-
expect(filteredOperations).toHaveLength(1);
|
|
1308
|
-
expect(filteredOperations[0].digest).toBe("tx2_300");
|
|
1309
|
-
});
|
|
1310
|
-
});
|
|
1311
|
-
describe("when cursor is not provided and operations don't reach limits", () => {
|
|
1312
|
-
test("should not apply timestamp filtering when neither list reaches limit", () => {
|
|
1313
|
-
const operationList1 = {
|
|
1314
|
-
operations: [
|
|
1315
|
-
createMockTransaction("tx1_1", "1000"),
|
|
1316
|
-
createMockTransaction("tx1_2", "2000"),
|
|
1317
|
-
],
|
|
1318
|
-
cursor: null,
|
|
1319
|
-
};
|
|
1320
|
-
const operationList2 = {
|
|
1321
|
-
operations: [
|
|
1322
|
-
createMockTransaction("tx2_1", "1500"),
|
|
1323
|
-
createMockTransaction("tx2_2", "2500"),
|
|
1324
|
-
],
|
|
1325
|
-
cursor: null,
|
|
1326
|
-
};
|
|
1327
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1328
|
-
// Should return all operations sorted by timestamp in descending order
|
|
1329
|
-
expect(result.operations).toHaveLength(4);
|
|
1330
|
-
expect(result.operations.map(tx => tx.digest)).toEqual(["tx2_2", "tx1_2", "tx2_1", "tx1_1"]);
|
|
1331
|
-
});
|
|
1332
|
-
test("should apply timestamp filtering when only one list reaches limit", () => {
|
|
1333
|
-
const operationList1 = {
|
|
1334
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, String(1000 + i * 100))),
|
|
1335
|
-
cursor: null,
|
|
1336
|
-
};
|
|
1337
|
-
const operationList2 = {
|
|
1338
|
-
operations: [createMockTransaction("tx2_1", "1500")],
|
|
1339
|
-
cursor: null,
|
|
1340
|
-
};
|
|
1341
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1342
|
-
// Should apply timestamp filtering since one list reaches limit
|
|
1343
|
-
// Filter timestamp should be the timestamp of the last operation in list1 (1000 + 299*100 = 30900)
|
|
1344
|
-
// Only operations with timestamp >= 30900 should remain
|
|
1345
|
-
const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 30900);
|
|
1346
|
-
expect(filteredOperations).toHaveLength(1);
|
|
1347
|
-
expect(filteredOperations[0].digest).toBe("tx1_300");
|
|
1348
|
-
});
|
|
1349
|
-
});
|
|
1350
|
-
describe("edge cases", () => {
|
|
1351
|
-
test("should handle null/undefined timestampMs values", () => {
|
|
1352
|
-
const operationList1 = {
|
|
1353
|
-
operations: [
|
|
1354
|
-
createMockTransaction("tx1_1", "1000"),
|
|
1355
|
-
createMockTransaction("tx1_2", null),
|
|
1356
|
-
createMockTransaction("tx1_3", "3000"),
|
|
1357
|
-
...Array.from({ length: sdk.TRANSACTIONS_LIMIT - 3 }, (_, i) => createMockTransaction(`tx1_${i + 4}`, String(4000 + i * 100))),
|
|
1358
|
-
],
|
|
1359
|
-
cursor: null,
|
|
1360
|
-
};
|
|
1361
|
-
const operationList2 = {
|
|
1362
|
-
operations: [
|
|
1363
|
-
createMockTransaction("tx2_1", null),
|
|
1364
|
-
createMockTransaction("tx2_2", "2000"),
|
|
1365
|
-
createMockTransaction("tx2_3", "4000"),
|
|
1366
|
-
],
|
|
1367
|
-
cursor: null,
|
|
1368
|
-
};
|
|
1369
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1370
|
-
// Filter timestamp should be the timestamp of the last operation in list1 (4000 + 296*100 = 33600)
|
|
1371
|
-
// Only operations with timestamp >= 33600 should remain
|
|
1372
|
-
const filteredOperations = result.operations.filter(tx => Number(tx.timestampMs) >= 33600);
|
|
1373
|
-
expect(filteredOperations).toHaveLength(1);
|
|
1374
|
-
expect(filteredOperations[0].digest).toBe("tx1_300");
|
|
1375
|
-
});
|
|
1376
|
-
test("should handle empty arrays", () => {
|
|
1377
|
-
const result = sdk.filterOperations({ operations: [], cursor: null }, { operations: [], cursor: null }, "ascending");
|
|
1378
|
-
expect(result.operations).toHaveLength(0);
|
|
1379
|
-
});
|
|
1380
|
-
test("should handle one empty array", () => {
|
|
1381
|
-
const operationList1 = {
|
|
1382
|
-
operations: [
|
|
1383
|
-
createMockTransaction("tx1_1", "1000"),
|
|
1384
|
-
createMockTransaction("tx1_2", "2000"),
|
|
1385
|
-
],
|
|
1386
|
-
cursor: null,
|
|
1387
|
-
};
|
|
1388
|
-
const operationList2 = {
|
|
1389
|
-
operations: [],
|
|
1390
|
-
cursor: null,
|
|
1391
|
-
};
|
|
1392
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1393
|
-
expect(result.operations).toHaveLength(2);
|
|
1394
|
-
expect(result.operations.map(tx => tx.digest)).toEqual(["tx1_2", "tx1_1"]);
|
|
1395
|
-
});
|
|
1396
|
-
test("should remove duplicate transactions by digest", () => {
|
|
1397
|
-
const operationList1 = {
|
|
1398
|
-
operations: [createMockTransaction("tx1", "1000"), createMockTransaction("tx2", "2000")],
|
|
1399
|
-
cursor: null,
|
|
1400
|
-
};
|
|
1401
|
-
const operationList2 = {
|
|
1402
|
-
operations: [
|
|
1403
|
-
createMockTransaction("tx2", "2000"), // Duplicate digest
|
|
1404
|
-
createMockTransaction("tx3", "3000"),
|
|
1405
|
-
],
|
|
1406
|
-
cursor: null,
|
|
1407
|
-
};
|
|
1408
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1409
|
-
// Should remove duplicate tx2
|
|
1410
|
-
expect(result.operations).toHaveLength(3);
|
|
1411
|
-
expect(result.operations.map(tx => tx.digest)).toEqual(["tx3", "tx2", "tx1"]);
|
|
1412
|
-
});
|
|
1413
|
-
test("should maintain chronological order after filtering", () => {
|
|
1414
|
-
const operationList1 = {
|
|
1415
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, String(1000 + i * 10))),
|
|
1416
|
-
cursor: null,
|
|
1417
|
-
};
|
|
1418
|
-
const operationList2 = {
|
|
1419
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx2_${i + 1}`, String(500 + i * 10))),
|
|
1420
|
-
cursor: null,
|
|
1421
|
-
};
|
|
1422
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1423
|
-
// Should be sorted by timestamp in descending order
|
|
1424
|
-
const timestamps = result.operations.map(tx => Number(tx.timestampMs));
|
|
1425
|
-
expect(timestamps).toEqual(timestamps.slice().sort((a, b) => b - a));
|
|
1426
|
-
});
|
|
1427
|
-
test("should handle operations with same timestamps", () => {
|
|
1428
|
-
const operationList1 = {
|
|
1429
|
-
operations: Array.from({ length: sdk.TRANSACTIONS_LIMIT }, (_, i) => createMockTransaction(`tx1_${i + 1}`, "1000")),
|
|
1430
|
-
cursor: null,
|
|
1431
|
-
};
|
|
1432
|
-
const operationList2 = {
|
|
1433
|
-
operations: [
|
|
1434
|
-
createMockTransaction("tx2_1", "1000"),
|
|
1435
|
-
createMockTransaction("tx2_2", "1000"),
|
|
1436
|
-
],
|
|
1437
|
-
cursor: null,
|
|
1438
|
-
};
|
|
1439
|
-
const result = sdk.filterOperations(operationList1, operationList2, "ascending");
|
|
1440
|
-
// Filter timestamp should be 1000 (the common timestamp)
|
|
1441
|
-
// All operations have timestamp 1000, so all should pass the filter
|
|
1442
|
-
expect(result.operations).toHaveLength(sdk.TRANSACTIONS_LIMIT + 2);
|
|
1443
|
-
});
|
|
1444
|
-
});
|
|
1445
|
-
describe("conversion methods", () => {
|
|
1446
|
-
test("toBlockOperation should map native transfers correctly", () => {
|
|
1447
|
-
expect(sdk.toBlockOperation(mockTransaction, {
|
|
1448
|
-
owner: {
|
|
1449
|
-
AddressOwner: "0x65449f57946938c84c5127",
|
|
1450
|
-
},
|
|
1451
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
1452
|
-
amount: "-10000000000",
|
|
1453
|
-
})).toEqual([
|
|
1454
|
-
{
|
|
1455
|
-
type: "transfer",
|
|
1456
|
-
address: "0x65449f57946938c84c5127",
|
|
1457
|
-
amount: -10000000000n,
|
|
1458
|
-
asset: { type: "native" },
|
|
1459
|
-
},
|
|
1460
|
-
]);
|
|
1461
|
-
});
|
|
1462
|
-
test("toBlockOperation should ignore transfers from shared owner", () => {
|
|
1463
|
-
expect(sdk.toBlockOperation(mockTransaction, {
|
|
1464
|
-
owner: {
|
|
1465
|
-
Shared: {
|
|
1466
|
-
initial_shared_version: "0",
|
|
1467
|
-
},
|
|
1468
|
-
},
|
|
1469
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
1470
|
-
amount: "-10000000000",
|
|
1471
|
-
})).toEqual([]);
|
|
1472
|
-
});
|
|
1473
|
-
test("toBlockOperation should ignore transfers from object owner", () => {
|
|
1474
|
-
expect(sdk.toBlockOperation(mockTransaction, {
|
|
1475
|
-
owner: {
|
|
1476
|
-
ObjectOwner: "test",
|
|
1477
|
-
},
|
|
1478
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
1479
|
-
amount: "-10000000000",
|
|
1480
|
-
})).toEqual([]);
|
|
1481
|
-
});
|
|
1482
|
-
test("toBlockOperation should ignore transfers from immutable owner", () => {
|
|
1483
|
-
expect(sdk.toBlockOperation(mockTransaction, {
|
|
1484
|
-
owner: "Immutable",
|
|
1485
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
1486
|
-
amount: "-10000000000",
|
|
1487
|
-
})).toEqual([]);
|
|
1488
|
-
});
|
|
1489
|
-
test("toBlockOperation should ignore transfers from consensus owner", () => {
|
|
1490
|
-
expect(sdk.toBlockOperation(mockTransaction, {
|
|
1491
|
-
owner: {
|
|
1492
|
-
ConsensusAddressOwner: {
|
|
1493
|
-
owner: "test",
|
|
1494
|
-
start_version: "1",
|
|
1495
|
-
},
|
|
1496
|
-
},
|
|
1497
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
1498
|
-
amount: "-10000000000",
|
|
1499
|
-
})).toEqual([]);
|
|
1500
|
-
});
|
|
1501
|
-
test("toBlockOperation should map token transfers correctly", () => {
|
|
1502
|
-
expect(sdk.toBlockOperation(mockTransaction, {
|
|
1503
|
-
owner: {
|
|
1504
|
-
AddressOwner: "0x65449f57946938c84c5127",
|
|
1505
|
-
},
|
|
1506
|
-
coinType: "0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC",
|
|
1507
|
-
amount: "8824",
|
|
1508
|
-
})).toEqual([
|
|
1509
|
-
{
|
|
1510
|
-
type: "transfer",
|
|
1511
|
-
address: "0x65449f57946938c84c5127",
|
|
1512
|
-
amount: 8824n,
|
|
1513
|
-
asset: {
|
|
1514
|
-
type: "token",
|
|
1515
|
-
assetReference: "0x168da5bf1f48dafc111b0a488fa454aca95e0b5e::usdc::USDC",
|
|
1516
|
-
},
|
|
1517
|
-
},
|
|
1518
|
-
]);
|
|
1519
|
-
});
|
|
1520
|
-
test("toBlockOperation should map staking operations correctly", () => {
|
|
1521
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
1522
|
-
expect(sdk.toBlockOperation(mockStakingTx(address, "-1000000000"), {
|
|
1523
|
-
owner: { AddressOwner: address },
|
|
1524
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
1525
|
-
amount: "-10000000000",
|
|
1526
|
-
})).toEqual([
|
|
1527
|
-
{
|
|
1528
|
-
type: "other",
|
|
1529
|
-
operationType: "DELEGATE",
|
|
1530
|
-
address: address,
|
|
1531
|
-
asset: { type: "native" },
|
|
1532
|
-
amount: 10000000000n,
|
|
1533
|
-
},
|
|
1534
|
-
]);
|
|
1535
|
-
});
|
|
1536
|
-
test("toBlockOperation should map unstaking operations correctly", () => {
|
|
1537
|
-
const address = "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24";
|
|
1538
|
-
expect(sdk.toBlockOperation(mockUnstakingTx(address, "1000000000"), {
|
|
1539
|
-
owner: { AddressOwner: address },
|
|
1540
|
-
coinType: sdk.DEFAULT_COIN_TYPE,
|
|
1541
|
-
amount: "10000000000",
|
|
1542
|
-
})).toEqual([
|
|
1543
|
-
{
|
|
1544
|
-
type: "other",
|
|
1545
|
-
operationType: "UNDELEGATE",
|
|
1546
|
-
address: address,
|
|
1547
|
-
asset: { type: "native" },
|
|
1548
|
-
amount: 10000000000n,
|
|
1549
|
-
},
|
|
1550
|
-
]);
|
|
1551
|
-
});
|
|
1552
|
-
test("toBlockInfo should map checkpoints correctly", () => {
|
|
1553
|
-
expect(sdk.toBlockInfo({
|
|
1554
|
-
checkpointCommitments: [],
|
|
1555
|
-
digest: "0xaaaaaaaaa",
|
|
1556
|
-
previousDigest: "0xbbbbbbbbbb",
|
|
1557
|
-
epoch: "",
|
|
1558
|
-
epochRollingGasCostSummary: {
|
|
1559
|
-
computationCost: "",
|
|
1560
|
-
nonRefundableStorageFee: "",
|
|
1561
|
-
storageCost: "",
|
|
1562
|
-
storageRebate: "",
|
|
1563
|
-
},
|
|
1564
|
-
networkTotalTransactions: "",
|
|
1565
|
-
sequenceNumber: "42",
|
|
1566
|
-
timestampMs: "1751696298663",
|
|
1567
|
-
transactions: [],
|
|
1568
|
-
validatorSignature: "",
|
|
1569
|
-
})).toEqual({
|
|
1570
|
-
height: 42,
|
|
1571
|
-
hash: "0xaaaaaaaaa",
|
|
1572
|
-
time: new Date(1751696298663),
|
|
1573
|
-
parent: {
|
|
1574
|
-
height: 41,
|
|
1575
|
-
hash: "0xbbbbbbbbbb",
|
|
1576
|
-
},
|
|
1577
|
-
});
|
|
1578
|
-
});
|
|
1579
|
-
test("toBlockTransaction should map transactions correctly", () => {
|
|
1580
|
-
expect(sdk.toBlockTransaction(
|
|
1581
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
1582
|
-
mockTransaction)).toEqual({
|
|
1583
|
-
hash: "DhKLpX5kwuKuyRa71RGqpX5EY2M8Efw535ZVXYXsRiDt",
|
|
1584
|
-
failed: false,
|
|
1585
|
-
fees: 1009880n,
|
|
1586
|
-
feesPayer: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
|
|
1587
|
-
operations: [
|
|
1588
|
-
{
|
|
1589
|
-
address: "0x65449f57946938c84c512732f1d69405d1fce417d9c9894696ddf4522f479e24",
|
|
1590
|
-
amount: -10000000000n,
|
|
1591
|
-
asset: { type: "native" },
|
|
1592
|
-
type: "transfer",
|
|
1593
|
-
},
|
|
1594
|
-
{
|
|
1595
|
-
address: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
1596
|
-
amount: 9998990120n,
|
|
1597
|
-
asset: { type: "native" },
|
|
1598
|
-
type: "transfer",
|
|
1599
|
-
},
|
|
1600
|
-
{
|
|
1601
|
-
address: "0x6e143fe0a8ca010a86580dafac44298e5b1b7d73efc345356a59a15f0d7824f0",
|
|
1602
|
-
amount: 500000n,
|
|
1603
|
-
asset: { type: "token", assetReference: "0x123::test::TOKEN" },
|
|
1604
|
-
type: "transfer",
|
|
1605
|
-
},
|
|
1606
|
-
],
|
|
1607
|
-
});
|
|
1608
|
-
});
|
|
1609
|
-
test("toSuiAsset should map native coin correctly", () => {
|
|
1610
|
-
expect(sdk.toSuiAsset(sdk.DEFAULT_COIN_TYPE)).toEqual({ type: "native" });
|
|
1611
|
-
});
|
|
1612
|
-
test("suiCoinTypeToAsset should map tokens correctly", () => {
|
|
1613
|
-
expect(sdk.toSuiAsset("0x123::test::TOKEN")).toEqual({
|
|
1614
|
-
type: "token",
|
|
1615
|
-
assetReference: "0x123::test::TOKEN",
|
|
1616
|
-
});
|
|
1617
|
-
});
|
|
1618
|
-
});
|
|
1619
|
-
});
|
|
1620
|
-
describe("getCoinsForAmount", () => {
|
|
1621
|
-
const mockAddress = "0x33444cf803c690db96527cec67e3c9ab512596f4ba2d4eace43f0b4f716e0164";
|
|
1622
|
-
const mockCoinType = "0x2::sui::SUI";
|
|
1623
|
-
beforeEach(() => {
|
|
1624
|
-
mockApi.getCoins.mockReset();
|
|
1625
|
-
});
|
|
1626
|
-
describe("basic functionality", () => {
|
|
1627
|
-
test("handles single coin scenarios", async () => {
|
|
1628
|
-
const sufficientCoins = createMockCoins(["1000"]);
|
|
1629
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: sufficientCoins, hasNextPage: false });
|
|
1630
|
-
let result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1631
|
-
expect(result).toHaveLength(1);
|
|
1632
|
-
expect(result[0].balance).toBe("1000");
|
|
1633
|
-
const insufficientCoins = createMockCoins(["500"]);
|
|
1634
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: insufficientCoins, hasNextPage: false });
|
|
1635
|
-
result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1636
|
-
expect(result).toHaveLength(1);
|
|
1637
|
-
expect(result[0].balance).toBe("500");
|
|
1638
|
-
});
|
|
1639
|
-
test("selects minimum coins needed", async () => {
|
|
1640
|
-
const exactMatchCoins = createMockCoins(["600", "400", "300"]);
|
|
1641
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: exactMatchCoins, hasNextPage: false });
|
|
1642
|
-
let result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1643
|
-
expect(result).toHaveLength(2);
|
|
1644
|
-
expect(result[0].balance).toBe("600");
|
|
1645
|
-
expect(result[1].balance).toBe("400");
|
|
1646
|
-
const exceedCoins = createMockCoins(["800", "400", "200"]);
|
|
1647
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: exceedCoins, hasNextPage: false });
|
|
1648
|
-
result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1649
|
-
expect(result).toHaveLength(2);
|
|
1650
|
-
expect(result[0].balance).toBe("800");
|
|
1651
|
-
expect(result[1].balance).toBe("400");
|
|
1652
|
-
});
|
|
1653
|
-
test("handles edge cases", async () => {
|
|
1654
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: [], hasNextPage: false });
|
|
1655
|
-
let result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1656
|
-
expect(result).toHaveLength(0);
|
|
1657
|
-
const coins = createMockCoins(["1000"]);
|
|
1658
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: coins, hasNextPage: false });
|
|
1659
|
-
result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 0);
|
|
1660
|
-
expect(result).toHaveLength(0);
|
|
1661
|
-
});
|
|
1662
|
-
});
|
|
1663
|
-
describe("sorting and filtering", () => {
|
|
1664
|
-
test("filters zero balance coins", async () => {
|
|
1665
|
-
const mockCoins = createMockCoins(["1000", "500"]);
|
|
1666
|
-
mockCoins.splice(1, 0, createMockCoins(["0"])[0]);
|
|
1667
|
-
mockCoins.push({ coinObjectId: "0xcoin4", balance: "0", digest: "0xdigest4", version: "1" });
|
|
1668
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: mockCoins, hasNextPage: false });
|
|
1669
|
-
const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1670
|
-
expect(result).toHaveLength(1);
|
|
1671
|
-
expect(result[0].balance).toBe("1000");
|
|
1672
|
-
expect(result.every(coin => parseInt(coin.balance) > 0)).toBe(true);
|
|
1673
|
-
});
|
|
1674
|
-
test("sorts and optimizes coin selection", async () => {
|
|
1675
|
-
const unsortedCoins = createMockCoins(["100", "800", "300", "500"]);
|
|
1676
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: unsortedCoins, hasNextPage: false });
|
|
1677
|
-
let result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1678
|
-
expect(result).toHaveLength(2);
|
|
1679
|
-
expect(result[0].balance).toBe("800");
|
|
1680
|
-
expect(result[1].balance).toBe("500");
|
|
1681
|
-
const mixedCoins = createMockCoins(["200", "800", "400"]);
|
|
1682
|
-
mixedCoins.unshift(createMockCoins(["0"])[0]);
|
|
1683
|
-
mixedCoins.splice(2, 0, createMockCoins(["0"])[0]);
|
|
1684
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: mixedCoins, hasNextPage: false });
|
|
1685
|
-
result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1686
|
-
expect(result).toHaveLength(2);
|
|
1687
|
-
expect(result[0].balance).toBe("800");
|
|
1688
|
-
expect(result[1].balance).toBe("400");
|
|
1689
|
-
expect(result.every(coin => parseInt(coin.balance) > 0)).toBe(true);
|
|
1690
|
-
});
|
|
1691
|
-
test("handles all zero balance coins", async () => {
|
|
1692
|
-
const mockCoins = createMockCoins(["0", "0", "0"]);
|
|
1693
|
-
mockApi.getCoins.mockResolvedValueOnce({ data: mockCoins, hasNextPage: false });
|
|
1694
|
-
const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1695
|
-
expect(result).toHaveLength(0);
|
|
1696
|
-
expect(result).toEqual([]);
|
|
1697
|
-
});
|
|
1698
|
-
});
|
|
1699
|
-
describe("pagination", () => {
|
|
1700
|
-
test("handles single page scenarios", async () => {
|
|
1701
|
-
const mockCoins = createMockCoins(["800", "400", "300"]);
|
|
1702
|
-
mockApi.getCoins.mockResolvedValueOnce({
|
|
1703
|
-
data: mockCoins,
|
|
1704
|
-
hasNextPage: true,
|
|
1705
|
-
nextCursor: "cursor1",
|
|
1706
|
-
});
|
|
1707
|
-
const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1708
|
-
expect(result).toHaveLength(2);
|
|
1709
|
-
expect(result[0].balance).toBe("800");
|
|
1710
|
-
expect(result[1].balance).toBe("400");
|
|
1711
|
-
expect(mockApi.getCoins).toHaveBeenCalledTimes(1);
|
|
1712
|
-
});
|
|
1713
|
-
test("handles multi-page scenarios", async () => {
|
|
1714
|
-
const firstPageCoins = createMockCoins(["300", "200"]);
|
|
1715
|
-
const secondPageCoins = createMockCoins(["600", "400", "100"]);
|
|
1716
|
-
mockApi.getCoins
|
|
1717
|
-
.mockResolvedValueOnce({
|
|
1718
|
-
data: firstPageCoins,
|
|
1719
|
-
hasNextPage: true,
|
|
1720
|
-
nextCursor: "cursor1",
|
|
1721
|
-
})
|
|
1722
|
-
.mockResolvedValueOnce({
|
|
1723
|
-
data: secondPageCoins,
|
|
1724
|
-
hasNextPage: false,
|
|
1725
|
-
});
|
|
1726
|
-
const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1727
|
-
expect(result).toHaveLength(3);
|
|
1728
|
-
expect(result[0].balance).toBe("300");
|
|
1729
|
-
expect(result[1].balance).toBe("200");
|
|
1730
|
-
expect(result[2].balance).toBe("600");
|
|
1731
|
-
expect(mockApi.getCoins).toHaveBeenCalledTimes(2);
|
|
1732
|
-
});
|
|
1733
|
-
test("handles insufficient funds across pages", async () => {
|
|
1734
|
-
const firstPageCoins = createMockCoins(["300", "200"]);
|
|
1735
|
-
const secondPageCoins = createMockCoins(["200", "100"]);
|
|
1736
|
-
mockApi.getCoins
|
|
1737
|
-
.mockResolvedValueOnce({
|
|
1738
|
-
data: firstPageCoins,
|
|
1739
|
-
hasNextPage: true,
|
|
1740
|
-
nextCursor: "cursor1",
|
|
1741
|
-
})
|
|
1742
|
-
.mockResolvedValueOnce({
|
|
1743
|
-
data: secondPageCoins,
|
|
1744
|
-
hasNextPage: false,
|
|
1745
|
-
});
|
|
1746
|
-
const result = await sdk.getCoinsForAmount(mockApi, mockAddress, mockCoinType, 1000);
|
|
1747
|
-
expect(result).toHaveLength(4);
|
|
1748
|
-
expect(result[0].balance).toBe("300");
|
|
1749
|
-
expect(result[1].balance).toBe("200");
|
|
1750
|
-
expect(result[2].balance).toBe("200");
|
|
1751
|
-
expect(result[3].balance).toBe("100");
|
|
1752
|
-
expect(mockApi.getCoins).toHaveBeenCalledTimes(2);
|
|
1753
|
-
});
|
|
1754
|
-
});
|
|
1755
|
-
});
|
|
1756
|
-
//# sourceMappingURL=sdk.test.js.map
|