@ledgerhq/live-common 34.51.0-nightly.0 → 34.51.0-nightly.2

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 (266) hide show
  1. package/lib/bridge/generic-alpaca/accountBridge.d.ts.map +1 -1
  2. package/lib/bridge/generic-alpaca/accountBridge.js +2 -0
  3. package/lib/bridge/generic-alpaca/accountBridge.js.map +1 -1
  4. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts +1 -0
  5. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts.map +1 -1
  6. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.js +3 -0
  7. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.js.map +1 -1
  8. package/lib/bridge/generic-alpaca/prepareTransaction.d.ts.map +1 -1
  9. package/lib/bridge/generic-alpaca/prepareTransaction.js +37 -45
  10. package/lib/bridge/generic-alpaca/prepareTransaction.js.map +1 -1
  11. package/lib/bridge/generic-alpaca/signOperation.d.ts.map +1 -1
  12. package/lib/bridge/generic-alpaca/signOperation.js +0 -20
  13. package/lib/bridge/generic-alpaca/signOperation.js.map +1 -1
  14. package/lib/bridge/generic-alpaca/signRawOperation.d.ts +8 -0
  15. package/lib/bridge/generic-alpaca/signRawOperation.d.ts.map +1 -0
  16. package/lib/bridge/generic-alpaca/signRawOperation.js +55 -0
  17. package/lib/bridge/generic-alpaca/signRawOperation.js.map +1 -0
  18. package/lib/bridge/generic-alpaca/tests/getAccountShape.test.js +1 -0
  19. package/lib/bridge/generic-alpaca/tests/getAccountShape.test.js.map +1 -1
  20. package/lib/bridge/generic-alpaca/tests/prepareTransaction.test.js +186 -88
  21. package/lib/bridge/generic-alpaca/tests/prepareTransaction.test.js.map +1 -1
  22. package/lib/bridge/generic-alpaca/utils.d.ts.map +1 -1
  23. package/lib/bridge/generic-alpaca/utils.js +1 -0
  24. package/lib/bridge/generic-alpaca/utils.js.map +1 -1
  25. package/lib/bridge/mockHelpers.d.ts +1 -0
  26. package/lib/bridge/mockHelpers.d.ts.map +1 -1
  27. package/lib/bridge/mockHelpers.js +53 -1
  28. package/lib/bridge/mockHelpers.js.map +1 -1
  29. package/lib/bridge/react/BridgeSync.d.ts +1 -0
  30. package/lib/bridge/react/BridgeSync.d.ts.map +1 -1
  31. package/lib/bridge/react/BridgeSync.js +19 -16
  32. package/lib/bridge/react/BridgeSync.js.map +1 -1
  33. package/lib/bridge/react/BridgeSync.test.js +403 -66
  34. package/lib/bridge/react/BridgeSync.test.js.map +1 -1
  35. package/lib/dada-client/entities/index.d.ts +1 -1
  36. package/lib/dada-client/entities/index.d.ts.map +1 -1
  37. package/lib/e2e/index.d.ts +8 -0
  38. package/lib/e2e/index.d.ts.map +1 -1
  39. package/lib/families/algorand/bridge/mock.d.ts.map +1 -1
  40. package/lib/families/algorand/bridge/mock.js +1 -0
  41. package/lib/families/algorand/bridge/mock.js.map +1 -1
  42. package/lib/families/bitcoin/bridge/mock.d.ts.map +1 -1
  43. package/lib/families/bitcoin/bridge/mock.js +1 -0
  44. package/lib/families/bitcoin/bridge/mock.js.map +1 -1
  45. package/lib/families/canton/bridge/mock.d.ts.map +1 -1
  46. package/lib/families/canton/bridge/mock.js +3 -0
  47. package/lib/families/canton/bridge/mock.js.map +1 -1
  48. package/lib/families/cardano/bridge/mock.d.ts.map +1 -1
  49. package/lib/families/cardano/bridge/mock.js +1 -0
  50. package/lib/families/cardano/bridge/mock.js.map +1 -1
  51. package/lib/families/casper/bridge/mock.d.ts.map +1 -1
  52. package/lib/families/casper/bridge/mock.js +1 -0
  53. package/lib/families/casper/bridge/mock.js.map +1 -1
  54. package/lib/families/cosmos/bridge/mock.d.ts.map +1 -1
  55. package/lib/families/cosmos/bridge/mock.js +1 -0
  56. package/lib/families/cosmos/bridge/mock.js.map +1 -1
  57. package/lib/families/evm/bridge/mock.d.ts.map +1 -1
  58. package/lib/families/evm/bridge/mock.js +1 -0
  59. package/lib/families/evm/bridge/mock.js.map +1 -1
  60. package/lib/families/icon/bridge/mock.d.ts.map +1 -1
  61. package/lib/families/icon/bridge/mock.js +1 -0
  62. package/lib/families/icon/bridge/mock.js.map +1 -1
  63. package/lib/families/multiversx/bridge/mock.d.ts.map +1 -1
  64. package/lib/families/multiversx/bridge/mock.js +1 -0
  65. package/lib/families/multiversx/bridge/mock.js.map +1 -1
  66. package/lib/families/polkadot/bridge/mock.d.ts.map +1 -1
  67. package/lib/families/polkadot/bridge/mock.js +1 -0
  68. package/lib/families/polkadot/bridge/mock.js.map +1 -1
  69. package/lib/families/polkadot/config.d.ts.map +1 -1
  70. package/lib/families/polkadot/config.js +84 -0
  71. package/lib/families/polkadot/config.js.map +1 -1
  72. package/lib/families/polkadot/setup.d.ts.map +1 -1
  73. package/lib/families/polkadot/setup.js +5 -4
  74. package/lib/families/polkadot/setup.js.map +1 -1
  75. package/lib/families/solana/bridge/mock.d.ts +1 -0
  76. package/lib/families/solana/bridge/mock.d.ts.map +1 -1
  77. package/lib/families/stellar/bridge/mock.d.ts.map +1 -1
  78. package/lib/families/stellar/bridge/mock.js +1 -0
  79. package/lib/families/stellar/bridge/mock.js.map +1 -1
  80. package/lib/families/tezos/bridge/mock.d.ts.map +1 -1
  81. package/lib/families/tezos/bridge/mock.js +1 -0
  82. package/lib/families/tezos/bridge/mock.js.map +1 -1
  83. package/lib/families/tron/bridge/mock.d.ts.map +1 -1
  84. package/lib/families/tron/bridge/mock.js +1 -0
  85. package/lib/families/tron/bridge/mock.js.map +1 -1
  86. package/lib/families/xrp/bridge/mock.d.ts.map +1 -1
  87. package/lib/families/xrp/bridge/mock.js +1 -0
  88. package/lib/families/xrp/bridge/mock.js.map +1 -1
  89. package/lib/featureFlags/defaultFeatures.d.ts +3 -0
  90. package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
  91. package/lib/featureFlags/defaultFeatures.js +10 -1
  92. package/lib/featureFlags/defaultFeatures.js.map +1 -1
  93. package/lib/featureFlags/useFeature.d.ts +1 -1
  94. package/lib/featureFlags/useFeature.d.ts.map +1 -1
  95. package/lib/generated/bridge/mock.d.ts +1 -0
  96. package/lib/generated/bridge/mock.d.ts.map +1 -1
  97. package/lib/hw/actions/rawTransaction.d.ts +37 -0
  98. package/lib/hw/actions/rawTransaction.d.ts.map +1 -0
  99. package/lib/hw/actions/rawTransaction.js +107 -0
  100. package/lib/hw/actions/rawTransaction.js.map +1 -0
  101. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.d.ts.map +1 -1
  102. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js +9 -0
  103. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js.map +1 -1
  104. package/lib/wallet-api/logic.d.ts +1 -0
  105. package/lib/wallet-api/logic.d.ts.map +1 -1
  106. package/lib/wallet-api/logic.js +21 -1
  107. package/lib/wallet-api/logic.js.map +1 -1
  108. package/lib/wallet-api/react.d.ts +9 -1
  109. package/lib/wallet-api/react.d.ts.map +1 -1
  110. package/lib/wallet-api/react.js +60 -2
  111. package/lib/wallet-api/react.js.map +1 -1
  112. package/lib/wallet-api/tracking.d.ts +3 -0
  113. package/lib/wallet-api/tracking.d.ts.map +1 -1
  114. package/lib/wallet-api/tracking.js +12 -0
  115. package/lib/wallet-api/tracking.js.map +1 -1
  116. package/lib-es/bridge/generic-alpaca/accountBridge.d.ts.map +1 -1
  117. package/lib-es/bridge/generic-alpaca/accountBridge.js +2 -0
  118. package/lib-es/bridge/generic-alpaca/accountBridge.js.map +1 -1
  119. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts +1 -0
  120. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts.map +1 -1
  121. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.js +3 -0
  122. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.js.map +1 -1
  123. package/lib-es/bridge/generic-alpaca/prepareTransaction.d.ts.map +1 -1
  124. package/lib-es/bridge/generic-alpaca/prepareTransaction.js +37 -45
  125. package/lib-es/bridge/generic-alpaca/prepareTransaction.js.map +1 -1
  126. package/lib-es/bridge/generic-alpaca/signOperation.d.ts.map +1 -1
  127. package/lib-es/bridge/generic-alpaca/signOperation.js +0 -17
  128. package/lib-es/bridge/generic-alpaca/signOperation.js.map +1 -1
  129. package/lib-es/bridge/generic-alpaca/signRawOperation.d.ts +8 -0
  130. package/lib-es/bridge/generic-alpaca/signRawOperation.d.ts.map +1 -0
  131. package/lib-es/bridge/generic-alpaca/signRawOperation.js +48 -0
  132. package/lib-es/bridge/generic-alpaca/signRawOperation.js.map +1 -0
  133. package/lib-es/bridge/generic-alpaca/tests/getAccountShape.test.js +1 -0
  134. package/lib-es/bridge/generic-alpaca/tests/getAccountShape.test.js.map +1 -1
  135. package/lib-es/bridge/generic-alpaca/tests/prepareTransaction.test.js +163 -88
  136. package/lib-es/bridge/generic-alpaca/tests/prepareTransaction.test.js.map +1 -1
  137. package/lib-es/bridge/generic-alpaca/utils.d.ts.map +1 -1
  138. package/lib-es/bridge/generic-alpaca/utils.js +1 -0
  139. package/lib-es/bridge/generic-alpaca/utils.js.map +1 -1
  140. package/lib-es/bridge/mockHelpers.d.ts +1 -0
  141. package/lib-es/bridge/mockHelpers.d.ts.map +1 -1
  142. package/lib-es/bridge/mockHelpers.js +51 -0
  143. package/lib-es/bridge/mockHelpers.js.map +1 -1
  144. package/lib-es/bridge/react/BridgeSync.d.ts +1 -0
  145. package/lib-es/bridge/react/BridgeSync.d.ts.map +1 -1
  146. package/lib-es/bridge/react/BridgeSync.js +17 -15
  147. package/lib-es/bridge/react/BridgeSync.js.map +1 -1
  148. package/lib-es/bridge/react/BridgeSync.test.js +382 -65
  149. package/lib-es/bridge/react/BridgeSync.test.js.map +1 -1
  150. package/lib-es/dada-client/entities/index.d.ts +1 -1
  151. package/lib-es/dada-client/entities/index.d.ts.map +1 -1
  152. package/lib-es/e2e/index.d.ts +8 -0
  153. package/lib-es/e2e/index.d.ts.map +1 -1
  154. package/lib-es/families/algorand/bridge/mock.d.ts.map +1 -1
  155. package/lib-es/families/algorand/bridge/mock.js +2 -1
  156. package/lib-es/families/algorand/bridge/mock.js.map +1 -1
  157. package/lib-es/families/bitcoin/bridge/mock.d.ts.map +1 -1
  158. package/lib-es/families/bitcoin/bridge/mock.js +2 -1
  159. package/lib-es/families/bitcoin/bridge/mock.js.map +1 -1
  160. package/lib-es/families/canton/bridge/mock.d.ts.map +1 -1
  161. package/lib-es/families/canton/bridge/mock.js +3 -0
  162. package/lib-es/families/canton/bridge/mock.js.map +1 -1
  163. package/lib-es/families/cardano/bridge/mock.d.ts.map +1 -1
  164. package/lib-es/families/cardano/bridge/mock.js +2 -1
  165. package/lib-es/families/cardano/bridge/mock.js.map +1 -1
  166. package/lib-es/families/casper/bridge/mock.d.ts.map +1 -1
  167. package/lib-es/families/casper/bridge/mock.js +2 -1
  168. package/lib-es/families/casper/bridge/mock.js.map +1 -1
  169. package/lib-es/families/cosmos/bridge/mock.d.ts.map +1 -1
  170. package/lib-es/families/cosmos/bridge/mock.js +2 -1
  171. package/lib-es/families/cosmos/bridge/mock.js.map +1 -1
  172. package/lib-es/families/evm/bridge/mock.d.ts.map +1 -1
  173. package/lib-es/families/evm/bridge/mock.js +2 -1
  174. package/lib-es/families/evm/bridge/mock.js.map +1 -1
  175. package/lib-es/families/icon/bridge/mock.d.ts.map +1 -1
  176. package/lib-es/families/icon/bridge/mock.js +2 -1
  177. package/lib-es/families/icon/bridge/mock.js.map +1 -1
  178. package/lib-es/families/multiversx/bridge/mock.d.ts.map +1 -1
  179. package/lib-es/families/multiversx/bridge/mock.js +2 -1
  180. package/lib-es/families/multiversx/bridge/mock.js.map +1 -1
  181. package/lib-es/families/polkadot/bridge/mock.d.ts.map +1 -1
  182. package/lib-es/families/polkadot/bridge/mock.js +2 -1
  183. package/lib-es/families/polkadot/bridge/mock.js.map +1 -1
  184. package/lib-es/families/polkadot/config.d.ts.map +1 -1
  185. package/lib-es/families/polkadot/config.js +84 -0
  186. package/lib-es/families/polkadot/config.js.map +1 -1
  187. package/lib-es/families/polkadot/setup.d.ts.map +1 -1
  188. package/lib-es/families/polkadot/setup.js +5 -4
  189. package/lib-es/families/polkadot/setup.js.map +1 -1
  190. package/lib-es/families/solana/bridge/mock.d.ts +1 -0
  191. package/lib-es/families/solana/bridge/mock.d.ts.map +1 -1
  192. package/lib-es/families/stellar/bridge/mock.d.ts.map +1 -1
  193. package/lib-es/families/stellar/bridge/mock.js +2 -1
  194. package/lib-es/families/stellar/bridge/mock.js.map +1 -1
  195. package/lib-es/families/tezos/bridge/mock.d.ts.map +1 -1
  196. package/lib-es/families/tezos/bridge/mock.js +2 -1
  197. package/lib-es/families/tezos/bridge/mock.js.map +1 -1
  198. package/lib-es/families/tron/bridge/mock.d.ts.map +1 -1
  199. package/lib-es/families/tron/bridge/mock.js +2 -1
  200. package/lib-es/families/tron/bridge/mock.js.map +1 -1
  201. package/lib-es/families/xrp/bridge/mock.d.ts.map +1 -1
  202. package/lib-es/families/xrp/bridge/mock.js +2 -1
  203. package/lib-es/families/xrp/bridge/mock.js.map +1 -1
  204. package/lib-es/featureFlags/defaultFeatures.d.ts +3 -0
  205. package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
  206. package/lib-es/featureFlags/defaultFeatures.js +10 -1
  207. package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
  208. package/lib-es/featureFlags/useFeature.d.ts +1 -1
  209. package/lib-es/featureFlags/useFeature.d.ts.map +1 -1
  210. package/lib-es/generated/bridge/mock.d.ts +1 -0
  211. package/lib-es/generated/bridge/mock.d.ts.map +1 -1
  212. package/lib-es/hw/actions/rawTransaction.d.ts +37 -0
  213. package/lib-es/hw/actions/rawTransaction.d.ts.map +1 -0
  214. package/lib-es/hw/actions/rawTransaction.js +103 -0
  215. package/lib-es/hw/actions/rawTransaction.js.map +1 -0
  216. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.d.ts.map +1 -1
  217. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js +9 -0
  218. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js.map +1 -1
  219. package/lib-es/wallet-api/logic.d.ts +1 -0
  220. package/lib-es/wallet-api/logic.d.ts.map +1 -1
  221. package/lib-es/wallet-api/logic.js +19 -0
  222. package/lib-es/wallet-api/logic.js.map +1 -1
  223. package/lib-es/wallet-api/react.d.ts +9 -1
  224. package/lib-es/wallet-api/react.d.ts.map +1 -1
  225. package/lib-es/wallet-api/react.js +61 -3
  226. package/lib-es/wallet-api/react.js.map +1 -1
  227. package/lib-es/wallet-api/tracking.d.ts +3 -0
  228. package/lib-es/wallet-api/tracking.d.ts.map +1 -1
  229. package/lib-es/wallet-api/tracking.js +12 -0
  230. package/lib-es/wallet-api/tracking.js.map +1 -1
  231. package/package.json +54 -54
  232. package/src/bridge/generic-alpaca/accountBridge.ts +2 -0
  233. package/src/bridge/generic-alpaca/alpaca/network/network-alpaca.ts +8 -0
  234. package/src/bridge/generic-alpaca/prepareTransaction.ts +46 -69
  235. package/src/bridge/generic-alpaca/signOperation.ts +0 -20
  236. package/src/bridge/generic-alpaca/signRawOperation.ts +86 -0
  237. package/src/bridge/generic-alpaca/tests/getAccountShape.test.ts +1 -0
  238. package/src/bridge/generic-alpaca/tests/prepareTransaction.test.ts +191 -109
  239. package/src/bridge/generic-alpaca/utils.ts +1 -0
  240. package/src/bridge/mockHelpers.ts +57 -0
  241. package/src/bridge/react/BridgeSync.test.tsx +513 -82
  242. package/src/bridge/react/BridgeSync.tsx +18 -17
  243. package/src/dada-client/MIGRATION_GUIDE.md +215 -0
  244. package/src/dada-client/entities/index.ts +1 -1
  245. package/src/families/algorand/bridge/mock.ts +2 -0
  246. package/src/families/bitcoin/bridge/mock.ts +2 -0
  247. package/src/families/canton/bridge/mock.ts +3 -0
  248. package/src/families/cardano/bridge/mock.ts +2 -0
  249. package/src/families/casper/bridge/mock.ts +2 -0
  250. package/src/families/cosmos/bridge/mock.ts +2 -0
  251. package/src/families/evm/bridge/mock.ts +2 -0
  252. package/src/families/icon/bridge/mock.ts +2 -0
  253. package/src/families/multiversx/bridge/mock.ts +2 -0
  254. package/src/families/polkadot/bridge/mock.ts +2 -0
  255. package/src/families/polkadot/config.ts +84 -0
  256. package/src/families/polkadot/setup.ts +6 -4
  257. package/src/families/stellar/bridge/mock.ts +2 -0
  258. package/src/families/tezos/bridge/mock.ts +2 -0
  259. package/src/families/tron/bridge/mock.ts +2 -0
  260. package/src/families/xrp/bridge/mock.ts +2 -0
  261. package/src/featureFlags/defaultFeatures.ts +10 -1
  262. package/src/hw/actions/rawTransaction.ts +190 -0
  263. package/src/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.ts +9 -0
  264. package/src/wallet-api/logic.ts +35 -0
  265. package/src/wallet-api/react.ts +87 -1
  266. package/src/wallet-api/tracking.ts +15 -0
@@ -14,6 +14,7 @@ import { genericEstimateMaxSpendable } from "./estimateMaxSpendable";
14
14
  import { createTransaction } from "./createTransaction";
15
15
  import { genericBroadcast } from "./broadcast";
16
16
  import { genericSignOperation } from "./signOperation";
17
+ import { genericSignRawOperation } from "./signRawOperation";
17
18
  import type { AlpacaSigner } from "./signer/types";
18
19
 
19
20
  export function getAlpacaAccountBridge(
@@ -32,6 +33,7 @@ export function getAlpacaAccountBridge(
32
33
  estimateMaxSpendable: genericEstimateMaxSpendable(network, kind),
33
34
  broadcast: genericBroadcast(network, kind),
34
35
  signOperation: genericSignOperation(network, kind)(signer.context),
36
+ signRawOperation: genericSignRawOperation(network, kind)(signer.context),
35
37
  getSerializedAddressParameters, // NOTE: check wether it should be exposed by coin-module's api instead?
36
38
  } satisfies Partial<AccountBridge<any>>;
37
39
  }
@@ -186,6 +186,14 @@ export const getNetworkAlpacaApi = (networkFamily: string) =>
186
186
  listOperations: buildListOperations(networkFamily),
187
187
  lastBlock: buildLastBlock(networkFamily),
188
188
  craftTransaction: buildCraftTransaction(networkFamily),
189
+ craftRawTransaction: (
190
+ _transaction: string,
191
+ _sender: string,
192
+ _publicKey: string,
193
+ _sequence: number,
194
+ ): Promise<CraftedTransaction> => {
195
+ throw new Error("craftRawTransaction is not supported");
196
+ },
189
197
  getBlock(_height): Promise<Block> {
190
198
  throw new Error("getBlock is not supported");
191
199
  },
@@ -7,10 +7,6 @@ import { decodeTokenAccountId } from "@ledgerhq/coin-framework/account/index";
7
7
  import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
8
8
  import { GenericTransaction } from "./types";
9
9
 
10
- function bnEq(a: BigNumber | null | undefined, b: BigNumber | null | undefined): boolean {
11
- return !a && !b ? true : !a || !b ? false : a.eq(b);
12
- }
13
-
14
10
  function assetInfosFallback(transaction: GenericTransaction): {
15
11
  assetReference: string;
16
12
  assetOwner: string;
@@ -26,86 +22,67 @@ export function genericPrepareTransaction(
26
22
  kind,
27
23
  ): AccountBridge<GenericTransaction, Account>["prepareTransaction"] {
28
24
  return async (account, transaction: GenericTransaction) => {
29
- const { getAssetFromToken, computeIntentType, estimateFees, validateIntent } = getAlpacaApi(
25
+ const { getAssetFromToken, computeIntentType, estimateFees } = getAlpacaApi(
30
26
  account.currency.id,
31
27
  kind,
32
28
  );
33
29
  const { assetReference, assetOwner } = getAssetFromToken
34
30
  ? getAssetInfos(transaction, account.freshAddress, getAssetFromToken)
35
31
  : assetInfosFallback(transaction);
36
- const customParametersFees = transaction.customFees?.parameters?.fees;
37
- let fees: BigNumber | bigint | null = customParametersFees || null;
38
- if (fees === null) {
39
- fees = (
40
- await estimateFees(
41
- transactionToIntent(
42
- account,
43
- {
44
- ...transaction,
45
- },
46
- computeIntentType,
47
- ),
48
- )
49
- ).value;
32
+
33
+ const next: GenericTransaction = {
34
+ ...transaction,
35
+ assetOwner,
36
+ assetReference,
37
+ };
38
+
39
+ const useAllAmount = !!next.useAllAmount || ["stake", "unstake"].includes(next.mode ?? "");
40
+
41
+ // Anticipate use cases where token amounts impact fee calculuses
42
+ if (useAllAmount && next.subAccountId) {
43
+ const subAccount = account.subAccounts?.find(sub => sub.id === next.subAccountId);
44
+
45
+ next.amount = subAccount?.spendableBalance ?? new BigNumber(0);
50
46
  }
51
47
 
52
- if (!bnEq(transaction.fees, new BigNumber(fees.toString()))) {
53
- const next: GenericTransaction = {
54
- ...transaction,
55
- fees: new BigNumber(fees.toString()),
56
- assetReference,
57
- assetOwner,
58
- customFees: {
59
- parameters: {
60
- fees: customParametersFees ? new BigNumber(customParametersFees.toString()) : undefined,
61
- },
62
- },
63
- };
64
-
65
- // propagate storageLimit fee parameter when present (ex: tezos)
66
- const feeEstimation = await estimateFees(
67
- transactionToIntent(
68
- account,
69
- {
70
- ...transaction,
71
- },
72
- computeIntentType,
73
- ),
74
- );
75
- const params = feeEstimation?.parameters;
76
- if (params) {
77
- const storageLimit = params["storageLimit"];
78
- if (
79
- storageLimit !== undefined &&
80
- (typeof storageLimit === "bigint" ||
81
- typeof storageLimit === "number" ||
82
- typeof storageLimit === "string")
83
- ) {
84
- next.storageLimit = new BigNumber(storageLimit.toString());
85
- }
48
+ const intent = transactionToIntent(account, next, computeIntentType);
49
+ const estimation = await estimateFees(intent);
50
+ const customFeesValue = next.customFees?.parameters?.fees; // e.g. Stellar
51
+
52
+ next.fees = customFeesValue ?? new BigNumber(estimation.value.toString());
53
+
54
+ const fieldsToPropagate = ["storageLimit"] as const;
55
+
56
+ for (const field of fieldsToPropagate) {
57
+ const parameter = estimation.parameters?.[field];
58
+
59
+ if (
60
+ typeof parameter === "bigint" ||
61
+ typeof parameter === "number" ||
62
+ typeof parameter === "string"
63
+ ) {
64
+ next[field] = new BigNumber(parameter.toString());
86
65
  }
66
+ }
87
67
 
88
- // align with stellar/xrp: when send max (or staking intents), reflect validated amount in UI
68
+ // Fees are now fixed, compute max spendable native
69
+ if (useAllAmount && !next.subAccountId) {
70
+ // Check if the estimation has been done for a custom amount
71
+ const estimatedAmount = estimation.parameters?.amount;
89
72
  if (
90
- transaction.useAllAmount ||
91
- transaction["mode"] === "stake" ||
92
- transaction["mode"] === "unstake"
73
+ typeof estimatedAmount === "bigint" ||
74
+ typeof estimatedAmount === "number" ||
75
+ typeof estimatedAmount === "string"
93
76
  ) {
94
- const { amount } = await validateIntent(
95
- transactionToIntent(
96
- account,
97
- {
98
- ...transaction,
99
- },
100
- computeIntentType,
101
- ),
102
- );
103
- next.amount = new BigNumber(amount.toString());
77
+ next.amount = new BigNumber(estimatedAmount.toString());
78
+ } else {
79
+ next.amount = account.spendableBalance.gt(next.fees)
80
+ ? account.spendableBalance.minus(next.fees)
81
+ : new BigNumber(0);
104
82
  }
105
- return next;
106
83
  }
107
84
 
108
- return transaction;
85
+ return next;
109
86
  };
110
87
  }
111
88
 
@@ -8,7 +8,6 @@ import { Result } from "@ledgerhq/coin-framework/derivation";
8
8
  import { MapMemo, TransactionIntent } from "@ledgerhq/coin-framework/api/types";
9
9
  import { StellarMemo } from "@ledgerhq/coin-stellar/types/bridge";
10
10
  import { log } from "@ledgerhq/logs";
11
- import BigNumber from "bignumber.js";
12
11
  import { GenericTransaction } from "./types";
13
12
 
14
13
  /**
@@ -86,25 +85,6 @@ export const genericSignOperation =
86
85
  const alpacaApi = getAlpacaApi(account.currency.id, kind);
87
86
  if (!transaction.fees) throw new FeeNotLoaded();
88
87
  const fees = BigInt(transaction.fees?.toString() || "0");
89
- if (transaction.useAllAmount) {
90
- const draftTransaction = {
91
- mode: transaction.mode,
92
- recipient: transaction.recipient,
93
- amount: transaction.amount ?? 0,
94
- useAllAmount: !!transaction.useAllAmount,
95
- assetReference: transaction?.assetReference || "",
96
- assetOwner: transaction?.assetOwner || "",
97
- subAccountId: transaction.subAccountId || "",
98
- family: transaction.family,
99
- feesStrategy: transaction.feesStrategy,
100
- data: transaction.data,
101
- };
102
- const { amount } = await alpacaApi.validateIntent(
103
- transactionToIntent(account, draftTransaction, alpacaApi.computeIntentType),
104
- { value: fees },
105
- );
106
- transaction.amount = new BigNumber(amount.toString());
107
- }
108
88
  const signedInfo = await signerContext(deviceId, async signer => {
109
89
  const derivationPath = account.freshAddressPath;
110
90
  const { publicKey } = (await signer.getAddress(derivationPath)) as Result;
@@ -0,0 +1,86 @@
1
+ import { Observable } from "rxjs";
2
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
3
+ import type { Account, DeviceId, SignOperationEvent, AccountBridge } from "@ledgerhq/types-live";
4
+ import { getAlpacaApi } from "./alpaca";
5
+ import { buildOptimisticOperation } from "./utils";
6
+ import { Result } from "@ledgerhq/coin-framework/derivation";
7
+ import { log } from "@ledgerhq/logs";
8
+ import BigNumber from "bignumber.js";
9
+ import { GenericTransaction } from "./types";
10
+
11
+ /**
12
+ * Sign Transaction with Ledger hardware
13
+ */
14
+ export const genericSignRawOperation =
15
+ (network, kind) =>
16
+ (signerContext: SignerContext<any>): AccountBridge<GenericTransaction>["signRawOperation"] =>
17
+ ({
18
+ account,
19
+ transaction,
20
+ deviceId,
21
+ }: {
22
+ account: Account;
23
+ transaction: string;
24
+ deviceId: DeviceId;
25
+ }): Observable<SignOperationEvent> =>
26
+ new Observable(o => {
27
+ async function main() {
28
+ const alpacaApi = getAlpacaApi(account.currency.id, kind);
29
+ const signedInfo = await signerContext(deviceId, async signer => {
30
+ const derivationPath = account.freshAddressPath;
31
+ const { publicKey } = (await signer.getAddress(derivationPath)) as Result;
32
+
33
+ const sender = account.freshAddress;
34
+
35
+ // TODO: should compute it and pass it down to craftTransaction (duplicate call right now)
36
+ const sequenceNumber = await alpacaApi.getSequence(sender);
37
+
38
+ /* Craft unsigned blob via Alpaca */
39
+ const { transaction: unsigned } = await alpacaApi.craftRawTransaction(
40
+ transaction,
41
+ sender,
42
+ publicKey,
43
+ sequenceNumber,
44
+ );
45
+
46
+ /* Notify UI that the device is now showing the tx */
47
+ o.next({ type: "device-signature-requested" });
48
+ /* Sign on Ledger device */
49
+ const txnSig = await signer.signTransaction(derivationPath, unsigned);
50
+ return { unsigned, txnSig, publicKey, sequence: sequenceNumber };
51
+ });
52
+
53
+ /* If the user cancelled inside signerContext */
54
+ if (!signedInfo) return;
55
+ o.next({ type: "device-signature-granted" });
56
+
57
+ /* Combine payload + signature for broadcast */
58
+ const combined = await alpacaApi.combine(
59
+ signedInfo.unsigned,
60
+ signedInfo.txnSig,
61
+ signedInfo.publicKey,
62
+ );
63
+ const operation = buildOptimisticOperation(
64
+ account,
65
+ { family: account.currency.family, amount: new BigNumber(0), recipient: "" },
66
+ signedInfo.sequence,
67
+ );
68
+ if (!operation.id) {
69
+ log("Generic alpaca", "buildOptimisticOperation", operation);
70
+ }
71
+ // NOTE: we set the transactionSequenceNumber before on the operation
72
+ // now that we create it in craftTransaction, we might need to return it back from craftTransaction also
73
+ o.next({
74
+ type: "signed",
75
+ signedOperation: {
76
+ operation,
77
+ signature: combined,
78
+ },
79
+ });
80
+ }
81
+
82
+ main().then(
83
+ () => o.complete(),
84
+ e => o.error(e),
85
+ );
86
+ });
@@ -48,6 +48,7 @@ jest.mock("../buildSubAccounts", () => ({
48
48
  const chains = [
49
49
  { currency: { id: "stellar", name: "Stellar" }, network: "testnet" },
50
50
  { currency: { id: "ripple", name: "XRP" }, network: "mainnet" },
51
+ { currency: { id: "tezos", name: "Tezos" }, network: "mainnet" },
51
52
  ];
52
53
 
53
54
  describe("genericGetAccountShape (stellar & xrp)", () => {
@@ -1,172 +1,254 @@
1
1
  import { genericPrepareTransaction } from "../prepareTransaction";
2
2
  import { getAlpacaApi } from "../alpaca";
3
- import { transactionToIntent } from "../utils";
4
3
  import BigNumber from "bignumber.js";
4
+ import * as accountModule from "@ledgerhq/coin-framework/account/index";
5
+ import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
6
+ import { Account } from "@ledgerhq/types-live";
5
7
 
6
8
  jest.mock("../alpaca", () => ({
7
9
  getAlpacaApi: jest.fn(),
8
10
  }));
9
11
 
10
- jest.mock("../utils", () => ({
11
- transactionToIntent: jest.fn(),
12
- }));
13
-
14
12
  describe("genericPrepareTransaction", () => {
15
13
  const network = "testnet";
16
14
  const kind = "local";
17
15
 
18
- const account = {
19
- id: "test-account",
20
- address: "0xabc",
21
- currency: { id: "ethereum" },
22
- } as any;
23
-
24
- const baseTransaction = {
25
- amount: new BigNumber(100_000),
26
- fees: new BigNumber(500),
27
- recipient: "0xrecipient",
28
- family: "family",
29
- };
30
-
31
- const txIntent = { mock: "intent" };
32
-
33
16
  beforeEach(() => {
34
17
  jest.clearAllMocks();
35
- (transactionToIntent as jest.Mock).mockReturnValue(txIntent);
36
18
  });
37
19
 
38
- it("updates fees if they differ", async () => {
39
- const newFee = new BigNumber(700);
40
-
20
+ it("embeds assets info, if existing", async () => {
41
21
  (getAlpacaApi as jest.Mock).mockReturnValue({
42
- estimateFees: jest.fn().mockResolvedValue({ value: newFee }),
22
+ estimateFees: jest.fn().mockResolvedValue({ value: 500n }),
23
+ getAssetFromToken: jest.fn().mockImplementation((token, owner) => {
24
+ return {
25
+ assetOwner: owner,
26
+ assetReference: token.contractAddress,
27
+ };
28
+ }),
43
29
  });
30
+ jest.spyOn(accountModule, "decodeTokenAccountId").mockImplementation(accountId => {
31
+ const token =
32
+ accountId === "ethereum_usdc_sub_account"
33
+ ? ({ contractAddress: "usdc_contract" } as TokenCurrency)
34
+ : undefined;
44
35
 
45
- const prepareTransaction = genericPrepareTransaction(network, kind);
46
- const result = await prepareTransaction(account, { ...baseTransaction });
36
+ return { accountId, token };
37
+ });
47
38
 
48
- expect((result as any).fees.toString()).toBe(newFee.toString());
49
- expect(transactionToIntent).toHaveBeenCalledWith(
50
- account,
51
- expect.objectContaining(baseTransaction),
52
- undefined,
39
+ const prepareTransaction = genericPrepareTransaction(network, kind);
40
+ const resultUsdcToken = await prepareTransaction(
41
+ { currency: { id: "ethereum", units: [{}] }, freshAddress: "0xabc" } as Account,
42
+ {
43
+ amount: new BigNumber(100_000),
44
+ fees: new BigNumber(500),
45
+ recipient: "0xrecipient",
46
+ family: "family",
47
+ subAccountId: "ethereum_usdc_sub_account",
48
+ },
53
49
  );
54
- });
55
-
56
- it("returns original transaction if fees are the same", async () => {
57
- const sameFee = baseTransaction.fees;
58
50
 
59
- (getAlpacaApi as jest.Mock).mockReturnValue({
60
- estimateFees: jest.fn().mockResolvedValue({ value: sameFee }),
51
+ expect(resultUsdcToken).toEqual({
52
+ amount: new BigNumber(100_000),
53
+ fees: new BigNumber(500),
54
+ recipient: "0xrecipient",
55
+ family: "family",
56
+ assetReference: "usdc_contract",
57
+ assetOwner: "0xabc",
58
+ subAccountId: "ethereum_usdc_sub_account",
61
59
  });
62
60
 
63
- const prepareTransaction = genericPrepareTransaction(network, kind);
64
- const result = await prepareTransaction(account, baseTransaction);
61
+ const resultUnknownToken = await prepareTransaction(
62
+ { currency: { id: "ethereum", units: [{}] } } as Account,
63
+ {
64
+ amount: new BigNumber(100_000),
65
+ fees: new BigNumber(500),
66
+ recipient: "0xrecipient",
67
+ family: "family",
68
+ subAccountId: "ethereum_unknown_sub_account",
69
+ },
70
+ );
65
71
 
66
- expect(result).toBe(baseTransaction);
72
+ expect(resultUnknownToken).toEqual({
73
+ amount: new BigNumber(100_000),
74
+ fees: new BigNumber(500),
75
+ recipient: "0xrecipient",
76
+ family: "family",
77
+ assetReference: "",
78
+ assetOwner: "",
79
+ subAccountId: "ethereum_unknown_sub_account",
80
+ });
67
81
  });
68
82
 
69
- it("sets fee if original fees are undefined", async () => {
70
- const newFee = new BigNumber(1234);
83
+ it.each([
84
+ ["all native amount", { useAllAmount: true }, new BigNumber(42)],
85
+ ["all native amount on staking scenarios", { mode: "stake" }, new BigNumber(42)],
86
+ ["all native amount on unstaking scenarios", { mode: "unstake" }, new BigNumber(42)],
87
+ [
88
+ "all token amount",
89
+ { subAccountId: "ethereum_usdc_sub_account", useAllAmount: true },
90
+ new BigNumber(5),
91
+ ],
92
+ [
93
+ "all token amount on staking scenarios",
94
+ { subAccountId: "ethereum_usdc_sub_account", mode: "stake" },
95
+ new BigNumber(5),
96
+ ],
97
+ [
98
+ "all token amount on unstaking scenarios",
99
+ { subAccountId: "ethereum_usdc_sub_account", mode: "unstake" },
100
+ new BigNumber(5),
101
+ ],
102
+ ] as const)("uses %s, updating the amount", async (_s, partialTransaction, expectedAmount) => {
71
103
  (getAlpacaApi as jest.Mock).mockReturnValue({
72
- estimateFees: jest.fn().mockResolvedValue({ value: newFee }),
104
+ estimateFees: jest.fn().mockResolvedValue({ value: 8n }),
105
+ getAssetFromToken: jest.fn().mockImplementation((token, owner) => {
106
+ return {
107
+ assetOwner: owner,
108
+ assetReference: token.contractAddress,
109
+ };
110
+ }),
111
+ });
112
+ jest.spyOn(accountModule, "decodeTokenAccountId").mockImplementation(accountId => {
113
+ const token =
114
+ accountId === "ethereum_usdc_sub_account"
115
+ ? ({ contractAddress: "usdc_contract" } as TokenCurrency)
116
+ : undefined;
117
+
118
+ return { accountId, token };
73
119
  });
74
120
 
75
- const txWithoutFees = { ...baseTransaction, fees: undefined as any };
76
121
  const prepareTransaction = genericPrepareTransaction(network, kind);
77
- const result = await prepareTransaction(account, txWithoutFees);
122
+ const result = await prepareTransaction(
123
+ {
124
+ currency: { id: "ethereum", units: [{}] },
125
+ spendableBalance: new BigNumber(50),
126
+ subAccounts: [{ id: "ethereum_usdc_sub_account", spendableBalance: new BigNumber(5) }],
127
+ } as Account,
128
+ {
129
+ amount: new BigNumber(0),
130
+ recipient: "0xrecipient",
131
+ family: "family",
132
+ ...partialTransaction,
133
+ },
134
+ );
78
135
 
79
- expect((result as any).fees.toString()).toBe(newFee.toString());
80
- expect(result).not.toBe(txWithoutFees);
136
+ expect(result).toMatchObject({
137
+ amount: expectedAmount,
138
+ fees: new BigNumber(8),
139
+ recipient: "0xrecipient",
140
+ family: "family",
141
+ });
81
142
  });
82
143
 
83
- it("returns original if fees are BigNumber-equal but different instance", async () => {
84
- const sameValue = new BigNumber(baseTransaction.fees.toString()); // different instance
144
+ it("updates fees from the estimation", async () => {
85
145
  (getAlpacaApi as jest.Mock).mockReturnValue({
86
- estimateFees: jest.fn().mockResolvedValue({ value: sameValue }),
146
+ estimateFees: jest.fn().mockResolvedValue({ value: 700n }),
87
147
  });
88
148
 
89
149
  const prepareTransaction = genericPrepareTransaction(network, kind);
90
- const result = await prepareTransaction(account, baseTransaction);
150
+ const result = await prepareTransaction(
151
+ { currency: { id: "ethereum", units: [{}] } } as Account,
152
+ {
153
+ amount: new BigNumber(100_000),
154
+ fees: new BigNumber(500),
155
+ recipient: "0xrecipient",
156
+ family: "family",
157
+ },
158
+ );
91
159
 
92
- expect(result).toBe(baseTransaction); // still same reference
160
+ expect(result).toEqual({
161
+ amount: new BigNumber(100_000),
162
+ fees: new BigNumber(700),
163
+ recipient: "0xrecipient",
164
+ family: "family",
165
+ assetReference: "",
166
+ assetOwner: "",
167
+ });
93
168
  });
94
169
 
95
- it("propagates storageLimit from second estimation", async () => {
96
- const estimatedFee = new BigNumber(491);
97
-
98
- const estimateFeesFirstCall = jest.fn().mockResolvedValue({
99
- value: estimatedFee,
100
- parameters: { storageLimit: 300 },
170
+ it("updates fees from the existing custom", async () => {
171
+ (getAlpacaApi as jest.Mock).mockReturnValue({
172
+ estimateFees: jest.fn().mockResolvedValue({ value: 700n }),
101
173
  });
102
174
 
103
- const estimateFeesSecondCall = jest.fn().mockResolvedValue({
104
- value: estimatedFee,
105
- parameters: { storageLimit: 0 },
175
+ const prepareTransaction = genericPrepareTransaction(network, kind);
176
+ const result = await prepareTransaction(
177
+ { currency: { id: "ethereum", units: [{}] } } as Account,
178
+ {
179
+ amount: new BigNumber(100_000),
180
+ fees: new BigNumber(500),
181
+ recipient: "0xrecipient",
182
+ family: "family",
183
+ customFees: { parameters: { fees: new BigNumber(600) } },
184
+ },
185
+ );
186
+
187
+ expect(result).toEqual({
188
+ amount: new BigNumber(100_000),
189
+ fees: new BigNumber(600),
190
+ customFees: { parameters: { fees: new BigNumber(600) } },
191
+ recipient: "0xrecipient",
192
+ family: "family",
193
+ assetReference: "",
194
+ assetOwner: "",
106
195
  });
196
+ });
107
197
 
198
+ it("propagates estimated 'storageLimit'", async () => {
108
199
  (getAlpacaApi as jest.Mock).mockReturnValue({
109
200
  estimateFees: jest
110
201
  .fn()
111
- .mockImplementationOnce(() => estimateFeesFirstCall())
112
- .mockImplementationOnce(() => estimateFeesSecondCall()),
202
+ .mockResolvedValue({ value: 700n, parameters: { storageLimit: 277n } }),
113
203
  });
114
204
 
115
- const txWithoutCustomFees = { ...baseTransaction, customFees: undefined };
116
205
  const prepareTransaction = genericPrepareTransaction(network, kind);
117
- const result = await prepareTransaction(account, txWithoutCustomFees);
118
-
119
- expect(result).toEqual(
120
- expect.objectContaining({
121
- fees: estimatedFee,
122
- storageLimit: new BigNumber(0),
123
- customFees: {
124
- parameters: {
125
- fees: undefined,
126
- },
127
- },
128
- }),
206
+ const result = await prepareTransaction(
207
+ { currency: { id: "ethereum", units: [{}] } } as Account,
208
+ {
209
+ amount: new BigNumber(100_000),
210
+ fees: new BigNumber(500),
211
+ recipient: "0xrecipient",
212
+ family: "family",
213
+ },
129
214
  );
130
215
 
131
- expect((getAlpacaApi as jest.Mock)().estimateFees).toHaveBeenCalledTimes(2);
132
- });
133
-
134
- it("propagates storageLimit showing new account scenario", async () => {
135
- const estimatedFee = new BigNumber(491);
136
-
137
- const estimateFeesFirstCall = jest.fn().mockResolvedValue({
138
- value: estimatedFee,
139
- parameters: { storageLimit: 300 },
140
- });
141
-
142
- const estimateFeesSecondCall = jest.fn().mockResolvedValue({
143
- value: estimatedFee,
144
- parameters: { storageLimit: 277 },
216
+ expect(result).toEqual({
217
+ amount: new BigNumber(100_000),
218
+ fees: new BigNumber(700),
219
+ storageLimit: new BigNumber(277),
220
+ recipient: "0xrecipient",
221
+ family: "family",
222
+ assetReference: "",
223
+ assetOwner: "",
145
224
  });
225
+ });
146
226
 
227
+ it("keeps the amount used during the estimation when using all native amount", async () => {
147
228
  (getAlpacaApi as jest.Mock).mockReturnValue({
148
- estimateFees: jest
149
- .fn()
150
- .mockImplementationOnce(() => estimateFeesFirstCall())
151
- .mockImplementationOnce(() => estimateFeesSecondCall()),
229
+ estimateFees: jest.fn().mockResolvedValue({ value: 700n, parameters: { amount: 1000n } }),
152
230
  });
153
231
 
154
- const txWithoutCustomFees = { ...baseTransaction, customFees: undefined };
155
232
  const prepareTransaction = genericPrepareTransaction(network, kind);
156
- const result = await prepareTransaction(account, txWithoutCustomFees);
157
-
158
- expect(result).toEqual(
159
- expect.objectContaining({
160
- fees: estimatedFee,
161
- storageLimit: new BigNumber(277),
162
- customFees: {
163
- parameters: {
164
- fees: undefined,
165
- },
166
- },
167
- }),
233
+ const result = await prepareTransaction(
234
+ { currency: { id: "ethereum", units: [{}] } } as Account,
235
+ {
236
+ amount: new BigNumber(0),
237
+ fees: new BigNumber(500),
238
+ recipient: "0xrecipient",
239
+ family: "family",
240
+ useAllAmount: true,
241
+ },
168
242
  );
169
243
 
170
- expect((getAlpacaApi as jest.Mock)().estimateFees).toHaveBeenCalledTimes(2);
244
+ expect(result).toEqual({
245
+ amount: new BigNumber(1000),
246
+ fees: new BigNumber(700),
247
+ recipient: "0xrecipient",
248
+ family: "family",
249
+ assetReference: "",
250
+ assetOwner: "",
251
+ useAllAmount: true,
252
+ });
171
253
  });
172
254
  });