@ledgerhq/coin-hedera 1.15.0 → 1.16.0-nightly.20251210120335
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 +24 -0
- package/lib/bridge/buildOptimisticOperation.d.ts.map +1 -1
- package/lib/bridge/buildOptimisticOperation.js +33 -0
- package/lib/bridge/buildOptimisticOperation.js.map +1 -1
- package/lib/bridge/getTransactionStatus.d.ts.map +1 -1
- package/lib/bridge/getTransactionStatus.js +54 -0
- package/lib/bridge/getTransactionStatus.js.map +1 -1
- package/lib/bridge/index.d.ts.map +1 -1
- package/lib/bridge/index.js +4 -2
- package/lib/bridge/index.js.map +1 -1
- package/lib/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib/bridge/prepareTransaction.js +16 -0
- package/lib/bridge/prepareTransaction.js.map +1 -1
- package/lib/bridge/serialization.d.ts.map +1 -1
- package/lib/bridge/serialization.js +20 -0
- package/lib/bridge/serialization.js.map +1 -1
- package/lib/bridge/signOperation.d.ts +4 -4
- package/lib/bridge/signOperation.d.ts.map +1 -1
- package/lib/bridge/signOperation.js +10 -0
- package/lib/bridge/signOperation.js.map +1 -1
- package/lib/bridge/synchronisation.d.ts.map +1 -1
- package/lib/bridge/synchronisation.js +8 -0
- package/lib/bridge/synchronisation.js.map +1 -1
- package/lib/constants.d.ts +21 -1
- package/lib/constants.d.ts.map +1 -1
- package/lib/constants.js +22 -1
- package/lib/constants.js.map +1 -1
- package/lib/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/deviceTransactionConfig.js +30 -0
- package/lib/deviceTransactionConfig.js.map +1 -1
- package/lib/errors.d.ts +9 -0
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +4 -1
- package/lib/errors.js.map +1 -1
- package/lib/logic/craftTransaction.d.ts +2 -2
- package/lib/logic/craftTransaction.d.ts.map +1 -1
- package/lib/logic/craftTransaction.js +42 -8
- package/lib/logic/craftTransaction.js.map +1 -1
- package/lib/logic/getBlock.d.ts.map +1 -1
- package/lib/logic/getBlock.js +1 -0
- package/lib/logic/getBlock.js.map +1 -1
- package/lib/logic/listOperations.d.ts.map +1 -1
- package/lib/logic/listOperations.js +39 -7
- package/lib/logic/listOperations.js.map +1 -1
- package/lib/logic/utils.d.ts +61 -3
- package/lib/logic/utils.d.ts.map +1 -1
- package/lib/logic/utils.js +117 -4
- package/lib/logic/utils.js.map +1 -1
- package/lib/network/api.d.ts +3 -1
- package/lib/network/api.d.ts.map +1 -1
- package/lib/network/api.js +19 -0
- package/lib/network/api.js.map +1 -1
- package/lib/preload-data.d.ts +7 -0
- package/lib/preload-data.d.ts.map +1 -0
- package/lib/preload-data.js +37 -0
- package/lib/preload-data.js.map +1 -0
- package/lib/preload.d.ts +8 -0
- package/lib/preload.d.ts.map +1 -0
- package/lib/preload.js +76 -0
- package/lib/preload.js.map +1 -0
- package/lib/test/fixtures/account.fixture.d.ts +1 -1
- package/lib/test/fixtures/account.fixture.d.ts.map +1 -1
- package/lib/test/fixtures/account.fixture.js +2 -0
- package/lib/test/fixtures/account.fixture.js.map +1 -1
- package/lib/transaction.d.ts.map +1 -1
- package/lib/transaction.js +34 -0
- package/lib/transaction.js.map +1 -1
- package/lib/types/alpaca.d.ts +3 -0
- package/lib/types/alpaca.d.ts.map +1 -1
- package/lib/types/bridge.d.ts +87 -3
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib/types/logic.d.ts +5 -1
- package/lib/types/logic.d.ts.map +1 -1
- package/lib/types/mirror.d.ts +19 -0
- package/lib/types/mirror.d.ts.map +1 -1
- package/lib-es/bridge/buildOptimisticOperation.d.ts.map +1 -1
- package/lib-es/bridge/buildOptimisticOperation.js +34 -1
- package/lib-es/bridge/buildOptimisticOperation.js.map +1 -1
- package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -1
- package/lib-es/bridge/getTransactionStatus.js +57 -3
- package/lib-es/bridge/getTransactionStatus.js.map +1 -1
- package/lib-es/bridge/index.d.ts.map +1 -1
- package/lib-es/bridge/index.js +4 -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 +15 -2
- package/lib-es/bridge/prepareTransaction.js.map +1 -1
- package/lib-es/bridge/serialization.d.ts.map +1 -1
- package/lib-es/bridge/serialization.js +17 -0
- package/lib-es/bridge/serialization.js.map +1 -1
- package/lib-es/bridge/signOperation.d.ts +4 -4
- package/lib-es/bridge/signOperation.d.ts.map +1 -1
- package/lib-es/bridge/signOperation.js +11 -1
- 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 +8 -0
- package/lib-es/bridge/synchronisation.js.map +1 -1
- package/lib-es/constants.d.ts +21 -1
- package/lib-es/constants.d.ts.map +1 -1
- package/lib-es/constants.js +21 -0
- package/lib-es/constants.js.map +1 -1
- package/lib-es/deviceTransactionConfig.d.ts.map +1 -1
- package/lib-es/deviceTransactionConfig.js +31 -1
- package/lib-es/deviceTransactionConfig.js.map +1 -1
- package/lib-es/errors.d.ts +9 -0
- package/lib-es/errors.d.ts.map +1 -1
- package/lib-es/errors.js +3 -0
- package/lib-es/errors.js.map +1 -1
- package/lib-es/logic/craftTransaction.d.ts +2 -2
- package/lib-es/logic/craftTransaction.d.ts.map +1 -1
- package/lib-es/logic/craftTransaction.js +44 -10
- package/lib-es/logic/craftTransaction.js.map +1 -1
- package/lib-es/logic/getBlock.d.ts.map +1 -1
- package/lib-es/logic/getBlock.js +2 -1
- package/lib-es/logic/getBlock.js.map +1 -1
- package/lib-es/logic/listOperations.d.ts.map +1 -1
- package/lib-es/logic/listOperations.js +39 -7
- package/lib-es/logic/listOperations.js.map +1 -1
- package/lib-es/logic/utils.d.ts +61 -3
- package/lib-es/logic/utils.d.ts.map +1 -1
- package/lib-es/logic/utils.js +107 -4
- package/lib-es/logic/utils.js.map +1 -1
- package/lib-es/network/api.d.ts +3 -1
- package/lib-es/network/api.d.ts.map +1 -1
- package/lib-es/network/api.js +19 -0
- package/lib-es/network/api.js.map +1 -1
- package/lib-es/preload-data.d.ts +7 -0
- package/lib-es/preload-data.d.ts.map +1 -0
- package/lib-es/preload-data.js +31 -0
- package/lib-es/preload-data.js.map +1 -0
- package/lib-es/preload.d.ts +8 -0
- package/lib-es/preload.d.ts.map +1 -0
- package/lib-es/preload.js +67 -0
- package/lib-es/preload.js.map +1 -0
- package/lib-es/test/fixtures/account.fixture.d.ts +1 -1
- package/lib-es/test/fixtures/account.fixture.d.ts.map +1 -1
- package/lib-es/test/fixtures/account.fixture.js +2 -0
- package/lib-es/test/fixtures/account.fixture.js.map +1 -1
- package/lib-es/transaction.d.ts.map +1 -1
- package/lib-es/transaction.js +34 -0
- 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 -1
- package/lib-es/types/bridge.d.ts +87 -3
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/lib-es/types/logic.d.ts +5 -1
- package/lib-es/types/logic.d.ts.map +1 -1
- package/lib-es/types/mirror.d.ts +19 -0
- package/lib-es/types/mirror.d.ts.map +1 -1
- package/package.json +13 -12
- package/src/api/index.integ.test.ts +11 -1
- package/src/bridge/buildOptimisticOperation.integration.test.ts +159 -4
- package/src/bridge/buildOptimisticOperation.ts +50 -2
- package/src/bridge/getTransactionStatus.test.ts +191 -21
- package/src/bridge/getTransactionStatus.ts +75 -1
- package/src/bridge/index.ts +4 -2
- package/src/bridge/prepareTransaction.test.ts +112 -8
- package/src/bridge/prepareTransaction.ts +20 -2
- package/src/bridge/serialization.ts +17 -0
- package/src/bridge/signOperation.ts +15 -5
- package/src/bridge/synchronisation.ts +9 -0
- package/src/bridge/utils.integration.test.ts +3 -10
- package/src/constants.ts +22 -0
- package/src/deviceTransactionConfig.test.ts +315 -0
- package/src/deviceTransactionConfig.ts +37 -1
- package/src/errors.ts +7 -0
- package/src/logic/craftTransaction.ts +70 -13
- package/src/logic/getBalance.test.ts +15 -16
- package/src/logic/getBlock.ts +2 -1
- package/src/logic/listOperations.test.ts +86 -29
- package/src/logic/listOperations.ts +46 -6
- package/src/logic/utils.test.ts +362 -8
- package/src/logic/utils.ts +158 -4
- package/src/network/api.test.ts +58 -6
- package/src/network/api.ts +25 -0
- package/src/network/thirdweb.test.ts +2 -2
- package/src/network/utils.test.ts +4 -6
- package/src/preload-data.ts +38 -0
- package/src/preload.test.ts +64 -0
- package/src/preload.ts +80 -0
- package/src/test/fixtures/account.fixture.ts +3 -1
- package/src/transaction.ts +42 -0
- package/src/types/alpaca.ts +4 -0
- package/src/types/bridge.ts +108 -3
- package/src/types/logic.ts +6 -1
- package/src/types/mirror.ts +21 -0
|
@@ -4,18 +4,24 @@ import {
|
|
|
4
4
|
InvalidAddressBecauseDestinationIsAlsoSource,
|
|
5
5
|
AmountRequired,
|
|
6
6
|
NotEnoughBalance,
|
|
7
|
+
ClaimRewardsFeesWarning,
|
|
8
|
+
RecipientRequired,
|
|
7
9
|
} from "@ledgerhq/errors";
|
|
8
10
|
import { HEDERA_TRANSACTION_MODES } from "../constants";
|
|
9
11
|
import {
|
|
10
12
|
HederaInsufficientFundsForAssociation,
|
|
13
|
+
HederaInvalidStakingNodeIdError,
|
|
14
|
+
HederaNoStakingRewardsError,
|
|
11
15
|
HederaRecipientEvmAddressVerificationRequired,
|
|
12
16
|
HederaRecipientInvalidChecksum,
|
|
13
17
|
HederaRecipientTokenAssociationRequired,
|
|
14
18
|
HederaRecipientTokenAssociationUnverified,
|
|
19
|
+
HederaRedundantStakingNodeIdError,
|
|
15
20
|
} from "../errors";
|
|
16
21
|
import { getTransactionStatus } from "./getTransactionStatus";
|
|
17
22
|
import * as estimateFees from "../logic/estimateFees";
|
|
18
23
|
import * as logicUtils from "../logic/utils";
|
|
24
|
+
import * as preloadData from "../preload-data";
|
|
19
25
|
import { rpcClient } from "../network/rpc";
|
|
20
26
|
import { getMockedAccount, getMockedTokenAccount } from "../test/fixtures/account.fixture";
|
|
21
27
|
import {
|
|
@@ -23,26 +29,28 @@ import {
|
|
|
23
29
|
getMockedHTSTokenCurrency,
|
|
24
30
|
} from "../test/fixtures/currency.fixture";
|
|
25
31
|
import { getMockedTransaction } from "../test/fixtures/transaction.fixture";
|
|
26
|
-
import type { EstimateFeesResult } from "../types";
|
|
32
|
+
import type { EstimateFeesResult, HederaPreloadData } from "../types";
|
|
27
33
|
|
|
28
34
|
describe("getTransactionStatus", () => {
|
|
29
35
|
const mockedEstimatedFee: EstimateFeesResult = { tinybars: new BigNumber(1) };
|
|
30
36
|
const mockedUsdRate = new BigNumber(1);
|
|
37
|
+
const mockPreload = { validators: [{ nodeId: 1 }, { nodeId: 2 }] } as HederaPreloadData;
|
|
31
38
|
const validRecipientAddress = "0.0.1234567";
|
|
32
39
|
const validRecipientAddressWithChecksum = "0.0.1234567-ylkls";
|
|
33
40
|
|
|
34
41
|
beforeEach(() => {
|
|
35
42
|
jest.clearAllMocks();
|
|
36
43
|
|
|
37
|
-
jest.spyOn(logicUtils, "getCurrencyToUSDRate").mockResolvedValueOnce(mockedUsdRate);
|
|
38
44
|
jest.spyOn(estimateFees, "estimateFees").mockResolvedValueOnce(mockedEstimatedFee);
|
|
45
|
+
jest.spyOn(logicUtils, "getCurrencyToUSDRate").mockResolvedValueOnce(mockedUsdRate);
|
|
46
|
+
jest.spyOn(preloadData, "getCurrentHederaPreloadData").mockReturnValueOnce(mockPreload);
|
|
39
47
|
});
|
|
40
48
|
|
|
41
49
|
afterAll(() => {
|
|
42
50
|
rpcClient._resetInstance();
|
|
43
51
|
});
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
it("coin transfer with valid recipient and sufficient balance completes successfully", async () => {
|
|
46
54
|
const mockedAccount = getMockedAccount({ balance: new BigNumber(1000) });
|
|
47
55
|
const mockedTransaction = getMockedTransaction({
|
|
48
56
|
recipient: validRecipientAddress,
|
|
@@ -57,7 +65,7 @@ describe("getTransactionStatus", () => {
|
|
|
57
65
|
expect(result.totalSpent.isGreaterThan(100)).toBe(true);
|
|
58
66
|
});
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
it("hts token transfer with valid recipient and sufficient balance completes successfully", async () => {
|
|
61
69
|
jest.spyOn(logicUtils, "checkAccountTokenAssociationStatus").mockResolvedValueOnce(true);
|
|
62
70
|
|
|
63
71
|
const tokenCurrency = getMockedHTSTokenCurrency();
|
|
@@ -76,7 +84,7 @@ describe("getTransactionStatus", () => {
|
|
|
76
84
|
expect(result.amount).toEqual(new BigNumber(200));
|
|
77
85
|
});
|
|
78
86
|
|
|
79
|
-
|
|
87
|
+
it("erc20 token transfer with valid recipient and sufficient balance completes successfully", async () => {
|
|
80
88
|
const tokenCurrency = getMockedERC20TokenCurrency();
|
|
81
89
|
const tokenAccount = getMockedTokenAccount(tokenCurrency, { balance: new BigNumber(500) });
|
|
82
90
|
const account = getMockedAccount({ balance: new BigNumber(1000), subAccounts: [tokenAccount] });
|
|
@@ -95,7 +103,7 @@ describe("getTransactionStatus", () => {
|
|
|
95
103
|
expect(result.amount).toEqual(new BigNumber(200));
|
|
96
104
|
});
|
|
97
105
|
|
|
98
|
-
|
|
106
|
+
it("token associate transaction with sufficient USD worth completes successfully", async () => {
|
|
99
107
|
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
100
108
|
const mockedAccount = getMockedAccount();
|
|
101
109
|
const mockedTransaction = getMockedTransaction({
|
|
@@ -114,7 +122,7 @@ describe("getTransactionStatus", () => {
|
|
|
114
122
|
expect(result.estimatedFees).toEqual(mockedEstimatedFee.tinybars);
|
|
115
123
|
});
|
|
116
124
|
|
|
117
|
-
|
|
125
|
+
it("recipient with checksum is supported", async () => {
|
|
118
126
|
const mockedAccount = getMockedAccount({ balance: new BigNumber(1000) });
|
|
119
127
|
const mockedTransaction = getMockedTransaction({
|
|
120
128
|
recipient: validRecipientAddressWithChecksum,
|
|
@@ -127,22 +135,25 @@ describe("getTransactionStatus", () => {
|
|
|
127
135
|
expect(result.warnings).toEqual({});
|
|
128
136
|
});
|
|
129
137
|
|
|
130
|
-
|
|
138
|
+
it("adds error for invalid recipient address", async () => {
|
|
131
139
|
const mockedAccount = getMockedAccount();
|
|
132
140
|
|
|
133
|
-
const
|
|
141
|
+
const txWithInvalidAddress1 = getMockedTransaction({ recipient: "" });
|
|
142
|
+
const txWithInvalidAddress2 = getMockedTransaction({ recipient: "invalid_address" });
|
|
134
143
|
const txWithInvalidAddressChecksum = getMockedTransaction({ recipient: "0.0.9124531-invld" });
|
|
135
144
|
|
|
136
|
-
const [result1, result2] = await Promise.all([
|
|
137
|
-
getTransactionStatus(mockedAccount,
|
|
145
|
+
const [result1, result2, result3] = await Promise.all([
|
|
146
|
+
getTransactionStatus(mockedAccount, txWithInvalidAddress1),
|
|
147
|
+
getTransactionStatus(mockedAccount, txWithInvalidAddress2),
|
|
138
148
|
getTransactionStatus(mockedAccount, txWithInvalidAddressChecksum),
|
|
139
149
|
]);
|
|
140
150
|
|
|
141
|
-
expect(result1.errors.recipient).toBeInstanceOf(
|
|
142
|
-
expect(result2.errors.recipient).toBeInstanceOf(
|
|
151
|
+
expect(result1.errors.recipient).toBeInstanceOf(RecipientRequired);
|
|
152
|
+
expect(result2.errors.recipient).toBeInstanceOf(InvalidAddress);
|
|
153
|
+
expect(result3.errors.recipient).toBeInstanceOf(HederaRecipientInvalidChecksum);
|
|
143
154
|
});
|
|
144
155
|
|
|
145
|
-
|
|
156
|
+
it("adds error for self transfers", async () => {
|
|
146
157
|
const mockedAccount = getMockedAccount();
|
|
147
158
|
const mockedTransaction = getMockedTransaction({
|
|
148
159
|
recipient: mockedAccount.freshAddress,
|
|
@@ -153,7 +164,7 @@ describe("getTransactionStatus", () => {
|
|
|
153
164
|
expect(result.errors.recipient).toBeInstanceOf(InvalidAddressBecauseDestinationIsAlsoSource);
|
|
154
165
|
});
|
|
155
166
|
|
|
156
|
-
|
|
167
|
+
it("adds error during coin transfer with insufficient balance", async () => {
|
|
157
168
|
const mockedAccount = getMockedAccount({ balance: new BigNumber(0) });
|
|
158
169
|
const mockedTransaction = getMockedTransaction({
|
|
159
170
|
amount: new BigNumber(100),
|
|
@@ -165,7 +176,7 @@ describe("getTransactionStatus", () => {
|
|
|
165
176
|
expect(result.errors.amount).toBeInstanceOf(NotEnoughBalance);
|
|
166
177
|
});
|
|
167
178
|
|
|
168
|
-
|
|
179
|
+
it("adds error if USD balance is too low for token association", async () => {
|
|
169
180
|
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
170
181
|
const mockedAccount = getMockedAccount({ balance: new BigNumber(0) });
|
|
171
182
|
const mockedTransaction = getMockedTransaction({
|
|
@@ -182,7 +193,7 @@ describe("getTransactionStatus", () => {
|
|
|
182
193
|
);
|
|
183
194
|
});
|
|
184
195
|
|
|
185
|
-
|
|
196
|
+
it("adds warning during token transfer if recipient has no token associated", async () => {
|
|
186
197
|
jest.spyOn(logicUtils, "checkAccountTokenAssociationStatus").mockResolvedValueOnce(false);
|
|
187
198
|
|
|
188
199
|
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
@@ -200,7 +211,7 @@ describe("getTransactionStatus", () => {
|
|
|
200
211
|
);
|
|
201
212
|
});
|
|
202
213
|
|
|
203
|
-
|
|
214
|
+
it("adds evm address verification warning during ERC20 token transfer", async () => {
|
|
204
215
|
const mockedTokenCurrency = getMockedERC20TokenCurrency();
|
|
205
216
|
const mockedTokenAccount = getMockedTokenAccount(mockedTokenCurrency);
|
|
206
217
|
const mockedAccount = getMockedAccount({ subAccounts: [mockedTokenAccount] });
|
|
@@ -216,7 +227,7 @@ describe("getTransactionStatus", () => {
|
|
|
216
227
|
);
|
|
217
228
|
});
|
|
218
229
|
|
|
219
|
-
|
|
230
|
+
it("adds warning if token association status can't be verified", async () => {
|
|
220
231
|
jest
|
|
221
232
|
.spyOn(logicUtils, "checkAccountTokenAssociationStatus")
|
|
222
233
|
.mockRejectedValueOnce(new HederaRecipientTokenAssociationUnverified());
|
|
@@ -236,7 +247,7 @@ describe("getTransactionStatus", () => {
|
|
|
236
247
|
);
|
|
237
248
|
});
|
|
238
249
|
|
|
239
|
-
|
|
250
|
+
it("adds error during token transfer with insufficient balance", async () => {
|
|
240
251
|
const mockedTokenCurrency = getMockedHTSTokenCurrency();
|
|
241
252
|
const mockedTokenAccount = getMockedTokenAccount(mockedTokenCurrency, {
|
|
242
253
|
balance: new BigNumber(0),
|
|
@@ -253,7 +264,7 @@ describe("getTransactionStatus", () => {
|
|
|
253
264
|
expect(result.errors.amount).toBeInstanceOf(NotEnoughBalance);
|
|
254
265
|
});
|
|
255
266
|
|
|
256
|
-
|
|
267
|
+
it("adds error if amount is zero and useAllAmount is false", async () => {
|
|
257
268
|
const mockedAccount = getMockedAccount();
|
|
258
269
|
const mockedTransaction = getMockedTransaction({
|
|
259
270
|
recipient: validRecipientAddress,
|
|
@@ -265,4 +276,163 @@ describe("getTransactionStatus", () => {
|
|
|
265
276
|
|
|
266
277
|
expect(result.errors.amount).toBeInstanceOf(AmountRequired);
|
|
267
278
|
});
|
|
279
|
+
|
|
280
|
+
it("delegate transaction with valid node completes successfully", async () => {
|
|
281
|
+
const account = getMockedAccount();
|
|
282
|
+
const transaction = getMockedTransaction({
|
|
283
|
+
mode: HEDERA_TRANSACTION_MODES.Delegate,
|
|
284
|
+
properties: { stakingNodeId: 1 },
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const result = await getTransactionStatus(account, transaction);
|
|
288
|
+
|
|
289
|
+
expect(result.errors).toEqual({});
|
|
290
|
+
expect(result.warnings).toEqual({});
|
|
291
|
+
expect(result.amount).toEqual(new BigNumber(0));
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it("adds error for delegation without staking node id", async () => {
|
|
295
|
+
const account = getMockedAccount();
|
|
296
|
+
const transaction = getMockedTransaction({
|
|
297
|
+
mode: HEDERA_TRANSACTION_MODES.Delegate,
|
|
298
|
+
properties: {} as any,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const result = await getTransactionStatus(account, transaction);
|
|
302
|
+
|
|
303
|
+
expect(result.errors.missingStakingNodeId).toBeInstanceOf(HederaInvalidStakingNodeIdError);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it("adds error for delegation with invalid staking node id", async () => {
|
|
307
|
+
const account = getMockedAccount();
|
|
308
|
+
const transaction = getMockedTransaction({
|
|
309
|
+
mode: HEDERA_TRANSACTION_MODES.Delegate,
|
|
310
|
+
properties: { stakingNodeId: 999 },
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
const result = await getTransactionStatus(account, transaction);
|
|
314
|
+
|
|
315
|
+
expect(result.errors.stakingNodeId).toBeInstanceOf(HederaInvalidStakingNodeIdError);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it("adds error for delegation to already delegated node", async () => {
|
|
319
|
+
const account = getMockedAccount({
|
|
320
|
+
hederaResources: {
|
|
321
|
+
maxAutomaticTokenAssociations: 0,
|
|
322
|
+
isAutoTokenAssociationEnabled: false,
|
|
323
|
+
delegation: {
|
|
324
|
+
nodeId: 1,
|
|
325
|
+
pendingReward: new BigNumber(0),
|
|
326
|
+
delegated: new BigNumber(1000),
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
const transaction = getMockedTransaction({
|
|
331
|
+
mode: HEDERA_TRANSACTION_MODES.Delegate,
|
|
332
|
+
properties: { stakingNodeId: 1 },
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
const result = await getTransactionStatus(account, transaction);
|
|
336
|
+
|
|
337
|
+
expect(result.errors.stakingNodeId).toBeInstanceOf(HederaRedundantStakingNodeIdError);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it("adds error during staking transfer with insufficient balance", async () => {
|
|
341
|
+
const mockedAccount = getMockedAccount({ balance: new BigNumber(0) });
|
|
342
|
+
const mockedDelegateTransaction = getMockedTransaction({
|
|
343
|
+
mode: HEDERA_TRANSACTION_MODES.Delegate,
|
|
344
|
+
properties: { stakingNodeId: 1 },
|
|
345
|
+
});
|
|
346
|
+
const mockedUndelegateTransaction = getMockedTransaction({
|
|
347
|
+
mode: HEDERA_TRANSACTION_MODES.Undelegate,
|
|
348
|
+
properties: { stakingNodeId: null },
|
|
349
|
+
});
|
|
350
|
+
const mockedRedelegateTransaction = getMockedTransaction({
|
|
351
|
+
mode: HEDERA_TRANSACTION_MODES.Redelegate,
|
|
352
|
+
properties: { stakingNodeId: 2 },
|
|
353
|
+
});
|
|
354
|
+
const mockedClaimRewardsTransaction = getMockedTransaction({
|
|
355
|
+
mode: HEDERA_TRANSACTION_MODES.ClaimRewards,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const [resultDelegate, resultUndelegate, resultRedelegate, resultClaimRewards] =
|
|
359
|
+
await Promise.all([
|
|
360
|
+
getTransactionStatus(mockedAccount, mockedDelegateTransaction),
|
|
361
|
+
getTransactionStatus(mockedAccount, mockedUndelegateTransaction),
|
|
362
|
+
getTransactionStatus(mockedAccount, mockedRedelegateTransaction),
|
|
363
|
+
getTransactionStatus(mockedAccount, mockedClaimRewardsTransaction),
|
|
364
|
+
]);
|
|
365
|
+
|
|
366
|
+
expect(resultDelegate.errors.fee).toBeInstanceOf(NotEnoughBalance);
|
|
367
|
+
expect(resultUndelegate.errors.fee).toBeInstanceOf(NotEnoughBalance);
|
|
368
|
+
expect(resultRedelegate.errors.fee).toBeInstanceOf(NotEnoughBalance);
|
|
369
|
+
expect(resultClaimRewards.errors.fee).toBeInstanceOf(NotEnoughBalance);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("adds error when claiming rewards with no rewards available", async () => {
|
|
373
|
+
const account = getMockedAccount({
|
|
374
|
+
hederaResources: {
|
|
375
|
+
maxAutomaticTokenAssociations: 0,
|
|
376
|
+
isAutoTokenAssociationEnabled: false,
|
|
377
|
+
delegation: {
|
|
378
|
+
nodeId: 1,
|
|
379
|
+
pendingReward: new BigNumber(0),
|
|
380
|
+
delegated: new BigNumber(1000),
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
const transaction = getMockedTransaction({
|
|
385
|
+
mode: HEDERA_TRANSACTION_MODES.ClaimRewards,
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const result = await getTransactionStatus(account, transaction);
|
|
389
|
+
|
|
390
|
+
expect(result.errors.noRewardsToClaim).toBeInstanceOf(HederaNoStakingRewardsError);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("adds warning when claiming rewards with fee higher than rewards", async () => {
|
|
394
|
+
const account = getMockedAccount({
|
|
395
|
+
hederaResources: {
|
|
396
|
+
maxAutomaticTokenAssociations: 0,
|
|
397
|
+
isAutoTokenAssociationEnabled: false,
|
|
398
|
+
delegation: {
|
|
399
|
+
nodeId: 1,
|
|
400
|
+
pendingReward: new BigNumber(10),
|
|
401
|
+
delegated: new BigNumber(1000),
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
const transaction = getMockedTransaction({
|
|
406
|
+
mode: HEDERA_TRANSACTION_MODES.ClaimRewards,
|
|
407
|
+
maxFee: new BigNumber(100),
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
const result = await getTransactionStatus(account, transaction);
|
|
411
|
+
|
|
412
|
+
expect(result.warnings.claimRewardsFee).toBeInstanceOf(ClaimRewardsFeesWarning);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it("claim rewards with sufficient rewards completes successfully", async () => {
|
|
416
|
+
const account = getMockedAccount({
|
|
417
|
+
hederaResources: {
|
|
418
|
+
maxAutomaticTokenAssociations: 0,
|
|
419
|
+
isAutoTokenAssociationEnabled: false,
|
|
420
|
+
delegation: {
|
|
421
|
+
nodeId: 1,
|
|
422
|
+
pendingReward: new BigNumber(100),
|
|
423
|
+
delegated: new BigNumber(1000),
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
const transaction = getMockedTransaction({
|
|
428
|
+
mode: HEDERA_TRANSACTION_MODES.ClaimRewards,
|
|
429
|
+
maxFee: new BigNumber(10),
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
const result = await getTransactionStatus(account, transaction);
|
|
433
|
+
|
|
434
|
+
expect(result.errors).toEqual({});
|
|
435
|
+
expect(result.warnings).toEqual({});
|
|
436
|
+
expect(result.amount).toEqual(new BigNumber(0));
|
|
437
|
+
});
|
|
268
438
|
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
|
+
import invariant from "invariant";
|
|
2
3
|
import {
|
|
3
4
|
AmountRequired,
|
|
4
5
|
NotEnoughBalance,
|
|
5
6
|
InvalidAddressBecauseDestinationIsAlsoSource,
|
|
6
7
|
RecipientRequired,
|
|
8
|
+
ClaimRewardsFeesWarning,
|
|
7
9
|
} from "@ledgerhq/errors";
|
|
8
10
|
import type { Account, AccountBridge, TokenAccount } from "@ledgerhq/types-live";
|
|
9
11
|
import { findSubAccountById } from "@ledgerhq/coin-framework/account";
|
|
@@ -14,6 +16,9 @@ import {
|
|
|
14
16
|
HederaRecipientTokenAssociationRequired,
|
|
15
17
|
HederaRecipientTokenAssociationUnverified,
|
|
16
18
|
HederaRecipientEvmAddressVerificationRequired,
|
|
19
|
+
HederaInvalidStakingNodeIdError,
|
|
20
|
+
HederaRedundantStakingNodeIdError,
|
|
21
|
+
HederaNoStakingRewardsError,
|
|
17
22
|
} from "../errors";
|
|
18
23
|
import { estimateFees } from "../logic/estimateFees";
|
|
19
24
|
import {
|
|
@@ -22,8 +27,15 @@ import {
|
|
|
22
27
|
getCurrencyToUSDRate,
|
|
23
28
|
checkAccountTokenAssociationStatus,
|
|
24
29
|
safeParseAccountId,
|
|
30
|
+
isStakingTransaction,
|
|
25
31
|
} from "../logic/utils";
|
|
26
|
-
import
|
|
32
|
+
import { getCurrentHederaPreloadData } from "../preload-data";
|
|
33
|
+
import type {
|
|
34
|
+
HederaAccount,
|
|
35
|
+
Transaction,
|
|
36
|
+
TransactionStatus,
|
|
37
|
+
TransactionTokenAssociate,
|
|
38
|
+
} from "../types";
|
|
27
39
|
import { calculateAmount } from "./utils";
|
|
28
40
|
|
|
29
41
|
type Errors = Record<string, Error>;
|
|
@@ -241,6 +253,66 @@ async function handleCoinTransaction(
|
|
|
241
253
|
};
|
|
242
254
|
}
|
|
243
255
|
|
|
256
|
+
async function handleStakingTransaction(account: HederaAccount, transaction: Transaction) {
|
|
257
|
+
invariant(isStakingTransaction(transaction), "invalid transaction properties");
|
|
258
|
+
|
|
259
|
+
const errors: Record<string, Error> = {};
|
|
260
|
+
const warnings: Record<string, Error> = {};
|
|
261
|
+
const { validators } = getCurrentHederaPreloadData(account.currency);
|
|
262
|
+
const estimatedFees = await estimateFees({
|
|
263
|
+
operationType: HEDERA_OPERATION_TYPES.CryptoUpdate,
|
|
264
|
+
currency: account.currency,
|
|
265
|
+
});
|
|
266
|
+
const amount = BigNumber(0);
|
|
267
|
+
const totalSpent = amount.plus(estimatedFees.tinybars);
|
|
268
|
+
|
|
269
|
+
if (
|
|
270
|
+
transaction.mode === HEDERA_TRANSACTION_MODES.Delegate ||
|
|
271
|
+
transaction.mode === HEDERA_TRANSACTION_MODES.Redelegate
|
|
272
|
+
) {
|
|
273
|
+
if (typeof transaction.properties?.stakingNodeId === "number") {
|
|
274
|
+
const isValid = validators.some(validator => {
|
|
275
|
+
return validator.nodeId === transaction.properties?.stakingNodeId;
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
if (!isValid) {
|
|
279
|
+
errors.stakingNodeId = new HederaInvalidStakingNodeIdError();
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
errors.missingStakingNodeId = new HederaInvalidStakingNodeIdError("Validator must be set");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (account.hederaResources?.delegation?.nodeId === transaction.properties?.stakingNodeId) {
|
|
286
|
+
errors.stakingNodeId = new HederaRedundantStakingNodeIdError();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (transaction.mode === HEDERA_TRANSACTION_MODES.ClaimRewards) {
|
|
291
|
+
const rewardsToClaim = account.hederaResources?.delegation?.pendingReward || new BigNumber(0);
|
|
292
|
+
const transactionFee = transaction.maxFee ?? new BigNumber(0);
|
|
293
|
+
|
|
294
|
+
if (rewardsToClaim.lte(0)) {
|
|
295
|
+
errors.noRewardsToClaim = new HederaNoStakingRewardsError();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (transactionFee.gt(rewardsToClaim)) {
|
|
299
|
+
warnings.claimRewardsFee = new ClaimRewardsFeesWarning();
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (account.balance.isLessThan(totalSpent)) {
|
|
304
|
+
errors.fee = new NotEnoughBalance("");
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
amount: new BigNumber(0),
|
|
309
|
+
estimatedFees: estimatedFees.tinybars,
|
|
310
|
+
totalSpent,
|
|
311
|
+
errors,
|
|
312
|
+
warnings,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
244
316
|
export const getTransactionStatus: AccountBridge<
|
|
245
317
|
Transaction,
|
|
246
318
|
Account,
|
|
@@ -258,6 +330,8 @@ export const getTransactionStatus: AccountBridge<
|
|
|
258
330
|
return handleHTSTokenTransaction(account, subAccount, transaction);
|
|
259
331
|
} else if (isERC20TokenTransaction) {
|
|
260
332
|
return handleERC20TokenTransaction(account, subAccount, transaction);
|
|
333
|
+
} else if (isStakingTransaction(transaction)) {
|
|
334
|
+
return handleStakingTransaction(account, transaction);
|
|
261
335
|
} else {
|
|
262
336
|
return handleCoinTransaction(account, transaction);
|
|
263
337
|
}
|
package/src/bridge/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { estimateMaxSpendable } from "./estimateMaxSpendable";
|
|
|
13
13
|
import { getTransactionStatus } from "./getTransactionStatus";
|
|
14
14
|
import { prepareTransaction } from "./prepareTransaction";
|
|
15
15
|
import { receive } from "./receive";
|
|
16
|
+
import { getPreloadStrategy, hydrate, preload } from "../preload";
|
|
16
17
|
import { buildSignOperation } from "./signOperation";
|
|
17
18
|
import { getAccountShape, buildIterateResult, postSync } from "./synchronisation";
|
|
18
19
|
import { assignFromAccountRaw, assignToAccountRaw } from "./serialization";
|
|
@@ -29,8 +30,9 @@ function buildCurrencyBridge(signerContext: SignerContext<HederaSigner>): Curren
|
|
|
29
30
|
});
|
|
30
31
|
|
|
31
32
|
return {
|
|
32
|
-
preload
|
|
33
|
-
hydrate
|
|
33
|
+
preload,
|
|
34
|
+
hydrate,
|
|
35
|
+
getPreloadStrategy,
|
|
34
36
|
scanAccounts,
|
|
35
37
|
};
|
|
36
38
|
}
|
|
@@ -1,32 +1,136 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
2
|
import { estimateFees } from "../logic/estimateFees";
|
|
3
3
|
import { prepareTransaction } from "./prepareTransaction";
|
|
4
|
-
import { getMockedAccount } from "../test/fixtures/account.fixture";
|
|
4
|
+
import { getMockedAccount, getMockedTokenAccount } from "../test/fixtures/account.fixture";
|
|
5
5
|
import { getMockedTransaction } from "../test/fixtures/transaction.fixture";
|
|
6
6
|
import * as utils from "./utils";
|
|
7
7
|
import type { EstimateFeesResult } from "../types";
|
|
8
|
+
import { HEDERA_OPERATION_TYPES, HEDERA_TRANSACTION_MODES } from "../constants";
|
|
9
|
+
import {
|
|
10
|
+
getMockedERC20TokenCurrency,
|
|
11
|
+
getMockedHTSTokenCurrency,
|
|
12
|
+
} from "../test/fixtures/currency.fixture";
|
|
8
13
|
|
|
9
14
|
jest.mock("../logic/estimateFees");
|
|
10
15
|
|
|
11
16
|
describe("prepareTransaction", () => {
|
|
12
17
|
const mockAccount = getMockedAccount();
|
|
13
18
|
const mockTx = getMockedTransaction();
|
|
14
|
-
const mockFeeEstimation: EstimateFeesResult = {
|
|
19
|
+
const mockFeeEstimation: EstimateFeesResult = {
|
|
20
|
+
tinybars: new BigNumber(10),
|
|
21
|
+
gas: new BigNumber(5),
|
|
22
|
+
};
|
|
23
|
+
const mockCalculatedAmount = {
|
|
24
|
+
amount: new BigNumber(100),
|
|
25
|
+
totalSpent: new BigNumber(100),
|
|
26
|
+
};
|
|
15
27
|
|
|
16
28
|
beforeEach(() => {
|
|
17
29
|
jest.clearAllMocks();
|
|
18
30
|
|
|
19
31
|
(estimateFees as jest.Mock).mockResolvedValue(mockFeeEstimation);
|
|
20
|
-
jest
|
|
21
|
-
.spyOn(utils, "calculateAmount")
|
|
22
|
-
.mockResolvedValue(
|
|
23
|
-
Promise.resolve({ amount: new BigNumber(100), totalSpent: new BigNumber(100) }),
|
|
24
|
-
);
|
|
32
|
+
jest.spyOn(utils, "calculateAmount").mockResolvedValue(mockCalculatedAmount);
|
|
25
33
|
});
|
|
26
34
|
|
|
27
|
-
|
|
35
|
+
it("should set amount and maxFee from utils", async () => {
|
|
28
36
|
const result = await prepareTransaction(mockAccount, mockTx);
|
|
37
|
+
|
|
29
38
|
expect(result.amount).toStrictEqual(new BigNumber(100));
|
|
30
39
|
expect(result.maxFee).toStrictEqual(new BigNumber(10));
|
|
31
40
|
});
|
|
41
|
+
|
|
42
|
+
it("should build ContractCall estimation params with txIntent", async () => {
|
|
43
|
+
const mockTokenERC20 = getMockedERC20TokenCurrency();
|
|
44
|
+
const tokenAccount = getMockedTokenAccount(mockTokenERC20);
|
|
45
|
+
const accountWithToken = getMockedAccount({ subAccounts: [tokenAccount] });
|
|
46
|
+
const transaction = getMockedTransaction({
|
|
47
|
+
mode: HEDERA_TRANSACTION_MODES.Send,
|
|
48
|
+
subAccountId: tokenAccount.id,
|
|
49
|
+
amount: new BigNumber(5000),
|
|
50
|
+
recipient: "0.0.9999",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
await prepareTransaction(accountWithToken, transaction);
|
|
54
|
+
|
|
55
|
+
expect(estimateFees).toHaveBeenCalledWith({
|
|
56
|
+
operationType: HEDERA_OPERATION_TYPES.ContractCall,
|
|
57
|
+
txIntent: {
|
|
58
|
+
intentType: "transaction",
|
|
59
|
+
type: HEDERA_TRANSACTION_MODES.Send,
|
|
60
|
+
asset: {
|
|
61
|
+
type: mockTokenERC20.tokenType,
|
|
62
|
+
assetReference: mockTokenERC20.contractAddress,
|
|
63
|
+
assetOwner: accountWithToken.freshAddress,
|
|
64
|
+
},
|
|
65
|
+
amount: BigInt(5000),
|
|
66
|
+
sender: accountWithToken.freshAddress,
|
|
67
|
+
recipient: transaction.recipient,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should set gasLimit for ERC20 transactions when gas is estimated", async () => {
|
|
73
|
+
const mockTokenERC20 = getMockedERC20TokenCurrency();
|
|
74
|
+
const tokenAccount = getMockedTokenAccount(mockTokenERC20);
|
|
75
|
+
const accountWithToken = getMockedAccount({ subAccounts: [tokenAccount] });
|
|
76
|
+
const transaction = getMockedTransaction({
|
|
77
|
+
mode: HEDERA_TRANSACTION_MODES.Send,
|
|
78
|
+
subAccountId: tokenAccount.id,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const result = await prepareTransaction(accountWithToken, transaction);
|
|
82
|
+
|
|
83
|
+
expect(result).toMatchObject({
|
|
84
|
+
gasLimit: mockFeeEstimation.gas,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("should use TokenTransfer operation type for HTS tokens", async () => {
|
|
89
|
+
const mockTokenHTS = getMockedHTSTokenCurrency();
|
|
90
|
+
const tokenAccount = getMockedTokenAccount(mockTokenHTS);
|
|
91
|
+
const accountWithToken = getMockedAccount({ subAccounts: [tokenAccount] });
|
|
92
|
+
const transaction = getMockedTransaction({
|
|
93
|
+
mode: HEDERA_TRANSACTION_MODES.Send,
|
|
94
|
+
subAccountId: tokenAccount.id,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await prepareTransaction(accountWithToken, transaction);
|
|
98
|
+
|
|
99
|
+
expect(estimateFees).toHaveBeenCalledWith({
|
|
100
|
+
currency: accountWithToken.currency,
|
|
101
|
+
operationType: HEDERA_OPERATION_TYPES.TokenTransfer,
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("should use TokenAssociate operation type", async () => {
|
|
106
|
+
const mockTokenHTS = getMockedHTSTokenCurrency();
|
|
107
|
+
const transaction = getMockedTransaction({
|
|
108
|
+
mode: HEDERA_TRANSACTION_MODES.TokenAssociate,
|
|
109
|
+
properties: {
|
|
110
|
+
token: mockTokenHTS,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await prepareTransaction(mockAccount, transaction);
|
|
115
|
+
|
|
116
|
+
expect(estimateFees).toHaveBeenCalledWith({
|
|
117
|
+
currency: mockAccount.currency,
|
|
118
|
+
operationType: HEDERA_OPERATION_TYPES.TokenAssociate,
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should use CryptoTransfer operation type for native transfers", async () => {
|
|
123
|
+
const transaction = getMockedTransaction({
|
|
124
|
+
mode: HEDERA_TRANSACTION_MODES.Send,
|
|
125
|
+
amount: new BigNumber(1000000),
|
|
126
|
+
recipient: "0.0.12345",
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await prepareTransaction(mockAccount, transaction);
|
|
130
|
+
|
|
131
|
+
expect(estimateFees).toHaveBeenCalledWith({
|
|
132
|
+
currency: mockAccount.currency,
|
|
133
|
+
operationType: HEDERA_OPERATION_TYPES.CryptoTransfer,
|
|
134
|
+
});
|
|
135
|
+
});
|
|
32
136
|
});
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
1
2
|
import { findSubAccountById } from "@ledgerhq/coin-framework/account/helpers";
|
|
3
|
+
import { getEnv } from "@ledgerhq/live-env";
|
|
2
4
|
import type { AccountBridge } from "@ledgerhq/types-live";
|
|
3
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
HEDERA_OPERATION_TYPES,
|
|
7
|
+
HEDERA_TRANSACTION_MODES,
|
|
8
|
+
MAP_STAKING_MODE_TO_MEMO,
|
|
9
|
+
} from "../constants";
|
|
4
10
|
import { estimateFees } from "../logic/estimateFees";
|
|
5
|
-
import { isTokenAssociateTransaction } from "../logic/utils";
|
|
11
|
+
import { isTokenAssociateTransaction, isStakingTransaction } from "../logic/utils";
|
|
6
12
|
import type { EstimateFeesParams, Transaction } from "../types";
|
|
7
13
|
import { calculateAmount } from "./utils";
|
|
8
14
|
|
|
@@ -32,6 +38,8 @@ export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"
|
|
|
32
38
|
operationType = HEDERA_OPERATION_TYPES.TokenTransfer;
|
|
33
39
|
} else if (isERC20TokenTransaction) {
|
|
34
40
|
operationType = HEDERA_OPERATION_TYPES.ContractCall;
|
|
41
|
+
} else if (isStakingTransaction(transaction)) {
|
|
42
|
+
operationType = HEDERA_OPERATION_TYPES.CryptoUpdate;
|
|
35
43
|
} else {
|
|
36
44
|
operationType = HEDERA_OPERATION_TYPES.CryptoTransfer;
|
|
37
45
|
}
|
|
@@ -79,5 +87,15 @@ export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"
|
|
|
79
87
|
transaction.gasLimit = estimatedFees.gas;
|
|
80
88
|
}
|
|
81
89
|
|
|
90
|
+
if (isStakingTransaction(transaction)) {
|
|
91
|
+
transaction.memo = MAP_STAKING_MODE_TO_MEMO[transaction.mode];
|
|
92
|
+
|
|
93
|
+
// claiming staking rewards is triggered by sending 1 tinybar to staking reward account
|
|
94
|
+
if (transaction.mode === HEDERA_TRANSACTION_MODES.ClaimRewards) {
|
|
95
|
+
transaction.recipient = getEnv("HEDERA_CLAIM_REWARDS_RECIPIENT_ACCOUNT_ID");
|
|
96
|
+
transaction.amount = new BigNumber(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
82
100
|
return transaction;
|
|
83
101
|
};
|