@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
|
@@ -7,20 +7,26 @@ import {
|
|
|
7
7
|
} from "@ledgerhq/errors";
|
|
8
8
|
import { HEDERA_TRANSACTION_MODES } from "../constants";
|
|
9
9
|
import {
|
|
10
|
-
HederaRecipientInvalidChecksum,
|
|
11
10
|
HederaInsufficientFundsForAssociation,
|
|
11
|
+
HederaRecipientEvmAddressVerificationRequired,
|
|
12
|
+
HederaRecipientInvalidChecksum,
|
|
12
13
|
HederaRecipientTokenAssociationRequired,
|
|
13
14
|
HederaRecipientTokenAssociationUnverified,
|
|
14
15
|
} from "../errors";
|
|
15
16
|
import { getTransactionStatus } from "./getTransactionStatus";
|
|
16
17
|
import * as estimateFees from "../logic/estimateFees";
|
|
17
18
|
import * as logicUtils from "../logic/utils";
|
|
19
|
+
import { rpcClient } from "../network/rpc";
|
|
18
20
|
import { getMockedAccount, getMockedTokenAccount } from "../test/fixtures/account.fixture";
|
|
19
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
getMockedERC20TokenCurrency,
|
|
23
|
+
getMockedHTSTokenCurrency,
|
|
24
|
+
} from "../test/fixtures/currency.fixture";
|
|
20
25
|
import { getMockedTransaction } from "../test/fixtures/transaction.fixture";
|
|
26
|
+
import type { EstimateFeesResult } from "../types";
|
|
21
27
|
|
|
22
28
|
describe("getTransactionStatus", () => {
|
|
23
|
-
const mockedEstimatedFee = new BigNumber(1);
|
|
29
|
+
const mockedEstimatedFee: EstimateFeesResult = { tinybars: new BigNumber(1) };
|
|
24
30
|
const mockedUsdRate = new BigNumber(1);
|
|
25
31
|
const validRecipientAddress = "0.0.1234567";
|
|
26
32
|
const validRecipientAddressWithChecksum = "0.0.1234567-ylkls";
|
|
@@ -32,6 +38,10 @@ describe("getTransactionStatus", () => {
|
|
|
32
38
|
jest.spyOn(estimateFees, "estimateFees").mockResolvedValueOnce(mockedEstimatedFee);
|
|
33
39
|
});
|
|
34
40
|
|
|
41
|
+
afterAll(() => {
|
|
42
|
+
rpcClient._resetInstance();
|
|
43
|
+
});
|
|
44
|
+
|
|
35
45
|
test("coin transfer with valid recipient and sufficient balance completes successfully", async () => {
|
|
36
46
|
const mockedAccount = getMockedAccount({ balance: new BigNumber(1000) });
|
|
37
47
|
const mockedTransaction = getMockedTransaction({
|
|
@@ -47,10 +57,10 @@ describe("getTransactionStatus", () => {
|
|
|
47
57
|
expect(result.totalSpent.isGreaterThan(100)).toBe(true);
|
|
48
58
|
});
|
|
49
59
|
|
|
50
|
-
test("token transfer with valid recipient and sufficient balance completes successfully", async () => {
|
|
60
|
+
test("hts token transfer with valid recipient and sufficient balance completes successfully", async () => {
|
|
51
61
|
jest.spyOn(logicUtils, "checkAccountTokenAssociationStatus").mockResolvedValueOnce(true);
|
|
52
62
|
|
|
53
|
-
const tokenCurrency =
|
|
63
|
+
const tokenCurrency = getMockedHTSTokenCurrency();
|
|
54
64
|
const tokenAccount = getMockedTokenAccount(tokenCurrency, { balance: new BigNumber(500) });
|
|
55
65
|
const account = getMockedAccount({ balance: new BigNumber(1000), subAccounts: [tokenAccount] });
|
|
56
66
|
const transaction = getMockedTransaction({
|
|
@@ -66,8 +76,27 @@ describe("getTransactionStatus", () => {
|
|
|
66
76
|
expect(result.amount).toEqual(new BigNumber(200));
|
|
67
77
|
});
|
|
68
78
|
|
|
79
|
+
test("erc20 token transfer with valid recipient and sufficient balance completes successfully", async () => {
|
|
80
|
+
const tokenCurrency = getMockedERC20TokenCurrency();
|
|
81
|
+
const tokenAccount = getMockedTokenAccount(tokenCurrency, { balance: new BigNumber(500) });
|
|
82
|
+
const account = getMockedAccount({ balance: new BigNumber(1000), subAccounts: [tokenAccount] });
|
|
83
|
+
const transaction = getMockedTransaction({
|
|
84
|
+
subAccountId: tokenAccount.id,
|
|
85
|
+
recipient: validRecipientAddress,
|
|
86
|
+
amount: new BigNumber(200),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const result = await getTransactionStatus(account, transaction);
|
|
90
|
+
|
|
91
|
+
expect(result.errors).toEqual({});
|
|
92
|
+
expect(result.warnings).toMatchObject({
|
|
93
|
+
unverifiedEvmAddress: expect.any(Error),
|
|
94
|
+
});
|
|
95
|
+
expect(result.amount).toEqual(new BigNumber(200));
|
|
96
|
+
});
|
|
97
|
+
|
|
69
98
|
test("token associate transaction with sufficient USD worth completes successfully", async () => {
|
|
70
|
-
const mockedTokenCurrency =
|
|
99
|
+
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
71
100
|
const mockedAccount = getMockedAccount();
|
|
72
101
|
const mockedTransaction = getMockedTransaction({
|
|
73
102
|
mode: HEDERA_TRANSACTION_MODES.TokenAssociate,
|
|
@@ -81,8 +110,8 @@ describe("getTransactionStatus", () => {
|
|
|
81
110
|
expect(result.amount).toEqual(new BigNumber(0));
|
|
82
111
|
expect(result.errors).toEqual({});
|
|
83
112
|
expect(result.warnings).toEqual({});
|
|
84
|
-
expect(result.totalSpent).toEqual(mockedEstimatedFee);
|
|
85
|
-
expect(result.estimatedFees).toEqual(mockedEstimatedFee);
|
|
113
|
+
expect(result.totalSpent).toEqual(mockedEstimatedFee.tinybars);
|
|
114
|
+
expect(result.estimatedFees).toEqual(mockedEstimatedFee.tinybars);
|
|
86
115
|
});
|
|
87
116
|
|
|
88
117
|
test("recipient with checksum is supported", async () => {
|
|
@@ -137,7 +166,7 @@ describe("getTransactionStatus", () => {
|
|
|
137
166
|
});
|
|
138
167
|
|
|
139
168
|
test("adds error if USD balance is too low for token association", async () => {
|
|
140
|
-
const mockedTokenCurrency =
|
|
169
|
+
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
141
170
|
const mockedAccount = getMockedAccount({ balance: new BigNumber(0) });
|
|
142
171
|
const mockedTransaction = getMockedTransaction({
|
|
143
172
|
mode: HEDERA_TRANSACTION_MODES.TokenAssociate,
|
|
@@ -156,7 +185,7 @@ describe("getTransactionStatus", () => {
|
|
|
156
185
|
test("adds warning during token transfer if recipient has no token associated", async () => {
|
|
157
186
|
jest.spyOn(logicUtils, "checkAccountTokenAssociationStatus").mockResolvedValueOnce(false);
|
|
158
187
|
|
|
159
|
-
const mockedTokenCurrency =
|
|
188
|
+
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
160
189
|
const mockedTokenAccount = getMockedTokenAccount(mockedTokenCurrency);
|
|
161
190
|
const mockedAccount = getMockedAccount({ subAccounts: [mockedTokenAccount] });
|
|
162
191
|
const mockedTransaction = getMockedTransaction({
|
|
@@ -171,12 +200,28 @@ describe("getTransactionStatus", () => {
|
|
|
171
200
|
);
|
|
172
201
|
});
|
|
173
202
|
|
|
203
|
+
test("adds evm address verification warning during ERC20 token transfer", async () => {
|
|
204
|
+
const mockedTokenCurrency = getMockedERC20TokenCurrency();
|
|
205
|
+
const mockedTokenAccount = getMockedTokenAccount(mockedTokenCurrency);
|
|
206
|
+
const mockedAccount = getMockedAccount({ subAccounts: [mockedTokenAccount] });
|
|
207
|
+
const mockedTransaction = getMockedTransaction({
|
|
208
|
+
subAccountId: mockedTokenAccount.id,
|
|
209
|
+
recipient: validRecipientAddress,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const result = await getTransactionStatus(mockedAccount, mockedTransaction);
|
|
213
|
+
|
|
214
|
+
expect(result.warnings.unverifiedEvmAddress).toBeInstanceOf(
|
|
215
|
+
HederaRecipientEvmAddressVerificationRequired,
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
|
|
174
219
|
test("adds warning if token association status can't be verified", async () => {
|
|
175
220
|
jest
|
|
176
221
|
.spyOn(logicUtils, "checkAccountTokenAssociationStatus")
|
|
177
222
|
.mockRejectedValueOnce(new HederaRecipientTokenAssociationUnverified());
|
|
178
223
|
|
|
179
|
-
const mockedTokenCurrency =
|
|
224
|
+
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
180
225
|
const mockedTokenAccount = getMockedTokenAccount(mockedTokenCurrency);
|
|
181
226
|
const mockedAccount = getMockedAccount({ subAccounts: [mockedTokenAccount] });
|
|
182
227
|
const mockedTransaction = getMockedTransaction({
|
|
@@ -192,7 +237,7 @@ describe("getTransactionStatus", () => {
|
|
|
192
237
|
});
|
|
193
238
|
|
|
194
239
|
test("adds error during token transfer with insufficient balance", async () => {
|
|
195
|
-
const mockedTokenCurrency =
|
|
240
|
+
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
196
241
|
const mockedTokenAccount = getMockedTokenAccount(mockedTokenCurrency, {
|
|
197
242
|
balance: new BigNumber(0),
|
|
198
243
|
});
|
|
@@ -6,13 +6,14 @@ import {
|
|
|
6
6
|
RecipientRequired,
|
|
7
7
|
} from "@ledgerhq/errors";
|
|
8
8
|
import type { Account, AccountBridge, TokenAccount } from "@ledgerhq/types-live";
|
|
9
|
-
import { findSubAccountById
|
|
9
|
+
import { findSubAccountById } from "@ledgerhq/coin-framework/account";
|
|
10
10
|
import { getEnv } from "@ledgerhq/live-env";
|
|
11
|
-
import { HEDERA_OPERATION_TYPES } from "../constants";
|
|
11
|
+
import { HEDERA_OPERATION_TYPES, HEDERA_TRANSACTION_MODES } from "../constants";
|
|
12
12
|
import {
|
|
13
13
|
HederaInsufficientFundsForAssociation,
|
|
14
14
|
HederaRecipientTokenAssociationRequired,
|
|
15
15
|
HederaRecipientTokenAssociationUnverified,
|
|
16
|
+
HederaRecipientEvmAddressVerificationRequired,
|
|
16
17
|
} from "../errors";
|
|
17
18
|
import { estimateFees } from "../logic/estimateFees";
|
|
18
19
|
import {
|
|
@@ -57,11 +58,14 @@ async function handleTokenAssociateTransaction(
|
|
|
57
58
|
|
|
58
59
|
const [usdRate, estimatedFees] = await Promise.all([
|
|
59
60
|
getCurrencyToUSDRate(account.currency),
|
|
60
|
-
estimateFees(
|
|
61
|
+
estimateFees({
|
|
62
|
+
currency: account.currency,
|
|
63
|
+
operationType: HEDERA_OPERATION_TYPES.TokenAssociate,
|
|
64
|
+
}),
|
|
61
65
|
]);
|
|
62
66
|
|
|
63
67
|
const amount = BigNumber(0);
|
|
64
|
-
const totalSpent = amount.plus(estimatedFees);
|
|
68
|
+
const totalSpent = amount.plus(estimatedFees.tinybars);
|
|
65
69
|
const isAssociationFlow = isTokenAssociationRequired(account, transaction.properties.token);
|
|
66
70
|
|
|
67
71
|
if (isAssociationFlow) {
|
|
@@ -79,22 +83,26 @@ async function handleTokenAssociateTransaction(
|
|
|
79
83
|
return {
|
|
80
84
|
amount,
|
|
81
85
|
totalSpent,
|
|
82
|
-
estimatedFees,
|
|
86
|
+
estimatedFees: estimatedFees.tinybars,
|
|
83
87
|
errors,
|
|
84
88
|
warnings,
|
|
85
89
|
};
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
async function
|
|
92
|
+
async function handleHTSTokenTransaction(
|
|
89
93
|
account: Account,
|
|
90
94
|
subAccount: TokenAccount,
|
|
91
95
|
transaction: Transaction,
|
|
92
96
|
): Promise<TransactionStatus> {
|
|
93
97
|
const errors: Errors = {};
|
|
94
98
|
const warnings: Warnings = {};
|
|
99
|
+
|
|
95
100
|
const [calculatedAmount, estimatedFees] = await Promise.all([
|
|
96
101
|
calculateAmount({ transaction, account }),
|
|
97
|
-
estimateFees(
|
|
102
|
+
estimateFees({
|
|
103
|
+
currency: account.currency,
|
|
104
|
+
operationType: HEDERA_OPERATION_TYPES.TokenTransfer,
|
|
105
|
+
}),
|
|
98
106
|
]);
|
|
99
107
|
|
|
100
108
|
const recipientError = validateRecipient(account, transaction.recipient);
|
|
@@ -107,7 +115,7 @@ async function handleTokenTransaction(
|
|
|
107
115
|
try {
|
|
108
116
|
const hasRecipientTokenAssociated = await checkAccountTokenAssociationStatus(
|
|
109
117
|
transaction.recipient,
|
|
110
|
-
subAccount.token
|
|
118
|
+
subAccount.token,
|
|
111
119
|
);
|
|
112
120
|
|
|
113
121
|
if (!hasRecipientTokenAssociated) {
|
|
@@ -126,14 +134,70 @@ async function handleTokenTransaction(
|
|
|
126
134
|
errors.amount = new NotEnoughBalance();
|
|
127
135
|
}
|
|
128
136
|
|
|
129
|
-
if (account.balance.isLessThan(estimatedFees)) {
|
|
137
|
+
if (account.balance.isLessThan(estimatedFees.tinybars)) {
|
|
138
|
+
errors.amount = new NotEnoughBalance();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
amount: calculatedAmount.amount,
|
|
143
|
+
totalSpent: calculatedAmount.totalSpent,
|
|
144
|
+
estimatedFees: estimatedFees.tinybars,
|
|
145
|
+
errors,
|
|
146
|
+
warnings,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function handleERC20TokenTransaction(
|
|
151
|
+
account: Account,
|
|
152
|
+
subAccount: TokenAccount,
|
|
153
|
+
transaction: Transaction,
|
|
154
|
+
): Promise<TransactionStatus> {
|
|
155
|
+
const errors: Errors = {};
|
|
156
|
+
const warnings: Warnings = {
|
|
157
|
+
unverifiedEvmAddress: new HederaRecipientEvmAddressVerificationRequired(),
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const [calculatedAmount, estimatedFees] = await Promise.all([
|
|
161
|
+
calculateAmount({ transaction, account }),
|
|
162
|
+
estimateFees({
|
|
163
|
+
operationType: HEDERA_OPERATION_TYPES.ContractCall,
|
|
164
|
+
txIntent: {
|
|
165
|
+
intentType: "transaction",
|
|
166
|
+
type: HEDERA_TRANSACTION_MODES.Send,
|
|
167
|
+
asset: {
|
|
168
|
+
type: "erc20",
|
|
169
|
+
assetReference: subAccount.token.contractAddress,
|
|
170
|
+
assetOwner: account.freshAddress,
|
|
171
|
+
},
|
|
172
|
+
amount: BigInt(transaction.amount.toString()),
|
|
173
|
+
sender: account.freshAddress,
|
|
174
|
+
recipient: transaction.recipient,
|
|
175
|
+
},
|
|
176
|
+
}),
|
|
177
|
+
]);
|
|
178
|
+
|
|
179
|
+
const recipientError = validateRecipient(account, transaction.recipient);
|
|
180
|
+
|
|
181
|
+
if (recipientError) {
|
|
182
|
+
errors.recipient = recipientError;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (transaction.amount.eq(0)) {
|
|
186
|
+
errors.amount = new AmountRequired();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (subAccount.balance.isLessThan(calculatedAmount.totalSpent)) {
|
|
190
|
+
errors.amount = new NotEnoughBalance();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (account.balance.isLessThan(estimatedFees.tinybars)) {
|
|
130
194
|
errors.amount = new NotEnoughBalance();
|
|
131
195
|
}
|
|
132
196
|
|
|
133
197
|
return {
|
|
134
198
|
amount: calculatedAmount.amount,
|
|
135
199
|
totalSpent: calculatedAmount.totalSpent,
|
|
136
|
-
estimatedFees,
|
|
200
|
+
estimatedFees: estimatedFees.tinybars,
|
|
137
201
|
errors,
|
|
138
202
|
warnings,
|
|
139
203
|
};
|
|
@@ -145,9 +209,13 @@ async function handleCoinTransaction(
|
|
|
145
209
|
): Promise<TransactionStatus> {
|
|
146
210
|
const errors: Errors = {};
|
|
147
211
|
const warnings: Warnings = {};
|
|
212
|
+
|
|
148
213
|
const [calculatedAmount, estimatedFees] = await Promise.all([
|
|
149
214
|
calculateAmount({ transaction, account }),
|
|
150
|
-
estimateFees(
|
|
215
|
+
estimateFees({
|
|
216
|
+
currency: account.currency,
|
|
217
|
+
operationType: HEDERA_OPERATION_TYPES.CryptoTransfer,
|
|
218
|
+
}),
|
|
151
219
|
]);
|
|
152
220
|
|
|
153
221
|
const recipientError = validateRecipient(account, transaction.recipient);
|
|
@@ -167,7 +235,7 @@ async function handleCoinTransaction(
|
|
|
167
235
|
return {
|
|
168
236
|
amount: calculatedAmount.amount,
|
|
169
237
|
totalSpent: calculatedAmount.totalSpent,
|
|
170
|
-
estimatedFees,
|
|
238
|
+
estimatedFees: estimatedFees.tinybars,
|
|
171
239
|
errors,
|
|
172
240
|
warnings,
|
|
173
241
|
};
|
|
@@ -179,12 +247,17 @@ export const getTransactionStatus: AccountBridge<
|
|
|
179
247
|
TransactionStatus
|
|
180
248
|
>["getTransactionStatus"] = async (account, transaction) => {
|
|
181
249
|
const subAccount = findSubAccountById(account, transaction?.subAccountId || "");
|
|
182
|
-
const
|
|
250
|
+
const isHTSTokenTransaction =
|
|
251
|
+
transaction.mode === HEDERA_TRANSACTION_MODES.Send && subAccount?.token.tokenType === "hts";
|
|
252
|
+
const isERC20TokenTransaction =
|
|
253
|
+
transaction.mode === HEDERA_TRANSACTION_MODES.Send && subAccount?.token.tokenType === "erc20";
|
|
183
254
|
|
|
184
255
|
if (isTokenAssociateTransaction(transaction)) {
|
|
185
256
|
return handleTokenAssociateTransaction(account, transaction);
|
|
186
|
-
} else if (
|
|
187
|
-
return
|
|
257
|
+
} else if (isHTSTokenTransaction) {
|
|
258
|
+
return handleHTSTokenTransaction(account, subAccount, transaction);
|
|
259
|
+
} else if (isERC20TokenTransaction) {
|
|
260
|
+
return handleERC20TokenTransaction(account, subAccount, transaction);
|
|
188
261
|
} else {
|
|
189
262
|
return handleCoinTransaction(account, transaction);
|
|
190
263
|
}
|
package/src/bridge/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { getTransactionStatus } from "./getTransactionStatus";
|
|
|
14
14
|
import { prepareTransaction } from "./prepareTransaction";
|
|
15
15
|
import { receive } from "./receive";
|
|
16
16
|
import { buildSignOperation } from "./signOperation";
|
|
17
|
-
import { getAccountShape, buildIterateResult } from "./synchronisation";
|
|
17
|
+
import { getAccountShape, buildIterateResult, postSync } from "./synchronisation";
|
|
18
18
|
import { assignFromAccountRaw, assignToAccountRaw } from "./serialization";
|
|
19
19
|
import resolver from "../signer/index";
|
|
20
20
|
import type { Transaction, TransactionStatus, HederaSigner, HederaAccount } from "../types";
|
|
@@ -35,7 +35,7 @@ function buildCurrencyBridge(signerContext: SignerContext<HederaSigner>): Curren
|
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const sync = makeSync({ getAccountShape });
|
|
38
|
+
const sync = makeSync({ getAccountShape, postSync, shouldMergeOps: false });
|
|
39
39
|
|
|
40
40
|
function buildAccountBridge(
|
|
41
41
|
signerContext: SignerContext<HederaSigner>,
|
|
@@ -3,21 +3,22 @@ import { createBridges } from ".";
|
|
|
3
3
|
import { HEDERA_OPERATION_TYPES } from "../constants";
|
|
4
4
|
import { estimateFees } from "../logic/estimateFees";
|
|
5
5
|
import { getMockedAccount, getMockedTokenAccount } from "../test/fixtures/account.fixture";
|
|
6
|
-
import {
|
|
6
|
+
import { getMockedHTSTokenCurrency } from "../test/fixtures/currency.fixture";
|
|
7
|
+
import type { EstimateFeesResult } from "../types";
|
|
7
8
|
|
|
8
9
|
describe("js-estimateMaxSpendable", () => {
|
|
9
10
|
let bridge: ReturnType<typeof createBridges>;
|
|
10
|
-
let estimatedFees: Record<"crypto",
|
|
11
|
+
let estimatedFees: Record<"crypto", EstimateFeesResult>;
|
|
11
12
|
|
|
12
13
|
beforeAll(async () => {
|
|
13
14
|
const signer = jest.fn();
|
|
14
15
|
bridge = createBridges(signer);
|
|
15
16
|
|
|
16
17
|
const mockedAccount = getMockedAccount();
|
|
17
|
-
const crypto = await estimateFees(
|
|
18
|
-
mockedAccount.currency,
|
|
19
|
-
HEDERA_OPERATION_TYPES.CryptoTransfer,
|
|
20
|
-
);
|
|
18
|
+
const crypto = await estimateFees({
|
|
19
|
+
currency: mockedAccount.currency,
|
|
20
|
+
operationType: HEDERA_OPERATION_TYPES.CryptoTransfer,
|
|
21
|
+
});
|
|
21
22
|
|
|
22
23
|
estimatedFees = { crypto };
|
|
23
24
|
});
|
|
@@ -29,11 +30,13 @@ describe("js-estimateMaxSpendable", () => {
|
|
|
29
30
|
account: mockedAccount,
|
|
30
31
|
});
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
const expected = mockedAccount.balance.minus(estimatedFees.crypto.tinybars);
|
|
34
|
+
|
|
35
|
+
expect(result).toEqual(expected);
|
|
33
36
|
});
|
|
34
37
|
|
|
35
38
|
test("estimateMaxSpendable returns 0 if balance < estimated fees", async () => {
|
|
36
|
-
const mockedAccount = getMockedAccount({ balance: estimatedFees.crypto.minus(1) });
|
|
39
|
+
const mockedAccount = getMockedAccount({ balance: estimatedFees.crypto.tinybars.minus(1) });
|
|
37
40
|
|
|
38
41
|
const result = await bridge.accountBridge.estimateMaxSpendable({
|
|
39
42
|
account: mockedAccount,
|
|
@@ -43,7 +46,7 @@ describe("js-estimateMaxSpendable", () => {
|
|
|
43
46
|
});
|
|
44
47
|
|
|
45
48
|
test("estimateMaxSpendable returns token balance for token account", async () => {
|
|
46
|
-
const mockedTokenCurrency =
|
|
49
|
+
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
47
50
|
const mockedTokenAccount = getMockedTokenAccount(mockedTokenCurrency);
|
|
48
51
|
const mockedAccount = getMockedAccount({ subAccounts: [mockedTokenAccount] });
|
|
49
52
|
|
|
@@ -4,17 +4,19 @@ import { prepareTransaction } from "./prepareTransaction";
|
|
|
4
4
|
import { getMockedAccount } from "../test/fixtures/account.fixture";
|
|
5
5
|
import { getMockedTransaction } from "../test/fixtures/transaction.fixture";
|
|
6
6
|
import * as utils from "./utils";
|
|
7
|
+
import type { EstimateFeesResult } from "../types";
|
|
7
8
|
|
|
8
9
|
jest.mock("../logic/estimateFees");
|
|
9
10
|
|
|
10
11
|
describe("prepareTransaction", () => {
|
|
11
12
|
const mockAccount = getMockedAccount();
|
|
12
13
|
const mockTx = getMockedTransaction();
|
|
14
|
+
const mockFeeEstimation: EstimateFeesResult = { tinybars: new BigNumber(10) };
|
|
13
15
|
|
|
14
16
|
beforeEach(() => {
|
|
15
17
|
jest.clearAllMocks();
|
|
16
18
|
|
|
17
|
-
(estimateFees as jest.Mock).mockResolvedValue(
|
|
19
|
+
(estimateFees as jest.Mock).mockResolvedValue(mockFeeEstimation);
|
|
18
20
|
jest
|
|
19
21
|
.spyOn(utils, "calculateAmount")
|
|
20
22
|
.mockResolvedValue(
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { findSubAccountById
|
|
1
|
+
import { findSubAccountById } from "@ledgerhq/coin-framework/account/helpers";
|
|
2
2
|
import type { AccountBridge } from "@ledgerhq/types-live";
|
|
3
|
-
import { HEDERA_OPERATION_TYPES } from "../constants";
|
|
3
|
+
import { HEDERA_OPERATION_TYPES, HEDERA_TRANSACTION_MODES } from "../constants";
|
|
4
4
|
import { estimateFees } from "../logic/estimateFees";
|
|
5
5
|
import { isTokenAssociateTransaction } from "../logic/utils";
|
|
6
|
-
import type { Transaction } from "../types";
|
|
6
|
+
import type { EstimateFeesParams, Transaction } from "../types";
|
|
7
7
|
import { calculateAmount } from "./utils";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -18,31 +18,66 @@ export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"
|
|
|
18
18
|
account,
|
|
19
19
|
transaction,
|
|
20
20
|
): Promise<Transaction> => {
|
|
21
|
-
|
|
22
|
-
const isTokenTransaction = isTokenAccount(subAccount);
|
|
21
|
+
let estimateFeesParams: EstimateFeesParams;
|
|
23
22
|
let operationType: HEDERA_OPERATION_TYPES;
|
|
23
|
+
const subAccount = findSubAccountById(account, transaction?.subAccountId || "");
|
|
24
|
+
const isHTSTokenTransaction =
|
|
25
|
+
transaction.mode === HEDERA_TRANSACTION_MODES.Send && subAccount?.token.tokenType === "hts";
|
|
26
|
+
const isERC20TokenTransaction =
|
|
27
|
+
transaction.mode === HEDERA_TRANSACTION_MODES.Send && subAccount?.token.tokenType === "erc20";
|
|
24
28
|
|
|
25
29
|
if (isTokenAssociateTransaction(transaction)) {
|
|
26
30
|
operationType = HEDERA_OPERATION_TYPES.TokenAssociate;
|
|
27
|
-
} else if (
|
|
31
|
+
} else if (isHTSTokenTransaction) {
|
|
28
32
|
operationType = HEDERA_OPERATION_TYPES.TokenTransfer;
|
|
33
|
+
} else if (isERC20TokenTransaction) {
|
|
34
|
+
operationType = HEDERA_OPERATION_TYPES.ContractCall;
|
|
29
35
|
} else {
|
|
30
36
|
operationType = HEDERA_OPERATION_TYPES.CryptoTransfer;
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
// build different estimation params for ERC20 ContractCall transactions
|
|
40
|
+
if (operationType === HEDERA_OPERATION_TYPES.ContractCall) {
|
|
41
|
+
estimateFeesParams = {
|
|
42
|
+
operationType,
|
|
43
|
+
txIntent: {
|
|
44
|
+
intentType: "transaction",
|
|
45
|
+
type: HEDERA_TRANSACTION_MODES.Send,
|
|
46
|
+
asset: {
|
|
47
|
+
type: "erc20",
|
|
48
|
+
assetReference: subAccount?.token.contractAddress ?? "",
|
|
49
|
+
assetOwner: account.freshAddress,
|
|
50
|
+
},
|
|
51
|
+
amount: BigInt(transaction.amount.toString()),
|
|
52
|
+
sender: account.freshAddress,
|
|
53
|
+
recipient: transaction.recipient,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
} else {
|
|
57
|
+
estimateFeesParams = {
|
|
58
|
+
currency: account.currency,
|
|
59
|
+
operationType,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
33
63
|
// explicitly calculate transaction amount to account for `useAllAmount` flag (send max flow)
|
|
34
64
|
// i.e. if `useAllAmount` has been toggled to true, this is where it will update the transaction to reflect that action
|
|
35
|
-
const [
|
|
65
|
+
const [calculatedAmount, estimatedFees] = await Promise.all([
|
|
36
66
|
calculateAmount({ account, transaction }),
|
|
37
|
-
estimateFees(
|
|
67
|
+
estimateFees(estimateFeesParams),
|
|
38
68
|
]);
|
|
39
69
|
|
|
70
|
+
transaction.amount = calculatedAmount.amount;
|
|
71
|
+
|
|
40
72
|
// `maxFee` must be explicitly set to avoid the @hashgraph/sdk default fallback
|
|
41
73
|
// this ensures device app validation passes (e.g. during swap flow)
|
|
42
74
|
// it's applied via `tx.setMaxTransactionFee` when building the transaction
|
|
43
|
-
transaction.maxFee = estimatedFees;
|
|
75
|
+
transaction.maxFee = estimatedFees.tinybars;
|
|
44
76
|
|
|
45
|
-
|
|
77
|
+
// ERC20 transactions should have gas limit set (tinybars fee is calculated based on gas)
|
|
78
|
+
if (isERC20TokenTransaction && estimatedFees.gas) {
|
|
79
|
+
transaction.gasLimit = estimatedFees.gas;
|
|
80
|
+
}
|
|
46
81
|
|
|
47
82
|
return transaction;
|
|
48
83
|
};
|
|
@@ -2,9 +2,9 @@ import { Observable } from "rxjs";
|
|
|
2
2
|
import { Account, AccountBridge } from "@ledgerhq/types-live";
|
|
3
3
|
import { AssetInfo, FeeEstimation } from "@ledgerhq/coin-framework/api/types";
|
|
4
4
|
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
5
|
-
import { findSubAccountById
|
|
5
|
+
import { findSubAccountById } from "@ledgerhq/coin-framework/account/helpers";
|
|
6
6
|
import { buildOptimisticOperation } from "./buildOptimisticOperation";
|
|
7
|
-
import { HEDERA_TRANSACTION_MODES } from "../constants";
|
|
7
|
+
import { DEFAULT_GAS_LIMIT, HEDERA_TRANSACTION_MODES } from "../constants";
|
|
8
8
|
import { combine } from "../logic/combine";
|
|
9
9
|
import { craftTransaction } from "../logic/craftTransaction";
|
|
10
10
|
import {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
getHederaTransactionBodyBytes,
|
|
14
14
|
isTokenAssociateTransaction,
|
|
15
15
|
} from "../logic/utils";
|
|
16
|
-
import type { Transaction, HederaSigner } from "../types";
|
|
16
|
+
import type { Transaction, HederaSigner, HederaTxData } from "../types";
|
|
17
17
|
|
|
18
18
|
export const buildSignOperation =
|
|
19
19
|
(
|
|
@@ -29,10 +29,16 @@ export const buildSignOperation =
|
|
|
29
29
|
|
|
30
30
|
let type: Transaction["mode"];
|
|
31
31
|
let asset: AssetInfo;
|
|
32
|
+
let data: HederaTxData | undefined;
|
|
32
33
|
const accountAddress = account.freshAddress;
|
|
33
34
|
const accountPublicKey = account.seedIdentifier;
|
|
34
35
|
const subAccount = findSubAccountById(account, transaction.subAccountId || "");
|
|
35
|
-
const
|
|
36
|
+
const isHTSTokenTransaction =
|
|
37
|
+
transaction.mode === HEDERA_TRANSACTION_MODES.Send &&
|
|
38
|
+
subAccount?.token.tokenType === "hts";
|
|
39
|
+
const isERC20TokenTransaction =
|
|
40
|
+
transaction.mode === HEDERA_TRANSACTION_MODES.Send &&
|
|
41
|
+
subAccount?.token.tokenType === "erc20";
|
|
36
42
|
|
|
37
43
|
if (isTokenAssociateTransaction(transaction)) {
|
|
38
44
|
type = HEDERA_TRANSACTION_MODES.TokenAssociate;
|
|
@@ -40,13 +46,24 @@ export const buildSignOperation =
|
|
|
40
46
|
type: transaction.properties.token.tokenType,
|
|
41
47
|
assetReference: transaction.properties.token.contractAddress,
|
|
42
48
|
};
|
|
43
|
-
} else if (
|
|
49
|
+
} else if (isHTSTokenTransaction) {
|
|
44
50
|
type = HEDERA_TRANSACTION_MODES.Send;
|
|
45
51
|
asset = {
|
|
46
52
|
type: subAccount.token.tokenType,
|
|
47
53
|
assetReference: subAccount.token.contractAddress,
|
|
48
54
|
assetOwner: accountAddress,
|
|
49
55
|
};
|
|
56
|
+
} else if (isERC20TokenTransaction) {
|
|
57
|
+
type = HEDERA_TRANSACTION_MODES.Send;
|
|
58
|
+
asset = {
|
|
59
|
+
type: subAccount.token.tokenType,
|
|
60
|
+
assetReference: subAccount.token.contractAddress,
|
|
61
|
+
assetOwner: accountAddress,
|
|
62
|
+
};
|
|
63
|
+
data = {
|
|
64
|
+
type: "erc20",
|
|
65
|
+
gasLimit: BigInt((transaction.gasLimit ?? DEFAULT_GAS_LIMIT).toString()),
|
|
66
|
+
};
|
|
50
67
|
} else {
|
|
51
68
|
type = HEDERA_TRANSACTION_MODES.Send;
|
|
52
69
|
asset = {
|
|
@@ -72,6 +89,7 @@ export const buildSignOperation =
|
|
|
72
89
|
type: "string",
|
|
73
90
|
value: transaction.memo ?? "",
|
|
74
91
|
},
|
|
92
|
+
...(data && { data }),
|
|
75
93
|
},
|
|
76
94
|
customFees,
|
|
77
95
|
);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Account } from "@ledgerhq/types-live";
|
|
2
|
+
import { postSync } from "./synchronisation";
|
|
3
|
+
import { getMockedAccount, getMockedTokenAccount } from "../test/fixtures/account.fixture";
|
|
4
|
+
import { getMockedOperation } from "../test/fixtures/operation.fixture";
|
|
5
|
+
import { getMockedHTSTokenCurrency } from "../test/fixtures/currency.fixture";
|
|
6
|
+
|
|
7
|
+
describe("postSync", () => {
|
|
8
|
+
it("should remove pending operations that match confirmed ERC20 operations", () => {
|
|
9
|
+
const confirmedERC20Ops = [
|
|
10
|
+
getMockedOperation({ hash: "hash1", standard: "erc20" }),
|
|
11
|
+
getMockedOperation({ hash: "hash2", standard: "erc20" }),
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const initialAccount = {} as Account;
|
|
15
|
+
const syncedAccount = getMockedAccount({
|
|
16
|
+
operations: [...confirmedERC20Ops, getMockedOperation({ hash: "otherHash" })],
|
|
17
|
+
pendingOperations: [
|
|
18
|
+
getMockedOperation({ hash: "hash1" }),
|
|
19
|
+
getMockedOperation({ hash: "hash2" }),
|
|
20
|
+
getMockedOperation({ hash: "hash3" }),
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const result = postSync(initialAccount, syncedAccount);
|
|
25
|
+
|
|
26
|
+
expect(result.pendingOperations).toHaveLength(1);
|
|
27
|
+
expect(result.pendingOperations).toMatchObject([{ hash: "hash3" }]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should filter pending operations from subaccounts", () => {
|
|
31
|
+
const mockToken1 = getMockedHTSTokenCurrency();
|
|
32
|
+
|
|
33
|
+
const confirmedERC20Ops = [
|
|
34
|
+
getMockedOperation({ hash: "hash1", standard: "erc20" }),
|
|
35
|
+
getMockedOperation({ hash: "hash2", standard: "erc20" }),
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const subAccounts = [
|
|
39
|
+
getMockedTokenAccount(mockToken1, {
|
|
40
|
+
pendingOperations: [
|
|
41
|
+
getMockedOperation({ hash: "hash1" }),
|
|
42
|
+
getMockedOperation({ hash: "hash4" }),
|
|
43
|
+
],
|
|
44
|
+
}),
|
|
45
|
+
getMockedTokenAccount(mockToken1, {
|
|
46
|
+
pendingOperations: [
|
|
47
|
+
getMockedOperation({ hash: "hash2" }),
|
|
48
|
+
getMockedOperation({ hash: "hash5" }),
|
|
49
|
+
],
|
|
50
|
+
}),
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const initialAccount = {} as Account;
|
|
54
|
+
const syncedAccount = getMockedAccount({
|
|
55
|
+
operations: [...confirmedERC20Ops, getMockedOperation({ hash: "otherHash" })],
|
|
56
|
+
subAccounts,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const result = postSync(initialAccount, syncedAccount);
|
|
60
|
+
|
|
61
|
+
expect(result.subAccounts).toHaveLength(2);
|
|
62
|
+
expect(result.subAccounts).toMatchObject([
|
|
63
|
+
{ pendingOperations: [{ hash: "hash4" }] },
|
|
64
|
+
{ pendingOperations: [{ hash: "hash5" }] },
|
|
65
|
+
]);
|
|
66
|
+
});
|
|
67
|
+
});
|