@ledgerhq/coin-hedera 1.12.1-nightly.1 → 1.13.0-nightly.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/.unimportedrc.json +1 -1
- package/CHANGELOG.md +29 -0
- package/jest.config.js +1 -1
- package/jest.integ.config.js +8 -0
- package/lib/api/index.d.ts +4 -0
- package/lib/api/index.d.ts.map +1 -0
- package/lib/api/index.js +119 -0
- package/lib/api/index.js.map +1 -0
- package/lib/bridge/broadcast.d.ts +1 -1
- package/lib/bridge/broadcast.d.ts.map +1 -1
- package/lib/bridge/broadcast.js +6 -9
- package/lib/bridge/broadcast.js.map +1 -1
- package/lib/bridge/buildOptimisticOperation.d.ts.map +1 -1
- package/lib/bridge/buildOptimisticOperation.js +14 -11
- package/lib/bridge/buildOptimisticOperation.js.map +1 -1
- package/lib/bridge/createTransaction.d.ts +1 -1
- package/lib/bridge/createTransaction.d.ts.map +1 -1
- package/lib/bridge/createTransaction.js +2 -0
- package/lib/bridge/createTransaction.js.map +1 -1
- package/lib/bridge/estimateMaxSpendable.d.ts.map +1 -1
- package/lib/bridge/estimateMaxSpendable.js +2 -2
- package/lib/bridge/estimateMaxSpendable.js.map +1 -1
- package/lib/bridge/getTransactionStatus.d.ts.map +1 -1
- package/lib/bridge/getTransactionStatus.js +11 -10
- package/lib/bridge/getTransactionStatus.js.map +1 -1
- package/lib/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib/bridge/prepareTransaction.js +6 -5
- package/lib/bridge/prepareTransaction.js.map +1 -1
- package/lib/bridge/signOperation.d.ts +1 -1
- package/lib/bridge/signOperation.d.ts.map +1 -1
- package/lib/bridge/signOperation.js +53 -14
- package/lib/bridge/signOperation.js.map +1 -1
- package/lib/bridge/synchronisation.d.ts.map +1 -1
- package/lib/bridge/synchronisation.js +24 -11
- package/lib/bridge/synchronisation.js.map +1 -1
- package/lib/bridge/utils.d.ts +3 -13
- package/lib/bridge/utils.d.ts.map +1 -1
- package/lib/bridge/utils.js +10 -119
- package/lib/bridge/utils.js.map +1 -1
- package/lib/config.d.ts +8 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +9 -0
- package/lib/config.js.map +1 -0
- package/lib/constants.d.ts +11 -8
- package/lib/constants.d.ts.map +1 -1
- package/lib/constants.js +17 -13
- package/lib/constants.js.map +1 -1
- package/lib/deviceTransactionConfig.d.ts +2 -2
- package/lib/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/deviceTransactionConfig.js +4 -4
- package/lib/deviceTransactionConfig.js.map +1 -1
- package/lib/logic/broadcast.d.ts +3 -0
- package/lib/logic/broadcast.d.ts.map +1 -0
- package/lib/logic/broadcast.js +11 -0
- package/lib/logic/broadcast.js.map +1 -0
- package/lib/logic/combine.d.ts +2 -0
- package/lib/logic/combine.d.ts.map +1 -0
- package/lib/logic/combine.js +19 -0
- package/lib/logic/combine.js.map +1 -0
- package/lib/logic/craftTransaction.d.ts +8 -0
- package/lib/logic/craftTransaction.d.ts.map +1 -0
- package/lib/logic/craftTransaction.js +107 -0
- package/lib/logic/craftTransaction.js.map +1 -0
- package/lib/logic/estimateFees.d.ts +5 -0
- package/lib/logic/estimateFees.d.ts.map +1 -0
- package/lib/logic/estimateFees.js +25 -0
- package/lib/logic/estimateFees.js.map +1 -0
- package/lib/logic/getAssetFromToken.d.ts +4 -0
- package/lib/logic/getAssetFromToken.d.ts.map +1 -0
- package/lib/logic/getAssetFromToken.js +14 -0
- package/lib/logic/getAssetFromToken.js.map +1 -0
- package/lib/logic/getBalance.d.ts +4 -0
- package/lib/logic/getBalance.d.ts.map +1 -0
- package/lib/logic/getBalance.js +36 -0
- package/lib/logic/getBalance.js.map +1 -0
- package/lib/logic/getTokenFromAsset.d.ts +4 -0
- package/lib/logic/getTokenFromAsset.d.ts.map +1 -0
- package/lib/logic/getTokenFromAsset.js +13 -0
- package/lib/logic/getTokenFromAsset.js.map +1 -0
- package/lib/logic/index.d.ts +10 -0
- package/lib/logic/index.d.ts.map +1 -0
- package/lib/logic/index.js +22 -0
- package/lib/logic/index.js.map +1 -0
- package/lib/logic/lastBlock.d.ts +12 -0
- package/lib/logic/lastBlock.d.ts.map +1 -0
- package/lib/logic/lastBlock.js +25 -0
- package/lib/logic/lastBlock.js.map +1 -0
- package/lib/logic/listOperations.d.ts +19 -0
- package/lib/logic/listOperations.d.ts.map +1 -0
- package/lib/logic/listOperations.js +179 -0
- package/lib/logic/listOperations.js.map +1 -0
- package/lib/logic/utils.d.ts +55 -0
- package/lib/logic/utils.d.ts.map +1 -0
- package/lib/logic/utils.js +197 -0
- package/lib/logic/utils.js.map +1 -0
- package/lib/network/api.d.ts +24 -0
- package/lib/network/api.d.ts.map +1 -0
- package/lib/network/api.js +119 -0
- package/lib/network/api.js.map +1 -0
- package/lib/network/rpc.d.ts +12 -0
- package/lib/network/rpc.d.ts.map +1 -0
- package/lib/network/rpc.js +22 -0
- package/lib/network/rpc.js.map +1 -0
- package/lib/{api → network}/utils.d.ts +1 -5
- package/lib/network/utils.d.ts.map +1 -0
- package/lib/network/utils.js +52 -0
- package/lib/network/utils.js.map +1 -0
- package/lib/test/bridgeDatasetTest.d.ts.map +1 -1
- package/lib/test/bridgeDatasetTest.js +5 -1
- package/lib/test/bridgeDatasetTest.js.map +1 -1
- package/lib/test/fixtures/account.fixture.d.ts +17 -0
- package/lib/test/fixtures/account.fixture.d.ts.map +1 -1
- package/lib/test/fixtures/account.fixture.js +18 -1
- package/lib/test/fixtures/account.fixture.js.map +1 -1
- package/lib/test/fixtures/currency.fixture.d.ts.map +1 -1
- package/lib/test/fixtures/currency.fixture.js +1 -1
- package/lib/test/fixtures/currency.fixture.js.map +1 -1
- package/lib/test/fixtures/mirror.fixture.d.ts +1 -1
- package/lib/test/fixtures/mirror.fixture.d.ts.map +1 -1
- package/lib/test/fixtures/network.fixture.d.ts +3 -0
- package/lib/test/fixtures/network.fixture.d.ts.map +1 -0
- package/lib/test/fixtures/network.fixture.js +9 -0
- package/lib/test/fixtures/network.fixture.js.map +1 -0
- package/lib/test/fixtures/transaction.fixture.d.ts.map +1 -1
- package/lib/test/fixtures/transaction.fixture.js +3 -0
- package/lib/test/fixtures/transaction.fixture.js.map +1 -1
- package/lib/transaction.d.ts +1 -1
- package/lib/transaction.d.ts.map +1 -1
- package/lib/transaction.js +35 -6
- package/lib/transaction.js.map +1 -1
- package/lib/types/alpaca.d.ts +3 -0
- package/lib/types/alpaca.d.ts.map +1 -0
- package/lib/{api/types.js → types/alpaca.js} +1 -1
- package/lib/types/alpaca.js.map +1 -0
- package/lib/types/bridge.d.ts +28 -9
- 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/{api/types.d.ts → types/mirror.d.ts} +21 -2
- package/lib/types/mirror.d.ts.map +1 -0
- package/lib/types/mirror.js +3 -0
- package/lib/types/mirror.js.map +1 -0
- package/lib-es/api/index.d.ts +4 -0
- package/lib-es/api/index.d.ts.map +1 -0
- package/lib-es/api/index.js +112 -0
- package/lib-es/api/index.js.map +1 -0
- package/lib-es/bridge/broadcast.d.ts +1 -1
- package/lib-es/bridge/broadcast.d.ts.map +1 -1
- package/lib-es/bridge/broadcast.js +4 -7
- 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 +12 -9
- package/lib-es/bridge/buildOptimisticOperation.js.map +1 -1
- package/lib-es/bridge/createTransaction.d.ts +1 -1
- package/lib-es/bridge/createTransaction.d.ts.map +1 -1
- package/lib-es/bridge/createTransaction.js +2 -0
- package/lib-es/bridge/createTransaction.js.map +1 -1
- package/lib-es/bridge/estimateMaxSpendable.d.ts.map +1 -1
- package/lib-es/bridge/estimateMaxSpendable.js +2 -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 +7 -6
- package/lib-es/bridge/getTransactionStatus.js.map +1 -1
- package/lib-es/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib-es/bridge/prepareTransaction.js +4 -3
- package/lib-es/bridge/prepareTransaction.js.map +1 -1
- package/lib-es/bridge/signOperation.d.ts +1 -1
- package/lib-es/bridge/signOperation.d.ts.map +1 -1
- package/lib-es/bridge/signOperation.js +53 -14
- package/lib-es/bridge/signOperation.js.map +1 -1
- package/lib-es/bridge/synchronisation.d.ts.map +1 -1
- package/lib-es/bridge/synchronisation.js +24 -11
- package/lib-es/bridge/synchronisation.js.map +1 -1
- package/lib-es/bridge/utils.d.ts +3 -13
- package/lib-es/bridge/utils.d.ts.map +1 -1
- package/lib-es/bridge/utils.js +7 -113
- package/lib-es/bridge/utils.js.map +1 -1
- package/lib-es/config.d.ts +8 -0
- package/lib-es/config.d.ts.map +1 -0
- package/lib-es/config.js +4 -0
- package/lib-es/config.js.map +1 -0
- package/lib-es/constants.d.ts +11 -8
- package/lib-es/constants.d.ts.map +1 -1
- package/lib-es/constants.js +13 -9
- package/lib-es/constants.js.map +1 -1
- package/lib-es/deviceTransactionConfig.d.ts +2 -2
- package/lib-es/deviceTransactionConfig.d.ts.map +1 -1
- package/lib-es/deviceTransactionConfig.js +2 -2
- package/lib-es/deviceTransactionConfig.js.map +1 -1
- package/lib-es/logic/broadcast.d.ts +3 -0
- package/lib-es/logic/broadcast.d.ts.map +1 -0
- package/lib-es/logic/broadcast.js +7 -0
- package/lib-es/logic/broadcast.js.map +1 -0
- package/lib-es/logic/combine.d.ts +2 -0
- package/lib-es/logic/combine.d.ts.map +1 -0
- package/lib-es/logic/combine.js +12 -0
- package/lib-es/logic/combine.js.map +1 -0
- package/lib-es/logic/craftTransaction.d.ts +8 -0
- package/lib-es/logic/craftTransaction.d.ts.map +1 -0
- package/lib-es/logic/craftTransaction.js +100 -0
- package/lib-es/logic/craftTransaction.js.map +1 -0
- package/lib-es/logic/estimateFees.d.ts +5 -0
- package/lib-es/logic/estimateFees.d.ts.map +1 -0
- package/lib-es/logic/estimateFees.js +18 -0
- package/lib-es/logic/estimateFees.js.map +1 -0
- package/lib-es/logic/getAssetFromToken.d.ts +4 -0
- package/lib-es/logic/getAssetFromToken.d.ts.map +1 -0
- package/lib-es/logic/getAssetFromToken.js +10 -0
- package/lib-es/logic/getAssetFromToken.js.map +1 -0
- package/lib-es/logic/getBalance.d.ts +4 -0
- package/lib-es/logic/getBalance.d.ts.map +1 -0
- package/lib-es/logic/getBalance.js +32 -0
- package/lib-es/logic/getBalance.js.map +1 -0
- package/lib-es/logic/getTokenFromAsset.d.ts +4 -0
- package/lib-es/logic/getTokenFromAsset.d.ts.map +1 -0
- package/lib-es/logic/getTokenFromAsset.js +9 -0
- package/lib-es/logic/getTokenFromAsset.js.map +1 -0
- package/lib-es/logic/index.d.ts +10 -0
- package/lib-es/logic/index.d.ts.map +1 -0
- package/lib-es/logic/index.js +10 -0
- package/lib-es/logic/index.js.map +1 -0
- package/lib-es/logic/lastBlock.d.ts +12 -0
- package/lib-es/logic/lastBlock.d.ts.map +1 -0
- package/lib-es/logic/lastBlock.js +21 -0
- package/lib-es/logic/lastBlock.js.map +1 -0
- package/lib-es/logic/listOperations.d.ts +19 -0
- package/lib-es/logic/listOperations.d.ts.map +1 -0
- package/lib-es/logic/listOperations.js +172 -0
- package/lib-es/logic/listOperations.js.map +1 -0
- package/lib-es/logic/utils.d.ts +55 -0
- package/lib-es/logic/utils.d.ts.map +1 -0
- package/lib-es/logic/utils.js +174 -0
- package/lib-es/logic/utils.js.map +1 -0
- package/lib-es/network/api.d.ts +24 -0
- package/lib-es/network/api.d.ts.map +1 -0
- package/lib-es/network/api.js +113 -0
- package/lib-es/network/api.js.map +1 -0
- package/lib-es/network/rpc.d.ts +12 -0
- package/lib-es/network/rpc.d.ts.map +1 -0
- package/lib-es/network/rpc.js +19 -0
- package/lib-es/network/rpc.js.map +1 -0
- package/lib-es/{api → network}/utils.d.ts +1 -5
- package/lib-es/network/utils.d.ts.map +1 -0
- package/lib-es/network/utils.js +45 -0
- package/lib-es/network/utils.js.map +1 -0
- package/lib-es/test/bridgeDatasetTest.d.ts.map +1 -1
- package/lib-es/test/bridgeDatasetTest.js +5 -1
- package/lib-es/test/bridgeDatasetTest.js.map +1 -1
- package/lib-es/test/fixtures/account.fixture.d.ts +17 -0
- package/lib-es/test/fixtures/account.fixture.d.ts.map +1 -1
- package/lib-es/test/fixtures/account.fixture.js +17 -0
- package/lib-es/test/fixtures/account.fixture.js.map +1 -1
- package/lib-es/test/fixtures/currency.fixture.d.ts.map +1 -1
- package/lib-es/test/fixtures/currency.fixture.js +1 -1
- package/lib-es/test/fixtures/currency.fixture.js.map +1 -1
- package/lib-es/test/fixtures/mirror.fixture.d.ts +1 -1
- package/lib-es/test/fixtures/mirror.fixture.d.ts.map +1 -1
- package/lib-es/test/fixtures/network.fixture.d.ts +3 -0
- package/lib-es/test/fixtures/network.fixture.d.ts.map +1 -0
- package/lib-es/test/fixtures/network.fixture.js +5 -0
- package/lib-es/test/fixtures/network.fixture.js.map +1 -0
- package/lib-es/test/fixtures/transaction.fixture.d.ts.map +1 -1
- package/lib-es/test/fixtures/transaction.fixture.js +3 -0
- package/lib-es/test/fixtures/transaction.fixture.js.map +1 -1
- package/lib-es/transaction.d.ts +1 -1
- package/lib-es/transaction.d.ts.map +1 -1
- package/lib-es/transaction.js +35 -6
- package/lib-es/transaction.js.map +1 -1
- package/lib-es/types/alpaca.d.ts +3 -0
- package/lib-es/types/alpaca.d.ts.map +1 -0
- package/lib-es/types/alpaca.js +2 -0
- package/lib-es/types/alpaca.js.map +1 -0
- package/lib-es/types/bridge.d.ts +28 -9
- 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/{api/types.d.ts → types/mirror.d.ts} +21 -2
- package/lib-es/types/mirror.d.ts.map +1 -0
- package/lib-es/types/mirror.js +2 -0
- package/lib-es/types/mirror.js.map +1 -0
- package/package.json +8 -7
- package/src/api/index.integ.test.ts +401 -0
- package/src/api/index.test.ts +30 -0
- package/src/api/index.ts +149 -0
- package/src/bridge/broadcast.ts +5 -10
- package/src/bridge/buildOptimisticOperation.integration.test.ts +8 -8
- package/src/bridge/buildOptimisticOperation.ts +13 -10
- package/src/bridge/createTransaction.ts +3 -1
- package/src/bridge/estimateMaxSpendable.ts +6 -3
- package/src/bridge/getTransactionStatus.test.ts +11 -10
- package/src/bridge/getTransactionStatus.ts +12 -11
- package/src/bridge/js-estimateMaxSpendable.integration.test.ts +6 -3
- package/src/bridge/prepareTransaction.test.ts +9 -17
- package/src/bridge/prepareTransaction.ts +5 -4
- package/src/bridge/serialization.test.ts +6 -6
- package/src/bridge/signOperation.ts +69 -16
- package/src/bridge/synchronisation.ts +22 -14
- package/src/bridge/utils.integration.test.ts +19 -248
- package/src/bridge/utils.ts +14 -160
- package/src/config.ts +7 -0
- package/src/constants.ts +15 -9
- package/src/deviceTransactionConfig.ts +4 -4
- package/src/logic/broadcast.test.ts +58 -0
- package/src/logic/broadcast.ts +8 -0
- package/src/logic/combine.test.ts +119 -0
- package/src/logic/combine.ts +14 -0
- package/src/logic/craftTransaction.test.ts +215 -0
- package/src/logic/craftTransaction.ts +175 -0
- package/src/logic/estimateFees.test.ts +99 -0
- package/src/logic/estimateFees.ts +28 -0
- package/src/logic/getAssetFromToken.test.ts +27 -0
- package/src/logic/getAssetFromToken.ts +12 -0
- package/src/logic/getBalance.test.ts +200 -0
- package/src/logic/getBalance.ts +39 -0
- package/src/logic/getTokenFromAsset.test.ts +22 -0
- package/src/logic/getTokenFromAsset.ts +17 -0
- package/src/logic/index.ts +9 -0
- package/src/logic/lastBlock.test.ts +23 -0
- package/src/logic/lastBlock.ts +23 -0
- package/src/logic/listOperations.test.ts +388 -0
- package/src/logic/listOperations.ts +247 -0
- package/src/logic/utils.test.ts +432 -0
- package/src/logic/utils.ts +255 -0
- package/src/{api/mirror.test.ts → network/api.test.ts} +81 -35
- package/src/network/api.ts +159 -0
- package/src/network/rpc.test.ts +68 -0
- package/src/network/rpc.ts +25 -0
- package/src/network/utils.test.ts +175 -0
- package/src/network/utils.ts +58 -0
- package/src/test/bridgeDatasetTest.ts +6 -2
- package/src/test/fixtures/account.fixture.ts +18 -0
- package/src/test/fixtures/currency.fixture.ts +1 -1
- package/src/test/fixtures/mirror.fixture.ts +1 -1
- package/src/test/fixtures/network.fixture.ts +6 -0
- package/src/test/fixtures/transaction.fixture.ts +5 -2
- package/src/transaction.ts +40 -9
- package/src/types/alpaca.ts +3 -0
- package/src/types/bridge.ts +36 -10
- package/src/types/index.ts +2 -0
- package/src/{api/types.ts → types/mirror.ts} +23 -1
- package/lib/api/mirror.d.ts +0 -6
- package/lib/api/mirror.d.ts.map +0 -1
- package/lib/api/mirror.js +0 -84
- package/lib/api/mirror.js.map +0 -1
- package/lib/api/network.d.ts +0 -11
- package/lib/api/network.d.ts.map +0 -1
- package/lib/api/network.js +0 -80
- package/lib/api/network.js.map +0 -1
- package/lib/api/types.d.ts.map +0 -1
- package/lib/api/types.js.map +0 -1
- package/lib/api/utils.d.ts.map +0 -1
- package/lib/api/utils.js +0 -132
- package/lib/api/utils.js.map +0 -1
- package/lib/logic.d.ts +0 -11
- package/lib/logic.d.ts.map +0 -1
- package/lib/logic.js +0 -37
- package/lib/logic.js.map +0 -1
- package/lib-es/api/mirror.d.ts +0 -6
- package/lib-es/api/mirror.d.ts.map +0 -1
- package/lib-es/api/mirror.js +0 -74
- package/lib-es/api/mirror.js.map +0 -1
- package/lib-es/api/network.d.ts +0 -11
- package/lib-es/api/network.d.ts.map +0 -1
- package/lib-es/api/network.js +0 -71
- package/lib-es/api/network.js.map +0 -1
- package/lib-es/api/types.d.ts.map +0 -1
- package/lib-es/api/types.js +0 -2
- package/lib-es/api/types.js.map +0 -1
- package/lib-es/api/utils.d.ts.map +0 -1
- package/lib-es/api/utils.js +0 -124
- package/lib-es/api/utils.js.map +0 -1
- package/lib-es/logic.d.ts +0 -11
- package/lib-es/logic.d.ts.map +0 -1
- package/lib-es/logic.js +0 -29
- package/lib-es/logic.js.map +0 -1
- package/src/api/mirror.ts +0 -91
- package/src/api/network.test.ts +0 -49
- package/src/api/network.ts +0 -125
- package/src/api/utils.ts +0 -150
- package/src/logic.test.ts +0 -152
- package/src/logic.ts +0 -66
|
@@ -1,30 +1,25 @@
|
|
|
1
|
-
import network from "@ledgerhq/live-network
|
|
2
|
-
import {
|
|
1
|
+
import network from "@ledgerhq/live-network";
|
|
2
|
+
import { apiClient } from "./api";
|
|
3
|
+
import { getMockResponse } from "../test/fixtures/network.fixture";
|
|
3
4
|
|
|
4
|
-
jest.mock("@ledgerhq/live-network
|
|
5
|
+
jest.mock("@ledgerhq/live-network");
|
|
5
6
|
const mockedNetwork = jest.mocked(network);
|
|
6
7
|
|
|
7
|
-
const makeMockResponse = (data: any): Awaited<ReturnType<typeof network>> => ({
|
|
8
|
-
data,
|
|
9
|
-
status: 200,
|
|
10
|
-
statusText: "OK",
|
|
11
|
-
headers: {},
|
|
12
|
-
config: {
|
|
13
|
-
headers: {} as any,
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
|
|
17
8
|
describe("getAccountTransactions", () => {
|
|
18
9
|
beforeEach(() => {
|
|
19
|
-
jest.
|
|
10
|
+
jest.resetAllMocks();
|
|
20
11
|
});
|
|
21
12
|
|
|
22
13
|
test("should include 'account.id', 'limit=100' and 'order=desc' query params", async () => {
|
|
23
14
|
mockedNetwork.mockResolvedValueOnce(
|
|
24
|
-
|
|
15
|
+
getMockResponse({ transactions: [], links: { next: null } }),
|
|
25
16
|
);
|
|
26
17
|
|
|
27
|
-
await getAccountTransactions(
|
|
18
|
+
await apiClient.getAccountTransactions({
|
|
19
|
+
address: "0.0.1234",
|
|
20
|
+
pagingToken: null,
|
|
21
|
+
fetchAllPages: true,
|
|
22
|
+
});
|
|
28
23
|
|
|
29
24
|
const requestUrl = mockedNetwork.mock.calls[0][0].url;
|
|
30
25
|
expect(requestUrl).toContain("account.id=0.0.1234");
|
|
@@ -32,55 +27,106 @@ describe("getAccountTransactions", () => {
|
|
|
32
27
|
expect(requestUrl).toContain("order=desc");
|
|
33
28
|
});
|
|
34
29
|
|
|
35
|
-
test("should keep fetching if links.next is present", async () => {
|
|
30
|
+
test("should keep fetching if fetchAllPages is set and links.next is present", async () => {
|
|
36
31
|
mockedNetwork
|
|
37
32
|
.mockResolvedValueOnce(
|
|
38
|
-
|
|
33
|
+
getMockResponse({
|
|
39
34
|
transactions: [{ consensus_timestamp: "1" }],
|
|
40
35
|
links: { next: "/next-1" },
|
|
41
36
|
}),
|
|
42
37
|
)
|
|
43
38
|
.mockResolvedValueOnce(
|
|
44
|
-
|
|
39
|
+
getMockResponse({
|
|
45
40
|
transactions: [],
|
|
46
41
|
links: { next: "/next-2" },
|
|
47
42
|
}),
|
|
48
43
|
)
|
|
49
44
|
.mockResolvedValueOnce(
|
|
50
|
-
|
|
45
|
+
getMockResponse({
|
|
51
46
|
transactions: [{ consensus_timestamp: "3" }],
|
|
52
47
|
links: { next: "/next-3" },
|
|
53
48
|
}),
|
|
54
49
|
)
|
|
55
50
|
.mockResolvedValueOnce(
|
|
56
|
-
|
|
57
|
-
transactions: [],
|
|
51
|
+
getMockResponse({
|
|
52
|
+
transactions: [{ consensus_timestamp: "4" }],
|
|
58
53
|
links: { next: "/next-4" },
|
|
59
54
|
}),
|
|
60
55
|
)
|
|
61
56
|
.mockResolvedValueOnce(
|
|
62
|
-
|
|
57
|
+
getMockResponse({
|
|
63
58
|
transactions: [],
|
|
64
59
|
links: { next: null },
|
|
65
60
|
}),
|
|
66
61
|
);
|
|
67
62
|
|
|
68
|
-
const result = await getAccountTransactions(
|
|
63
|
+
const result = await apiClient.getAccountTransactions({
|
|
64
|
+
address: "0.0.1234",
|
|
65
|
+
pagingToken: null,
|
|
66
|
+
fetchAllPages: true,
|
|
67
|
+
});
|
|
69
68
|
|
|
70
|
-
expect(result).toHaveLength(
|
|
71
|
-
expect(result.map(tx => tx.consensus_timestamp)).toEqual(["1", "3"]);
|
|
69
|
+
expect(result.transactions).toHaveLength(3);
|
|
70
|
+
expect(result.transactions.map(tx => tx.consensus_timestamp)).toEqual(["1", "3", "4"]);
|
|
71
|
+
expect(result.nextCursor).toBeNull();
|
|
72
72
|
expect(mockedNetwork).toHaveBeenCalledTimes(5);
|
|
73
73
|
});
|
|
74
|
+
|
|
75
|
+
test("should paginate if fetchAllPages is not set", async () => {
|
|
76
|
+
mockedNetwork
|
|
77
|
+
.mockResolvedValueOnce(
|
|
78
|
+
getMockResponse({
|
|
79
|
+
transactions: [{ consensus_timestamp: "1" }],
|
|
80
|
+
links: { next: "/next-1" },
|
|
81
|
+
}),
|
|
82
|
+
)
|
|
83
|
+
.mockResolvedValueOnce(
|
|
84
|
+
getMockResponse({
|
|
85
|
+
transactions: [],
|
|
86
|
+
links: { next: "/next-2" },
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
.mockResolvedValueOnce(
|
|
90
|
+
getMockResponse({
|
|
91
|
+
transactions: [{ consensus_timestamp: "3" }],
|
|
92
|
+
links: { next: "/next-3" },
|
|
93
|
+
}),
|
|
94
|
+
)
|
|
95
|
+
.mockResolvedValueOnce(
|
|
96
|
+
getMockResponse({
|
|
97
|
+
transactions: [{ consensus_timestamp: "4" }],
|
|
98
|
+
links: { next: "/next-4" },
|
|
99
|
+
}),
|
|
100
|
+
)
|
|
101
|
+
.mockResolvedValueOnce(
|
|
102
|
+
getMockResponse({
|
|
103
|
+
transactions: [],
|
|
104
|
+
links: { next: null },
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const result = await apiClient.getAccountTransactions({
|
|
109
|
+
address: "0.0.1234",
|
|
110
|
+
pagingToken: null,
|
|
111
|
+
limit: 2,
|
|
112
|
+
fetchAllPages: false,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(result.transactions).toHaveLength(2);
|
|
116
|
+
expect(result.transactions.map(tx => tx.consensus_timestamp)).toEqual(["1", "3"]);
|
|
117
|
+
expect(result.nextCursor).toBe("3");
|
|
118
|
+
expect(mockedNetwork).toHaveBeenCalledTimes(3);
|
|
119
|
+
});
|
|
74
120
|
});
|
|
75
121
|
|
|
76
122
|
describe("getAccount", () => {
|
|
77
123
|
beforeEach(() => {
|
|
78
|
-
jest.
|
|
124
|
+
jest.resetAllMocks();
|
|
79
125
|
});
|
|
80
126
|
|
|
81
127
|
it("should call the correct endpoint and return account data", async () => {
|
|
82
128
|
mockedNetwork.mockResolvedValueOnce(
|
|
83
|
-
|
|
129
|
+
getMockResponse({
|
|
84
130
|
account: "0.0.1234",
|
|
85
131
|
max_automatic_token_associations: 0,
|
|
86
132
|
balance: {
|
|
@@ -91,7 +137,7 @@ describe("getAccount", () => {
|
|
|
91
137
|
}),
|
|
92
138
|
);
|
|
93
139
|
|
|
94
|
-
const result = await getAccount("0.0.1234");
|
|
140
|
+
const result = await apiClient.getAccount("0.0.1234");
|
|
95
141
|
const requestUrl = mockedNetwork.mock.calls[0][0].url;
|
|
96
142
|
|
|
97
143
|
expect(result.account).toEqual("0.0.1234");
|
|
@@ -102,12 +148,12 @@ describe("getAccount", () => {
|
|
|
102
148
|
|
|
103
149
|
describe("getAccountTokens", () => {
|
|
104
150
|
beforeEach(() => {
|
|
105
|
-
jest.
|
|
151
|
+
jest.resetAllMocks();
|
|
106
152
|
});
|
|
107
153
|
|
|
108
154
|
it("should return all tokens if only one page is needed", async () => {
|
|
109
155
|
mockedNetwork.mockResolvedValueOnce(
|
|
110
|
-
|
|
156
|
+
getMockResponse({
|
|
111
157
|
tokens: [
|
|
112
158
|
{ token_id: "0.0.1001", balance: 10 },
|
|
113
159
|
{ token_id: "0.0.1002", balance: 20 },
|
|
@@ -116,7 +162,7 @@ describe("getAccountTokens", () => {
|
|
|
116
162
|
}),
|
|
117
163
|
);
|
|
118
164
|
|
|
119
|
-
const result = await getAccountTokens("0.0.1234");
|
|
165
|
+
const result = await apiClient.getAccountTokens("0.0.1234");
|
|
120
166
|
const requestUrl = mockedNetwork.mock.calls[0][0].url;
|
|
121
167
|
|
|
122
168
|
expect(result.map(t => t.token_id)).toEqual(["0.0.1001", "0.0.1002"]);
|
|
@@ -128,19 +174,19 @@ describe("getAccountTokens", () => {
|
|
|
128
174
|
it("should keep fetching if links.next is present and new tokens are returned", async () => {
|
|
129
175
|
mockedNetwork
|
|
130
176
|
.mockResolvedValueOnce(
|
|
131
|
-
|
|
177
|
+
getMockResponse({
|
|
132
178
|
tokens: [{ token_id: "0.0.1001", balance: 10 }],
|
|
133
179
|
links: { next: "/next-1" },
|
|
134
180
|
}),
|
|
135
181
|
)
|
|
136
182
|
.mockResolvedValueOnce(
|
|
137
|
-
|
|
183
|
+
getMockResponse({
|
|
138
184
|
tokens: [{ token_id: "0.0.1002", balance: 20 }],
|
|
139
185
|
links: { next: null },
|
|
140
186
|
}),
|
|
141
187
|
);
|
|
142
188
|
|
|
143
|
-
const result = await getAccountTokens("0.0.1234");
|
|
189
|
+
const result = await apiClient.getAccountTokens("0.0.1234");
|
|
144
190
|
|
|
145
191
|
expect(result.map(t => t.token_id)).toEqual(["0.0.1001", "0.0.1002"]);
|
|
146
192
|
expect(mockedNetwork).toHaveBeenCalledTimes(2);
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import network from "@ledgerhq/live-network";
|
|
2
|
+
import type { LiveNetworkResponse } from "@ledgerhq/live-network/network";
|
|
3
|
+
import { getEnv } from "@ledgerhq/live-env";
|
|
4
|
+
import { LedgerAPI4xx } from "@ledgerhq/errors";
|
|
5
|
+
import { HederaAddAccountError } from "../errors";
|
|
6
|
+
import type {
|
|
7
|
+
HederaMirrorAccountTokensResponse,
|
|
8
|
+
HederaMirrorTransactionsResponse,
|
|
9
|
+
HederaMirrorAccount,
|
|
10
|
+
HederaMirrorAccountsResponse,
|
|
11
|
+
HederaMirrorToken,
|
|
12
|
+
HederaMirrorTransaction,
|
|
13
|
+
} from "../types";
|
|
14
|
+
|
|
15
|
+
const getMirrorApiUrl = (): string => getEnv("API_HEDERA_MIRROR");
|
|
16
|
+
|
|
17
|
+
const fetch = <Result>(path: string) => {
|
|
18
|
+
return network<Result>({
|
|
19
|
+
method: "GET",
|
|
20
|
+
url: `${getMirrorApiUrl()}${path}`,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
async function getAccountsForPublicKey(publicKey: string): Promise<HederaMirrorAccount[]> {
|
|
25
|
+
let res;
|
|
26
|
+
try {
|
|
27
|
+
res = await fetch<HederaMirrorAccountsResponse>(
|
|
28
|
+
`/api/v1/accounts?account.publicKey=${publicKey}&balance=true&limit=100`,
|
|
29
|
+
);
|
|
30
|
+
} catch (e: unknown) {
|
|
31
|
+
if (e instanceof LedgerAPI4xx) return [];
|
|
32
|
+
throw e;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const accounts = res.data.accounts;
|
|
36
|
+
|
|
37
|
+
return accounts;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function getAccount(address: string): Promise<HederaMirrorAccount> {
|
|
41
|
+
try {
|
|
42
|
+
const res = await fetch<HederaMirrorAccount>(`/api/v1/accounts/${address}`);
|
|
43
|
+
const account = res.data;
|
|
44
|
+
|
|
45
|
+
return account;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error instanceof LedgerAPI4xx && "status" in error && error.status === 404) {
|
|
48
|
+
throw new HederaAddAccountError();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function getAccountTransactions({
|
|
56
|
+
address,
|
|
57
|
+
pagingToken,
|
|
58
|
+
limit = 100,
|
|
59
|
+
order = "desc",
|
|
60
|
+
fetchAllPages,
|
|
61
|
+
}: {
|
|
62
|
+
address: string;
|
|
63
|
+
pagingToken: string | null;
|
|
64
|
+
limit?: number | undefined;
|
|
65
|
+
order?: "asc" | "desc" | undefined;
|
|
66
|
+
fetchAllPages: boolean;
|
|
67
|
+
}): Promise<{ transactions: HederaMirrorTransaction[]; nextCursor: string | null }> {
|
|
68
|
+
const transactions: HederaMirrorTransaction[] = [];
|
|
69
|
+
const params = new URLSearchParams({
|
|
70
|
+
"account.id": address,
|
|
71
|
+
limit: limit.toString(),
|
|
72
|
+
order,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// keeps old behavior when all pages are fetched
|
|
76
|
+
const getTimestampDirection = () => {
|
|
77
|
+
if (fetchAllPages) return "gt";
|
|
78
|
+
return order === "asc" ? "gt" : "lt";
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (pagingToken) {
|
|
82
|
+
params.append("timestamp", `${getTimestampDirection()}:${pagingToken}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let nextCursor: string | null = null;
|
|
86
|
+
let nextUrl: string | null = `/api/v1/transactions?${params.toString()}`;
|
|
87
|
+
|
|
88
|
+
// WARNING: don't break the loop when `transactions` array is empty but `links.next` is present
|
|
89
|
+
// the mirror node API enforces a 60-day max time range per query, even if `timestamp` param is set
|
|
90
|
+
// see: https://hedera.com/blog/changes-to-the-hedera-operated-mirror-node
|
|
91
|
+
while (nextUrl) {
|
|
92
|
+
const res: LiveNetworkResponse<HederaMirrorTransactionsResponse> = await fetch(nextUrl);
|
|
93
|
+
const newTransactions = res.data.transactions;
|
|
94
|
+
transactions.push(...newTransactions);
|
|
95
|
+
nextUrl = res.data.links.next;
|
|
96
|
+
|
|
97
|
+
// stop fetching if pagination mode is used and we reached the limit
|
|
98
|
+
if (!fetchAllPages && transactions.length >= limit) {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ensure we don't exceed the limit in pagination mode
|
|
104
|
+
if (!fetchAllPages && transactions.length > limit) {
|
|
105
|
+
transactions.splice(limit);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// set the next cursor only if we have more transactions to fetch
|
|
109
|
+
if (!fetchAllPages && nextUrl) {
|
|
110
|
+
const lastTx = transactions.at(-1);
|
|
111
|
+
nextCursor = lastTx?.consensus_timestamp ?? null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { transactions, nextCursor };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function getAccountTokens(address: string): Promise<HederaMirrorToken[]> {
|
|
118
|
+
const tokens: HederaMirrorToken[] = [];
|
|
119
|
+
const params = new URLSearchParams({
|
|
120
|
+
limit: "100",
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
let nextUrl: string | null = `/api/v1/accounts/${address}/tokens?${params.toString()}`;
|
|
124
|
+
|
|
125
|
+
while (nextUrl) {
|
|
126
|
+
const res: LiveNetworkResponse<HederaMirrorAccountTokensResponse> = await fetch(nextUrl);
|
|
127
|
+
const newTokens = res.data.tokens;
|
|
128
|
+
tokens.push(...newTokens);
|
|
129
|
+
nextUrl = res.data.links.next;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return tokens;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function getLatestTransaction(): Promise<HederaMirrorTransaction> {
|
|
136
|
+
const params = new URLSearchParams({
|
|
137
|
+
limit: "1",
|
|
138
|
+
order: "desc",
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const res = await fetch<HederaMirrorTransactionsResponse>(
|
|
142
|
+
`/api/v1/transactions?${params.toString()}`,
|
|
143
|
+
);
|
|
144
|
+
const transaction = res.data.transactions[0];
|
|
145
|
+
|
|
146
|
+
if (!transaction) {
|
|
147
|
+
throw new Error("No transactions found on the Hedera network");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return transaction;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export const apiClient = {
|
|
154
|
+
getAccountsForPublicKey,
|
|
155
|
+
getAccount,
|
|
156
|
+
getAccountTokens,
|
|
157
|
+
getAccountTransactions,
|
|
158
|
+
getLatestTransaction,
|
|
159
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Client, Transaction, TransactionResponse } from "@hashgraph/sdk";
|
|
2
|
+
import { rpcClient } from "./rpc";
|
|
3
|
+
|
|
4
|
+
const mockClient = {
|
|
5
|
+
setMaxNodesPerTransaction: jest.fn().mockReturnThis(),
|
|
6
|
+
setNetwork: jest.fn().mockReturnThis(),
|
|
7
|
+
} as unknown as Client;
|
|
8
|
+
|
|
9
|
+
jest.mock("@hashgraph/sdk", () => {
|
|
10
|
+
return {
|
|
11
|
+
Transaction: jest.fn(),
|
|
12
|
+
Client: {
|
|
13
|
+
forMainnet: jest.fn(() => mockClient),
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("getInstance", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
jest.clearAllMocks();
|
|
21
|
+
rpcClient._resetInstance();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("returns cached client instance for multiple calls", () => {
|
|
25
|
+
const client1 = rpcClient.getInstance();
|
|
26
|
+
const client2 = rpcClient.getInstance();
|
|
27
|
+
|
|
28
|
+
expect(Client.forMainnet).toHaveBeenCalledTimes(1);
|
|
29
|
+
expect(client1).toBe(mockClient);
|
|
30
|
+
expect(client2).toBe(client1);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("broadcastTransaction", () => {
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
jest.clearAllMocks();
|
|
37
|
+
rpcClient._resetInstance();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("executes the transaction using the client", async () => {
|
|
41
|
+
const expectedResponse = { transactionId: "test-tx-id" } as unknown as TransactionResponse;
|
|
42
|
+
const mockedExecute = jest.fn().mockResolvedValue(expectedResponse);
|
|
43
|
+
const mockTransaction = { execute: mockedExecute } as unknown as Transaction;
|
|
44
|
+
|
|
45
|
+
const response = await rpcClient.broadcastTransaction(mockTransaction);
|
|
46
|
+
|
|
47
|
+
expect(mockedExecute).toHaveBeenCalledTimes(1);
|
|
48
|
+
expect(mockedExecute).toHaveBeenCalledWith(mockClient);
|
|
49
|
+
expect(response).toBe(expectedResponse);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("reuses the same client instance for multiple calls", async () => {
|
|
53
|
+
const mockedExecute1 = jest.fn();
|
|
54
|
+
const mockedExecute2 = jest.fn();
|
|
55
|
+
|
|
56
|
+
const mockTransaction1 = { execute: mockedExecute1 } as unknown as Transaction;
|
|
57
|
+
const mockTransaction2 = { execute: mockedExecute2 } as unknown as Transaction;
|
|
58
|
+
|
|
59
|
+
await rpcClient.broadcastTransaction(mockTransaction1);
|
|
60
|
+
await rpcClient.broadcastTransaction(mockTransaction2);
|
|
61
|
+
|
|
62
|
+
expect(Client.forMainnet).toHaveBeenCalledTimes(1);
|
|
63
|
+
expect(mockedExecute1).toHaveBeenCalledTimes(1);
|
|
64
|
+
expect(mockedExecute2).toHaveBeenCalledTimes(1);
|
|
65
|
+
expect(mockedExecute1).toHaveBeenCalledWith(mockClient);
|
|
66
|
+
expect(mockedExecute2).toHaveBeenCalledWith(mockClient);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Transaction as HederaTransaction, TransactionResponse } from "@hashgraph/sdk";
|
|
2
|
+
import { Client } from "@hashgraph/sdk";
|
|
3
|
+
|
|
4
|
+
function broadcastTransaction(transaction: HederaTransaction): Promise<TransactionResponse> {
|
|
5
|
+
return transaction.execute(getInstance());
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let _hederaClient: Client | null = null;
|
|
9
|
+
|
|
10
|
+
function getInstance(): Client {
|
|
11
|
+
_hederaClient ??= Client.forMainnet().setMaxNodesPerTransaction(1);
|
|
12
|
+
|
|
13
|
+
return _hederaClient;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// for testing purposes only, used to reset singleton client instance
|
|
17
|
+
function _resetInstance() {
|
|
18
|
+
_hederaClient = null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const rpcClient = {
|
|
22
|
+
getInstance,
|
|
23
|
+
broadcastTransaction,
|
|
24
|
+
_resetInstance,
|
|
25
|
+
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
import type { HederaMirrorCoinTransfer, HederaMirrorTokenTransfer } from "../types";
|
|
3
|
+
import { parseTransfers } from "./utils";
|
|
4
|
+
|
|
5
|
+
const createMirrorCoinTransfer = (account: string, amount: number): HederaMirrorCoinTransfer => ({
|
|
6
|
+
account,
|
|
7
|
+
amount,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const createMirrorTokenTransfer = (
|
|
11
|
+
account: string,
|
|
12
|
+
amount: number,
|
|
13
|
+
tokenId: string,
|
|
14
|
+
): HederaMirrorTokenTransfer => ({
|
|
15
|
+
token_id: tokenId,
|
|
16
|
+
account,
|
|
17
|
+
amount,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("parseTransfers", () => {
|
|
21
|
+
it("should correctly identify an incoming transfer", () => {
|
|
22
|
+
const userAddress = "0.0.1234";
|
|
23
|
+
const transfers = [
|
|
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]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should correctly identify an outgoing transfer", () => {
|
|
37
|
+
const userAddress = "0.0.1234";
|
|
38
|
+
const transfers = [
|
|
39
|
+
createMirrorCoinTransfer(userAddress, -100),
|
|
40
|
+
createMirrorCoinTransfer("0.0.5678", 100),
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const result = parseTransfers(transfers, userAddress);
|
|
44
|
+
|
|
45
|
+
expect(result.type).toBe("OUT");
|
|
46
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
47
|
+
expect(result.senders).toEqual([userAddress]);
|
|
48
|
+
expect(result.recipients).toEqual(["0.0.5678"]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should handle multiple senders and recipients", () => {
|
|
52
|
+
const userAddress = "0.0.1234";
|
|
53
|
+
const transfers = [
|
|
54
|
+
createMirrorCoinTransfer("0.0.5678", -50),
|
|
55
|
+
createMirrorCoinTransfer(userAddress, -50),
|
|
56
|
+
createMirrorCoinTransfer("0.0.9999", 100),
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
const result = parseTransfers(transfers, userAddress);
|
|
60
|
+
|
|
61
|
+
expect(result.type).toBe("OUT");
|
|
62
|
+
expect(result.value).toEqual(new BigNumber(50));
|
|
63
|
+
expect(result.senders).toEqual(["0.0.1234", "0.0.5678"]);
|
|
64
|
+
expect(result.recipients).toEqual(["0.0.9999"]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should correctly process token transfers", () => {
|
|
68
|
+
const userAddress = "0.0.1234";
|
|
69
|
+
const tokenId = "0.0.7777";
|
|
70
|
+
const transfers = [
|
|
71
|
+
createMirrorTokenTransfer(userAddress, -10, tokenId),
|
|
72
|
+
createMirrorTokenTransfer("0.0.5678", 10, tokenId),
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const result = parseTransfers(transfers, userAddress);
|
|
76
|
+
|
|
77
|
+
expect(result.type).toBe("OUT");
|
|
78
|
+
expect(result.value).toEqual(new BigNumber(10));
|
|
79
|
+
expect(result.senders).toEqual([userAddress]);
|
|
80
|
+
expect(result.recipients).toEqual(["0.0.5678"]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should exclude system accounts that are not nodes from recipients", () => {
|
|
84
|
+
const userAddress = "0.0.1234";
|
|
85
|
+
const systemAccount = "0.0.500";
|
|
86
|
+
const transfers = [
|
|
87
|
+
createMirrorCoinTransfer(userAddress, -100),
|
|
88
|
+
createMirrorCoinTransfer(systemAccount, 100),
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const result = parseTransfers(transfers, userAddress);
|
|
92
|
+
|
|
93
|
+
expect(result.type).toBe("OUT");
|
|
94
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
95
|
+
expect(result.senders).toEqual([userAddress]);
|
|
96
|
+
expect(result.recipients).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should include node accounts as recipients only if no other recipients", () => {
|
|
100
|
+
const userAddress = "0.0.1234";
|
|
101
|
+
const nodeAccount = "0.0.3";
|
|
102
|
+
const transfers = [
|
|
103
|
+
createMirrorCoinTransfer(userAddress, -100),
|
|
104
|
+
createMirrorCoinTransfer(nodeAccount, 100),
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
const result = parseTransfers(transfers, userAddress);
|
|
108
|
+
|
|
109
|
+
expect(result.type).toBe("OUT");
|
|
110
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
111
|
+
expect(result.senders).toEqual([userAddress]);
|
|
112
|
+
expect(result.recipients).toEqual([nodeAccount]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should exclude node accounts if there are other recipients", () => {
|
|
116
|
+
const userAddress = "0.0.1234";
|
|
117
|
+
const normalAccount = "0.0.5678";
|
|
118
|
+
const nodeAccount = "0.0.3";
|
|
119
|
+
const transfers = [
|
|
120
|
+
createMirrorCoinTransfer(userAddress, -100),
|
|
121
|
+
createMirrorCoinTransfer(normalAccount, 50),
|
|
122
|
+
createMirrorCoinTransfer(nodeAccount, 50),
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
const result = parseTransfers(transfers, userAddress);
|
|
126
|
+
|
|
127
|
+
expect(result.type).toBe("OUT");
|
|
128
|
+
expect(result.value).toEqual(new BigNumber(100));
|
|
129
|
+
expect(result.senders).toEqual([userAddress]);
|
|
130
|
+
expect(result.recipients).toEqual([normalAccount]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should handle transactions where user is not involved", () => {
|
|
134
|
+
const userAddress = "0.0.1234";
|
|
135
|
+
const transfers = [
|
|
136
|
+
createMirrorCoinTransfer("0.0.5678", -100),
|
|
137
|
+
createMirrorCoinTransfer("0.0.9999", 100),
|
|
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]);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
import { AccountId } from "@hashgraph/sdk";
|
|
3
|
+
import type { Operation, OperationType } from "@ledgerhq/types-live";
|
|
4
|
+
import type { HederaMirrorTokenTransfer, HederaMirrorCoinTransfer } from "../types";
|
|
5
|
+
|
|
6
|
+
function isValidRecipient(accountId: AccountId, recipients: string[]): boolean {
|
|
7
|
+
if (accountId.shard.eq(0) && accountId.realm.eq(0)) {
|
|
8
|
+
// account is a node, only add to list if we have none
|
|
9
|
+
if (accountId.num.lt(100)) {
|
|
10
|
+
return recipients.length === 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// account is a system account that is not a node, do NOT add
|
|
14
|
+
if (accountId.num.lt(1000)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function parseTransfers(
|
|
23
|
+
mirrorTransfers: (HederaMirrorCoinTransfer | HederaMirrorTokenTransfer)[],
|
|
24
|
+
address: string,
|
|
25
|
+
): Pick<Operation, "type" | "value" | "senders" | "recipients"> {
|
|
26
|
+
let value = new BigNumber(0);
|
|
27
|
+
let type: OperationType = "NONE";
|
|
28
|
+
|
|
29
|
+
const senders: string[] = [];
|
|
30
|
+
const recipients: string[] = [];
|
|
31
|
+
|
|
32
|
+
for (const transfer of mirrorTransfers) {
|
|
33
|
+
const amount = new BigNumber(transfer.amount);
|
|
34
|
+
const accountId = AccountId.fromString(transfer.account);
|
|
35
|
+
|
|
36
|
+
if (transfer.account === address) {
|
|
37
|
+
value = amount.abs();
|
|
38
|
+
type = amount.isNegative() ? "OUT" : "IN";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (amount.isNegative()) {
|
|
42
|
+
senders.push(transfer.account);
|
|
43
|
+
} else if (isValidRecipient(accountId, recipients)) {
|
|
44
|
+
recipients.push(transfer.account);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// NOTE: earlier addresses are the "fee" addresses
|
|
49
|
+
senders.reverse();
|
|
50
|
+
recipients.reverse();
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
type,
|
|
54
|
+
value,
|
|
55
|
+
senders,
|
|
56
|
+
recipients,
|
|
57
|
+
};
|
|
58
|
+
}
|