@ledgerhq/coin-hedera 1.15.0-nightly.20251126023856 → 1.15.0-nightly.20251126160702
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/CHANGELOG.md +10 -8
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +6 -2
- package/lib/api/index.js.map +1 -1
- package/lib/bridge/broadcast.js +1 -1
- package/lib/bridge/broadcast.js.map +1 -1
- package/lib/bridge/buildOptimisticOperation.d.ts.map +1 -1
- package/lib/bridge/buildOptimisticOperation.js +80 -15
- package/lib/bridge/buildOptimisticOperation.js.map +1 -1
- package/lib/bridge/estimateMaxSpendable.js +5 -2
- package/lib/bridge/estimateMaxSpendable.js.map +1 -1
- package/lib/bridge/getTransactionStatus.d.ts.map +1 -1
- package/lib/bridge/getTransactionStatus.js +70 -13
- package/lib/bridge/getTransactionStatus.js.map +1 -1
- package/lib/bridge/index.js +1 -1
- package/lib/bridge/index.js.map +1 -1
- package/lib/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib/bridge/prepareTransaction.js +40 -7
- package/lib/bridge/prepareTransaction.js.map +1 -1
- package/lib/bridge/signOperation.d.ts.map +1 -1
- package/lib/bridge/signOperation.js +19 -2
- package/lib/bridge/signOperation.js.map +1 -1
- package/lib/bridge/synchronisation.d.ts +2 -0
- package/lib/bridge/synchronisation.d.ts.map +1 -1
- package/lib/bridge/synchronisation.js +101 -30
- package/lib/bridge/synchronisation.js.map +1 -1
- package/lib/bridge/utils.d.ts +35 -2
- package/lib/bridge/utils.d.ts.map +1 -1
- package/lib/bridge/utils.js +215 -16
- package/lib/bridge/utils.js.map +1 -1
- package/lib/constants.d.ts +22 -2
- package/lib/constants.d.ts.map +1 -1
- package/lib/constants.js +42 -2
- package/lib/constants.js.map +1 -1
- package/lib/deviceTransactionConfig.d.ts +1 -1
- package/lib/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/deviceTransactionConfig.js +8 -0
- package/lib/deviceTransactionConfig.js.map +1 -1
- package/lib/errors.d.ts +3 -0
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +2 -1
- package/lib/errors.js.map +1 -1
- package/lib/logic/craftTransaction.d.ts +4 -4
- package/lib/logic/craftTransaction.d.ts.map +1 -1
- package/lib/logic/craftTransaction.js +46 -5
- package/lib/logic/craftTransaction.js.map +1 -1
- package/lib/logic/estimateFees.d.ts +2 -4
- package/lib/logic/estimateFees.d.ts.map +1 -1
- package/lib/logic/estimateFees.js +45 -5
- package/lib/logic/estimateFees.js.map +1 -1
- package/lib/logic/listOperations.d.ts.map +1 -1
- package/lib/logic/listOperations.js +7 -3
- package/lib/logic/listOperations.js.map +1 -1
- package/lib/logic/utils.d.ts +24 -2
- package/lib/logic/utils.d.ts.map +1 -1
- package/lib/logic/utils.js +66 -13
- package/lib/logic/utils.js.map +1 -1
- package/lib/network/api.d.ts +12 -1
- package/lib/network/api.d.ts.map +1 -1
- package/lib/network/api.js +91 -19
- package/lib/network/api.js.map +1 -1
- package/lib/network/rpc.d.ts.map +1 -1
- package/lib/network/rpc.js +1 -0
- package/lib/network/rpc.js.map +1 -1
- package/lib/network/thirdweb.d.ts +21 -0
- package/lib/network/thirdweb.d.ts.map +1 -0
- package/lib/network/thirdweb.js +72 -0
- package/lib/network/thirdweb.js.map +1 -0
- package/lib/network/utils.d.ts +4 -1
- package/lib/network/utils.d.ts.map +1 -1
- package/lib/network/utils.js +53 -1
- package/lib/network/utils.js.map +1 -1
- package/lib/test/bridgeDatasetTest.d.ts.map +1 -1
- package/lib/test/bridgeDatasetTest.js +4 -4
- package/lib/test/bridgeDatasetTest.js.map +1 -1
- package/lib/test/fixtures/account.fixture.js +1 -1
- package/lib/test/fixtures/account.fixture.js.map +1 -1
- package/lib/test/fixtures/common.fixture.d.ts +12 -0
- package/lib/test/fixtures/common.fixture.d.ts.map +1 -0
- package/lib/test/fixtures/common.fixture.js +66 -0
- package/lib/test/fixtures/common.fixture.js.map +1 -0
- package/lib/test/fixtures/currency.fixture.d.ts +3 -1
- package/lib/test/fixtures/currency.fixture.d.ts.map +1 -1
- package/lib/test/fixtures/currency.fixture.js +63 -16
- package/lib/test/fixtures/currency.fixture.js.map +1 -1
- package/lib/test/fixtures/mirror.fixture.d.ts +3 -1
- package/lib/test/fixtures/mirror.fixture.d.ts.map +1 -1
- package/lib/test/fixtures/mirror.fixture.js +12 -1
- package/lib/test/fixtures/mirror.fixture.js.map +1 -1
- package/lib/test/fixtures/thirdweb.fixture.d.ts +3 -0
- package/lib/test/fixtures/thirdweb.fixture.d.ts.map +1 -0
- package/lib/test/fixtures/thirdweb.fixture.js +34 -0
- package/lib/test/fixtures/thirdweb.fixture.js.map +1 -0
- package/lib/transaction.d.ts.map +1 -1
- package/lib/transaction.js +2 -0
- package/lib/transaction.js.map +1 -1
- package/lib/types/alpaca.d.ts +5 -1
- package/lib/types/alpaca.d.ts.map +1 -1
- package/lib/types/bridge.d.ts +6 -1
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib/types/index.d.ts +2 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +2 -0
- package/lib/types/index.js.map +1 -1
- package/lib/types/logic.d.ts +39 -0
- package/lib/types/logic.d.ts.map +1 -0
- package/lib/types/logic.js +3 -0
- package/lib/types/logic.js.map +1 -0
- package/lib/types/mirror.d.ts +29 -0
- package/lib/types/mirror.d.ts.map +1 -1
- package/lib/types/thirdweb.d.ts +34 -0
- package/lib/types/thirdweb.d.ts.map +1 -0
- package/lib/types/thirdweb.js +3 -0
- package/lib/types/thirdweb.js.map +1 -0
- package/lib-es/api/index.d.ts.map +1 -1
- package/lib-es/api/index.js +7 -3
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/bridge/broadcast.js +2 -2
- package/lib-es/bridge/broadcast.js.map +1 -1
- package/lib-es/bridge/buildOptimisticOperation.d.ts.map +1 -1
- package/lib-es/bridge/buildOptimisticOperation.js +83 -18
- package/lib-es/bridge/buildOptimisticOperation.js.map +1 -1
- package/lib-es/bridge/estimateMaxSpendable.js +5 -2
- package/lib-es/bridge/estimateMaxSpendable.js.map +1 -1
- package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -1
- package/lib-es/bridge/getTransactionStatus.js +73 -16
- package/lib-es/bridge/getTransactionStatus.js.map +1 -1
- package/lib-es/bridge/index.js +2 -2
- package/lib-es/bridge/index.js.map +1 -1
- package/lib-es/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib-es/bridge/prepareTransaction.js +42 -9
- package/lib-es/bridge/prepareTransaction.js.map +1 -1
- package/lib-es/bridge/signOperation.d.ts.map +1 -1
- package/lib-es/bridge/signOperation.js +21 -4
- package/lib-es/bridge/signOperation.js.map +1 -1
- package/lib-es/bridge/synchronisation.d.ts +2 -0
- package/lib-es/bridge/synchronisation.d.ts.map +1 -1
- package/lib-es/bridge/synchronisation.js +97 -27
- package/lib-es/bridge/synchronisation.js.map +1 -1
- package/lib-es/bridge/utils.d.ts +35 -2
- package/lib-es/bridge/utils.d.ts.map +1 -1
- package/lib-es/bridge/utils.js +211 -16
- package/lib-es/bridge/utils.js.map +1 -1
- package/lib-es/constants.d.ts +22 -2
- package/lib-es/constants.d.ts.map +1 -1
- package/lib-es/constants.js +38 -1
- package/lib-es/constants.js.map +1 -1
- package/lib-es/deviceTransactionConfig.d.ts +1 -1
- package/lib-es/deviceTransactionConfig.d.ts.map +1 -1
- package/lib-es/deviceTransactionConfig.js +8 -0
- package/lib-es/deviceTransactionConfig.js.map +1 -1
- package/lib-es/errors.d.ts +3 -0
- package/lib-es/errors.d.ts.map +1 -1
- package/lib-es/errors.js +1 -0
- package/lib-es/errors.js.map +1 -1
- package/lib-es/logic/craftTransaction.d.ts +4 -4
- package/lib-es/logic/craftTransaction.d.ts.map +1 -1
- package/lib-es/logic/craftTransaction.js +48 -7
- package/lib-es/logic/craftTransaction.js.map +1 -1
- package/lib-es/logic/estimateFees.d.ts +2 -4
- package/lib-es/logic/estimateFees.d.ts.map +1 -1
- package/lib-es/logic/estimateFees.js +47 -7
- package/lib-es/logic/estimateFees.js.map +1 -1
- package/lib-es/logic/listOperations.d.ts.map +1 -1
- package/lib-es/logic/listOperations.js +7 -3
- package/lib-es/logic/listOperations.js.map +1 -1
- package/lib-es/logic/utils.d.ts +24 -2
- package/lib-es/logic/utils.d.ts.map +1 -1
- package/lib-es/logic/utils.js +63 -13
- package/lib-es/logic/utils.js.map +1 -1
- package/lib-es/network/api.d.ts +12 -1
- package/lib-es/network/api.d.ts.map +1 -1
- package/lib-es/network/api.js +91 -19
- package/lib-es/network/api.js.map +1 -1
- package/lib-es/network/rpc.d.ts.map +1 -1
- package/lib-es/network/rpc.js +1 -0
- package/lib-es/network/rpc.js.map +1 -1
- package/lib-es/network/thirdweb.d.ts +21 -0
- package/lib-es/network/thirdweb.d.ts.map +1 -0
- package/lib-es/network/thirdweb.js +66 -0
- package/lib-es/network/thirdweb.js.map +1 -0
- package/lib-es/network/utils.d.ts +4 -1
- package/lib-es/network/utils.d.ts.map +1 -1
- package/lib-es/network/utils.js +49 -0
- package/lib-es/network/utils.js.map +1 -1
- package/lib-es/test/bridgeDatasetTest.d.ts.map +1 -1
- package/lib-es/test/bridgeDatasetTest.js +4 -4
- package/lib-es/test/bridgeDatasetTest.js.map +1 -1
- package/lib-es/test/fixtures/account.fixture.js +2 -2
- package/lib-es/test/fixtures/account.fixture.js.map +1 -1
- package/lib-es/test/fixtures/common.fixture.d.ts +12 -0
- package/lib-es/test/fixtures/common.fixture.d.ts.map +1 -0
- package/lib-es/test/fixtures/common.fixture.js +57 -0
- package/lib-es/test/fixtures/common.fixture.js.map +1 -0
- package/lib-es/test/fixtures/currency.fixture.d.ts +3 -1
- package/lib-es/test/fixtures/currency.fixture.d.ts.map +1 -1
- package/lib-es/test/fixtures/currency.fixture.js +59 -14
- package/lib-es/test/fixtures/currency.fixture.js.map +1 -1
- package/lib-es/test/fixtures/mirror.fixture.d.ts +3 -1
- package/lib-es/test/fixtures/mirror.fixture.d.ts.map +1 -1
- package/lib-es/test/fixtures/mirror.fixture.js +9 -0
- package/lib-es/test/fixtures/mirror.fixture.js.map +1 -1
- package/lib-es/test/fixtures/thirdweb.fixture.d.ts +3 -0
- package/lib-es/test/fixtures/thirdweb.fixture.d.ts.map +1 -0
- package/lib-es/test/fixtures/thirdweb.fixture.js +30 -0
- package/lib-es/test/fixtures/thirdweb.fixture.js.map +1 -0
- package/lib-es/transaction.d.ts.map +1 -1
- package/lib-es/transaction.js +2 -0
- package/lib-es/transaction.js.map +1 -1
- package/lib-es/types/alpaca.d.ts +5 -1
- package/lib-es/types/alpaca.d.ts.map +1 -1
- package/lib-es/types/bridge.d.ts +6 -1
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/lib-es/types/index.d.ts +2 -0
- package/lib-es/types/index.d.ts.map +1 -1
- package/lib-es/types/index.js +2 -0
- package/lib-es/types/index.js.map +1 -1
- package/lib-es/types/logic.d.ts +39 -0
- package/lib-es/types/logic.d.ts.map +1 -0
- package/lib-es/types/logic.js +2 -0
- package/lib-es/types/logic.js.map +1 -0
- package/lib-es/types/mirror.d.ts +29 -0
- package/lib-es/types/mirror.d.ts.map +1 -1
- package/lib-es/types/thirdweb.d.ts +34 -0
- package/lib-es/types/thirdweb.d.ts.map +1 -0
- package/lib-es/types/thirdweb.js +2 -0
- package/lib-es/types/thirdweb.js.map +1 -0
- package/package.json +9 -8
- package/src/api/index.integ.test.ts +11 -8
- package/src/api/index.ts +10 -3
- package/src/bridge/broadcast.ts +2 -2
- package/src/bridge/buildOptimisticOperation.integration.test.ts +70 -19
- package/src/bridge/buildOptimisticOperation.ts +98 -20
- package/src/bridge/estimateMaxSpendable.ts +5 -5
- package/src/bridge/getTransactionStatus.test.ts +57 -12
- package/src/bridge/getTransactionStatus.ts +88 -15
- package/src/bridge/index.ts +2 -2
- package/src/bridge/js-estimateMaxSpendable.integration.test.ts +12 -9
- package/src/bridge/prepareTransaction.test.ts +3 -1
- package/src/bridge/prepareTransaction.ts +45 -10
- package/src/bridge/signOperation.ts +23 -5
- package/src/bridge/synchronisation.test.ts +67 -0
- package/src/bridge/synchronisation.ts +114 -34
- package/src/bridge/utils.integration.test.ts +486 -180
- package/src/bridge/utils.test.ts +404 -0
- package/src/bridge/utils.ts +330 -27
- package/src/constants.ts +47 -2
- package/src/deviceTransactionConfig.ts +10 -1
- package/src/errors.ts +3 -0
- package/src/logic/craftTransaction.test.ts +49 -9
- package/src/logic/craftTransaction.ts +76 -11
- package/src/logic/estimateFees.test.ts +180 -31
- package/src/logic/estimateFees.ts +68 -7
- package/src/logic/getAssetFromToken.test.ts +2 -2
- package/src/logic/getBalance.test.ts +18 -57
- package/src/logic/getTokenFromAsset.test.ts +2 -2
- package/src/logic/listOperations.ts +9 -5
- package/src/logic/utils.test.ts +157 -69
- package/src/logic/utils.ts +75 -13
- package/src/network/api.test.ts +211 -3
- package/src/network/api.ts +118 -24
- package/src/network/rpc.test.ts +1 -0
- package/src/network/rpc.ts +1 -0
- package/src/network/thirdweb.test.ts +188 -0
- package/src/network/thirdweb.ts +101 -0
- package/src/network/utils.test.ts +364 -164
- package/src/network/utils.ts +83 -1
- package/src/test/bridgeDatasetTest.ts +4 -5
- package/src/test/fixtures/account.fixture.ts +2 -2
- package/src/test/fixtures/common.fixture.ts +74 -0
- package/src/test/fixtures/currency.fixture.ts +66 -14
- package/src/test/fixtures/mirror.fixture.ts +23 -1
- package/src/test/fixtures/thirdweb.fixture.ts +33 -0
- package/src/transaction.ts +2 -0
- package/src/types/alpaca.ts +8 -1
- package/src/types/bridge.ts +6 -1
- package/src/types/index.ts +2 -0
- package/src/types/logic.ts +44 -0
- package/src/types/mirror.ts +35 -0
- package/src/types/thirdweb.ts +36 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { pad } from "viem";
|
|
2
|
+
import { getEnv } from "@ledgerhq/live-env";
|
|
3
|
+
import network from "@ledgerhq/live-network";
|
|
4
|
+
import { HEDERA_MAINNET_CHAIN_ID, ERC20_TRANSFER_EVENT_TOPIC } from "../constants";
|
|
5
|
+
import { toEVMAddress } from "../logic/utils";
|
|
6
|
+
import type { HederaThirdwebTransaction, HederaThirdwebContractEventsResponse } from "../types";
|
|
7
|
+
|
|
8
|
+
interface FetchOptions extends Record<string, string> {
|
|
9
|
+
filterBlockTimestampGte?: string;
|
|
10
|
+
filterTopic0: string;
|
|
11
|
+
filterTopic1?: string;
|
|
12
|
+
filterTopic2?: string;
|
|
13
|
+
limit: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const API_URL = getEnv("API_HEDERA_THIRDWEB_URL");
|
|
17
|
+
|
|
18
|
+
async function fetchERC20Transactions(
|
|
19
|
+
contractAddress: string,
|
|
20
|
+
options: FetchOptions,
|
|
21
|
+
): Promise<HederaThirdwebTransaction[]> {
|
|
22
|
+
const transactions: HederaThirdwebTransaction[] = [];
|
|
23
|
+
const params = new URLSearchParams(options);
|
|
24
|
+
let page = 1;
|
|
25
|
+
let hasMorePages = true;
|
|
26
|
+
|
|
27
|
+
while (hasMorePages) {
|
|
28
|
+
params.set("page", page.toString());
|
|
29
|
+
const response = await network<HederaThirdwebContractEventsResponse>({
|
|
30
|
+
method: "GET",
|
|
31
|
+
url: `${API_URL}/v1/contracts/${HEDERA_MAINNET_CHAIN_ID}/${contractAddress}/events?${params.toString()}`,
|
|
32
|
+
});
|
|
33
|
+
const newTransactions = response.data.result.events;
|
|
34
|
+
transactions.push(...newTransactions);
|
|
35
|
+
|
|
36
|
+
// stop if we received fewer items than the limit or no items
|
|
37
|
+
if (newTransactions.length < Number(options.limit) || newTransactions.length === 0) {
|
|
38
|
+
hasMorePages = false;
|
|
39
|
+
} else {
|
|
40
|
+
page++;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return transactions;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function getERC20TransactionsForAccount({
|
|
48
|
+
address,
|
|
49
|
+
contractAddresses,
|
|
50
|
+
transactionFetcher = fetchERC20Transactions,
|
|
51
|
+
since,
|
|
52
|
+
}: {
|
|
53
|
+
address: string;
|
|
54
|
+
contractAddresses: string[];
|
|
55
|
+
since?: string | null;
|
|
56
|
+
transactionFetcher?: typeof fetchERC20Transactions; // optional dependency injection for testing
|
|
57
|
+
}): Promise<HederaThirdwebTransaction[]> {
|
|
58
|
+
const allTransactions: HederaThirdwebTransaction[] = [];
|
|
59
|
+
const evmAddress = toEVMAddress(address);
|
|
60
|
+
|
|
61
|
+
if (contractAddresses.length === 0) {
|
|
62
|
+
return allTransactions;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!evmAddress) {
|
|
66
|
+
return allTransactions;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const baseParams = {
|
|
70
|
+
limit: "1000",
|
|
71
|
+
filterTopic0: ERC20_TRANSFER_EVENT_TOPIC,
|
|
72
|
+
...(since && { filterBlockTimestampGte: since }),
|
|
73
|
+
} as const;
|
|
74
|
+
|
|
75
|
+
for (const contractAddress of contractAddresses) {
|
|
76
|
+
const outTransactionOptions: FetchOptions = {
|
|
77
|
+
...baseParams,
|
|
78
|
+
filterTopic1: pad(evmAddress as `0x${string}`).toString(),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const inTransactionOptions: FetchOptions = {
|
|
82
|
+
...baseParams,
|
|
83
|
+
filterTopic2: pad(evmAddress as `0x${string}`).toString(),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const outgoingTxs = await transactionFetcher(contractAddress, outTransactionOptions);
|
|
87
|
+
const incomingTxs = await transactionFetcher(contractAddress, inTransactionOptions);
|
|
88
|
+
|
|
89
|
+
allTransactions.push(...outgoingTxs, ...incomingTxs);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return allTransactions;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Thirdweb API is used in addition to mirror node because:
|
|
96
|
+
// - mirror node has a 1-week range limitation for ERC20 events queries
|
|
97
|
+
// - mirror node has rate limits that we could exceed with ERC20 integration
|
|
98
|
+
export const thirdwebClient = {
|
|
99
|
+
fetchERC20Transactions,
|
|
100
|
+
getERC20TransactionsForAccount,
|
|
101
|
+
};
|
|
@@ -1,175 +1,375 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
createMirrorCoinTransfer("0.0.5678", -100),
|
|
25
|
-
createMirrorCoinTransfer(userAddress, 100),
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const result = parseTransfers(transfers, userAddress);
|
|
29
|
-
|
|
30
|
-
expect(result.type).toBe("IN");
|
|
31
|
-
expect(result.value).toEqual(new BigNumber(100));
|
|
32
|
-
expect(result.senders).toEqual(["0.0.5678"]);
|
|
33
|
-
expect(result.recipients).toEqual([userAddress]);
|
|
2
|
+
import { setupMockCryptoAssetsStore } from "@ledgerhq/cryptoassets/cal-client/test-helpers";
|
|
3
|
+
import { apiClient } from "./api";
|
|
4
|
+
import { getMockedAccount } from "../test/fixtures/account.fixture";
|
|
5
|
+
import { getMockedERC20TokenCurrency } from "../test/fixtures/currency.fixture";
|
|
6
|
+
import {
|
|
7
|
+
createMirrorCoinTransfer,
|
|
8
|
+
createMirrorTokenTransfer,
|
|
9
|
+
} from "../test/fixtures/mirror.fixture";
|
|
10
|
+
import { getMockedThirdwebTransaction } from "../test/fixtures/thirdweb.fixture";
|
|
11
|
+
import type { HederaMirrorCoinTransfer } from "../types";
|
|
12
|
+
import {
|
|
13
|
+
getERC20BalancesForAccount,
|
|
14
|
+
getERC20Operations,
|
|
15
|
+
parseThirdwebTransactionParams,
|
|
16
|
+
parseTransfers,
|
|
17
|
+
} from "./utils";
|
|
18
|
+
|
|
19
|
+
jest.mock("./api");
|
|
20
|
+
|
|
21
|
+
describe("network utils", () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
jest.clearAllMocks();
|
|
34
24
|
});
|
|
35
25
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
26
|
+
describe("parseTransfers", () => {
|
|
27
|
+
it("should correctly identify an incoming transfer", () => {
|
|
28
|
+
const userAddress = "0.0.1234";
|
|
29
|
+
const transfers = [
|
|
30
|
+
createMirrorCoinTransfer("0.0.5678", -100),
|
|
31
|
+
createMirrorCoinTransfer(userAddress, 100),
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const result = parseTransfers(transfers, userAddress);
|
|
35
|
+
|
|
36
|
+
expect(result.type).toBe("IN");
|
|
37
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
38
|
+
expect(result.senders).toEqual(["0.0.5678"]);
|
|
39
|
+
expect(result.recipients).toEqual([userAddress]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should correctly identify an outgoing transfer", () => {
|
|
43
|
+
const userAddress = "0.0.1234";
|
|
44
|
+
const transfers = [
|
|
45
|
+
createMirrorCoinTransfer(userAddress, -100),
|
|
46
|
+
createMirrorCoinTransfer("0.0.5678", 100),
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const result = parseTransfers(transfers, userAddress);
|
|
50
|
+
|
|
51
|
+
expect(result.type).toBe("OUT");
|
|
52
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
53
|
+
expect(result.senders).toEqual([userAddress]);
|
|
54
|
+
expect(result.recipients).toEqual(["0.0.5678"]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should handle multiple senders and recipients", () => {
|
|
58
|
+
const userAddress = "0.0.1234";
|
|
59
|
+
const transfers = [
|
|
60
|
+
createMirrorCoinTransfer("0.0.5678", -50),
|
|
61
|
+
createMirrorCoinTransfer(userAddress, -50),
|
|
62
|
+
createMirrorCoinTransfer("0.0.9999", 100),
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const result = parseTransfers(transfers, userAddress);
|
|
66
|
+
|
|
67
|
+
expect(result.type).toBe("OUT");
|
|
68
|
+
expect(result.value).toEqual(new BigNumber(50));
|
|
69
|
+
expect(result.senders).toEqual(["0.0.1234", "0.0.5678"]);
|
|
70
|
+
expect(result.recipients).toEqual(["0.0.9999"]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should correctly process token transfers", () => {
|
|
74
|
+
const userAddress = "0.0.1234";
|
|
75
|
+
const tokenId = "0.0.7777";
|
|
76
|
+
const transfers = [
|
|
77
|
+
createMirrorTokenTransfer(userAddress, -10, tokenId),
|
|
78
|
+
createMirrorTokenTransfer("0.0.5678", 10, tokenId),
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
const result = parseTransfers(transfers, userAddress);
|
|
82
|
+
|
|
83
|
+
expect(result.type).toBe("OUT");
|
|
84
|
+
expect(result.value).toEqual(new BigNumber(10));
|
|
85
|
+
expect(result.senders).toEqual([userAddress]);
|
|
86
|
+
expect(result.recipients).toEqual(["0.0.5678"]);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should exclude system accounts that are not nodes from recipients", () => {
|
|
90
|
+
const userAddress = "0.0.1234";
|
|
91
|
+
const systemAccount = "0.0.500";
|
|
92
|
+
const transfers = [
|
|
93
|
+
createMirrorCoinTransfer(userAddress, -100),
|
|
94
|
+
createMirrorCoinTransfer(systemAccount, 100),
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const result = parseTransfers(transfers, userAddress);
|
|
98
|
+
|
|
99
|
+
expect(result.type).toBe("OUT");
|
|
100
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
101
|
+
expect(result.senders).toEqual([userAddress]);
|
|
102
|
+
expect(result.recipients).toEqual([]);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("should include node accounts as recipients only if no other recipients", () => {
|
|
106
|
+
const userAddress = "0.0.1234";
|
|
107
|
+
const nodeAccount = "0.0.3";
|
|
108
|
+
const transfers = [
|
|
109
|
+
createMirrorCoinTransfer(userAddress, -100),
|
|
110
|
+
createMirrorCoinTransfer(nodeAccount, 100),
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
const result = parseTransfers(transfers, userAddress);
|
|
114
|
+
|
|
115
|
+
expect(result.type).toBe("OUT");
|
|
116
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
117
|
+
expect(result.senders).toEqual([userAddress]);
|
|
118
|
+
expect(result.recipients).toEqual([nodeAccount]);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should exclude node accounts if there are other recipients", () => {
|
|
122
|
+
const userAddress = "0.0.1234";
|
|
123
|
+
const normalAccount = "0.0.5678";
|
|
124
|
+
const nodeAccount = "0.0.3";
|
|
125
|
+
const transfers = [
|
|
126
|
+
createMirrorCoinTransfer(userAddress, -100),
|
|
127
|
+
createMirrorCoinTransfer(normalAccount, 50),
|
|
128
|
+
createMirrorCoinTransfer(nodeAccount, 50),
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
const result = parseTransfers(transfers, userAddress);
|
|
132
|
+
|
|
133
|
+
expect(result.type).toBe("OUT");
|
|
134
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
135
|
+
expect(result.senders).toEqual([userAddress]);
|
|
136
|
+
expect(result.recipients).toEqual([normalAccount]);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should handle transactions where user is not involved", () => {
|
|
140
|
+
const userAddress = "0.0.1234";
|
|
141
|
+
const transfers = [
|
|
142
|
+
createMirrorCoinTransfer("0.0.5678", -100),
|
|
143
|
+
createMirrorCoinTransfer("0.0.9999", 100),
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
const result = parseTransfers(transfers, userAddress);
|
|
147
|
+
|
|
148
|
+
expect(result.type).toBe("NONE");
|
|
149
|
+
expect(result.value).toEqual(new BigNumber(0));
|
|
150
|
+
expect(result.senders).toEqual(["0.0.5678"]);
|
|
151
|
+
expect(result.recipients).toEqual(["0.0.9999"]);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should handle empty transfers array", () => {
|
|
155
|
+
const userAddress = "0.0.1234";
|
|
156
|
+
const transfers: HederaMirrorCoinTransfer[] = [];
|
|
157
|
+
|
|
158
|
+
const result = parseTransfers(transfers, userAddress);
|
|
159
|
+
|
|
160
|
+
expect(result.type).toBe("NONE");
|
|
161
|
+
expect(result.value).toEqual(new BigNumber(0));
|
|
162
|
+
expect(result.senders).toEqual([]);
|
|
163
|
+
expect(result.recipients).toEqual([]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should reverse the order of senders and recipients", () => {
|
|
167
|
+
const userAddress = "0.0.1234";
|
|
168
|
+
const transfers = [
|
|
169
|
+
createMirrorCoinTransfer("0.0.900", -5),
|
|
170
|
+
createMirrorCoinTransfer("0.0.5678", -95),
|
|
171
|
+
createMirrorCoinTransfer(userAddress, 100),
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
const result = parseTransfers(transfers, userAddress);
|
|
175
|
+
|
|
176
|
+
expect(result.type).toBe("IN");
|
|
177
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
178
|
+
expect(result.senders).toEqual(["0.0.5678", "0.0.900"]);
|
|
179
|
+
expect(result.recipients).toEqual([userAddress]);
|
|
180
|
+
});
|
|
49
181
|
});
|
|
50
182
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
183
|
+
describe("getERC20BalancesForAccount", () => {
|
|
184
|
+
it("returns balances only for supported ERC20 tokens and calls apiClient.getERC20Balance accordingly", async () => {
|
|
185
|
+
const mockAccount = getMockedAccount();
|
|
186
|
+
const mockedSupportedTokenIds = ["0/erc20/0x0", "0/erc20/0x1", "0/erc20/0x2"];
|
|
187
|
+
const erc20Token = getMockedERC20TokenCurrency();
|
|
188
|
+
|
|
189
|
+
const mockedResponse = Array.from({ length: mockedSupportedTokenIds.length }, () => ({
|
|
190
|
+
token: erc20Token,
|
|
191
|
+
balance: new BigNumber(123),
|
|
192
|
+
}));
|
|
193
|
+
|
|
194
|
+
(apiClient.getERC20Balance as jest.Mock).mockResolvedValue(new BigNumber(123));
|
|
195
|
+
setupMockCryptoAssetsStore({
|
|
196
|
+
findTokenById: jest.fn().mockReturnValue(erc20Token),
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const res = await getERC20BalancesForAccount(
|
|
200
|
+
mockAccount.freshAddress,
|
|
201
|
+
mockedSupportedTokenIds,
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
expect(apiClient.getERC20Balance).toHaveBeenCalledTimes(mockedSupportedTokenIds.length);
|
|
205
|
+
expect(apiClient.getERC20Balance).toHaveBeenCalledWith(
|
|
206
|
+
mockAccount.freshAddress,
|
|
207
|
+
erc20Token.contractAddress,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
expect(res).toHaveLength(mockedSupportedTokenIds.length);
|
|
211
|
+
expect(res).toMatchObject(mockedResponse);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("returns empty array when there are no supported ERC20 tokens", async () => {
|
|
215
|
+
const supportedTokenIds: string[] = [];
|
|
216
|
+
const res = await getERC20BalancesForAccount("0xaccount", supportedTokenIds);
|
|
217
|
+
|
|
218
|
+
expect(res).toEqual([]);
|
|
219
|
+
expect(apiClient.getERC20Balance).not.toHaveBeenCalled();
|
|
220
|
+
});
|
|
81
221
|
});
|
|
82
222
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
223
|
+
describe("getERC20Operations", () => {
|
|
224
|
+
beforeEach(() => {
|
|
225
|
+
jest.clearAllMocks();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("should fetch and combine data from thirdweb and mirror node", async () => {
|
|
229
|
+
const mockTokenERC20 = getMockedERC20TokenCurrency();
|
|
230
|
+
const mockThirdwebTransaction = getMockedThirdwebTransaction({
|
|
231
|
+
transactionHash: "0xTXHASH1",
|
|
232
|
+
address: mockTokenERC20.contractAddress,
|
|
233
|
+
decoded: {
|
|
234
|
+
name: "Transfer",
|
|
235
|
+
signature: "Transfer(address,address,uint256)",
|
|
236
|
+
params: {
|
|
237
|
+
from: "0x1234",
|
|
238
|
+
to: "0x5678",
|
|
239
|
+
value: "1000000",
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
const mockContractCallResult = {
|
|
244
|
+
timestamp: "1234567890.000000000",
|
|
245
|
+
contract_id: mockTokenERC20.contractAddress,
|
|
246
|
+
gas_consumed: 50000,
|
|
247
|
+
gas_limit: 100000,
|
|
248
|
+
gas_used: 50000,
|
|
249
|
+
};
|
|
250
|
+
const mockMirrorTransaction = {
|
|
251
|
+
consensus_timestamp: mockContractCallResult.timestamp,
|
|
252
|
+
transaction_hash: "BASE64HASH",
|
|
253
|
+
transaction_id: "0.0.123@1234567890.000",
|
|
254
|
+
charged_tx_fee: 100000,
|
|
255
|
+
memo_base64: "",
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
(apiClient.getContractCallResult as jest.Mock).mockResolvedValue(mockContractCallResult);
|
|
259
|
+
(apiClient.findTransactionByContractCall as jest.Mock).mockResolvedValue(
|
|
260
|
+
mockMirrorTransaction,
|
|
261
|
+
);
|
|
262
|
+
setupMockCryptoAssetsStore({
|
|
263
|
+
findTokenByAddressInCurrency: jest.fn().mockReturnValue(mockTokenERC20),
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const result = await getERC20Operations([mockThirdwebTransaction]);
|
|
267
|
+
|
|
268
|
+
expect(result).toHaveLength(1);
|
|
269
|
+
expect(result).toMatchObject([
|
|
270
|
+
{
|
|
271
|
+
thirdwebTransaction: mockThirdwebTransaction,
|
|
272
|
+
mirrorTransaction: mockMirrorTransaction,
|
|
273
|
+
contractCallResult: mockContractCallResult,
|
|
274
|
+
token: mockTokenERC20,
|
|
275
|
+
},
|
|
276
|
+
]);
|
|
277
|
+
expect(apiClient.getContractCallResult).toHaveBeenCalledTimes(1);
|
|
278
|
+
expect(apiClient.getContractCallResult).toHaveBeenCalledWith(
|
|
279
|
+
mockThirdwebTransaction.transactionHash,
|
|
280
|
+
);
|
|
281
|
+
expect(apiClient.findTransactionByContractCall).toHaveBeenCalledTimes(1);
|
|
282
|
+
expect(apiClient.findTransactionByContractCall).toHaveBeenCalledWith(
|
|
283
|
+
mockContractCallResult.timestamp,
|
|
284
|
+
mockTokenERC20.contractAddress,
|
|
285
|
+
);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it("should skip transactions for tokens not found in currency list", async () => {
|
|
289
|
+
const mockThirdwebTransactions = [
|
|
290
|
+
getMockedThirdwebTransaction({
|
|
291
|
+
transactionHash: "0xTXHASH1",
|
|
292
|
+
address: "unknown",
|
|
293
|
+
}),
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
setupMockCryptoAssetsStore({
|
|
297
|
+
findTokenByAddressInCurrency: jest.fn().mockReturnValue(undefined),
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const result = await getERC20Operations(mockThirdwebTransactions);
|
|
301
|
+
|
|
302
|
+
expect(result).toHaveLength(0);
|
|
303
|
+
expect(apiClient.getContractCallResult).not.toHaveBeenCalled();
|
|
304
|
+
expect(apiClient.findTransactionByContractCall).not.toHaveBeenCalled();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it("should skip transactions when mirror transaction is not found", async () => {
|
|
308
|
+
const mockTokenERC20 = getMockedERC20TokenCurrency();
|
|
309
|
+
const mockThirdwebTransactions = getMockedThirdwebTransaction({
|
|
310
|
+
transactionHash: "0xTXHASH1",
|
|
311
|
+
address: mockTokenERC20.contractAddress,
|
|
312
|
+
});
|
|
313
|
+
const mockContractCallResult = {
|
|
314
|
+
timestamp: "1234567890.000000000",
|
|
315
|
+
contract_id: mockTokenERC20.contractAddress,
|
|
316
|
+
gas_consumed: 50000,
|
|
317
|
+
gas_limit: 100000,
|
|
318
|
+
gas_used: 50000,
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
(apiClient.getContractCallResult as jest.Mock).mockResolvedValue(
|
|
322
|
+
mockContractCallResult as any,
|
|
323
|
+
);
|
|
324
|
+
(apiClient.findTransactionByContractCall as jest.Mock).mockResolvedValue(null);
|
|
325
|
+
setupMockCryptoAssetsStore({
|
|
326
|
+
findTokenByAddressInCurrency: jest.fn().mockReturnValue(mockTokenERC20),
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const result = await getERC20Operations([mockThirdwebTransactions]);
|
|
330
|
+
|
|
331
|
+
expect(result).toHaveLength(0);
|
|
332
|
+
});
|
|
97
333
|
});
|
|
98
334
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
];
|
|
139
|
-
|
|
140
|
-
const result = parseTransfers(transfers, userAddress);
|
|
141
|
-
|
|
142
|
-
expect(result.type).toBe("NONE");
|
|
143
|
-
expect(result.value).toEqual(new BigNumber(0));
|
|
144
|
-
expect(result.senders).toEqual(["0.0.5678"]);
|
|
145
|
-
expect(result.recipients).toEqual(["0.0.9999"]);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it("should handle empty transfers array", () => {
|
|
149
|
-
const userAddress = "0.0.1234";
|
|
150
|
-
const transfers: HederaMirrorCoinTransfer[] = [];
|
|
151
|
-
|
|
152
|
-
const result = parseTransfers(transfers, userAddress);
|
|
153
|
-
|
|
154
|
-
expect(result.type).toBe("NONE");
|
|
155
|
-
expect(result.value).toEqual(new BigNumber(0));
|
|
156
|
-
expect(result.senders).toEqual([]);
|
|
157
|
-
expect(result.recipients).toEqual([]);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it("should reverse the order of senders and recipients", () => {
|
|
161
|
-
const userAddress = "0.0.1234";
|
|
162
|
-
const transfers = [
|
|
163
|
-
createMirrorCoinTransfer("0.0.900", -5),
|
|
164
|
-
createMirrorCoinTransfer("0.0.5678", -95),
|
|
165
|
-
createMirrorCoinTransfer(userAddress, 100),
|
|
166
|
-
];
|
|
167
|
-
|
|
168
|
-
const result = parseTransfers(transfers, userAddress);
|
|
169
|
-
|
|
170
|
-
expect(result.type).toBe("IN");
|
|
171
|
-
expect(result.value).toEqual(new BigNumber(100));
|
|
172
|
-
expect(result.senders).toEqual(["0.0.5678", "0.0.900"]);
|
|
173
|
-
expect(result.recipients).toEqual([userAddress]);
|
|
335
|
+
describe("parseThirdwebTransactionParams", () => {
|
|
336
|
+
it("should parse valid transaction params", () => {
|
|
337
|
+
const mockTransaction = getMockedThirdwebTransaction({
|
|
338
|
+
decoded: {
|
|
339
|
+
name: "",
|
|
340
|
+
signature: "",
|
|
341
|
+
params: {
|
|
342
|
+
from: "0x1234",
|
|
343
|
+
to: "0x5678",
|
|
344
|
+
value: "1000000",
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
const result = parseThirdwebTransactionParams(mockTransaction);
|
|
350
|
+
|
|
351
|
+
expect(result).toEqual({
|
|
352
|
+
from: mockTransaction.decoded.params.from,
|
|
353
|
+
to: mockTransaction.decoded.params.to,
|
|
354
|
+
value: mockTransaction.decoded.params.value,
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it("should return null if params are invalid", () => {
|
|
359
|
+
const mockTransaction = getMockedThirdwebTransaction({
|
|
360
|
+
decoded: {
|
|
361
|
+
name: "",
|
|
362
|
+
signature: "",
|
|
363
|
+
params: {
|
|
364
|
+
from: "0x1234",
|
|
365
|
+
to: 123,
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
const result = parseThirdwebTransactionParams(mockTransaction);
|
|
371
|
+
|
|
372
|
+
expect(result).toBeNull();
|
|
373
|
+
});
|
|
174
374
|
});
|
|
175
375
|
});
|