@ledgerhq/live-common 21.22.1 → 21.23.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 (209) hide show
  1. package/lib/account/formatters.d.ts.map +1 -1
  2. package/lib/account/formatters.js +1 -0
  3. package/lib/account/formatters.js.map +1 -1
  4. package/lib/account/support.d.ts.map +1 -1
  5. package/lib/account/support.js +1 -0
  6. package/lib/account/support.js.map +1 -1
  7. package/lib/data/icons/react/sol.js +4 -2
  8. package/lib/data/icons/react/sol.js.map +1 -1
  9. package/lib/data/icons/reactNative/sol.js +4 -2
  10. package/lib/data/icons/reactNative/sol.js.map +1 -1
  11. package/lib/derivation.d.ts.map +1 -1
  12. package/lib/derivation.js +0 -3
  13. package/lib/derivation.js.map +1 -1
  14. package/lib/env.d.ts +5 -10
  15. package/lib/env.d.ts.map +1 -1
  16. package/lib/env.js +0 -5
  17. package/lib/env.js.map +1 -1
  18. package/lib/env.react.d.ts +1 -1
  19. package/lib/env.react.d.ts.map +1 -1
  20. package/lib/families/algorand/account.d.ts.map +1 -1
  21. package/lib/families/algorand/account.js +0 -4
  22. package/lib/families/algorand/account.js.map +1 -1
  23. package/lib/families/algorand/api/algodv2.d.ts +5 -0
  24. package/lib/families/algorand/api/algodv2.d.ts.map +1 -0
  25. package/lib/families/algorand/api/algodv2.js +118 -0
  26. package/lib/families/algorand/api/algodv2.js.map +1 -0
  27. package/lib/families/algorand/api/algodv2.types.d.ts +24 -0
  28. package/lib/families/algorand/api/algodv2.types.d.ts.map +1 -0
  29. package/lib/families/algorand/api/algodv2.types.js +3 -0
  30. package/lib/families/algorand/api/algodv2.types.js.map +1 -0
  31. package/lib/families/algorand/api/index.d.ts +5 -0
  32. package/lib/families/algorand/api/index.d.ts.map +1 -0
  33. package/lib/families/algorand/api/index.js +17 -0
  34. package/lib/families/algorand/api/index.js.map +1 -0
  35. package/lib/families/algorand/api/indexer.d.ts +3 -0
  36. package/lib/families/algorand/api/indexer.d.ts.map +1 -0
  37. package/lib/families/algorand/api/indexer.js +134 -0
  38. package/lib/families/algorand/api/indexer.js.map +1 -0
  39. package/lib/families/algorand/api/indexer.types.d.ts +35 -0
  40. package/lib/families/algorand/api/indexer.types.d.ts.map +1 -0
  41. package/lib/families/algorand/api/indexer.types.js +10 -0
  42. package/lib/families/algorand/api/indexer.types.js.map +1 -0
  43. package/lib/families/algorand/bridge/js.d.ts +8 -0
  44. package/lib/families/algorand/bridge/js.d.ts.map +1 -0
  45. package/lib/families/algorand/bridge/js.js +85 -0
  46. package/lib/families/algorand/bridge/js.js.map +1 -0
  47. package/lib/families/algorand/bridge/libcore.d.ts +3 -3
  48. package/lib/families/algorand/bridge/libcore.d.ts.map +1 -1
  49. package/lib/families/algorand/bridge/libcore.js.map +1 -1
  50. package/lib/families/algorand/bridge/mock.d.ts +2 -2
  51. package/lib/families/algorand/bridge/mock.d.ts.map +1 -1
  52. package/lib/families/algorand/bridge/mock.js.map +1 -1
  53. package/lib/families/algorand/buildTransaction.d.ts +8 -0
  54. package/lib/families/algorand/buildTransaction.d.ts.map +1 -0
  55. package/lib/families/algorand/buildTransaction.js +101 -0
  56. package/lib/families/algorand/buildTransaction.js.map +1 -0
  57. package/lib/families/algorand/cli-transaction.js +1 -1
  58. package/lib/families/algorand/cli-transaction.js.map +1 -1
  59. package/lib/families/algorand/deviceTransactionConfig.d.ts +2 -2
  60. package/lib/families/algorand/deviceTransactionConfig.d.ts.map +1 -1
  61. package/lib/families/algorand/deviceTransactionConfig.js +0 -13
  62. package/lib/families/algorand/deviceTransactionConfig.js.map +1 -1
  63. package/lib/families/algorand/hw-getAddress.d.ts.map +1 -1
  64. package/lib/families/algorand/hw-getAddress.js +2 -24
  65. package/lib/families/algorand/hw-getAddress.js.map +1 -1
  66. package/lib/families/algorand/js-broadcast.d.ts +9 -0
  67. package/lib/families/algorand/js-broadcast.d.ts.map +1 -0
  68. package/lib/families/algorand/js-broadcast.js +63 -0
  69. package/lib/families/algorand/js-broadcast.js.map +1 -0
  70. package/lib/families/algorand/js-estimateMaxSpendable.d.ts +9 -0
  71. package/lib/families/algorand/js-estimateMaxSpendable.d.ts.map +1 -0
  72. package/lib/families/algorand/js-estimateMaxSpendable.js +89 -0
  73. package/lib/families/algorand/js-estimateMaxSpendable.js.map +1 -0
  74. package/lib/families/algorand/js-getFeesForTransaction.d.ts +5 -0
  75. package/lib/families/algorand/js-getFeesForTransaction.d.ts.map +1 -0
  76. package/lib/families/algorand/js-getFeesForTransaction.js +69 -0
  77. package/lib/families/algorand/js-getFeesForTransaction.js.map +1 -0
  78. package/lib/families/algorand/js-getTransactionStatus.d.ts +11 -0
  79. package/lib/families/algorand/js-getTransactionStatus.d.ts.map +1 -0
  80. package/lib/families/algorand/js-getTransactionStatus.js +201 -0
  81. package/lib/families/algorand/js-getTransactionStatus.js.map +1 -0
  82. package/lib/families/algorand/js-prepareTransaction.d.ts +5 -0
  83. package/lib/families/algorand/js-prepareTransaction.d.ts.map +1 -0
  84. package/lib/families/algorand/js-prepareTransaction.js +101 -0
  85. package/lib/families/algorand/js-prepareTransaction.js.map +1 -0
  86. package/lib/families/algorand/js-signOperation.d.ts +10 -0
  87. package/lib/families/algorand/js-signOperation.d.ts.map +1 -0
  88. package/lib/families/algorand/js-signOperation.js +164 -0
  89. package/lib/families/algorand/js-signOperation.js.map +1 -0
  90. package/lib/families/algorand/js-synchronization.d.ts +10 -0
  91. package/lib/families/algorand/js-synchronization.d.ts.map +1 -0
  92. package/lib/families/algorand/js-synchronization.js +411 -0
  93. package/lib/families/algorand/js-synchronization.js.map +1 -0
  94. package/lib/families/algorand/libcore-buildTransaction.d.ts +2 -2
  95. package/lib/families/algorand/libcore-buildTransaction.d.ts.map +1 -1
  96. package/lib/families/algorand/libcore-getFeesForTransaction.d.ts +4 -4
  97. package/lib/families/algorand/libcore-getFeesForTransaction.d.ts.map +1 -1
  98. package/lib/families/algorand/libcore-getFeesForTransaction.js +2 -2
  99. package/lib/families/algorand/libcore-getFeesForTransaction.js.map +1 -1
  100. package/lib/families/algorand/libcore-postBuildAccount.d.ts.map +1 -1
  101. package/lib/families/algorand/libcore-postBuildAccount.js +5 -11
  102. package/lib/families/algorand/libcore-postBuildAccount.js.map +1 -1
  103. package/lib/families/algorand/libcore-signOperation.d.ts +2 -2
  104. package/lib/families/algorand/libcore-signOperation.d.ts.map +1 -1
  105. package/lib/families/algorand/libcore-signOperation.js.map +1 -1
  106. package/lib/families/algorand/logic.d.ts +10 -0
  107. package/lib/families/algorand/logic.d.ts.map +1 -1
  108. package/lib/families/algorand/logic.js +79 -1
  109. package/lib/families/algorand/logic.js.map +1 -1
  110. package/lib/families/algorand/mock.d.ts.map +1 -1
  111. package/lib/families/algorand/mock.js +4 -11
  112. package/lib/families/algorand/mock.js.map +1 -1
  113. package/lib/families/algorand/serialization.js +4 -4
  114. package/lib/families/algorand/serialization.js.map +1 -1
  115. package/lib/families/algorand/specs.d.ts +2 -2
  116. package/lib/families/algorand/specs.d.ts.map +1 -1
  117. package/lib/families/algorand/specs.js +8 -16
  118. package/lib/families/algorand/specs.js.map +1 -1
  119. package/lib/families/algorand/speculos-deviceActions.d.ts +2 -2
  120. package/lib/families/algorand/speculos-deviceActions.d.ts.map +1 -1
  121. package/lib/families/algorand/speculos-deviceActions.js +4 -0
  122. package/lib/families/algorand/speculos-deviceActions.js.map +1 -1
  123. package/lib/families/algorand/test-dataset.d.ts +2 -2
  124. package/lib/families/algorand/test-dataset.d.ts.map +1 -1
  125. package/lib/families/algorand/test-dataset.js +1 -2
  126. package/lib/families/algorand/test-dataset.js.map +1 -1
  127. package/lib/families/algorand/tokens.d.ts.map +1 -1
  128. package/lib/families/algorand/tokens.js.map +1 -1
  129. package/lib/families/algorand/transaction.d.ts +5 -5
  130. package/lib/families/algorand/transaction.d.ts.map +1 -1
  131. package/lib/families/algorand/transaction.js.map +1 -1
  132. package/lib/families/algorand/types.d.ts +7 -5
  133. package/lib/families/algorand/types.d.ts.map +1 -1
  134. package/lib/families/algorand/types.js.map +1 -1
  135. package/lib/families/bitcoin/js-prepareTransaction.d.ts.map +1 -1
  136. package/lib/families/bitcoin/js-prepareTransaction.js +3 -2
  137. package/lib/families/bitcoin/js-prepareTransaction.js.map +1 -1
  138. package/lib/families/bitcoin/js-synchronisation.d.ts.map +1 -1
  139. package/lib/families/bitcoin/js-synchronisation.js +3 -2
  140. package/lib/families/bitcoin/js-synchronisation.js.map +1 -1
  141. package/lib/families/bitcoin/wallet-btc/crypto/decred.d.ts.map +1 -1
  142. package/lib/families/bitcoin/wallet-btc/crypto/decred.js +3 -4
  143. package/lib/families/bitcoin/wallet-btc/crypto/decred.js.map +1 -1
  144. package/lib/generated/bridge/js.d.ts +4 -0
  145. package/lib/generated/bridge/js.d.ts.map +1 -1
  146. package/lib/generated/bridge/js.js +26 -24
  147. package/lib/generated/bridge/js.js.map +1 -1
  148. package/lib/generated/bridge/libcore.d.ts +1 -1
  149. package/lib/generated/bridge/mock.d.ts +1 -1
  150. package/lib/generated/specs.d.ts +1 -1
  151. package/lib/generated/speculos-deviceActions.d.ts +1 -1
  152. package/lib/generated/test-dataset.d.ts +1 -1
  153. package/lib/generated/transaction.d.ts +3 -3
  154. package/lib/libcore/buildAccount/index.d.ts.map +1 -1
  155. package/lib/libcore/buildAccount/index.js +0 -1
  156. package/lib/libcore/buildAccount/index.js.map +1 -1
  157. package/lib/mock/account.js +21 -21
  158. package/lib/mock/account.js.map +1 -1
  159. package/lib/types/operation.d.ts +1 -1
  160. package/lib/types/operation.d.ts.map +1 -1
  161. package/package.json +4 -3
  162. package/src/__tests__/__snapshots__/all.libcore.ts.snap +0 -107
  163. package/src/account/formatters.ts +1 -0
  164. package/src/account/support.ts +1 -0
  165. package/src/data/icons/react/sol.tsx +1 -1
  166. package/src/data/icons/reactNative/sol.tsx +1 -1
  167. package/src/data/icons/svg/SOL.svg +1 -3
  168. package/src/derivation.ts +0 -2
  169. package/src/env.ts +0 -5
  170. package/src/families/algorand/account.ts +0 -9
  171. package/src/families/algorand/api/algodv2.ts +68 -0
  172. package/src/families/algorand/api/algodv2.types.ts +27 -0
  173. package/src/families/algorand/api/index.ts +4 -0
  174. package/src/families/algorand/api/indexer.ts +99 -0
  175. package/src/families/algorand/api/indexer.types.ts +41 -0
  176. package/src/families/algorand/bridge/js.ts +46 -0
  177. package/src/families/algorand/bridge/libcore.ts +4 -4
  178. package/src/families/algorand/bridge/mock.ts +3 -3
  179. package/src/families/algorand/buildTransaction.ts +100 -0
  180. package/src/families/algorand/cli-transaction.ts +1 -1
  181. package/src/families/algorand/deviceTransactionConfig.ts +2 -16
  182. package/src/families/algorand/hw-getAddress.ts +1 -10
  183. package/src/families/algorand/js-broadcast.ts +17 -0
  184. package/src/families/algorand/js-estimateMaxSpendable.ts +51 -0
  185. package/src/families/algorand/js-getFeesForTransaction.ts +25 -0
  186. package/src/families/algorand/js-getTransactionStatus.ts +178 -0
  187. package/src/families/algorand/js-prepareTransaction.ts +42 -0
  188. package/src/families/algorand/js-signOperation.ts +145 -0
  189. package/src/families/algorand/js-synchronization.ts +433 -0
  190. package/src/families/algorand/libcore-buildTransaction.ts +2 -2
  191. package/src/families/algorand/libcore-getFeesForTransaction.ts +4 -4
  192. package/src/families/algorand/libcore-postBuildAccount.ts +2 -7
  193. package/src/families/algorand/libcore-signOperation.ts +2 -2
  194. package/src/families/algorand/logic.ts +47 -0
  195. package/src/families/algorand/mock.ts +2 -12
  196. package/src/families/algorand/serialization.ts +4 -4
  197. package/src/families/algorand/specs.ts +16 -22
  198. package/src/families/algorand/speculos-deviceActions.ts +87 -82
  199. package/src/families/algorand/test-dataset.ts +5 -6
  200. package/src/families/algorand/tokens.ts +1 -0
  201. package/src/families/algorand/transaction.ts +13 -4
  202. package/src/families/algorand/types.ts +10 -5
  203. package/src/families/bitcoin/js-prepareTransaction.ts +3 -2
  204. package/src/families/bitcoin/js-synchronisation.ts +3 -2
  205. package/src/families/bitcoin/wallet-btc/crypto/decred.ts +3 -4
  206. package/src/generated/bridge/js.ts +3 -0
  207. package/src/libcore/buildAccount/index.ts +1 -2
  208. package/src/mock/account.ts +27 -27
  209. package/src/types/operation.ts +9 -4
@@ -102,7 +102,7 @@ function inferTransactions(
102
102
  memo: opts.memo,
103
103
  mode: opts.mode || "send",
104
104
  subAccountId: account.type === "TokenAccount" ? account.id : null,
105
- assetId: "algorand/asa/" + opts.token,
105
+ assetId: opts.token ? "algorand/asa/" + opts.token : null,
106
106
  };
107
107
  });
108
108
  }
@@ -3,7 +3,7 @@ import type {
3
3
  TransactionStatus,
4
4
  TokenCurrency,
5
5
  } from "../../types";
6
- import type { Transaction } from "./types";
6
+ import type { AlgorandTransaction } from "./types";
7
7
  import type { DeviceTransactionField } from "../../transaction";
8
8
  import { getAccountUnit } from "../../account";
9
9
  import { formatCurrencyUnit, findTokenById } from "../../currencies";
@@ -68,7 +68,7 @@ function getDeviceTransactionConfig({
68
68
  status,
69
69
  }: {
70
70
  account: AccountLike;
71
- transaction: Transaction;
71
+ transaction: AlgorandTransaction;
72
72
  status: TransactionStatus;
73
73
  }): Array<DeviceTransactionField> {
74
74
  const { mode, assetId } = transaction;
@@ -121,20 +121,6 @@ function getDeviceTransactionConfig({
121
121
  });
122
122
  break;
123
123
 
124
- case "optOut":
125
- fields.push({
126
- type: "text",
127
- label: "Type",
128
- value: "Opt out",
129
- });
130
- if (assetId)
131
- fields.push({
132
- type: "text",
133
- label: "Asset id",
134
- value: assetId,
135
- });
136
- break;
137
-
138
124
  default:
139
125
  break;
140
126
  }
@@ -1,20 +1,11 @@
1
1
  import Algorand from "@ledgerhq/hw-app-algorand";
2
2
  import type { Resolver } from "../../hw/getAddress/types";
3
- import { withLibcore } from "../../libcore/access";
4
-
5
- const convertPubkeyToAddress = async (pubkey) => {
6
- return await withLibcore(async (core) => {
7
- const address = await core.AlgorandAddress.fromPublicKey(pubkey);
8
- return address;
9
- });
10
- };
11
3
 
12
4
  const resolver: Resolver = async (transport, { path, verify }) => {
13
5
  const algorand = new Algorand(transport);
14
6
  const r = await algorand.getAddress(path, verify || false);
15
- const address = await convertPubkeyToAddress(r.publicKey);
16
7
  return {
17
- address: address,
8
+ address: r.address,
18
9
  publicKey: r.publicKey,
19
10
  path,
20
11
  };
@@ -0,0 +1,17 @@
1
+ import { patchOperationWithHash } from "../../operation";
2
+ import type { Operation, SignedOperation } from "../../types";
3
+ import { broadcastTransaction as apiBroadcast } from "./api";
4
+
5
+ /**
6
+ * Broadcast a signed transaction
7
+ * @param {signature: string, operation: string} signedOperation
8
+ */
9
+ export const broadcast = async ({
10
+ signedOperation,
11
+ }: {
12
+ signedOperation: SignedOperation;
13
+ }): Promise<Operation> => {
14
+ const { signature, operation } = signedOperation;
15
+ const hash = await apiBroadcast(signature);
16
+ return patchOperationWithHash(operation, hash);
17
+ };
@@ -0,0 +1,51 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import type { Account, AccountLike } from "../../types";
3
+ import { getMainAccount } from "../../account";
4
+ import type { AlgorandTransaction } from "./types";
5
+ import { computeAlgoMaxSpendable } from "./logic";
6
+ import { createTransaction } from "./js-prepareTransaction";
7
+ import { getAbandonSeedAddress } from "@ledgerhq/cryptoassets";
8
+
9
+ export const estimateMaxSpendable = async ({
10
+ account,
11
+ parentAccount,
12
+ transaction,
13
+ }: {
14
+ account: AccountLike;
15
+ parentAccount?: Account | null | undefined;
16
+ transaction?: AlgorandTransaction | null | undefined;
17
+ }): Promise<BigNumber> => {
18
+ const mainAccount = getMainAccount(account, parentAccount);
19
+ const { algorandResources } = mainAccount;
20
+ if (!algorandResources) {
21
+ throw new Error("Algorand account expected");
22
+ }
23
+
24
+ const tx = {
25
+ ...createTransaction(),
26
+ subAccountId: account.type === "Account" ? null : account.id,
27
+ ...transaction,
28
+ recipient:
29
+ transaction?.recipient || getAbandonSeedAddress(mainAccount.currency.id),
30
+ useAllAmount: true,
31
+ };
32
+
33
+ const tokenAccount =
34
+ tx.subAccountId &&
35
+ mainAccount.subAccounts &&
36
+ mainAccount.subAccounts.find((ta) => ta.id === tx.subAccountId);
37
+
38
+ if (tokenAccount) {
39
+ return tokenAccount.balance;
40
+ } else {
41
+ let maxSpendable = computeAlgoMaxSpendable({
42
+ accountBalance: mainAccount.balance,
43
+ nbAccountAssets: algorandResources.nbAssets,
44
+ mode: tx.mode,
45
+ });
46
+ if (tx.fees) {
47
+ maxSpendable = maxSpendable.minus(tx.fees);
48
+ }
49
+ return maxSpendable.gte(0) ? maxSpendable : new BigNumber(0);
50
+ }
51
+ };
@@ -0,0 +1,25 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import type { Account } from "../../types";
3
+ import type { Transaction } from "./types";
4
+ import { getTransactionParams } from "./api";
5
+ import { buildTransactionPayload, encodeToSign } from "./buildTransaction";
6
+
7
+ // This is only true for a single signature. If we ever support different type of signatures
8
+ // (e.g multi signatures), we will have to add the correct corresponding number of bytes.
9
+ const SINGLE_SIGNATURE_SIZE = 71;
10
+
11
+ export const getEstimatedFees = async (
12
+ account: Account,
13
+ transaction: Transaction
14
+ ): Promise<BigNumber> => {
15
+ const params = await getTransactionParams();
16
+
17
+ let suggestedFees = 0;
18
+ if (params.fee) {
19
+ const payload = await buildTransactionPayload(account, transaction);
20
+ const encoded = await encodeToSign(payload);
21
+ suggestedFees =
22
+ params.fee * (Buffer.from(encoded, "hex").length + SINGLE_SIGNATURE_SIZE);
23
+ }
24
+ return new BigNumber(Math.max(suggestedFees, params.minFee));
25
+ };
@@ -0,0 +1,178 @@
1
+ import invariant from "invariant";
2
+ import { BigNumber } from "bignumber.js";
3
+ import { isValidAddress } from "algosdk";
4
+
5
+ import {
6
+ RecipientRequired,
7
+ AmountRequired,
8
+ InvalidAddressBecauseDestinationIsAlsoSource,
9
+ NotEnoughBalance,
10
+ FeeNotLoaded,
11
+ FeeTooHigh,
12
+ NotEnoughBalanceBecauseDestinationNotCreated,
13
+ NotEnoughBalanceInParentAccount,
14
+ InvalidAddress,
15
+ } from "@ledgerhq/errors";
16
+
17
+ import {
18
+ ClaimRewardsFeesWarning,
19
+ AlgorandASANotOptInInRecipient,
20
+ } from "../../errors";
21
+ import type { Account } from "../../types";
22
+ import type { AlgorandResources, Transaction } from "./types";
23
+ import { extractTokenId } from "./tokens";
24
+ import {
25
+ ALGORAND_MAX_MEMO_SIZE,
26
+ recipientHasAsset,
27
+ isAmountValid,
28
+ computeAlgoMaxSpendable,
29
+ } from "./logic";
30
+
31
+ /*
32
+ * Here are the list of the differents things we check
33
+ * - Check if recipient is the same in case of send
34
+ * - Check if recipient is valid
35
+ * - Check if amounts are set
36
+ * - Check if fees are loaded
37
+ * - Check if is a send Max and set the amount
38
+ * - Check if Token is already optin at the recipient
39
+ * - Check if memo is too long
40
+ */
41
+ export const getTransactionStatus = async (a: Account, t: Transaction) => {
42
+ const errors: any = {};
43
+ const warnings: any = {};
44
+ const tokenAccount = !t.subAccountId
45
+ ? null
46
+ : a.subAccounts && a.subAccounts.find((ta) => ta.id === t.subAccountId);
47
+
48
+ if (!t.recipient) {
49
+ errors.recipient = new RecipientRequired();
50
+ } else if (!(await isValidAddress(t.recipient))) {
51
+ errors.recipient = new InvalidAddress("", {
52
+ currencyName: a.currency.name,
53
+ });
54
+ } else if (t.mode === "send" && a.freshAddress === t.recipient) {
55
+ errors.recipient = new InvalidAddressBecauseDestinationIsAlsoSource();
56
+ }
57
+
58
+ const estimatedFees = t.fees || new BigNumber(0);
59
+ let amount = t.amount;
60
+ let totalSpent = estimatedFees;
61
+
62
+ invariant(a.algorandResources, "Algorand family expected");
63
+ const algorandResources = a.algorandResources as AlgorandResources;
64
+
65
+ const algoSpendableBalance = computeAlgoMaxSpendable({
66
+ accountBalance: a.balance,
67
+ nbAccountAssets: algorandResources.nbAssets,
68
+ mode: t.mode,
69
+ });
70
+
71
+ switch (t.mode) {
72
+ case "send": {
73
+ if (amount.lte(0) && !t.useAllAmount) {
74
+ errors.amount = new AmountRequired();
75
+ }
76
+
77
+ if (!t.fees || !t.fees.gt(0)) {
78
+ errors.fees = new FeeNotLoaded();
79
+ }
80
+
81
+ if (
82
+ tokenAccount &&
83
+ tokenAccount.type === "TokenAccount" &&
84
+ !errors.recipient &&
85
+ !(await recipientHasAsset(
86
+ t.recipient,
87
+ extractTokenId(tokenAccount.token.id)
88
+ ))
89
+ ) {
90
+ errors.recipient = new AlgorandASANotOptInInRecipient();
91
+ }
92
+
93
+ amount = t.useAllAmount
94
+ ? tokenAccount
95
+ ? tokenAccount.balance
96
+ : algoSpendableBalance.minus(estimatedFees)
97
+ : amount;
98
+
99
+ if (amount.lt(0)) {
100
+ amount = new BigNumber(0);
101
+ }
102
+
103
+ totalSpent = tokenAccount ? amount : amount.plus(estimatedFees);
104
+
105
+ if (!errors.recipient && !(await isAmountValid(t.recipient, amount))) {
106
+ errors.amount = new NotEnoughBalanceBecauseDestinationNotCreated("", {
107
+ minimalAmount: "0.1 ALGO",
108
+ });
109
+ }
110
+
111
+ if (!tokenAccount && amount.gt(0) && estimatedFees.times(10).gt(amount)) {
112
+ warnings.feeTooHigh = new FeeTooHigh();
113
+ }
114
+
115
+ if (
116
+ (amount.lte(0) && t.useAllAmount) || // if use all Amount sets an amount at 0
117
+ (!errors.recipient && !errors.amount && tokenAccount
118
+ ? totalSpent.gt(tokenAccount.balance)
119
+ : totalSpent.gt(algoSpendableBalance)) // if spendable balance lower than total
120
+ ) {
121
+ errors.amount = new NotEnoughBalance();
122
+ }
123
+
124
+ // if spendable balance lower than fees for token
125
+ if (
126
+ !errors.amount &&
127
+ tokenAccount &&
128
+ algoSpendableBalance.lt(estimatedFees)
129
+ ) {
130
+ errors.amount = new NotEnoughBalanceInParentAccount();
131
+ }
132
+
133
+ break;
134
+ }
135
+
136
+ case "optIn": {
137
+ if (!t.fees || !t.fees.gt(0)) {
138
+ errors.fees = new FeeNotLoaded();
139
+ }
140
+
141
+ // This error doesn't need to be translate,
142
+ // it will use to block until the user choose an assetId
143
+ if (!t.assetId) {
144
+ errors.assetId = new Error("Asset Id is not set");
145
+ }
146
+
147
+ if (algoSpendableBalance.lt(estimatedFees)) {
148
+ errors.amount = new NotEnoughBalance();
149
+ }
150
+
151
+ break;
152
+ }
153
+
154
+ case "claimReward": {
155
+ if (algoSpendableBalance.lt(totalSpent)) {
156
+ errors.amount = new NotEnoughBalance();
157
+ }
158
+
159
+ if (estimatedFees.gt(algorandResources.rewards)) {
160
+ warnings.claimReward = new ClaimRewardsFeesWarning();
161
+ }
162
+
163
+ break;
164
+ }
165
+ }
166
+
167
+ if (t.memo && t.memo.length > ALGORAND_MAX_MEMO_SIZE) {
168
+ throw new Error("Memo is too long");
169
+ }
170
+
171
+ return Promise.resolve({
172
+ errors,
173
+ warnings,
174
+ estimatedFees,
175
+ amount,
176
+ totalSpent,
177
+ });
178
+ };
@@ -0,0 +1,42 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import type { Account } from "../../types";
3
+ import type { Transaction } from "./types";
4
+ import { getEstimatedFees } from "./js-getFeesForTransaction";
5
+ import { estimateMaxSpendable } from "./js-estimateMaxSpendable";
6
+
7
+ export const createTransaction = (): Transaction => ({
8
+ family: "algorand",
9
+ amount: new BigNumber(0),
10
+ fees: null,
11
+ recipient: "",
12
+ useAllAmount: false,
13
+ memo: null,
14
+ mode: "send",
15
+ assetId: null,
16
+ });
17
+
18
+ export const prepareTransaction = async (
19
+ account: Account,
20
+ transaction: Transaction
21
+ ): Promise<Transaction> => {
22
+ let recipient: string;
23
+ let amount: BigNumber;
24
+ if (transaction.mode === "send") {
25
+ recipient = transaction.recipient;
26
+ amount = transaction.useAllAmount
27
+ ? await estimateMaxSpendable({ account, transaction })
28
+ : transaction.amount;
29
+ } else if (
30
+ transaction.mode === "optIn" ||
31
+ transaction.mode === "claimReward"
32
+ ) {
33
+ recipient = account.freshAddress;
34
+ amount = new BigNumber(0);
35
+ } else {
36
+ throw new Error(`Unsupported transaction mode '${transaction.mode}'`);
37
+ }
38
+
39
+ const fees = await getEstimatedFees(account, transaction);
40
+
41
+ return { ...transaction, fees, amount, recipient };
42
+ };
@@ -0,0 +1,145 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import { Observable } from "rxjs";
3
+ import { FeeNotLoaded } from "@ledgerhq/errors";
4
+ import Algorand from "@ledgerhq/hw-app-algorand";
5
+ import type { Account, Operation, SignOperationEvent } from "../../types";
6
+ import { withDevice } from "../../hw/deviceAccess";
7
+ import type { Transaction } from "./types";
8
+ import {
9
+ buildTransactionPayload,
10
+ encodeToSign,
11
+ encodeToBroadcast,
12
+ } from "./buildTransaction";
13
+
14
+ export const signOperation = ({
15
+ account,
16
+ transaction,
17
+ deviceId,
18
+ }: {
19
+ account: Account;
20
+ transaction: Transaction;
21
+ deviceId: any;
22
+ }): Observable<SignOperationEvent> =>
23
+ withDevice(deviceId)((transport) =>
24
+ Observable.create((o) => {
25
+ let cancelled;
26
+
27
+ async function main() {
28
+ if (!transaction.fees) {
29
+ throw new FeeNotLoaded();
30
+ }
31
+
32
+ const algoTx = await buildTransactionPayload(account, transaction);
33
+
34
+ const toSign = await encodeToSign(algoTx);
35
+
36
+ const hwApp = new Algorand(transport);
37
+ const { freshAddressPath } = account;
38
+
39
+ o.next({ type: "device-signature-requested" });
40
+
41
+ const { signature } = await hwApp.sign(freshAddressPath, toSign);
42
+
43
+ if (cancelled) return;
44
+
45
+ o.next({ type: "device-signature-granted" });
46
+
47
+ if (!signature) {
48
+ throw new Error("No signature");
49
+ }
50
+
51
+ const toBroadcast = await encodeToBroadcast(algoTx, signature);
52
+
53
+ const operation = buildOptimisticOperation(account, transaction);
54
+
55
+ o.next({
56
+ type: "signed",
57
+ signedOperation: {
58
+ operation,
59
+ signature: toBroadcast,
60
+ expirationDate: null,
61
+ },
62
+ });
63
+ }
64
+
65
+ main().then(
66
+ () => o.complete(),
67
+ (e) => o.error(e)
68
+ );
69
+
70
+ return () => {
71
+ cancelled = true;
72
+ };
73
+ })
74
+ );
75
+
76
+ const buildOptimisticOperation = (
77
+ account: Account,
78
+ transaction: Transaction
79
+ ): Operation => {
80
+ const { spendableBalance, id, freshAddress, subAccounts } = account;
81
+
82
+ const senders = [freshAddress];
83
+ const recipients = [transaction.recipient];
84
+ const { subAccountId, fees } = transaction;
85
+
86
+ if (!fees) {
87
+ throw new FeeNotLoaded();
88
+ }
89
+
90
+ const value = subAccountId
91
+ ? fees
92
+ : transaction.useAllAmount
93
+ ? spendableBalance
94
+ : transaction.amount.plus(fees);
95
+
96
+ const type = subAccountId
97
+ ? "FEES"
98
+ : transaction.mode === "optIn"
99
+ ? "OPT_IN"
100
+ : "OUT";
101
+
102
+ const op: Operation = {
103
+ id: `${id}--${type}`,
104
+ hash: "",
105
+ type,
106
+ value,
107
+ fee: fees,
108
+ blockHash: null,
109
+ blockHeight: null,
110
+ senders,
111
+ recipients,
112
+ accountId: id,
113
+ date: new Date(),
114
+ extra: {},
115
+ };
116
+
117
+ const tokenAccount = !subAccountId
118
+ ? null
119
+ : subAccounts && subAccounts.find((ta) => ta.id === subAccountId);
120
+
121
+ if (tokenAccount && subAccountId) {
122
+ op.subOperations = [
123
+ {
124
+ id: `${subAccountId}--OUT`,
125
+ hash: "",
126
+ type: "OUT",
127
+ value: transaction.useAllAmount
128
+ ? tokenAccount.balance
129
+ : transaction.amount,
130
+ fee: new BigNumber(0),
131
+ blockHash: null,
132
+ blockHeight: null,
133
+ senders,
134
+ recipients,
135
+ accountId: subAccountId,
136
+ date: new Date(),
137
+ extra: {},
138
+ },
139
+ ];
140
+ }
141
+
142
+ return op;
143
+ };
144
+
145
+ export default signOperation;