@ledgerhq/live-common 23.0.0-next.0 → 23.0.0-next.3

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 (249) hide show
  1. package/lib/__tests__/test-helpers/setup.js +2 -0
  2. package/lib/__tests__/test-helpers/setup.js.map +1 -1
  3. package/lib/account/pending.d.ts +2 -1
  4. package/lib/account/pending.d.ts.map +1 -1
  5. package/lib/account/serialization.d.ts +3 -1
  6. package/lib/account/serialization.d.ts.map +1 -1
  7. package/lib/account/serialization.js +12 -3
  8. package/lib/account/serialization.js.map +1 -1
  9. package/lib/cross.d.ts.map +1 -1
  10. package/lib/cross.js +2 -1
  11. package/lib/cross.js.map +1 -1
  12. package/lib/derivation.d.ts +4 -0
  13. package/lib/derivation.d.ts.map +1 -1
  14. package/lib/derivation.js +18 -2
  15. package/lib/derivation.js.map +1 -1
  16. package/lib/env.d.ts +15 -5
  17. package/lib/env.d.ts.map +1 -1
  18. package/lib/env.js +10 -0
  19. package/lib/env.js.map +1 -1
  20. package/lib/env.react.d.ts +1 -1
  21. package/lib/env.react.d.ts.map +1 -1
  22. package/lib/errors.d.ts +1 -0
  23. package/lib/errors.d.ts.map +1 -1
  24. package/lib/errors.js +1 -0
  25. package/lib/errors.js.map +1 -1
  26. package/lib/families/algorand/js-synchronization.d.ts +2 -2
  27. package/lib/families/bitcoin/exchange.d.ts +1 -1
  28. package/lib/families/bitcoin/js-synchronisation.d.ts +2 -2
  29. package/lib/families/cardano/api/api-types.d.ts +38 -0
  30. package/lib/families/cardano/api/api-types.d.ts.map +1 -0
  31. package/lib/families/cardano/api/api-types.js +3 -0
  32. package/lib/families/cardano/api/api-types.js.map +1 -0
  33. package/lib/families/cardano/api/getNetworkInfo.d.ts +4 -0
  34. package/lib/families/cardano/api/getNetworkInfo.d.ts.map +1 -0
  35. package/lib/families/cardano/api/getNetworkInfo.js +83 -0
  36. package/lib/families/cardano/api/getNetworkInfo.js.map +1 -0
  37. package/lib/families/cardano/api/getTransactions.d.ts +10 -0
  38. package/lib/families/cardano/api/getTransactions.d.ts.map +1 -0
  39. package/lib/families/cardano/api/getTransactions.js +257 -0
  40. package/lib/families/cardano/api/getTransactions.js.map +1 -0
  41. package/lib/families/cardano/api/submitTransaction.d.ts +7 -0
  42. package/lib/families/cardano/api/submitTransaction.d.ts.map +1 -0
  43. package/lib/families/cardano/api/submitTransaction.js +69 -0
  44. package/lib/families/cardano/api/submitTransaction.js.map +1 -0
  45. package/lib/families/cardano/bridge/js.d.ts +8 -0
  46. package/lib/families/cardano/bridge/js.d.ts.map +1 -0
  47. package/lib/families/cardano/bridge/js.js +69 -0
  48. package/lib/families/cardano/bridge/js.js.map +1 -0
  49. package/lib/families/cardano/bridge.test.d.ts +2 -0
  50. package/lib/families/cardano/bridge.test.d.ts.map +1 -0
  51. package/lib/families/cardano/bridge.test.js +11 -0
  52. package/lib/families/cardano/bridge.test.js.map +1 -0
  53. package/lib/families/cardano/buildSubAccounts.d.ts +25 -0
  54. package/lib/families/cardano/buildSubAccounts.d.ts.map +1 -0
  55. package/lib/families/cardano/buildSubAccounts.js +176 -0
  56. package/lib/families/cardano/buildSubAccounts.js.map +1 -0
  57. package/lib/families/cardano/cli-transaction.d.ts +19 -0
  58. package/lib/families/cardano/cli-transaction.d.ts.map +1 -0
  59. package/lib/families/cardano/cli-transaction.js +70 -0
  60. package/lib/families/cardano/cli-transaction.js.map +1 -0
  61. package/lib/families/cardano/constants.d.ts +8 -0
  62. package/lib/families/cardano/constants.d.ts.map +1 -0
  63. package/lib/families/cardano/constants.js +12 -0
  64. package/lib/families/cardano/constants.js.map +1 -0
  65. package/lib/families/cardano/datasets/rawAccount.1.d.ts +3 -0
  66. package/lib/families/cardano/datasets/rawAccount.1.d.ts.map +1 -0
  67. package/lib/families/cardano/datasets/rawAccount.1.js +27 -0
  68. package/lib/families/cardano/datasets/rawAccount.1.js.map +1 -0
  69. package/lib/families/cardano/datasets/scanAccounts.d.ts +5 -0
  70. package/lib/families/cardano/datasets/scanAccounts.d.ts.map +1 -0
  71. package/lib/families/cardano/datasets/scanAccounts.js +10 -0
  72. package/lib/families/cardano/datasets/scanAccounts.js.map +1 -0
  73. package/lib/families/cardano/errors.d.ts +7 -0
  74. package/lib/families/cardano/errors.d.ts.map +1 -0
  75. package/lib/families/cardano/errors.js +9 -0
  76. package/lib/families/cardano/errors.js.map +1 -0
  77. package/lib/families/cardano/hw-getAddress.d.ts +4 -0
  78. package/lib/families/cardano/hw-getAddress.d.ts.map +1 -0
  79. package/lib/families/cardano/hw-getAddress.js +126 -0
  80. package/lib/families/cardano/hw-getAddress.js.map +1 -0
  81. package/lib/families/cardano/js-broadcast.d.ts +8 -0
  82. package/lib/families/cardano/js-broadcast.d.ts.map +1 -0
  83. package/lib/families/cardano/js-broadcast.js +65 -0
  84. package/lib/families/cardano/js-broadcast.js.map +1 -0
  85. package/lib/families/cardano/js-buildTransaction.d.ts +12 -0
  86. package/lib/families/cardano/js-buildTransaction.d.ts.map +1 -0
  87. package/lib/families/cardano/js-buildTransaction.js +253 -0
  88. package/lib/families/cardano/js-buildTransaction.js.map +1 -0
  89. package/lib/families/cardano/js-estimateMaxSpendable.d.ts +15 -0
  90. package/lib/families/cardano/js-estimateMaxSpendable.d.ts.map +1 -0
  91. package/lib/families/cardano/js-estimateMaxSpendable.js +99 -0
  92. package/lib/families/cardano/js-estimateMaxSpendable.js.map +1 -0
  93. package/lib/families/cardano/js-getFeesForTransaction.d.ts +15 -0
  94. package/lib/families/cardano/js-getFeesForTransaction.d.ts.map +1 -0
  95. package/lib/families/cardano/js-getFeesForTransaction.js +61 -0
  96. package/lib/families/cardano/js-getFeesForTransaction.js.map +1 -0
  97. package/lib/families/cardano/js-getTransactionStatus.d.ts +5 -0
  98. package/lib/families/cardano/js-getTransactionStatus.d.ts.map +1 -0
  99. package/lib/families/cardano/js-getTransactionStatus.js +156 -0
  100. package/lib/families/cardano/js-getTransactionStatus.js.map +1 -0
  101. package/lib/families/cardano/js-signOperation.d.ts +13 -0
  102. package/lib/families/cardano/js-signOperation.d.ts.map +1 -0
  103. package/lib/families/cardano/js-signOperation.js +274 -0
  104. package/lib/families/cardano/js-signOperation.js.map +1 -0
  105. package/lib/families/cardano/js-synchronisation.d.ts +11 -0
  106. package/lib/families/cardano/js-synchronisation.d.ts.map +1 -0
  107. package/lib/families/cardano/js-synchronisation.js +247 -0
  108. package/lib/families/cardano/js-synchronisation.js.map +1 -0
  109. package/lib/families/cardano/js-transaction.d.ts +23 -0
  110. package/lib/families/cardano/js-transaction.d.ts.map +1 -0
  111. package/lib/families/cardano/js-transaction.js +112 -0
  112. package/lib/families/cardano/js-transaction.js.map +1 -0
  113. package/lib/families/cardano/logic.d.ts +92 -0
  114. package/lib/families/cardano/logic.d.ts.map +1 -0
  115. package/lib/families/cardano/logic.js +371 -0
  116. package/lib/families/cardano/logic.js.map +1 -0
  117. package/lib/families/cardano/networks.d.ts +3 -0
  118. package/lib/families/cardano/networks.d.ts.map +1 -0
  119. package/lib/families/cardano/networks.js +34 -0
  120. package/lib/families/cardano/networks.js.map +1 -0
  121. package/lib/families/cardano/postSyncPatch.d.ts +7 -0
  122. package/lib/families/cardano/postSyncPatch.d.ts.map +1 -0
  123. package/lib/families/cardano/postSyncPatch.js +37 -0
  124. package/lib/families/cardano/postSyncPatch.js.map +1 -0
  125. package/lib/families/cardano/serialization.d.ts +4 -0
  126. package/lib/families/cardano/serialization.d.ts.map +1 -0
  127. package/lib/families/cardano/serialization.js +121 -0
  128. package/lib/families/cardano/serialization.js.map +1 -0
  129. package/lib/families/cardano/specs.d.ts +7 -0
  130. package/lib/families/cardano/specs.d.ts.map +1 -0
  131. package/lib/families/cardano/specs.js +83 -0
  132. package/lib/families/cardano/specs.js.map +1 -0
  133. package/lib/families/cardano/speculos-deviceActions.d.ts +7 -0
  134. package/lib/families/cardano/speculos-deviceActions.d.ts.map +1 -0
  135. package/lib/families/cardano/speculos-deviceActions.js +69 -0
  136. package/lib/families/cardano/speculos-deviceActions.js.map +1 -0
  137. package/lib/families/cardano/test-dataset.d.ts +5 -0
  138. package/lib/families/cardano/test-dataset.d.ts.map +1 -0
  139. package/lib/families/cardano/test-dataset.js +42 -0
  140. package/lib/families/cardano/test-dataset.js.map +1 -0
  141. package/lib/families/cardano/transaction.d.ts +12 -0
  142. package/lib/families/cardano/transaction.d.ts.map +1 -0
  143. package/lib/families/cardano/transaction.js +47 -0
  144. package/lib/families/cardano/transaction.js.map +1 -0
  145. package/lib/families/cardano/types.d.ts +152 -0
  146. package/lib/families/cardano/types.d.ts.map +1 -0
  147. package/lib/families/cardano/types.js +18 -0
  148. package/lib/families/cardano/types.js.map +1 -0
  149. package/lib/families/celo/js-synchronisation.d.ts +2 -2
  150. package/lib/families/cosmos/js-synchronisation.d.ts +2 -2
  151. package/lib/families/cosmos/test-dataset.d.ts.map +1 -1
  152. package/lib/families/cosmos/test-dataset.js +1 -1
  153. package/lib/families/cosmos/test-dataset.js.map +1 -1
  154. package/lib/families/crypto_org/js-synchronisation.d.ts +2 -2
  155. package/lib/families/elrond/js-synchronisation.d.ts +2 -2
  156. package/lib/families/hedera/js-synchronisation.d.ts +2 -2
  157. package/lib/families/polkadot/js-synchronisation.d.ts +2 -2
  158. package/lib/families/ripple/js-synchronization.d.ts +2 -2
  159. package/lib/families/stellar/js-synchronization.d.ts +2 -2
  160. package/lib/generated/bridge/js.d.ts +4 -0
  161. package/lib/generated/bridge/js.d.ts.map +1 -1
  162. package/lib/generated/bridge/js.js +30 -28
  163. package/lib/generated/bridge/js.js.map +1 -1
  164. package/lib/generated/cli-transaction.d.ts +15 -0
  165. package/lib/generated/cli-transaction.d.ts.map +1 -1
  166. package/lib/generated/cli-transaction.js +28 -26
  167. package/lib/generated/cli-transaction.js.map +1 -1
  168. package/lib/generated/exchange.d.ts +1 -1
  169. package/lib/generated/hw-getAddress.d.ts +1 -0
  170. package/lib/generated/hw-getAddress.d.ts.map +1 -1
  171. package/lib/generated/hw-getAddress.js +30 -28
  172. package/lib/generated/hw-getAddress.js.map +1 -1
  173. package/lib/generated/specs.d.ts +3 -0
  174. package/lib/generated/specs.d.ts.map +1 -1
  175. package/lib/generated/specs.js +28 -26
  176. package/lib/generated/specs.js.map +1 -1
  177. package/lib/generated/speculos-deviceActions.d.ts +3 -0
  178. package/lib/generated/speculos-deviceActions.d.ts.map +1 -1
  179. package/lib/generated/speculos-deviceActions.js +28 -26
  180. package/lib/generated/speculos-deviceActions.js.map +1 -1
  181. package/lib/generated/test-dataset.d.ts +1 -0
  182. package/lib/generated/test-dataset.d.ts.map +1 -1
  183. package/lib/generated/test-dataset.js +26 -24
  184. package/lib/generated/test-dataset.js.map +1 -1
  185. package/lib/generated/transaction.d.ts +5 -0
  186. package/lib/generated/transaction.d.ts.map +1 -1
  187. package/lib/generated/transaction.js +30 -28
  188. package/lib/generated/transaction.js.map +1 -1
  189. package/lib/generated/types.d.ts +4 -2
  190. package/lib/generated/types.d.ts.map +1 -1
  191. package/lib/hw/actions/startExchange.d.ts.map +1 -1
  192. package/lib/hw/actions/startExchange.js +3 -2
  193. package/lib/hw/actions/startExchange.js.map +1 -1
  194. package/lib/reconciliation.d.ts.map +1 -1
  195. package/lib/reconciliation.js +6 -0
  196. package/lib/reconciliation.js.map +1 -1
  197. package/lib/types/account.d.ts +3 -0
  198. package/lib/types/account.d.ts.map +1 -1
  199. package/package.json +4 -1
  200. package/src/__tests__/test-helpers/setup.ts +2 -0
  201. package/src/account/serialization.ts +15 -0
  202. package/src/cross.ts +2 -1
  203. package/src/derivation.ts +10 -0
  204. package/src/env.ts +10 -0
  205. package/src/errors.ts +1 -0
  206. package/src/families/cardano/__snapshots__/bridge.test.ts.snap +1667 -0
  207. package/src/families/cardano/api/api-types.ts +33 -0
  208. package/src/families/cardano/api/getNetworkInfo.ts +38 -0
  209. package/src/families/cardano/api/getTransactions.ts +240 -0
  210. package/src/families/cardano/api/submitTransaction.ts +27 -0
  211. package/src/families/cardano/bridge/js.ts +35 -0
  212. package/src/families/cardano/bridge.test.ts +6 -0
  213. package/src/families/cardano/buildSubAccounts.ts +182 -0
  214. package/src/families/cardano/cli-transaction.ts +78 -0
  215. package/src/families/cardano/constants.ts +12 -0
  216. package/src/families/cardano/datasets/rawAccount.1.ts +28 -0
  217. package/src/families/cardano/datasets/scanAccounts.ts +23 -0
  218. package/src/families/cardano/errors.ts +8 -0
  219. package/src/families/cardano/hw-getAddress.ts +61 -0
  220. package/src/families/cardano/js-broadcast.ts +25 -0
  221. package/src/families/cardano/js-buildTransaction.ts +293 -0
  222. package/src/families/cardano/js-estimateMaxSpendable.ts +60 -0
  223. package/src/families/cardano/js-getFeesForTransaction.ts +25 -0
  224. package/src/families/cardano/js-getTransactionStatus.ts +123 -0
  225. package/src/families/cardano/js-signOperation.ts +265 -0
  226. package/src/families/cardano/js-synchronisation.ts +255 -0
  227. package/src/families/cardano/js-transaction.ts +69 -0
  228. package/src/families/cardano/logic.ts +450 -0
  229. package/src/families/cardano/networks.ts +33 -0
  230. package/src/families/cardano/postSyncPatch.ts +45 -0
  231. package/src/families/cardano/serialization.ts +179 -0
  232. package/src/families/cardano/specs.ts +96 -0
  233. package/src/families/cardano/speculos-deviceActions.ts +66 -0
  234. package/src/families/cardano/test-dataset.ts +41 -0
  235. package/src/families/cardano/transaction.ts +55 -0
  236. package/src/families/cardano/types.ts +178 -0
  237. package/src/families/cosmos/__snapshots__/bridge.test.ts.snap +134 -6
  238. package/src/families/cosmos/test-dataset.ts +2 -0
  239. package/src/generated/bridge/js.ts +3 -0
  240. package/src/generated/cli-transaction.ts +3 -0
  241. package/src/generated/hw-getAddress.ts +3 -0
  242. package/src/generated/specs.ts +3 -0
  243. package/src/generated/speculos-deviceActions.ts +3 -0
  244. package/src/generated/test-dataset.ts +3 -0
  245. package/src/generated/transaction.ts +3 -0
  246. package/src/generated/types.ts +4 -0
  247. package/src/hw/actions/startExchange.ts +3 -2
  248. package/src/reconciliation.ts +10 -0
  249. package/src/types/account.ts +6 -0
@@ -0,0 +1,33 @@
1
+ import { ProtocolParams } from "../types";
2
+
3
+ type APIToken = { assetName: string; policyId: string; value: string };
4
+
5
+ type APIMetadata = { label: string; value: string };
6
+
7
+ export type APITransaction = {
8
+ fees: string;
9
+ hash: string;
10
+ timestamp: string;
11
+ blockHeight: number;
12
+ inputs: Array<{
13
+ txId: string;
14
+ index: number;
15
+ address: string;
16
+ value: string;
17
+ paymentKey: string;
18
+ tokens: Array<APIToken>;
19
+ }>;
20
+ outputs: Array<{
21
+ address: string;
22
+ value: string;
23
+ paymentKey: string;
24
+ tokens: Array<APIToken>;
25
+ }>;
26
+ metadata?: {
27
+ data: Array<APIMetadata>;
28
+ };
29
+ };
30
+
31
+ export type APINetworkInfo = {
32
+ protocolParams: ProtocolParams;
33
+ };
@@ -0,0 +1,38 @@
1
+ import network from "../../../network";
2
+ import { Account, CryptoCurrency } from "../../../types";
3
+ import { APINetworkInfo } from "./api-types";
4
+ import { getEpoch, isTestnet } from "../logic";
5
+ import {
6
+ CARDANO_API_ENDPOINT,
7
+ CARDANO_TESTNET_API_ENDPOINT,
8
+ } from "../constants";
9
+
10
+ async function fetchNetworkInfo(
11
+ currency: CryptoCurrency
12
+ ): Promise<APINetworkInfo> {
13
+ const res = await network({
14
+ method: "GET",
15
+ url: isTestnet(currency)
16
+ ? `${CARDANO_TESTNET_API_ENDPOINT}/v1/network/info`
17
+ : `${CARDANO_API_ENDPOINT}/v1/network/info`,
18
+ });
19
+ return res && (res.data as APINetworkInfo);
20
+ }
21
+
22
+ export async function getNetworkInfo(
23
+ a: Account | undefined,
24
+ currency: CryptoCurrency
25
+ ): Promise<APINetworkInfo> {
26
+ if (a && a.cardanoResources) {
27
+ const currencyId = a.currency.id;
28
+ const currentEpoch = getEpoch(currencyId, new Date());
29
+ const lastSyncedEpoch = getEpoch(currencyId, a.lastSyncDate);
30
+
31
+ if (currentEpoch === lastSyncedEpoch) {
32
+ return {
33
+ protocolParams: a.cardanoResources.protocolParams,
34
+ };
35
+ }
36
+ }
37
+ return fetchNetworkInfo(currency);
38
+ }
@@ -0,0 +1,240 @@
1
+ import network from "../../../network";
2
+ import * as ApiTypes from "./api-types";
3
+ import { Bip32PublicKey } from "@stricahq/bip32ed25519";
4
+ import { PaymentChain, PaymentCredential } from "../types";
5
+ import { getEnv } from "../../../env";
6
+ import {
7
+ getBipPath,
8
+ getCredentialKey,
9
+ getExtendedPublicKeyFromHex,
10
+ isTestnet,
11
+ } from "../logic";
12
+ import range from "lodash/range";
13
+ import chunk from "lodash/chunk";
14
+ import { Account, CryptoCurrency } from "../../../types";
15
+ import { APITransaction } from "./api-types";
16
+ import {
17
+ CARDANO_API_ENDPOINT,
18
+ CARDANO_TESTNET_API_ENDPOINT,
19
+ } from "../constants";
20
+
21
+ async function fetchTransactions(
22
+ paymentKeys: Array<string>,
23
+ pageNo: number,
24
+ blockHeight: number,
25
+ currency: CryptoCurrency
26
+ ): Promise<{
27
+ pageNo: number;
28
+ limit: number;
29
+ blockHeight: number;
30
+ transactions: Array<APITransaction>;
31
+ }> {
32
+ const res = await network({
33
+ method: "POST",
34
+ url: isTestnet(currency)
35
+ ? `${CARDANO_TESTNET_API_ENDPOINT}/v1/transaction`
36
+ : `${CARDANO_API_ENDPOINT}/v1/transaction`,
37
+ data: {
38
+ paymentKeys,
39
+ pageNo,
40
+ blockHeight,
41
+ },
42
+ });
43
+ return res.data;
44
+ }
45
+
46
+ async function getAllTransactionsByKeys(
47
+ paymentKeys: Array<string>,
48
+ blockHeight: number,
49
+ currency: CryptoCurrency
50
+ ): Promise<{
51
+ transactions: Array<ApiTypes.APITransaction>;
52
+ blockHeight: number;
53
+ }> {
54
+ const transactions: Array<ApiTypes.APITransaction> = [];
55
+ let latestBlockHeight = 0;
56
+ let isAllTrxFetched = false;
57
+ let pageNo = 1;
58
+
59
+ while (!isAllTrxFetched) {
60
+ const res = await fetchTransactions(
61
+ paymentKeys,
62
+ pageNo,
63
+ blockHeight,
64
+ currency
65
+ );
66
+ transactions.push(...res.transactions);
67
+ latestBlockHeight = Math.max(res.blockHeight, latestBlockHeight);
68
+ isAllTrxFetched = res.transactions.length < res.limit;
69
+ pageNo += 1;
70
+ }
71
+ return {
72
+ transactions,
73
+ blockHeight: latestBlockHeight,
74
+ };
75
+ }
76
+
77
+ async function getSyncedTransactionsByChain(
78
+ accountPubKey: Bip32PublicKey,
79
+ accountIndex: number,
80
+ chainType: PaymentChain,
81
+ blockHeight: number,
82
+ initialPaymentCredentials: Array<PaymentCredential>,
83
+ currency: CryptoCurrency
84
+ ): Promise<{
85
+ transactions: Array<ApiTypes.APITransaction>;
86
+ latestBlockHeight: number;
87
+ paymentCredentials: Array<PaymentCredential>;
88
+ }> {
89
+ const keyChainRange = getEnv("KEYCHAIN_OBSERVABLE_RANGE") || 20;
90
+
91
+ // credentialsMap for efficient use
92
+ const initialPaymentCredentialMap: Record<string, PaymentCredential> = {};
93
+ let maxUsedKeyIndex = -1;
94
+ initialPaymentCredentials.forEach((cred) => {
95
+ initialPaymentCredentialMap[cred.key] = cred;
96
+ if (cred.isUsed) maxUsedKeyIndex = cred.path.index;
97
+ });
98
+
99
+ const transactions: Array<ApiTypes.APITransaction> = [];
100
+ let latestBlockHeight = 0;
101
+
102
+ // fetch transactions for existing keys
103
+ const trxsRes = await Promise.all(
104
+ chunk(Object.keys(initialPaymentCredentialMap), keyChainRange).map((keys) =>
105
+ getAllTransactionsByKeys(keys, blockHeight, currency)
106
+ )
107
+ );
108
+ trxsRes.forEach((txRes) => {
109
+ transactions.push(...txRes.transactions);
110
+ latestBlockHeight = Math.max(latestBlockHeight, txRes.blockHeight);
111
+ });
112
+
113
+ // fetch transactions for new avaialble keys
114
+ let newPaymentCredentialsMap: Record<string, PaymentCredential> = {};
115
+ let lastSyncedKeyIndex = initialPaymentCredentials.length
116
+ ? initialPaymentCredentials[initialPaymentCredentials.length - 1].path.index
117
+ : -1;
118
+ let syncToKeyIndex = maxUsedKeyIndex + keyChainRange;
119
+ while (syncToKeyIndex !== lastSyncedKeyIndex) {
120
+ const currentPaymentKeysMap: Record<string, PaymentCredential> = {};
121
+ range(lastSyncedKeyIndex + 1, syncToKeyIndex + 1, 1).forEach((keyIndex) => {
122
+ const keyPath = getCredentialKey(
123
+ accountPubKey,
124
+ getBipPath({
125
+ account: accountIndex,
126
+ chain: chainType,
127
+ index: keyIndex,
128
+ })
129
+ );
130
+ currentPaymentKeysMap[keyPath.key] = {
131
+ isUsed: false,
132
+ key: keyPath.key,
133
+ path: keyPath.path,
134
+ };
135
+ });
136
+ const trxRes = await getAllTransactionsByKeys(
137
+ Object.keys(currentPaymentKeysMap),
138
+ blockHeight,
139
+ currency
140
+ );
141
+ transactions.push(...trxRes.transactions);
142
+
143
+ lastSyncedKeyIndex = syncToKeyIndex;
144
+ latestBlockHeight = Math.max(latestBlockHeight, trxRes.blockHeight);
145
+ newPaymentCredentialsMap = Object.assign(
146
+ {},
147
+ newPaymentCredentialsMap,
148
+ currentPaymentKeysMap
149
+ );
150
+ maxUsedKeyIndex = trxRes.transactions.reduce(
151
+ (maxIndexA, { inputs, outputs }) =>
152
+ [...inputs, ...outputs].reduce(
153
+ (maxIndexB, io) =>
154
+ Math.max(
155
+ newPaymentCredentialsMap[io.paymentKey]?.path.index || -1,
156
+ maxIndexB
157
+ ),
158
+ maxIndexA
159
+ ),
160
+ maxUsedKeyIndex
161
+ );
162
+ syncToKeyIndex = maxUsedKeyIndex + keyChainRange;
163
+ }
164
+
165
+ const availablePaymentCredentialsMap = {
166
+ ...initialPaymentCredentialMap,
167
+ ...newPaymentCredentialsMap,
168
+ };
169
+ transactions.forEach((trx) => {
170
+ [...trx.inputs, ...trx.outputs].forEach((io) => {
171
+ if (availablePaymentCredentialsMap[io.paymentKey]) {
172
+ availablePaymentCredentialsMap[io.paymentKey].isUsed = true;
173
+ }
174
+ });
175
+ });
176
+
177
+ return {
178
+ transactions,
179
+ latestBlockHeight,
180
+ paymentCredentials: Object.values(availablePaymentCredentialsMap).sort(
181
+ (aCred, bCred) => aCred.path.index - bCred.path.index
182
+ ),
183
+ };
184
+ }
185
+
186
+ export async function getTransactions(
187
+ xpub: string,
188
+ accountIndex: number,
189
+ initialAccount: Account | undefined,
190
+ blockHeight: number,
191
+ currency: CryptoCurrency
192
+ ): Promise<{
193
+ transactions: Array<ApiTypes.APITransaction>;
194
+ blockHeight: number;
195
+ externalCredentials: Array<PaymentCredential>;
196
+ internalCredentials: Array<PaymentCredential>;
197
+ }> {
198
+ const accountPubKey = getExtendedPublicKeyFromHex(xpub);
199
+ const oldExternalCredentials =
200
+ initialAccount?.cardanoResources?.externalCredentials || [];
201
+ const oldInternalCredentials =
202
+ initialAccount?.cardanoResources?.internalCredentials || [];
203
+
204
+ const [
205
+ {
206
+ transactions: externalKeyTransactions,
207
+ latestBlockHeight: aBlockHeight,
208
+ paymentCredentials: externalCredentials,
209
+ },
210
+ {
211
+ transactions: internalKeyTransactions,
212
+ latestBlockHeight: bBlockHeight,
213
+ paymentCredentials: internalCredentials,
214
+ },
215
+ ] = await Promise.all([
216
+ getSyncedTransactionsByChain(
217
+ accountPubKey,
218
+ accountIndex,
219
+ PaymentChain.external,
220
+ blockHeight,
221
+ oldExternalCredentials,
222
+ currency
223
+ ),
224
+ getSyncedTransactionsByChain(
225
+ accountPubKey,
226
+ accountIndex,
227
+ PaymentChain.internal,
228
+ blockHeight,
229
+ oldInternalCredentials,
230
+ currency
231
+ ),
232
+ ]);
233
+
234
+ return {
235
+ transactions: [...externalKeyTransactions, ...internalKeyTransactions],
236
+ blockHeight: Math.max(aBlockHeight, bBlockHeight),
237
+ externalCredentials,
238
+ internalCredentials,
239
+ };
240
+ }
@@ -0,0 +1,27 @@
1
+ import { CryptoCurrency } from "@ledgerhq/cryptoassets";
2
+ import network from "../../../network";
3
+ import {
4
+ CARDANO_API_ENDPOINT,
5
+ CARDANO_TESTNET_API_ENDPOINT,
6
+ } from "../constants";
7
+ import { isTestnet } from "../logic";
8
+ import { APITransaction } from "./api-types";
9
+
10
+ export async function submitTransaction({
11
+ transaction,
12
+ currency,
13
+ }: {
14
+ transaction: string;
15
+ currency: CryptoCurrency;
16
+ }): Promise<APITransaction> {
17
+ const res = await network({
18
+ method: "POST",
19
+ url: isTestnet(currency)
20
+ ? `${CARDANO_TESTNET_API_ENDPOINT}/v1/transaction/submit`
21
+ : `${CARDANO_API_ENDPOINT}/v1/transaction/submit`,
22
+ data: {
23
+ transaction: transaction,
24
+ },
25
+ });
26
+ return res.data.transaction;
27
+ }
@@ -0,0 +1,35 @@
1
+ import type { Transaction } from "../types";
2
+ import type { AccountBridge, CurrencyBridge } from "../../../types";
3
+ import { scanAccounts, sync } from "../js-synchronisation";
4
+ import estimateMaxSpendable from "../js-estimateMaxSpendable";
5
+ import {
6
+ createTransaction,
7
+ prepareTransaction,
8
+ updateTransaction,
9
+ } from "../js-transaction";
10
+ import getTransactionStatus from "../js-getTransactionStatus";
11
+ import signOperation from "../js-signOperation";
12
+ import broadcast from "../js-broadcast";
13
+ import { makeAccountBridgeReceive } from "../../../bridge/jsHelpers";
14
+
15
+ const receive = makeAccountBridgeReceive();
16
+
17
+ const accountBridge: AccountBridge<Transaction> = {
18
+ estimateMaxSpendable,
19
+ createTransaction,
20
+ updateTransaction,
21
+ getTransactionStatus,
22
+ prepareTransaction,
23
+ sync,
24
+ receive,
25
+ signOperation,
26
+ broadcast,
27
+ };
28
+
29
+ const currencyBridge: CurrencyBridge = {
30
+ scanAccounts,
31
+ preload: async () => ({}),
32
+ hydrate: () => {},
33
+ };
34
+
35
+ export default { currencyBridge, accountBridge };
@@ -0,0 +1,6 @@
1
+ import { setup } from "../../__tests__/test-helpers/libcore-setup";
2
+ import { testBridge } from "../../__tests__/test-helpers/bridge";
3
+ import dataset from "./test-dataset";
4
+
5
+ setup("cardano_testnet");
6
+ testBridge("cardano_testnet", dataset);
@@ -0,0 +1,182 @@
1
+ import BigNumber from "bignumber.js";
2
+ import { encodeOperationId } from "../../operation";
3
+ import { Account, CryptoCurrency, Operation, TokenAccount } from "../../types";
4
+ import { APITransaction } from "./api/api-types";
5
+ import { getAccountChange, getMemoFromTx, isHexString } from "./logic";
6
+ import { PaymentCredential, Token } from "./types";
7
+ import { utils as TyphonUtils } from "@stricahq/typhonjs";
8
+ import { findTokenById } from "@ledgerhq/cryptoassets";
9
+ import {
10
+ decodeTokenAccountId,
11
+ emptyHistoryCache,
12
+ encodeTokenAccountId,
13
+ } from "../../account";
14
+ import { groupBy, keyBy } from "lodash";
15
+ import { mergeOps } from "../../bridge/jsHelpers";
16
+
17
+ export const getTokenAssetId = ({
18
+ policyId,
19
+ assetName,
20
+ }: {
21
+ policyId: string;
22
+ assetName: string;
23
+ }): string => `${policyId}${assetName}`;
24
+
25
+ export const decodeTokenAssetId = (
26
+ id: string
27
+ ): { policyId: string; assetName: string } => {
28
+ const policyId = id.slice(0, 56);
29
+ const assetName = id.slice(56);
30
+ return { policyId, assetName };
31
+ };
32
+
33
+ const encodeTokenCurrencyId = (
34
+ parentCurrency: CryptoCurrency,
35
+ assetId: string
36
+ ): string => `${parentCurrency.id}/native/${assetId}`;
37
+
38
+ export const decodeTokenCurrencyId = (
39
+ id: string
40
+ ): { parentCurrencyId: string; type: string; assetId: string } => {
41
+ const [parentCurrencyId, type, assetId] = id.split("/");
42
+ return {
43
+ parentCurrencyId,
44
+ type,
45
+ assetId,
46
+ };
47
+ };
48
+
49
+ /**
50
+ * @returns operations of tokens that are defined in ledgerjs cryptoassets
51
+ */
52
+ const mapTxToTokenAccountOperation = ({
53
+ parentAccountId,
54
+ parentCurrency,
55
+ newTransactions,
56
+ accountCredentialsMap,
57
+ }: {
58
+ parentAccountId: string;
59
+ parentCurrency: CryptoCurrency;
60
+ newTransactions: Array<APITransaction>;
61
+ accountCredentialsMap: Record<string, PaymentCredential>;
62
+ }): Array<Operation> => {
63
+ const operations: Array<Operation> = [];
64
+
65
+ newTransactions.forEach((tx) => {
66
+ const accountChange = getAccountChange(tx, accountCredentialsMap);
67
+ accountChange.tokens.forEach((token) => {
68
+ const assetId = getTokenAssetId({
69
+ policyId: token.policyId,
70
+ assetName: token.assetName,
71
+ });
72
+ const tokenCurrencyId = encodeTokenCurrencyId(parentCurrency, assetId);
73
+ const tokenCurrency = findTokenById(tokenCurrencyId);
74
+ // skip the unsupported tokens by ledger-live
75
+ if (tokenCurrency === null || tokenCurrency === undefined) {
76
+ return;
77
+ }
78
+
79
+ const tokenAccountId = encodeTokenAccountId(
80
+ parentAccountId,
81
+ tokenCurrency
82
+ );
83
+
84
+ const tokenOperationType = token.amount.lt(0) ? "OUT" : "IN";
85
+ const memo = getMemoFromTx(tx);
86
+ const operation: Operation = {
87
+ accountId: tokenAccountId,
88
+ id: encodeOperationId(tokenAccountId, tx.hash, tokenOperationType),
89
+ hash: tx.hash,
90
+ type: tokenOperationType,
91
+ fee: new BigNumber(tx.fees),
92
+ value: token.amount.absoluteValue(),
93
+ senders: tx.inputs.map((i) =>
94
+ isHexString(i.address)
95
+ ? TyphonUtils.getAddressFromHex(i.address).getBech32()
96
+ : i.address
97
+ ),
98
+ recipients: tx.outputs.map((o) =>
99
+ isHexString(o.address)
100
+ ? TyphonUtils.getAddressFromHex(o.address).getBech32()
101
+ : o.address
102
+ ),
103
+ blockHeight: tx.blockHeight,
104
+ date: new Date(tx.timestamp),
105
+ extra: {
106
+ memo,
107
+ },
108
+ blockHash: undefined,
109
+ };
110
+ operations.push(operation);
111
+ });
112
+ });
113
+
114
+ return operations;
115
+ };
116
+
117
+ export function buildSubAccounts({
118
+ initialAccount,
119
+ parentAccountId,
120
+ parentCurrency,
121
+ newTransactions,
122
+ tokens,
123
+ accountCredentialsMap,
124
+ }: {
125
+ initialAccount: Account | undefined;
126
+ parentAccountId: string;
127
+ parentCurrency: CryptoCurrency;
128
+ newTransactions: Array<APITransaction>;
129
+ tokens: Array<Token>;
130
+ accountCredentialsMap: Record<string, PaymentCredential>;
131
+ }): Array<TokenAccount> {
132
+ const tokenAccountsById: Record<string, TokenAccount> = {};
133
+
134
+ if (initialAccount && initialAccount.subAccounts) {
135
+ for (const existingAccount of initialAccount.subAccounts) {
136
+ if (existingAccount.type === "TokenAccount") {
137
+ tokenAccountsById[existingAccount.id] = existingAccount;
138
+ }
139
+ }
140
+ }
141
+
142
+ const tokenOperations: Array<Operation> = mapTxToTokenAccountOperation({
143
+ parentAccountId,
144
+ parentCurrency,
145
+ newTransactions: newTransactions,
146
+ accountCredentialsMap,
147
+ });
148
+ const tokenOperationsByAccId = groupBy(tokenOperations, (o) => o.accountId);
149
+ const tokensBalanceByAssetId = keyBy(tokens, (t) => getTokenAssetId(t));
150
+ for (const tokenAccountId in tokenOperationsByAccId) {
151
+ const initialTokenAccount = tokenAccountsById[tokenAccountId];
152
+ const oldOperations = initialTokenAccount?.operations || [];
153
+ const newOperations = tokenOperationsByAccId[tokenAccountId] || [];
154
+ const operations = mergeOps(oldOperations, newOperations);
155
+ const { token: tokenCurrency } = decodeTokenAccountId(tokenAccountId);
156
+ if (tokenCurrency) {
157
+ const accountBalance =
158
+ tokensBalanceByAssetId[tokenCurrency.contractAddress]?.amount ||
159
+ new BigNumber(0);
160
+ const tokenAccount: TokenAccount = {
161
+ type: "TokenAccount",
162
+ id: tokenAccountId,
163
+ parentId: parentAccountId,
164
+ token: tokenCurrency,
165
+ balance: accountBalance,
166
+ spendableBalance: accountBalance,
167
+ creationDate:
168
+ operations.length > 0
169
+ ? operations[operations.length - 1].date
170
+ : new Date(),
171
+ operationsCount: operations.length,
172
+ operations,
173
+ pendingOperations: [],
174
+ starred: false,
175
+ balanceHistoryCache: emptyHistoryCache,
176
+ swapHistory: [],
177
+ };
178
+ tokenAccountsById[tokenAccountId] = tokenAccount;
179
+ }
180
+ }
181
+ return Object.values(tokenAccountsById);
182
+ }
@@ -0,0 +1,78 @@
1
+ import invariant from "invariant";
2
+ import flatMap from "lodash/flatMap";
3
+ import { getAccountCurrency } from "../../account";
4
+ import type { AccountLike, Account } from "../../types";
5
+ import { TokenAccount } from "../solana/api/chain/account/token";
6
+ import { Transaction } from "./types";
7
+
8
+ const options = [
9
+ {
10
+ name: "mode",
11
+ type: String,
12
+ desc: "mode of transaction: send",
13
+ },
14
+ {
15
+ name: "token",
16
+ type: String,
17
+ desc: "uses subAccount(TokenAccount) of the account",
18
+ },
19
+ ];
20
+
21
+ function inferAccounts(
22
+ account: Account,
23
+ opts: Record<string, any>
24
+ ): Account[] | TokenAccount[] {
25
+ invariant(account.currency.family === "cardano", "cardano family");
26
+
27
+ if (!opts.token) {
28
+ const accounts: Account[] = [account];
29
+ return accounts;
30
+ }
31
+
32
+ return opts.token.map((token) => {
33
+ const subAccounts = account.subAccounts || [];
34
+
35
+ const subAccount = subAccounts.find((a) => {
36
+ const currency = getAccountCurrency(a);
37
+ return token.toLowerCase() === currency.id.toLowerCase();
38
+ });
39
+
40
+ if (!subAccount) {
41
+ throw new Error(
42
+ "token account '" +
43
+ token +
44
+ "' not found. Available: " +
45
+ subAccounts.map((t) => t.id).join("\n")
46
+ );
47
+ }
48
+
49
+ return subAccount;
50
+ });
51
+ }
52
+
53
+ function inferTransactions(
54
+ transactions: Array<{ account: AccountLike; transaction: Transaction }>,
55
+ opts: Record<string, any>
56
+ ): Transaction[] {
57
+ return flatMap(transactions, ({ transaction, account }) => {
58
+ if (transaction.family !== "cardano") {
59
+ throw new Error("transaction is not of type cardano");
60
+ }
61
+
62
+ if (account.type === "Account" && !account.cardanoResources) {
63
+ throw new Error("unactivated account");
64
+ }
65
+
66
+ return {
67
+ ...transaction,
68
+ mode: opts.mode || "send",
69
+ subAccountId: account.type === "TokenAccount" ? account.id : undefined,
70
+ };
71
+ });
72
+ }
73
+
74
+ export default {
75
+ options,
76
+ inferAccounts,
77
+ inferTransactions,
78
+ };
@@ -0,0 +1,12 @@
1
+ import { getEnv } from "../../env";
2
+
3
+ export const STAKING_ADDRESS_INDEX = 0;
4
+ export const TTL_GAP = 7200;
5
+ export const CARDANO_PURPOSE = 1852;
6
+ export const CARDANO_COIN_TYPE = 1815;
7
+ export const MEMO_LABEL = 674;
8
+
9
+ export const CARDANO_API_ENDPOINT = getEnv("CARDANO_API_ENDPOINT");
10
+ export const CARDANO_TESTNET_API_ENDPOINT = getEnv(
11
+ "CARDANO_TESTNET_API_ENDPOINT"
12
+ );
@@ -0,0 +1,28 @@
1
+ import { AccountRaw } from "../../../types";
2
+
3
+ export const cardanoRawAccount1: AccountRaw = {
4
+ id: "js:2:cardano_testnet:a902bc61a79256e1d5858d2ba49cab7011a26ad49580daace7412e255e818b1c1eba2defa321ff2937deba397f639f5bbabb0f0064516301fa4d08663c83f5b2:",
5
+ seedIdentifier:
6
+ "a902bc61a79256e1d5858d2ba49cab7011a26ad49580daace7412e255e818b1c1eba2defa321ff2937deba397f639f5bbabb0f0064516301fa4d08663c83f5b2",
7
+ name: "Cardano (Testnet) legacy a902bc61...3c83f5b2",
8
+ derivationMode: "",
9
+ index: 0,
10
+ freshAddress:
11
+ "addr_test1qqllvql2yldah5rsfafafmxu80lx6stlc965ad8fecr8pfz3krjmh2m86v92yu0my7rqydx3h5erqwty82kwgjuc4els8n93zs",
12
+ freshAddressPath: "1852'/1815'/0'/0/2",
13
+ freshAddresses: [
14
+ {
15
+ address:
16
+ "addr_test1qqllvql2yldah5rsfafafmxu80lx6stlc965ad8fecr8pfz3krjmh2m86v92yu0my7rqydx3h5erqwty82kwgjuc4els8n93zs",
17
+ derivationPath: "1852'/1815'/0'/0/2",
18
+ },
19
+ ],
20
+ blockHeight: 0,
21
+ operations: [],
22
+ pendingOperations: [],
23
+ currencyId: "cardano_testnet",
24
+ unitMagnitude: 6,
25
+ lastSyncDate: "",
26
+ balance: "1021211139",
27
+ xpub: "a902bc61a79256e1d5858d2ba49cab7011a26ad49580daace7412e255e818b1c1eba2defa321ff2937deba397f639f5bbabb0f0064516301fa4d08663c83f5b2",
28
+ };