@ledgerhq/coin-hedera 1.15.0-nightly.20251126023856 → 1.15.0-nightly.20251127023715
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
package/src/bridge/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
|
-
import type { Account, Operation, TokenAccount } from "@ledgerhq/types-live";
|
|
2
|
+
import type { Account, Operation, OperationType, TokenAccount } from "@ledgerhq/types-live";
|
|
3
3
|
import {
|
|
4
4
|
decodeTokenAccountId,
|
|
5
5
|
emptyHistoryCache,
|
|
@@ -7,15 +7,31 @@ import {
|
|
|
7
7
|
findSubAccountById,
|
|
8
8
|
isTokenAccount,
|
|
9
9
|
} from "@ledgerhq/coin-framework/account";
|
|
10
|
+
import { mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
10
11
|
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
11
12
|
import type { TokenCurrency } from "@ledgerhq/types-cryptoassets";
|
|
12
|
-
import { mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
13
13
|
import { getCryptoAssetsStore } from "@ledgerhq/cryptoassets/state";
|
|
14
14
|
import { HEDERA_OPERATION_TYPES } from "../constants";
|
|
15
15
|
import { estimateMaxSpendable } from "./estimateMaxSpendable";
|
|
16
16
|
import { estimateFees } from "../logic/estimateFees";
|
|
17
|
-
import {
|
|
18
|
-
|
|
17
|
+
import {
|
|
18
|
+
fromEVMAddress,
|
|
19
|
+
toEVMAddress,
|
|
20
|
+
getMemoFromBase64,
|
|
21
|
+
isTokenAssociateTransaction,
|
|
22
|
+
isValidExtra,
|
|
23
|
+
base64ToUrlSafeBase64,
|
|
24
|
+
} from "../logic/utils";
|
|
25
|
+
import { getERC20Operations, parseThirdwebTransactionParams } from "../network/utils";
|
|
26
|
+
import type {
|
|
27
|
+
HederaOperationExtra,
|
|
28
|
+
Transaction,
|
|
29
|
+
OperationERC20,
|
|
30
|
+
HederaMirrorToken,
|
|
31
|
+
HederaERC20TokenBalance,
|
|
32
|
+
HederaThirdwebTransaction,
|
|
33
|
+
ERC20OperationFields,
|
|
34
|
+
} from "../types";
|
|
19
35
|
|
|
20
36
|
interface CalculateAmountResult {
|
|
21
37
|
amount: BigNumber;
|
|
@@ -29,16 +45,16 @@ const calculateCoinAmount = async ({
|
|
|
29
45
|
}: {
|
|
30
46
|
account: Account;
|
|
31
47
|
transaction: Transaction;
|
|
32
|
-
operationType: HEDERA_OPERATION_TYPES
|
|
48
|
+
operationType: Exclude<HEDERA_OPERATION_TYPES, HEDERA_OPERATION_TYPES.ContractCall>;
|
|
33
49
|
}): Promise<CalculateAmountResult> => {
|
|
34
|
-
const estimatedFees = await estimateFees(account.currency, operationType);
|
|
50
|
+
const estimatedFees = await estimateFees({ currency: account.currency, operationType });
|
|
35
51
|
const amount = transaction.useAllAmount
|
|
36
52
|
? await estimateMaxSpendable({ account, transaction })
|
|
37
53
|
: transaction.amount;
|
|
38
54
|
|
|
39
55
|
return {
|
|
40
56
|
amount,
|
|
41
|
-
totalSpent: amount.plus(estimatedFees),
|
|
57
|
+
totalSpent: amount.plus(estimatedFees.tinybars),
|
|
42
58
|
};
|
|
43
59
|
};
|
|
44
60
|
|
|
@@ -82,15 +98,24 @@ export const calculateAmount = ({
|
|
|
82
98
|
return calculateCoinAmount({ account, transaction, operationType });
|
|
83
99
|
};
|
|
84
100
|
|
|
85
|
-
export const getSubAccounts = async (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
export const getSubAccounts = async ({
|
|
102
|
+
ledgerAccountId,
|
|
103
|
+
latestHTSTokenOperations,
|
|
104
|
+
latestERC20TokenOperations,
|
|
105
|
+
mirrorTokens,
|
|
106
|
+
erc20Tokens,
|
|
107
|
+
}: {
|
|
108
|
+
ledgerAccountId: string;
|
|
109
|
+
latestHTSTokenOperations: Operation[];
|
|
110
|
+
latestERC20TokenOperations: Operation[];
|
|
111
|
+
mirrorTokens: HederaMirrorToken[];
|
|
112
|
+
erc20Tokens: HederaERC20TokenBalance[];
|
|
113
|
+
}): Promise<TokenAccount[]> => {
|
|
90
114
|
// Creating a Map of Operations by TokenCurrencies in order to know which TokenAccounts should be synced as well
|
|
91
115
|
const operationsByToken = new Map<TokenCurrency, Operation[]>();
|
|
116
|
+
const subAccounts: TokenAccount[] = [];
|
|
92
117
|
|
|
93
|
-
for (const tokenOperation of
|
|
118
|
+
for (const tokenOperation of [...latestHTSTokenOperations, ...latestERC20TokenOperations]) {
|
|
94
119
|
const { token } = await decodeTokenAccountId(tokenOperation.accountId);
|
|
95
120
|
if (!token) continue;
|
|
96
121
|
|
|
@@ -107,13 +132,18 @@ export const getSubAccounts = async (
|
|
|
107
132
|
operationsByToken.get(token)?.push(tokenOperation);
|
|
108
133
|
}
|
|
109
134
|
|
|
110
|
-
const subAccounts: TokenAccount[] = [];
|
|
111
|
-
|
|
112
135
|
// extract token accounts from existing operations
|
|
113
136
|
for (const [token, tokenOperations] of operationsByToken.entries()) {
|
|
114
|
-
const parentAccountId =
|
|
115
|
-
|
|
116
|
-
|
|
137
|
+
const parentAccountId = ledgerAccountId;
|
|
138
|
+
let balance: BigNumber | null = null;
|
|
139
|
+
|
|
140
|
+
if (token.tokenType === "erc20") {
|
|
141
|
+
const rawBalance = erc20Tokens.find(t => t.token.contractAddress === token.contractAddress);
|
|
142
|
+
balance = rawBalance === undefined ? null : new BigNumber(rawBalance.balance);
|
|
143
|
+
} else {
|
|
144
|
+
const rawBalance = mirrorTokens.find(t => t.token_id === token.contractAddress)?.balance;
|
|
145
|
+
balance = rawBalance === undefined ? null : new BigNumber(rawBalance);
|
|
146
|
+
}
|
|
117
147
|
|
|
118
148
|
if (!balance) {
|
|
119
149
|
continue;
|
|
@@ -137,34 +167,41 @@ export const getSubAccounts = async (
|
|
|
137
167
|
}
|
|
138
168
|
|
|
139
169
|
// extract token accounts existing in the account's balance, but with no recorded operations yet
|
|
140
|
-
// e.g. tokens added via association flow, without any subsequent activity
|
|
141
|
-
|
|
142
|
-
|
|
170
|
+
// e.g. hts tokens added via association flow, without any subsequent activity
|
|
171
|
+
// or erc20 tokens received from 3rd party
|
|
172
|
+
for (const rawToken of [...mirrorTokens, ...erc20Tokens]) {
|
|
173
|
+
const parentAccountId = ledgerAccountId;
|
|
143
174
|
const rawBalance = rawToken.balance;
|
|
144
175
|
const balance = new BigNumber(rawBalance);
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
);
|
|
176
|
+
const isERC20 = "token" in rawToken;
|
|
177
|
+
const tokenAddress = isERC20 ? rawToken.token.contractAddress : rawToken.token_id;
|
|
178
|
+
const token = await getCryptoAssetsStore().findTokenByAddressInCurrency(tokenAddress, "hedera");
|
|
149
179
|
|
|
150
180
|
if (!token) {
|
|
151
181
|
continue;
|
|
152
182
|
}
|
|
153
183
|
|
|
154
184
|
const id = encodeTokenAccountId(parentAccountId, token);
|
|
185
|
+
const operations = operationsByToken.get(token) ?? [];
|
|
155
186
|
|
|
156
187
|
if (subAccounts.some(a => a.id === id)) {
|
|
157
188
|
continue;
|
|
158
189
|
}
|
|
159
190
|
|
|
191
|
+
if (isERC20 && operations.length === 0 && balance.isZero()) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
160
195
|
subAccounts.push({
|
|
161
196
|
type: "TokenAccount",
|
|
162
|
-
id
|
|
197
|
+
id,
|
|
163
198
|
parentId: parentAccountId,
|
|
164
199
|
token,
|
|
165
200
|
balance,
|
|
166
201
|
spendableBalance: balance,
|
|
167
|
-
creationDate:
|
|
202
|
+
creationDate: isERC20
|
|
203
|
+
? new Date()
|
|
204
|
+
: new Date(Number.parseFloat(rawToken.created_timestamp) * 1000),
|
|
168
205
|
operations: [],
|
|
169
206
|
operationsCount: 0,
|
|
170
207
|
pendingOperations: [],
|
|
@@ -350,3 +387,269 @@ export function patchOperationWithExtra(
|
|
|
350
387
|
nftOperations: (operation.nftOperations ?? []).map(op => ({ ...op, extra })),
|
|
351
388
|
};
|
|
352
389
|
}
|
|
390
|
+
|
|
391
|
+
// filter out CONTRACT_CALL operations based on pending and already existing ERC20 operations to avoid duplicates
|
|
392
|
+
export const removeDuplicatedContractCallOperations = (
|
|
393
|
+
operations: Operation[],
|
|
394
|
+
pendingOperationHashes: Set<string>,
|
|
395
|
+
erc20OperationHashes: Set<string>,
|
|
396
|
+
): Operation[] => {
|
|
397
|
+
return operations.filter(op => {
|
|
398
|
+
if (op.type !== "CONTRACT_CALL") {
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const hashAlreadyExists =
|
|
403
|
+
erc20OperationHashes.has(op.hash) || pendingOperationHashes.has(op.hash);
|
|
404
|
+
|
|
405
|
+
return !hashAlreadyExists;
|
|
406
|
+
});
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
// loop over latestERC20Operations and prepare lists of transactions that should be patched and added
|
|
410
|
+
// - patching happens when we have a matching CONTRACT_CALL operation without blockHash set (mirror node transaction without ERC20 details)
|
|
411
|
+
// - adding happens when we have no matching operation
|
|
412
|
+
export const classifyERC20Operations = ({
|
|
413
|
+
latestERC20Operations,
|
|
414
|
+
operationsByHash,
|
|
415
|
+
evmAccountAddress,
|
|
416
|
+
}: {
|
|
417
|
+
latestERC20Operations: OperationERC20[];
|
|
418
|
+
operationsByHash: Map<string, Operation>;
|
|
419
|
+
evmAccountAddress: string | null;
|
|
420
|
+
}): {
|
|
421
|
+
erc20OperationsToPatch: Map<string, OperationERC20>;
|
|
422
|
+
erc20OperationsToAdd: Map<string, OperationERC20>;
|
|
423
|
+
} => {
|
|
424
|
+
const erc20OperationsToPatch = new Map<string, OperationERC20>();
|
|
425
|
+
const erc20OperationsToAdd = new Map<string, OperationERC20>();
|
|
426
|
+
|
|
427
|
+
for (const erc20Operation of latestERC20Operations) {
|
|
428
|
+
const hash = base64ToUrlSafeBase64(erc20Operation.mirrorTransaction.transaction_hash);
|
|
429
|
+
const existingOp = operationsByHash.get(hash);
|
|
430
|
+
const type =
|
|
431
|
+
erc20Operation.thirdwebTransaction.decoded.params.from === evmAccountAddress ? "OUT" : "IN";
|
|
432
|
+
|
|
433
|
+
if (!existingOp) {
|
|
434
|
+
erc20OperationsToAdd.set(hash, erc20Operation);
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (existingOp.type === "CONTRACT_CALL" && type === "OUT" && !existingOp.blockHash) {
|
|
439
|
+
erc20OperationsToPatch.set(hash, erc20Operation);
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return { erc20OperationsToPatch, erc20OperationsToAdd };
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
// extracts common fields from an ERC20 operation
|
|
448
|
+
const buildERC20OperationFields = ({
|
|
449
|
+
erc20Operation,
|
|
450
|
+
relatedExistingOperation,
|
|
451
|
+
variant,
|
|
452
|
+
evmAddress,
|
|
453
|
+
}: {
|
|
454
|
+
variant: "patch" | "add";
|
|
455
|
+
evmAddress: string | null;
|
|
456
|
+
erc20Operation: OperationERC20;
|
|
457
|
+
relatedExistingOperation?: Operation;
|
|
458
|
+
}): ERC20OperationFields | null => {
|
|
459
|
+
const decodedParams = parseThirdwebTransactionParams(erc20Operation.thirdwebTransaction);
|
|
460
|
+
|
|
461
|
+
if (!decodedParams) {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
let type: OperationType = "OUT";
|
|
466
|
+
const standard = "erc20";
|
|
467
|
+
const blockHeight = 5;
|
|
468
|
+
const blockHash = erc20Operation.thirdwebTransaction.blockHash;
|
|
469
|
+
const consensusTimestamp = erc20Operation.mirrorTransaction.consensus_timestamp;
|
|
470
|
+
const timestamp = new Date(Number.parseInt(consensusTimestamp.split(".")[0], 10) * 1000);
|
|
471
|
+
const fee = BigNumber(erc20Operation.mirrorTransaction.charged_tx_fee);
|
|
472
|
+
const value = BigNumber(decodedParams.value);
|
|
473
|
+
const senderAddress = fromEVMAddress(decodedParams.from) ?? decodedParams.from;
|
|
474
|
+
const recipientAddress = fromEVMAddress(decodedParams.to) ?? decodedParams.to;
|
|
475
|
+
const memo = getMemoFromBase64(erc20Operation.mirrorTransaction.memo_base64);
|
|
476
|
+
const extra: HederaOperationExtra = {
|
|
477
|
+
...(isValidExtra(relatedExistingOperation?.extra) && relatedExistingOperation.extra),
|
|
478
|
+
...(memo && { memo }),
|
|
479
|
+
consensusTimestamp: erc20Operation.contractCallResult.timestamp,
|
|
480
|
+
transactionId: erc20Operation.mirrorTransaction.transaction_id,
|
|
481
|
+
gasConsumed: erc20Operation.contractCallResult.gas_consumed,
|
|
482
|
+
gasLimit: erc20Operation.contractCallResult.gas_limit,
|
|
483
|
+
gasUsed: erc20Operation.contractCallResult.gas_used,
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
if (variant === "add") {
|
|
487
|
+
type = decodedParams.from === evmAddress ? "OUT" : "IN";
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return {
|
|
491
|
+
date: timestamp,
|
|
492
|
+
type,
|
|
493
|
+
fee,
|
|
494
|
+
value,
|
|
495
|
+
senders: [senderAddress],
|
|
496
|
+
recipients: [recipientAddress],
|
|
497
|
+
blockHeight,
|
|
498
|
+
blockHash,
|
|
499
|
+
extra,
|
|
500
|
+
standard,
|
|
501
|
+
hasFailed: false,
|
|
502
|
+
};
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// patches an existing CONTRACT_CALL operation with ERC20 token operation details
|
|
506
|
+
export const patchContractCallOperation = ({
|
|
507
|
+
relatedExistingOperation,
|
|
508
|
+
ledgerAccountId,
|
|
509
|
+
hash,
|
|
510
|
+
erc20Fields,
|
|
511
|
+
tokenOperation,
|
|
512
|
+
}: {
|
|
513
|
+
relatedExistingOperation: Operation;
|
|
514
|
+
ledgerAccountId: string;
|
|
515
|
+
hash: string;
|
|
516
|
+
erc20Fields: ERC20OperationFields;
|
|
517
|
+
tokenOperation: Operation;
|
|
518
|
+
}): void => {
|
|
519
|
+
Object.assign(relatedExistingOperation, {
|
|
520
|
+
...erc20Fields,
|
|
521
|
+
id: encodeOperationId(ledgerAccountId, hash, "FEES"),
|
|
522
|
+
type: "FEES",
|
|
523
|
+
value: erc20Fields.fee,
|
|
524
|
+
subOperations: [tokenOperation],
|
|
525
|
+
});
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
export const integrateERC20Operations = async ({
|
|
529
|
+
ledgerAccountId,
|
|
530
|
+
address,
|
|
531
|
+
allOperations,
|
|
532
|
+
latestERC20Transactions,
|
|
533
|
+
pendingOperationHashes,
|
|
534
|
+
erc20OperationHashes,
|
|
535
|
+
}: {
|
|
536
|
+
ledgerAccountId: string;
|
|
537
|
+
address: string;
|
|
538
|
+
allOperations: Operation[];
|
|
539
|
+
latestERC20Transactions: HederaThirdwebTransaction[];
|
|
540
|
+
pendingOperationHashes: Set<string>;
|
|
541
|
+
erc20OperationHashes: Set<string>;
|
|
542
|
+
}): Promise<{
|
|
543
|
+
updatedOperations: Operation[];
|
|
544
|
+
newERC20TokenOperations: Operation[];
|
|
545
|
+
}> => {
|
|
546
|
+
const newERC20TokenOperations: Operation[] = [];
|
|
547
|
+
const latestERC20Operations = await getERC20Operations(latestERC20Transactions);
|
|
548
|
+
const evmAddress = toEVMAddress(address);
|
|
549
|
+
|
|
550
|
+
// avoid duplicated CONTRACT_CALL operations if ERC20 operations are already present
|
|
551
|
+
const uniqueOperations = removeDuplicatedContractCallOperations(
|
|
552
|
+
allOperations,
|
|
553
|
+
pendingOperationHashes,
|
|
554
|
+
erc20OperationHashes,
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
// nothing to patch/add if no new ERC20 operations found
|
|
558
|
+
if (latestERC20Operations.length === 0) {
|
|
559
|
+
return {
|
|
560
|
+
updatedOperations: uniqueOperations,
|
|
561
|
+
newERC20TokenOperations,
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// create copy to avoid mutating original array and index by hash for easy lookup
|
|
566
|
+
const updatedOperations = uniqueOperations.map(op => ({ ...op }));
|
|
567
|
+
const operationsByHash = updatedOperations.reduce((acc, curr) => {
|
|
568
|
+
acc.set(curr.hash, curr);
|
|
569
|
+
return acc;
|
|
570
|
+
}, new Map<string, Operation>());
|
|
571
|
+
|
|
572
|
+
// split erc20 operations into patch and add lists
|
|
573
|
+
const { erc20OperationsToPatch, erc20OperationsToAdd } = classifyERC20Operations({
|
|
574
|
+
latestERC20Operations,
|
|
575
|
+
operationsByHash,
|
|
576
|
+
evmAccountAddress: evmAddress,
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
// patch existing operations with data from thirdweb
|
|
580
|
+
for (const [hash, erc20Operation] of erc20OperationsToPatch.entries()) {
|
|
581
|
+
const relatedExistingOperation = operationsByHash.get(hash);
|
|
582
|
+
if (!relatedExistingOperation) continue;
|
|
583
|
+
|
|
584
|
+
const erc20Fields = buildERC20OperationFields({
|
|
585
|
+
variant: "patch",
|
|
586
|
+
evmAddress,
|
|
587
|
+
erc20Operation,
|
|
588
|
+
relatedExistingOperation,
|
|
589
|
+
});
|
|
590
|
+
if (!erc20Fields) continue;
|
|
591
|
+
|
|
592
|
+
const encodedTokenAccountId = encodeTokenAccountId(ledgerAccountId, erc20Operation.token);
|
|
593
|
+
const encodedOperationId = encodeOperationId(encodedTokenAccountId, hash, erc20Fields.type);
|
|
594
|
+
const tokenOperation: Operation<HederaOperationExtra> = {
|
|
595
|
+
...erc20Fields,
|
|
596
|
+
id: encodedOperationId,
|
|
597
|
+
accountId: encodedTokenAccountId,
|
|
598
|
+
hash,
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
patchContractCallOperation({
|
|
602
|
+
relatedExistingOperation,
|
|
603
|
+
ledgerAccountId,
|
|
604
|
+
hash,
|
|
605
|
+
erc20Fields,
|
|
606
|
+
tokenOperation,
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
newERC20TokenOperations.push(tokenOperation);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// create new operations for remaining ERC20 operations
|
|
613
|
+
for (const [hash, erc20Operation] of erc20OperationsToAdd.entries()) {
|
|
614
|
+
const erc20Fields = buildERC20OperationFields({
|
|
615
|
+
variant: "add",
|
|
616
|
+
evmAddress,
|
|
617
|
+
erc20Operation,
|
|
618
|
+
});
|
|
619
|
+
if (!erc20Fields) continue;
|
|
620
|
+
|
|
621
|
+
const encodedTokenAccountId = encodeTokenAccountId(ledgerAccountId, erc20Operation.token);
|
|
622
|
+
const encodedOperationId = encodeOperationId(encodedTokenAccountId, hash, erc20Fields.type);
|
|
623
|
+
const tokenOperation: Operation<HederaOperationExtra> = {
|
|
624
|
+
...erc20Fields,
|
|
625
|
+
id: encodedOperationId,
|
|
626
|
+
accountId: encodedTokenAccountId,
|
|
627
|
+
hash,
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
const coinOperation: Operation<HederaOperationExtra> =
|
|
631
|
+
erc20Fields.type === "OUT"
|
|
632
|
+
? {
|
|
633
|
+
...erc20Fields,
|
|
634
|
+
id: encodeOperationId(ledgerAccountId, hash, "FEES"),
|
|
635
|
+
accountId: ledgerAccountId,
|
|
636
|
+
type: "FEES",
|
|
637
|
+
value: erc20Fields.fee,
|
|
638
|
+
hash,
|
|
639
|
+
}
|
|
640
|
+
: await makeCoinOperationForOrphanChildOperation(tokenOperation);
|
|
641
|
+
|
|
642
|
+
coinOperation.subOperations = [tokenOperation];
|
|
643
|
+
updatedOperations.push(coinOperation);
|
|
644
|
+
newERC20TokenOperations.push(tokenOperation);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// ensure operations lists are sorted correctly
|
|
648
|
+
updatedOperations.sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
649
|
+
newERC20TokenOperations.sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
650
|
+
|
|
651
|
+
return {
|
|
652
|
+
updatedOperations,
|
|
653
|
+
newERC20TokenOperations,
|
|
654
|
+
};
|
|
655
|
+
};
|
package/src/constants.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Internal types to distinguish custom Hedera transaction behaviors.
|
|
3
5
|
* These can be used in transaction.mode and used to route specific preparation logic.
|
|
@@ -14,17 +16,29 @@ export enum HEDERA_OPERATION_TYPES {
|
|
|
14
16
|
CryptoTransfer = "CryptoTransfer",
|
|
15
17
|
TokenTransfer = "TokenTransfer",
|
|
16
18
|
TokenAssociate = "TokenAssociate",
|
|
19
|
+
ContractCall = "ContractCall",
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
export const TINYBAR_SCALE = 8;
|
|
20
23
|
|
|
21
|
-
export const ESTIMATED_FEE_SAFETY_RATE = 2;
|
|
22
|
-
|
|
23
24
|
// old value moved from https://github.com/LedgerHQ/ledger-live/blob/8447b68b7c6f1e7ccd4aa9db4da0e6c8de36a88e/libs/coin-modules/coin-hedera/src/bridge/utils.ts#L77
|
|
24
25
|
export const DEFAULT_TINYBAR_FEE = 150200;
|
|
25
26
|
|
|
26
27
|
export const SYNTHETIC_BLOCK_WINDOW_SECONDS = 10;
|
|
27
28
|
|
|
29
|
+
export const ERC20_TRANSFER_EVENT_TOPIC =
|
|
30
|
+
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
31
|
+
|
|
32
|
+
export const ESTIMATED_GAS_SAFETY_RATE = 1.2;
|
|
33
|
+
|
|
34
|
+
export const ESTIMATED_FEE_SAFETY_RATE = 2;
|
|
35
|
+
|
|
36
|
+
export const DEFAULT_GAS_LIMIT = new BigNumber(100_000);
|
|
37
|
+
|
|
38
|
+
export const DEFAULT_GAS_PRICE_TINYBARS = new BigNumber(100);
|
|
39
|
+
|
|
40
|
+
export const HEDERA_MAINNET_CHAIN_ID = 295;
|
|
41
|
+
|
|
28
42
|
/**
|
|
29
43
|
* https://docs.hedera.com/hedera/networks/mainnet/fees
|
|
30
44
|
*
|
|
@@ -38,4 +52,35 @@ export const BASE_USD_FEE_BY_OPERATION_TYPE = {
|
|
|
38
52
|
[HEDERA_OPERATION_TYPES.CryptoTransfer]: 0.0001 * 10 ** TINYBAR_SCALE,
|
|
39
53
|
[HEDERA_OPERATION_TYPES.TokenTransfer]: 0.001 * 10 ** TINYBAR_SCALE,
|
|
40
54
|
[HEDERA_OPERATION_TYPES.TokenAssociate]: 0.05 * 10 ** TINYBAR_SCALE,
|
|
55
|
+
[HEDERA_OPERATION_TYPES.ContractCall]: 0, // Contract call fees are based on gas used and are handled separately
|
|
41
56
|
} as const satisfies Record<HEDERA_OPERATION_TYPES, number>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Array of supported ERC20 token IDs for Hedera.
|
|
60
|
+
*
|
|
61
|
+
* This is a temporary solution to allow bypassing deprecated methods.
|
|
62
|
+
* It is essential to update this list in the future to ensure support
|
|
63
|
+
* for other erc20 tokens.
|
|
64
|
+
*/
|
|
65
|
+
export const SUPPORTED_ERC20_TOKENS = [
|
|
66
|
+
{
|
|
67
|
+
id: "hedera/erc20/weth_0xca367694cdac8f152e33683bb36cc9d6a73f1ef2",
|
|
68
|
+
contractAddress: "0xca367694cdac8f152e33683bb36cc9d6a73f1ef2",
|
|
69
|
+
tokenId: "0.0.9470869",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "hedera/erc20/bonzo_atoken_usdc_0xb7687538c7f4cad022d5e97cc778d0b46457c5db",
|
|
73
|
+
contractAddress: "0xb7687538c7f4cad022d5e97cc778d0b46457c5db",
|
|
74
|
+
tokenId: "0.0.7308496",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "hedera/erc20/audd_0x39ceba2b467fa987546000eb5d1373acf1f3a2e1",
|
|
78
|
+
contractAddress: "0x39ceba2b467fa987546000eb5d1373acf1f3a2e1",
|
|
79
|
+
tokenId: "0.0.8317070",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "hedera/erc20/wrapped_btc_0xd7d4d91d64a6061fa00a94e2b3a2d2a5fb677849",
|
|
83
|
+
contractAddress: "0xd7d4d91d64a6061fa00a94e2b3a2d2a5fb677849",
|
|
84
|
+
tokenId: "0.0.10047837",
|
|
85
|
+
},
|
|
86
|
+
];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { AccountLike, Account } from "@ledgerhq/types-live";
|
|
2
1
|
import type { CommonDeviceTransactionField as DeviceTransactionField } from "@ledgerhq/coin-framework/transaction/common";
|
|
2
|
+
import type { AccountLike, Account } from "@ledgerhq/types-live";
|
|
3
|
+
import { HEDERA_TRANSACTION_MODES } from "./constants";
|
|
3
4
|
import { isTokenAssociateTransaction } from "./logic/utils";
|
|
4
5
|
import type { Transaction, TransactionStatus } from "./types";
|
|
5
6
|
|
|
@@ -40,6 +41,14 @@ async function getDeviceTransactionConfig({
|
|
|
40
41
|
});
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
if (transaction.mode === HEDERA_TRANSACTION_MODES.Send && transaction.gasLimit) {
|
|
45
|
+
fields.push({
|
|
46
|
+
type: "text",
|
|
47
|
+
label: "Gas Limit",
|
|
48
|
+
value: transaction.gasLimit.toString(),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
if (transaction.memo) {
|
|
44
53
|
fields.push({
|
|
45
54
|
type: "text",
|
package/src/errors.ts
CHANGED
|
@@ -13,3 +13,6 @@ export const HederaRecipientTokenAssociationRequired = createCustomErrorClass(
|
|
|
13
13
|
export const HederaRecipientTokenAssociationUnverified = createCustomErrorClass(
|
|
14
14
|
"HederaRecipientTokenAssociationUnverified",
|
|
15
15
|
);
|
|
16
|
+
export const HederaRecipientEvmAddressVerificationRequired = createCustomErrorClass(
|
|
17
|
+
"HederaRecipientEvmAddressVerificationRequired",
|
|
18
|
+
);
|
|
@@ -3,7 +3,7 @@ import * as sdk from "@hashgraph/sdk";
|
|
|
3
3
|
import type { FeeEstimation, TransactionIntent } from "@ledgerhq/coin-framework/api/index";
|
|
4
4
|
import { HEDERA_TRANSACTION_MODES, TINYBAR_SCALE } from "../constants";
|
|
5
5
|
import { craftTransaction } from "./craftTransaction";
|
|
6
|
-
import type { HederaMemo } from "../types";
|
|
6
|
+
import type { HederaMemo, HederaTxData } from "../types";
|
|
7
7
|
import { serializeTransaction } from "./utils";
|
|
8
8
|
|
|
9
9
|
jest.mock("./utils");
|
|
@@ -39,8 +39,8 @@ describe("craftTransaction", () => {
|
|
|
39
39
|
const senderTransfer = result.tx.hbarTransfers?.get(txIntent.sender);
|
|
40
40
|
const recipientTransfer = result.tx.hbarTransfers?.get(txIntent.recipient);
|
|
41
41
|
|
|
42
|
-
expect(senderTransfer).toEqual(sdk.Hbar.fromTinybars(-txIntent.amount));
|
|
43
|
-
expect(recipientTransfer).toEqual(sdk.Hbar.fromTinybars(txIntent.amount));
|
|
42
|
+
expect(senderTransfer).toEqual(sdk.Hbar.fromTinybars((-txIntent.amount).toString()));
|
|
43
|
+
expect(recipientTransfer).toEqual(sdk.Hbar.fromTinybars(txIntent.amount.toString()));
|
|
44
44
|
expect(result.tx.transactionMemo).toBe(txIntent.memo.value);
|
|
45
45
|
expect(serializeTransaction).toHaveBeenCalled();
|
|
46
46
|
expect(result).toEqual({
|
|
@@ -49,7 +49,7 @@ describe("craftTransaction", () => {
|
|
|
49
49
|
});
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
it("should craft
|
|
52
|
+
it("should craft HTS token transfer transaction", async () => {
|
|
53
53
|
const txIntent = {
|
|
54
54
|
intentType: "transaction",
|
|
55
55
|
type: HEDERA_TRANSACTION_MODES.Send,
|
|
@@ -76,10 +76,50 @@ describe("craftTransaction", () => {
|
|
|
76
76
|
const senderTransfer = tokenTransfers?.get(txIntent.sender);
|
|
77
77
|
const recipientTransfer = tokenTransfers?.get(txIntent.recipient);
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
expect(
|
|
82
|
-
expect(
|
|
79
|
+
expect(senderTransfer).toEqual(sdk.Long.fromBigInt(-txIntent.amount));
|
|
80
|
+
expect(recipientTransfer).toEqual(sdk.Long.fromBigInt(txIntent.amount));
|
|
81
|
+
expect(result.tx.transactionMemo).toBe("Token transfer");
|
|
82
|
+
expect(serializeTransaction).toHaveBeenCalled();
|
|
83
|
+
expect(result).toEqual({
|
|
84
|
+
tx: expect.any(Object),
|
|
85
|
+
serializedTx: "serialized-transaction",
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should craft ERC20 token transfer transaction", async () => {
|
|
90
|
+
const txIntent = {
|
|
91
|
+
intentType: "transaction",
|
|
92
|
+
type: HEDERA_TRANSACTION_MODES.Send,
|
|
93
|
+
amount: BigInt(1000),
|
|
94
|
+
recipient: "0.0.12345",
|
|
95
|
+
sender: "0.0.54321",
|
|
96
|
+
asset: {
|
|
97
|
+
type: "erc20",
|
|
98
|
+
assetReference: "0x39ceba2b467fa987546000eb5d1373acf1f3a2e1",
|
|
99
|
+
},
|
|
100
|
+
memo: {
|
|
101
|
+
kind: "text",
|
|
102
|
+
type: "string",
|
|
103
|
+
value: "Token transfer",
|
|
104
|
+
},
|
|
105
|
+
data: {
|
|
106
|
+
type: "erc20",
|
|
107
|
+
gasLimit: BigInt(100000),
|
|
108
|
+
},
|
|
109
|
+
} satisfies TransactionIntent<HederaMemo, HederaTxData>;
|
|
110
|
+
|
|
111
|
+
const result = await craftTransaction(txIntent);
|
|
112
|
+
|
|
113
|
+
expect(result.tx).toBeInstanceOf(sdk.ContractExecuteTransaction);
|
|
114
|
+
invariant(
|
|
115
|
+
result.tx instanceof sdk.ContractExecuteTransaction,
|
|
116
|
+
"ContractExecuteTransaction type guard",
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
expect(result.tx.gas).toEqual(sdk.Long.fromBigInt(txIntent.data.gasLimit));
|
|
120
|
+
expect(result.tx.contractId).toEqual(
|
|
121
|
+
sdk.ContractId.fromEvmAddress(0, 0, txIntent.asset.assetReference),
|
|
122
|
+
);
|
|
83
123
|
expect(result.tx.transactionMemo).toBe("Token transfer");
|
|
84
124
|
expect(serializeTransaction).toHaveBeenCalled();
|
|
85
125
|
expect(result).toEqual({
|
|
@@ -150,7 +190,7 @@ describe("craftTransaction", () => {
|
|
|
150
190
|
|
|
151
191
|
expect(result.tx).toBeInstanceOf(sdk.TransferTransaction);
|
|
152
192
|
invariant(result.tx instanceof sdk.TransferTransaction, "TransferTransaction type guard");
|
|
153
|
-
expect(result.tx.maxTransactionFee).toEqual(sdk.Hbar.fromTinybars(customFees.value));
|
|
193
|
+
expect(result.tx.maxTransactionFee).toEqual(sdk.Hbar.fromTinybars(customFees.value.toString()));
|
|
154
194
|
});
|
|
155
195
|
|
|
156
196
|
it("should throw error when token associate transaction has invalid asset type", async () => {
|