@ledgerhq/coin-hedera 1.12.0-nightly.7 → 1.12.0

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.
Files changed (134) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +26 -76
  3. package/lib/api/mirror.test.d.ts +2 -0
  4. package/lib/api/mirror.test.d.ts.map +1 -0
  5. package/lib/api/mirror.test.js +114 -0
  6. package/lib/api/mirror.test.js.map +1 -0
  7. package/lib/api/network.d.ts +6 -2
  8. package/lib/api/network.d.ts.map +1 -1
  9. package/lib/api/network.js +25 -4
  10. package/lib/api/network.js.map +1 -1
  11. package/lib/api/network.test.d.ts +2 -0
  12. package/lib/api/network.test.d.ts.map +1 -0
  13. package/lib/api/network.test.js +45 -0
  14. package/lib/api/network.test.js.map +1 -0
  15. package/lib/bridge/buildOptimisticOperation.d.ts.map +1 -1
  16. package/lib/bridge/buildOptimisticOperation.integration.test.d.ts +2 -0
  17. package/lib/bridge/buildOptimisticOperation.integration.test.d.ts.map +1 -0
  18. package/lib/bridge/buildOptimisticOperation.integration.test.js +82 -0
  19. package/lib/bridge/buildOptimisticOperation.integration.test.js.map +1 -0
  20. package/lib/bridge/buildOptimisticOperation.js +2 -6
  21. package/lib/bridge/buildOptimisticOperation.js.map +1 -1
  22. package/lib/bridge/getTransactionStatus.d.ts.map +1 -1
  23. package/lib/bridge/getTransactionStatus.js +13 -10
  24. package/lib/bridge/getTransactionStatus.js.map +1 -1
  25. package/lib/bridge/getTransactionStatus.test.d.ts +2 -0
  26. package/lib/bridge/getTransactionStatus.test.d.ts.map +1 -0
  27. package/lib/bridge/getTransactionStatus.test.js +176 -0
  28. package/lib/bridge/getTransactionStatus.test.js.map +1 -0
  29. package/lib/bridge/js-estimateMaxSpendable.integration.test.d.ts +2 -0
  30. package/lib/bridge/js-estimateMaxSpendable.integration.test.d.ts.map +1 -0
  31. package/lib/bridge/js-estimateMaxSpendable.integration.test.js +47 -0
  32. package/lib/bridge/js-estimateMaxSpendable.integration.test.js.map +1 -0
  33. package/lib/bridge/js-transaction.test.d.ts +2 -0
  34. package/lib/bridge/js-transaction.test.d.ts.map +1 -0
  35. package/lib/bridge/js-transaction.test.js +40 -0
  36. package/lib/bridge/js-transaction.test.js.map +1 -0
  37. package/lib/bridge/prepareTransaction.test.d.ts +2 -0
  38. package/lib/bridge/prepareTransaction.test.d.ts.map +1 -0
  39. package/lib/bridge/prepareTransaction.test.js +58 -0
  40. package/lib/bridge/prepareTransaction.test.js.map +1 -0
  41. package/lib/bridge/serialization.test.d.ts +2 -0
  42. package/lib/bridge/serialization.test.d.ts.map +1 -0
  43. package/lib/bridge/serialization.test.js +27 -0
  44. package/lib/bridge/serialization.test.js.map +1 -0
  45. package/lib/bridge/transaction.test.d.ts +2 -0
  46. package/lib/bridge/transaction.test.d.ts.map +1 -0
  47. package/lib/bridge/transaction.test.js +37 -0
  48. package/lib/bridge/transaction.test.js.map +1 -0
  49. package/lib/bridge/utils.d.ts +0 -4
  50. package/lib/bridge/utils.d.ts.map +1 -1
  51. package/lib/bridge/utils.integration.test.d.ts +2 -0
  52. package/lib/bridge/utils.integration.test.d.ts.map +1 -0
  53. package/lib/bridge/utils.integration.test.js +428 -0
  54. package/lib/bridge/utils.integration.test.js.map +1 -0
  55. package/lib/bridge/utils.js +3 -41
  56. package/lib/bridge/utils.js.map +1 -1
  57. package/lib/errors.d.ts +0 -12
  58. package/lib/errors.d.ts.map +1 -1
  59. package/lib/errors.js +1 -5
  60. package/lib/errors.js.map +1 -1
  61. package/lib/logic.test.d.ts +2 -0
  62. package/lib/logic.test.d.ts.map +1 -0
  63. package/lib/logic.test.js +111 -0
  64. package/lib/logic.test.js.map +1 -0
  65. package/lib-es/api/mirror.test.d.ts +2 -0
  66. package/lib-es/api/mirror.test.d.ts.map +1 -0
  67. package/lib-es/api/mirror.test.js +109 -0
  68. package/lib-es/api/mirror.test.js.map +1 -0
  69. package/lib-es/api/network.d.ts +6 -2
  70. package/lib-es/api/network.d.ts.map +1 -1
  71. package/lib-es/api/network.js +24 -3
  72. package/lib-es/api/network.js.map +1 -1
  73. package/lib-es/api/network.test.d.ts +2 -0
  74. package/lib-es/api/network.test.d.ts.map +1 -0
  75. package/lib-es/api/network.test.js +40 -0
  76. package/lib-es/api/network.test.js.map +1 -0
  77. package/lib-es/bridge/buildOptimisticOperation.d.ts.map +1 -1
  78. package/lib-es/bridge/buildOptimisticOperation.integration.test.d.ts +2 -0
  79. package/lib-es/bridge/buildOptimisticOperation.integration.test.d.ts.map +1 -0
  80. package/lib-es/bridge/buildOptimisticOperation.integration.test.js +77 -0
  81. package/lib-es/bridge/buildOptimisticOperation.integration.test.js.map +1 -0
  82. package/lib-es/bridge/buildOptimisticOperation.js +3 -7
  83. package/lib-es/bridge/buildOptimisticOperation.js.map +1 -1
  84. package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -1
  85. package/lib-es/bridge/getTransactionStatus.js +12 -9
  86. package/lib-es/bridge/getTransactionStatus.js.map +1 -1
  87. package/lib-es/bridge/getTransactionStatus.test.d.ts +2 -0
  88. package/lib-es/bridge/getTransactionStatus.test.d.ts.map +1 -0
  89. package/lib-es/bridge/getTransactionStatus.test.js +148 -0
  90. package/lib-es/bridge/getTransactionStatus.test.js.map +1 -0
  91. package/lib-es/bridge/js-estimateMaxSpendable.integration.test.d.ts +2 -0
  92. package/lib-es/bridge/js-estimateMaxSpendable.integration.test.d.ts.map +1 -0
  93. package/lib-es/bridge/js-estimateMaxSpendable.integration.test.js +42 -0
  94. package/lib-es/bridge/js-estimateMaxSpendable.integration.test.js.map +1 -0
  95. package/lib-es/bridge/js-transaction.test.d.ts +2 -0
  96. package/lib-es/bridge/js-transaction.test.d.ts.map +1 -0
  97. package/lib-es/bridge/js-transaction.test.js +35 -0
  98. package/lib-es/bridge/js-transaction.test.js.map +1 -0
  99. package/lib-es/bridge/prepareTransaction.test.d.ts +2 -0
  100. package/lib-es/bridge/prepareTransaction.test.d.ts.map +1 -0
  101. package/lib-es/bridge/prepareTransaction.test.js +30 -0
  102. package/lib-es/bridge/prepareTransaction.test.js.map +1 -0
  103. package/lib-es/bridge/serialization.test.d.ts +2 -0
  104. package/lib-es/bridge/serialization.test.d.ts.map +1 -0
  105. package/lib-es/bridge/serialization.test.js +25 -0
  106. package/lib-es/bridge/serialization.test.js.map +1 -0
  107. package/lib-es/bridge/transaction.test.d.ts +2 -0
  108. package/lib-es/bridge/transaction.test.d.ts.map +1 -0
  109. package/lib-es/bridge/transaction.test.js +32 -0
  110. package/lib-es/bridge/transaction.test.js.map +1 -0
  111. package/lib-es/bridge/utils.d.ts +0 -4
  112. package/lib-es/bridge/utils.d.ts.map +1 -1
  113. package/lib-es/bridge/utils.integration.test.d.ts +2 -0
  114. package/lib-es/bridge/utils.integration.test.d.ts.map +1 -0
  115. package/lib-es/bridge/utils.integration.test.js +423 -0
  116. package/lib-es/bridge/utils.integration.test.js.map +1 -0
  117. package/lib-es/bridge/utils.js +3 -40
  118. package/lib-es/bridge/utils.js.map +1 -1
  119. package/lib-es/errors.d.ts +0 -12
  120. package/lib-es/errors.d.ts.map +1 -1
  121. package/lib-es/errors.js +0 -4
  122. package/lib-es/errors.js.map +1 -1
  123. package/lib-es/logic.test.d.ts +2 -0
  124. package/lib-es/logic.test.d.ts.map +1 -0
  125. package/lib-es/logic.test.js +109 -0
  126. package/lib-es/logic.test.js.map +1 -0
  127. package/package.json +10 -10
  128. package/src/api/network.ts +35 -2
  129. package/src/bridge/buildOptimisticOperation.ts +3 -7
  130. package/src/bridge/getTransactionStatus.test.ts +5 -27
  131. package/src/bridge/getTransactionStatus.ts +13 -14
  132. package/src/bridge/utils.integration.test.ts +0 -52
  133. package/src/bridge/utils.ts +2 -49
  134. package/src/errors.ts +0 -12
@@ -0,0 +1,109 @@
1
+ import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets";
2
+ import { getTransactionExplorer, isAutoTokenAssociationEnabled, isTokenAssociateTransaction, isTokenAssociationRequired, isValidExtra, sendRecipientCanNext, } from "./logic";
3
+ import { getMockedAccount, getMockedTokenAccount } from "./test/fixtures/account.fixture";
4
+ import { getMockedOperation } from "./test/fixtures/operation.fixture";
5
+ import { getMockedTokenCurrency } from "./test/fixtures/currency.fixture";
6
+ import { HEDERA_TRANSACTION_KINDS } from "./constants";
7
+ describe("logic", () => {
8
+ describe("getTransactionExplorer", () => {
9
+ test("Tx explorer URL is converted from hash to consensus timestamp", async () => {
10
+ const explorerView = getCryptoCurrencyById("hedera").explorerViews[0];
11
+ expect(explorerView).toEqual({
12
+ tx: expect.any(String),
13
+ address: expect.any(String),
14
+ });
15
+ const mockedOperation = getMockedOperation({
16
+ extra: { consensusTimestamp: "1.2.3.4" },
17
+ });
18
+ const newUrl = getTransactionExplorer(explorerView, mockedOperation);
19
+ expect(newUrl).toBe("https://hashscan.io/mainnet/transaction/1.2.3.4");
20
+ });
21
+ test("Tx explorer URL is based on transaction id if consensus timestamp is not available", async () => {
22
+ const explorerView = getCryptoCurrencyById("hedera").explorerViews[0];
23
+ expect(explorerView).toEqual({
24
+ tx: expect.any(String),
25
+ address: expect.any(String),
26
+ });
27
+ const mockedOperation = getMockedOperation({
28
+ extra: { transactionId: "0.0.1234567-123-123" },
29
+ });
30
+ const newUrl = getTransactionExplorer(explorerView, mockedOperation);
31
+ expect(newUrl).toBe("https://hashscan.io/mainnet/transaction/0.0.1234567-123-123");
32
+ });
33
+ });
34
+ describe("isTokenAssociateTransaction", () => {
35
+ test("returns correct value based on tx.properties", () => {
36
+ expect(isTokenAssociateTransaction({
37
+ properties: { name: HEDERA_TRANSACTION_KINDS.TokenAssociate.name },
38
+ })).toBe(true);
39
+ expect(isTokenAssociateTransaction({
40
+ properties: { name: "transfer" },
41
+ })).toBe(false);
42
+ expect(isTokenAssociateTransaction({})).toBe(false);
43
+ });
44
+ });
45
+ describe("isAutoTokenAssociationEnabled", () => {
46
+ test("returns value based on isAutoTokenAssociationEnabled flag", () => {
47
+ expect(isAutoTokenAssociationEnabled({
48
+ hederaResources: { isAutoTokenAssociationEnabled: true },
49
+ })).toBe(true);
50
+ expect(isAutoTokenAssociationEnabled({
51
+ hederaResources: { isAutoTokenAssociationEnabled: false },
52
+ })).toBe(false);
53
+ expect(isAutoTokenAssociationEnabled({})).toBe(false);
54
+ });
55
+ });
56
+ describe("isTokenAssociationRequired", () => {
57
+ test("should return false if token is already associated (token account exists)", () => {
58
+ const mockedTokenCurrency = getMockedTokenCurrency();
59
+ const mockedTokenAccount = getMockedTokenAccount(mockedTokenCurrency);
60
+ const mockedAccount = getMockedAccount({ subAccounts: [mockedTokenAccount] });
61
+ expect(isTokenAssociationRequired(mockedAccount, mockedTokenCurrency)).toBe(false);
62
+ });
63
+ test("should return false if auto token associations are enabled", () => {
64
+ const mockedTokenCurrency = getMockedTokenCurrency();
65
+ const mockedAccount = getMockedAccount({
66
+ subAccounts: [],
67
+ hederaResources: {
68
+ maxAutomaticTokenAssociations: -1,
69
+ isAutoTokenAssociationEnabled: true,
70
+ },
71
+ });
72
+ expect(isTokenAssociationRequired(mockedAccount, mockedTokenCurrency)).toBe(false);
73
+ });
74
+ test("should return true if token is not associated and auto associations are disabled", () => {
75
+ const mockedTokenCurrency = getMockedTokenCurrency();
76
+ const mockedAccount = getMockedAccount({ subAccounts: [] });
77
+ expect(isTokenAssociationRequired(mockedAccount, mockedTokenCurrency)).toBe(true);
78
+ });
79
+ test("should return false if token is undefined", () => {
80
+ const mockedAccount = getMockedAccount({ subAccounts: [] });
81
+ expect(isTokenAssociationRequired(mockedAccount, undefined)).toBe(false);
82
+ });
83
+ test("should return false for legacy accounts without subAccounts or hederaResources", () => {
84
+ const mockedTokenCurrency = getMockedTokenCurrency();
85
+ const mockedAccount = getMockedAccount();
86
+ delete mockedAccount.subAccounts;
87
+ delete mockedAccount.hederaResources;
88
+ expect(isTokenAssociationRequired(mockedAccount, mockedTokenCurrency)).toBe(true);
89
+ });
90
+ });
91
+ describe("isValidExtra", () => {
92
+ test("returns true for object and false for invalid types", () => {
93
+ expect(isValidExtra({ some: "value" })).toBe(true);
94
+ expect(isValidExtra(null)).toBe(false);
95
+ expect(isValidExtra(undefined)).toBe(false);
96
+ expect(isValidExtra("string")).toBe(false);
97
+ expect(isValidExtra(123)).toBe(false);
98
+ expect(isValidExtra([])).toBe(false);
99
+ });
100
+ });
101
+ describe("sendRecipientCanNext", () => {
102
+ test("handles association warnings", () => {
103
+ expect(sendRecipientCanNext({ warnings: {} })).toBe(true);
104
+ expect(sendRecipientCanNext({ warnings: { missingAssociation: new Error() } })).toBe(false);
105
+ expect(sendRecipientCanNext({ warnings: { unverifiedAssociation: new Error() } })).toBe(false);
106
+ });
107
+ });
108
+ });
109
+ //# sourceMappingURL=logic.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logic.test.js","sourceRoot":"","sources":["../src/logic.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/coin-hedera",
3
- "version": "1.12.0-nightly.7",
3
+ "version": "1.12.0",
4
4
  "description": "Ledger Hedera Coin integration",
5
5
  "keywords": [
6
6
  "Ledger",
@@ -82,14 +82,14 @@
82
82
  "invariant": "^2.2.2",
83
83
  "lodash": "^4.17.21",
84
84
  "rxjs": "^7.8.1",
85
- "@ledgerhq/coin-framework": "^6.7.0-nightly.7",
86
- "@ledgerhq/cryptoassets": "^13.31.0-nightly.7",
87
- "@ledgerhq/devices": "8.6.2-nightly.0",
88
- "@ledgerhq/errors": "^6.27.0-nightly.0",
89
- "@ledgerhq/live-countervalues": "^0.8.0-nightly.7",
90
- "@ledgerhq/live-env": "^2.19.0-nightly.2",
91
- "@ledgerhq/live-network": "^2.0.20-nightly.3",
92
- "@ledgerhq/types-live": "^6.87.0-nightly.5"
85
+ "@ledgerhq/coin-framework": "^6.7.0",
86
+ "@ledgerhq/cryptoassets": "^13.31.0",
87
+ "@ledgerhq/devices": "8.6.1",
88
+ "@ledgerhq/errors": "^6.26.0",
89
+ "@ledgerhq/live-countervalues": "^0.8.0",
90
+ "@ledgerhq/live-env": "^2.19.0",
91
+ "@ledgerhq/live-network": "^2.0.20",
92
+ "@ledgerhq/types-live": "^6.87.0"
93
93
  },
94
94
  "devDependencies": {
95
95
  "@types/imurmurhash": "^0.1.4",
@@ -100,7 +100,7 @@
100
100
  "jest": "^29.7.0",
101
101
  "ts-jest": "^29.1.1",
102
102
  "@ledgerhq/disable-network-setup": "^0.0.0",
103
- "@ledgerhq/types-cryptoassets": "^7.29.0-nightly.0"
103
+ "@ledgerhq/types-cryptoassets": "^7.29.0"
104
104
  },
105
105
  "scripts": {
106
106
  "clean": "rimraf lib lib-es",
@@ -1,3 +1,4 @@
1
+ import BigNumber from "bignumber.js";
1
2
  import invariant from "invariant";
2
3
  import type { Transaction as HederaTransaction, TransactionResponse } from "@hashgraph/sdk";
3
4
  import {
@@ -6,15 +7,18 @@ import {
6
7
  Hbar,
7
8
  AccountId,
8
9
  TransactionId,
10
+ AccountBalanceQuery,
11
+ HbarUnit,
9
12
  TokenAssociateTransaction,
10
13
  } from "@hashgraph/sdk";
11
14
  import type { Account, TokenAccount } from "@ledgerhq/types-live";
12
15
  import { findSubAccountById, isTokenAccount } from "@ledgerhq/coin-framework/account/helpers";
16
+ import { HederaAddAccountError } from "../errors";
13
17
  import { Transaction } from "../types";
14
18
  import { isTokenAssociateTransaction } from "../logic";
15
19
 
16
20
  export function broadcastTransaction(transaction: HederaTransaction): Promise<TransactionResponse> {
17
- return transaction.execute(getHederaClient());
21
+ return transaction.execute(getClient());
18
22
  }
19
23
 
20
24
  // https://github.com/LedgerHQ/ledger-live/pull/72/commits/1e942687d4301660e43e0c4b5419fcfa2733b290
@@ -114,12 +118,41 @@ export async function buildUnsignedTransaction({
114
118
  }
115
119
  }
116
120
 
121
+ export interface AccountBalance {
122
+ balance: BigNumber;
123
+ }
124
+
125
+ export async function getAccountBalance(address: string): Promise<AccountBalance> {
126
+ const accountId = AccountId.fromString(address);
127
+ let accountBalance;
128
+
129
+ try {
130
+ accountBalance = await new AccountBalanceQuery({
131
+ accountId,
132
+ }).execute(getBalanceClient());
133
+ } catch {
134
+ throw new HederaAddAccountError();
135
+ }
136
+
137
+ return {
138
+ balance: accountBalance.hbars.to(HbarUnit.Tinybar),
139
+ };
140
+ }
141
+
117
142
  let _hederaClient: Client | null = null;
118
143
 
119
- export function getHederaClient(): Client {
144
+ let _hederaBalanceClient: Client | null = null;
145
+
146
+ function getClient(): Client {
120
147
  _hederaClient ??= Client.forMainnet().setMaxNodesPerTransaction(1);
121
148
 
122
149
  //_hederaClient.setNetwork({ mainnet: "https://hedera.coin.ledger.com" });
123
150
 
124
151
  return _hederaClient;
125
152
  }
153
+
154
+ function getBalanceClient(): Client {
155
+ _hederaBalanceClient ??= Client.forMainnet();
156
+
157
+ return _hederaBalanceClient;
158
+ }
@@ -3,7 +3,7 @@ import type { Account, Operation, OperationType, TokenAccount } from "@ledgerhq/
3
3
  import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
4
4
  import { findSubAccountById, isTokenAccount } from "@ledgerhq/coin-framework/account/helpers";
5
5
  import type { HederaOperationExtra, Transaction } from "../types";
6
- import { getEstimatedFees, safeParseAccountId } from "./utils";
6
+ import { getEstimatedFees } from "./utils";
7
7
  import { isTokenAssociateTransaction } from "../logic";
8
8
  import { HEDERA_OPERATION_TYPES } from "../constants";
9
9
 
@@ -55,8 +55,6 @@ const buildOptimisticCoinOperation = async ({
55
55
  : await getEstimatedFees(account, HEDERA_OPERATION_TYPES.CryptoTransfer);
56
56
  const value = transaction.amount;
57
57
  const type: OperationType = transactionType ?? "OUT";
58
- const [_, recipientAddress] = safeParseAccountId(transaction.recipient);
59
- const recipientWithoutChecksum = recipientAddress?.accountId ?? transaction.recipient;
60
58
 
61
59
  const operation: Operation = {
62
60
  id: encodeOperationId(account.id, "", type),
@@ -67,7 +65,7 @@ const buildOptimisticCoinOperation = async ({
67
65
  blockHash: null,
68
66
  blockHeight: null,
69
67
  senders: [account.freshAddress.toString()],
70
- recipients: [recipientWithoutChecksum],
68
+ recipients: [transaction.recipient],
71
69
  accountId: account.id,
72
70
  date: new Date(),
73
71
  extra: {},
@@ -88,8 +86,6 @@ const buildOptimisticTokenOperation = async ({
88
86
  const estimatedFee = await getEstimatedFees(account, HEDERA_OPERATION_TYPES.TokenTransfer);
89
87
  const value = transaction.amount;
90
88
  const type: OperationType = "OUT";
91
- const [_, recipientAddress] = safeParseAccountId(transaction.recipient);
92
- const recipientWithoutChecksum = recipientAddress?.accountId ?? transaction.recipient;
93
89
 
94
90
  const coinOperation = await buildOptimisticCoinOperation({
95
91
  account,
@@ -113,7 +109,7 @@ const buildOptimisticTokenOperation = async ({
113
109
  blockHash: null,
114
110
  blockHeight: null,
115
111
  senders: [account.freshAddress.toString()],
116
- recipients: [recipientWithoutChecksum],
112
+ recipients: [transaction.recipient],
117
113
  accountId: tokenAccount.id,
118
114
  date: new Date(),
119
115
  extra: {},
@@ -4,13 +4,10 @@ import {
4
4
  InvalidAddressBecauseDestinationIsAlsoSource,
5
5
  AmountRequired,
6
6
  NotEnoughBalance,
7
- } from "@ledgerhq/errors";
8
- import {
9
- HederaRecipientInvalidChecksum,
10
7
  HederaInsufficientFundsForAssociation,
11
8
  HederaRecipientTokenAssociationRequired,
12
9
  HederaRecipientTokenAssociationUnverified,
13
- } from "../errors";
10
+ } from "@ledgerhq/errors";
14
11
  import { getMockedAccount, getMockedTokenAccount } from "../test/fixtures/account.fixture";
15
12
  import { getMockedTokenCurrency } from "../test/fixtures/currency.fixture";
16
13
  import { getMockedTransaction } from "../test/fixtures/transaction.fixture";
@@ -22,7 +19,7 @@ describe("getTransactionStatus", () => {
22
19
  const mockedEstimatedFee = new BigNumber(1);
23
20
  const mockedUsdRate = new BigNumber(1);
24
21
  const validRecipientAddress = "0.0.1234567";
25
- const validRecipientAddressWithChecksum = "0.0.1234567-ylkls";
22
+ const invalidRecipientAddress = "invalid_address";
26
23
 
27
24
  beforeEach(() => {
28
25
  jest.clearAllMocks();
@@ -84,32 +81,13 @@ describe("getTransactionStatus", () => {
84
81
  expect(result.estimatedFees).toEqual(mockedEstimatedFee);
85
82
  });
86
83
 
87
- test("recipient with checksum is supported", async () => {
88
- const mockedAccount = getMockedAccount({ balance: new BigNumber(1000) });
89
- const mockedTransaction = getMockedTransaction({
90
- recipient: validRecipientAddressWithChecksum,
91
- amount: new BigNumber(100),
92
- });
93
-
94
- const result = await getTransactionStatus(mockedAccount, mockedTransaction);
95
-
96
- expect(result.errors).toEqual({});
97
- expect(result.warnings).toEqual({});
98
- });
99
-
100
84
  test("adds error for invalid recipient address", async () => {
101
85
  const mockedAccount = getMockedAccount();
86
+ const mockedTransaction = getMockedTransaction({ recipient: invalidRecipientAddress });
102
87
 
103
- const txWithInvalidAddress = getMockedTransaction({ recipient: "invalid_address" });
104
- const txWithInvalidAddressChecksum = getMockedTransaction({ recipient: "0.0.9124531-invld" });
105
-
106
- const [result1, result2] = await Promise.all([
107
- getTransactionStatus(mockedAccount, txWithInvalidAddress),
108
- getTransactionStatus(mockedAccount, txWithInvalidAddressChecksum),
109
- ]);
88
+ const result = await getTransactionStatus(mockedAccount, mockedTransaction);
110
89
 
111
- expect(result1.errors.recipient).toBeInstanceOf(InvalidAddress);
112
- expect(result2.errors.recipient).toBeInstanceOf(HederaRecipientInvalidChecksum);
90
+ expect(result.errors.recipient).toBeInstanceOf(InvalidAddress);
113
91
  });
114
92
 
115
93
  test("adds error for self transfers", async () => {
@@ -1,18 +1,18 @@
1
1
  import BigNumber from "bignumber.js";
2
+ import { AccountId } from "@hashgraph/sdk";
2
3
  import {
3
4
  AmountRequired,
4
5
  NotEnoughBalance,
6
+ InvalidAddress,
5
7
  InvalidAddressBecauseDestinationIsAlsoSource,
6
8
  RecipientRequired,
9
+ HederaInsufficientFundsForAssociation,
10
+ HederaRecipientTokenAssociationRequired,
11
+ HederaRecipientTokenAssociationUnverified,
7
12
  } from "@ledgerhq/errors";
8
13
  import type { Account, AccountBridge, TokenAccount } from "@ledgerhq/types-live";
9
14
  import { findSubAccountById, isTokenAccount } from "@ledgerhq/coin-framework/account";
10
15
  import { getEnv } from "@ledgerhq/live-env";
11
- import {
12
- HederaInsufficientFundsForAssociation,
13
- HederaRecipientTokenAssociationRequired,
14
- HederaRecipientTokenAssociationUnverified,
15
- } from "../errors";
16
16
  import { isTokenAssociateTransaction, isTokenAssociationRequired } from "../logic";
17
17
  import type { TokenAssociateProperties, Transaction, TransactionStatus } from "../types";
18
18
  import {
@@ -20,7 +20,6 @@ import {
20
20
  checkAccountTokenAssociationStatus,
21
21
  getCurrencyToUSDRate,
22
22
  getEstimatedFees,
23
- safeParseAccountId,
24
23
  } from "./utils";
25
24
  import { HEDERA_OPERATION_TYPES } from "../constants";
26
25
 
@@ -32,16 +31,16 @@ function validateRecipient(account: Account, recipient: string): Error | null {
32
31
  return new RecipientRequired();
33
32
  }
34
33
 
35
- const [parsingError, parsingResult] = safeParseAccountId(recipient);
36
-
37
- if (parsingError) {
38
- return parsingError;
34
+ if (account.freshAddress === recipient) {
35
+ return new InvalidAddressBecauseDestinationIsAlsoSource();
39
36
  }
40
37
 
41
- const recipientWithoutChecksum = parsingResult.accountId;
42
-
43
- if (account.freshAddress === recipientWithoutChecksum) {
44
- return new InvalidAddressBecauseDestinationIsAlsoSource();
38
+ try {
39
+ AccountId.fromString(recipient);
40
+ } catch (err) {
41
+ return new InvalidAddress("", {
42
+ currencyName: account.currency.name,
43
+ });
45
44
  }
46
45
 
47
46
  return null;
@@ -1,5 +1,4 @@
1
1
  import BigNumber from "bignumber.js";
2
- import { InvalidAddress } from "@ledgerhq/errors";
3
2
  import cvsApi from "@ledgerhq/live-countervalues/api/index";
4
3
  import { encodeTokenAccountId } from "@ledgerhq/coin-framework/account";
5
4
  import { getMockedAccount, getMockedTokenAccount } from "../test/fixtures/account.fixture";
@@ -13,7 +12,6 @@ import {
13
12
  getSubAccounts,
14
13
  getSyncHash,
15
14
  mergeSubAccounts,
16
- safeParseAccountId,
17
15
  patchOperationWithExtra,
18
16
  prepareOperations,
19
17
  } from "./utils";
@@ -25,7 +23,6 @@ import {
25
23
  import { getMockedOperation } from "../test/fixtures/operation.fixture";
26
24
  import { HederaOperationExtra } from "../types";
27
25
  import { getAccount } from "../api/mirror";
28
- import { HederaRecipientInvalidChecksum } from "../errors";
29
26
  import { isValidExtra } from "../logic";
30
27
  import { getMockedMirrorToken } from "../test/fixtures/mirror.fixture";
31
28
  import { HEDERA_OPERATION_TYPES, HEDERA_TRANSACTION_KINDS } from "../constants";
@@ -542,54 +539,5 @@ describe("utils", () => {
542
539
  const result = await checkAccountTokenAssociationStatus(accountId, tokenId);
543
540
  expect(result).toBe(false);
544
541
  });
545
-
546
- test("supports addresses with checksum", async () => {
547
- const addressWithChecksum = "0.0.9124531-xrxlv";
548
-
549
- mockedGetAccount.mockResolvedValueOnce({
550
- account: accountId,
551
- max_automatic_token_associations: 0,
552
- balance: {
553
- balance: 1,
554
- timestamp: "",
555
- tokens: [{ token_id: "0.0.9999", balance: 1 }],
556
- },
557
- });
558
-
559
- await checkAccountTokenAssociationStatus(addressWithChecksum, tokenId);
560
- expect(mockedGetAccount).toHaveBeenCalledWith("0.0.9124531");
561
- });
562
- });
563
-
564
- describe("safeParseAccountId", () => {
565
- test("returns account id and no checksum for valid address without checksum", () => {
566
- const [error, result] = safeParseAccountId("0.0.9124531");
567
-
568
- expect(error).toBeNull();
569
- expect(result?.accountId).toBe("0.0.9124531");
570
- expect(result?.checksum).toBeNull();
571
- });
572
-
573
- test("returns account id and checksum for valid address with correct checksum", () => {
574
- const [error, result] = safeParseAccountId("0.0.9124531-xrxlv");
575
-
576
- expect(error).toBeNull();
577
- expect(result?.accountId).toBe("0.0.9124531");
578
- expect(result?.checksum).toBe("xrxlv");
579
- });
580
-
581
- test("returns error for valid address with incorrect checksum", () => {
582
- const [error, accountId] = safeParseAccountId("0.0.9124531-invld");
583
-
584
- expect(error).toBeInstanceOf(HederaRecipientInvalidChecksum);
585
- expect(accountId).toBeNull();
586
- });
587
-
588
- test("returns error for invalid address format", () => {
589
- const [error, accountId] = safeParseAccountId("not-a-valid-address");
590
-
591
- expect(error).toBeInstanceOf(InvalidAddress);
592
- expect(accountId).toBeNull();
593
- });
594
542
  });
595
543
  });
@@ -1,12 +1,9 @@
1
1
  import BigNumber from "bignumber.js";
2
2
  import murmurhash from "imurmurhash";
3
3
  import invariant from "invariant";
4
- import { AccountId } from "@hashgraph/sdk";
5
- import { InvalidAddress } from "@ledgerhq/errors";
6
4
  import type { Account, Operation, TokenAccount } from "@ledgerhq/types-live";
7
5
  import cvsApi from "@ledgerhq/live-countervalues/api/index";
8
6
  import {
9
- findCryptoCurrencyById,
10
7
  findTokenByAddressInCurrency,
11
8
  getFiatCurrencyByTicker,
12
9
  listTokensForCryptoCurrency,
@@ -25,9 +22,7 @@ import { makeLRUCache, seconds } from "@ledgerhq/live-network/cache";
25
22
  import { estimateMaxSpendable } from "./estimateMaxSpendable";
26
23
  import type { HederaOperationExtra, Transaction } from "../types";
27
24
  import { getAccount } from "../api/mirror";
28
- import { getHederaClient } from "../api/network";
29
25
  import type { HederaMirrorToken } from "../api/types";
30
- import { HederaRecipientInvalidChecksum } from "../errors";
31
26
  import { isTokenAssociateTransaction, isValidExtra } from "../logic";
32
27
  import { BASE_USD_FEE_BY_OPERATION_TYPE, HEDERA_OPERATION_TYPES } from "../constants";
33
28
 
@@ -458,15 +453,8 @@ export function patchOperationWithExtra(
458
453
  }
459
454
 
460
455
  export const checkAccountTokenAssociationStatus = makeLRUCache(
461
- async (address: string, tokenId: string) => {
462
- const [parsingError, parsingResult] = safeParseAccountId(address);
463
-
464
- if (parsingError) {
465
- throw parsingError;
466
- }
467
-
468
- const addressWithoutChecksum = parsingResult.accountId;
469
- const mirrorAccount = await getAccount(addressWithoutChecksum);
456
+ async (accountId: string, tokenId: string) => {
457
+ const mirrorAccount = await getAccount(accountId);
470
458
 
471
459
  // auto association is enabled
472
460
  if (mirrorAccount.max_automatic_token_associations === -1) {
@@ -482,38 +470,3 @@ export const checkAccountTokenAssociationStatus = makeLRUCache(
482
470
  (accountId, tokenId) => `${accountId}-${tokenId}`,
483
471
  seconds(30),
484
472
  );
485
-
486
- export const safeParseAccountId = (
487
- address: string,
488
- ): [Error, null] | [null, { accountId: string; checksum: string | null }] => {
489
- const currency = findCryptoCurrencyById("hedera");
490
- const currencyName = currency?.name ?? "Hedera";
491
-
492
- try {
493
- const accountId = AccountId.fromString(address);
494
-
495
- // verify checksum if present
496
- // FIXME: migrate to EntityIdHelper methods once SDK is upgraded:
497
- // https://github.com/hiero-ledger/hiero-sdk-js/blob/main/src/EntityIdHelper.js#L197
498
- // https://github.com/hiero-ledger/hiero-sdk-js/blob/main/src/EntityIdHelper.js#L446
499
- const checksum: string | null = address.split("-")[1] ?? null;
500
- if (checksum) {
501
- const client = getHederaClient();
502
- const recipientWithChecksum = accountId.toStringWithChecksum(client);
503
- const expectedChecksum = recipientWithChecksum.split("-")[1];
504
-
505
- if (checksum !== expectedChecksum) {
506
- return [new HederaRecipientInvalidChecksum(), null];
507
- }
508
- }
509
-
510
- const result = {
511
- accountId: accountId.toString(),
512
- checksum,
513
- };
514
-
515
- return [null, result];
516
- } catch (err) {
517
- return [new InvalidAddress("", { currencyName }), null];
518
- }
519
- };
package/src/errors.ts CHANGED
@@ -1,15 +1,3 @@
1
1
  import { createCustomErrorClass } from "@ledgerhq/errors";
2
2
 
3
3
  export const HederaAddAccountError = createCustomErrorClass("HederaAddAccountError");
4
- export const HederaRecipientInvalidChecksum = createCustomErrorClass(
5
- "HederaRecipientInvalidChecksum",
6
- );
7
- export const HederaInsufficientFundsForAssociation = createCustomErrorClass(
8
- "HederaInsufficientFundsForAssociation",
9
- );
10
- export const HederaRecipientTokenAssociationRequired = createCustomErrorClass(
11
- "HederaRecipientTokenAssociationRequired",
12
- );
13
- export const HederaRecipientTokenAssociationUnverified = createCustomErrorClass(
14
- "HederaRecipientTokenAssociationUnverified",
15
- );