@ledgerhq/coin-internet_computer 1.4.0-nightly.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 (304) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.unimportedrc.json +38 -0
  3. package/CHANGELOG.md +7 -0
  4. package/LICENSE.txt +21 -0
  5. package/jest.config.js +9 -0
  6. package/lib/api/api.d.ts +12 -0
  7. package/lib/api/api.d.ts.map +1 -0
  8. package/lib/api/api.js +82 -0
  9. package/lib/api/api.js.map +1 -0
  10. package/lib/api/index.d.ts +2 -0
  11. package/lib/api/index.d.ts.map +1 -0
  12. package/lib/api/index.js +18 -0
  13. package/lib/api/index.js.map +1 -0
  14. package/lib/bridge/bridgeHelpers/account.d.ts +3 -0
  15. package/lib/bridge/bridgeHelpers/account.d.ts.map +1 -0
  16. package/lib/bridge/bridgeHelpers/account.js +127 -0
  17. package/lib/bridge/bridgeHelpers/account.js.map +1 -0
  18. package/lib/bridge/bridgeHelpers/addresses.d.ts +12 -0
  19. package/lib/bridge/bridgeHelpers/addresses.d.ts.map +1 -0
  20. package/lib/bridge/bridgeHelpers/addresses.js +46 -0
  21. package/lib/bridge/bridgeHelpers/addresses.js.map +1 -0
  22. package/lib/bridge/bridgeHelpers/fee.d.ts +3 -0
  23. package/lib/bridge/bridgeHelpers/fee.d.ts.map +1 -0
  24. package/lib/bridge/bridgeHelpers/fee.js +13 -0
  25. package/lib/bridge/bridgeHelpers/fee.js.map +1 -0
  26. package/lib/bridge/bridgeHelpers/icpRosetta/index.d.ts +30 -0
  27. package/lib/bridge/bridgeHelpers/icpRosetta/index.d.ts.map +1 -0
  28. package/lib/bridge/bridgeHelpers/icpRosetta/index.js +87 -0
  29. package/lib/bridge/bridgeHelpers/icpRosetta/index.js.map +1 -0
  30. package/lib/bridge/bridgeHelpers/icpRosetta/types.d.ts +145 -0
  31. package/lib/bridge/bridgeHelpers/icpRosetta/types.d.ts.map +1 -0
  32. package/lib/bridge/bridgeHelpers/icpRosetta/types.js +3 -0
  33. package/lib/bridge/bridgeHelpers/icpRosetta/types.js.map +1 -0
  34. package/lib/bridge/bridgeHelpers/icpRosetta/utils.d.ts +17 -0
  35. package/lib/bridge/bridgeHelpers/icpRosetta/utils.d.ts.map +1 -0
  36. package/lib/bridge/bridgeHelpers/icpRosetta/utils.js +154 -0
  37. package/lib/bridge/bridgeHelpers/icpRosetta/utils.js.map +1 -0
  38. package/lib/bridge/broadcast.d.ts +4 -0
  39. package/lib/bridge/broadcast.d.ts.map +1 -0
  40. package/lib/bridge/broadcast.js +21 -0
  41. package/lib/bridge/broadcast.js.map +1 -0
  42. package/lib/bridge/buildOptimisticOperation.d.ts +4 -0
  43. package/lib/bridge/buildOptimisticOperation.d.ts.map +1 -0
  44. package/lib/bridge/buildOptimisticOperation.js +37 -0
  45. package/lib/bridge/buildOptimisticOperation.js.map +1 -0
  46. package/lib/bridge/createTransaction.d.ts +4 -0
  47. package/lib/bridge/createTransaction.d.ts.map +1 -0
  48. package/lib/bridge/createTransaction.js +20 -0
  49. package/lib/bridge/createTransaction.js.map +1 -0
  50. package/lib/bridge/deviceTransactionConfig.d.ts +11 -0
  51. package/lib/bridge/deviceTransactionConfig.d.ts.map +1 -0
  52. package/lib/bridge/deviceTransactionConfig.js +41 -0
  53. package/lib/bridge/deviceTransactionConfig.js.map +1 -0
  54. package/lib/bridge/estimateMaxSpendable.d.ts +4 -0
  55. package/lib/bridge/estimateMaxSpendable.d.ts.map +1 -0
  56. package/lib/bridge/estimateMaxSpendable.js +28 -0
  57. package/lib/bridge/estimateMaxSpendable.js.map +1 -0
  58. package/lib/bridge/getTransactionStatus.d.ts +4 -0
  59. package/lib/bridge/getTransactionStatus.d.ts.map +1 -0
  60. package/lib/bridge/getTransactionStatus.js +71 -0
  61. package/lib/bridge/getTransactionStatus.js.map +1 -0
  62. package/lib/bridge/index.d.ts +8 -0
  63. package/lib/bridge/index.d.ts.map +1 -0
  64. package/lib/bridge/index.js +54 -0
  65. package/lib/bridge/index.js.map +1 -0
  66. package/lib/bridge/prepareTransaction.d.ts +4 -0
  67. package/lib/bridge/prepareTransaction.d.ts.map +1 -0
  68. package/lib/bridge/prepareTransaction.js +32 -0
  69. package/lib/bridge/prepareTransaction.js.map +1 -0
  70. package/lib/bridge/signOperation.d.ts +6 -0
  71. package/lib/bridge/signOperation.d.ts.map +1 -0
  72. package/lib/bridge/signOperation.js +53 -0
  73. package/lib/bridge/signOperation.js.map +1 -0
  74. package/lib/bridge/transaction.d.ts +14 -0
  75. package/lib/bridge/transaction.d.ts.map +1 -0
  76. package/lib/bridge/transaction.js +41 -0
  77. package/lib/bridge/transaction.js.map +1 -0
  78. package/lib/common-logic/index.d.ts +2 -0
  79. package/lib/common-logic/index.d.ts.map +1 -0
  80. package/lib/common-logic/index.js +12 -0
  81. package/lib/common-logic/index.js.map +1 -0
  82. package/lib/common-logic/utils.d.ts +9 -0
  83. package/lib/common-logic/utils.d.ts.map +1 -0
  84. package/lib/common-logic/utils.js +44 -0
  85. package/lib/common-logic/utils.js.map +1 -0
  86. package/lib/consts.d.ts +6 -0
  87. package/lib/consts.d.ts.map +1 -0
  88. package/lib/consts.js +12 -0
  89. package/lib/consts.js.map +1 -0
  90. package/lib/errors.d.ts +4 -0
  91. package/lib/errors.d.ts.map +1 -0
  92. package/lib/errors.js +9 -0
  93. package/lib/errors.js.map +1 -0
  94. package/lib/hw-signMessage.d.ts +12 -0
  95. package/lib/hw-signMessage.d.ts.map +1 -0
  96. package/lib/hw-signMessage.js +43 -0
  97. package/lib/hw-signMessage.js.map +1 -0
  98. package/lib/signer/getAddress.d.ts +6 -0
  99. package/lib/signer/getAddress.d.ts.map +1 -0
  100. package/lib/signer/getAddress.js +35 -0
  101. package/lib/signer/getAddress.js.map +1 -0
  102. package/lib/signer/index.d.ts +3 -0
  103. package/lib/signer/index.d.ts.map +1 -0
  104. package/lib/signer/index.js +8 -0
  105. package/lib/signer/index.js.map +1 -0
  106. package/lib/test/bot-specs.d.ts +7 -0
  107. package/lib/test/bot-specs.d.ts.map +1 -0
  108. package/lib/test/bot-specs.js +103 -0
  109. package/lib/test/bot-specs.js.map +1 -0
  110. package/lib/test/bridgeDatasetTest.d.ts +4 -0
  111. package/lib/test/bridgeDatasetTest.d.ts.map +1 -0
  112. package/lib/test/bridgeDatasetTest.js +141 -0
  113. package/lib/test/bridgeDatasetTest.js.map +1 -0
  114. package/lib/test/cli.d.ts +15 -0
  115. package/lib/test/cli.d.ts.map +1 -0
  116. package/lib/test/cli.js +27 -0
  117. package/lib/test/cli.js.map +1 -0
  118. package/lib/test/index.d.ts +4 -0
  119. package/lib/test/index.d.ts.map +1 -0
  120. package/lib/test/index.js +20 -0
  121. package/lib/test/index.js.map +1 -0
  122. package/lib/test/speculos-deviceActions.d.ts +4 -0
  123. package/lib/test/speculos-deviceActions.d.ts.map +1 -0
  124. package/lib/test/speculos-deviceActions.js +55 -0
  125. package/lib/test/speculos-deviceActions.js.map +1 -0
  126. package/lib/types/common.d.ts +21 -0
  127. package/lib/types/common.d.ts.map +1 -0
  128. package/lib/types/common.js +3 -0
  129. package/lib/types/common.js.map +1 -0
  130. package/lib/types/index.d.ts +3 -0
  131. package/lib/types/index.d.ts.map +1 -0
  132. package/lib/types/index.js +19 -0
  133. package/lib/types/index.js.map +1 -0
  134. package/lib/types/signer.d.ts +22 -0
  135. package/lib/types/signer.d.ts.map +1 -0
  136. package/lib/types/signer.js +3 -0
  137. package/lib/types/signer.js.map +1 -0
  138. package/lib-es/api/api.d.ts +12 -0
  139. package/lib-es/api/api.d.ts.map +1 -0
  140. package/lib-es/api/api.js +71 -0
  141. package/lib-es/api/api.js.map +1 -0
  142. package/lib-es/api/index.d.ts +2 -0
  143. package/lib-es/api/index.d.ts.map +1 -0
  144. package/lib-es/api/index.js +2 -0
  145. package/lib-es/api/index.js.map +1 -0
  146. package/lib-es/bridge/bridgeHelpers/account.d.ts +3 -0
  147. package/lib-es/bridge/bridgeHelpers/account.d.ts.map +1 -0
  148. package/lib-es/bridge/bridgeHelpers/account.js +120 -0
  149. package/lib-es/bridge/bridgeHelpers/account.js.map +1 -0
  150. package/lib-es/bridge/bridgeHelpers/addresses.d.ts +12 -0
  151. package/lib-es/bridge/bridgeHelpers/addresses.d.ts.map +1 -0
  152. package/lib-es/bridge/bridgeHelpers/addresses.js +37 -0
  153. package/lib-es/bridge/bridgeHelpers/addresses.js.map +1 -0
  154. package/lib-es/bridge/bridgeHelpers/fee.d.ts +3 -0
  155. package/lib-es/bridge/bridgeHelpers/fee.d.ts.map +1 -0
  156. package/lib-es/bridge/bridgeHelpers/fee.js +6 -0
  157. package/lib-es/bridge/bridgeHelpers/fee.js.map +1 -0
  158. package/lib-es/bridge/bridgeHelpers/icpRosetta/index.d.ts +30 -0
  159. package/lib-es/bridge/bridgeHelpers/icpRosetta/index.d.ts.map +1 -0
  160. package/lib-es/bridge/bridgeHelpers/icpRosetta/index.js +75 -0
  161. package/lib-es/bridge/bridgeHelpers/icpRosetta/index.js.map +1 -0
  162. package/lib-es/bridge/bridgeHelpers/icpRosetta/types.d.ts +145 -0
  163. package/lib-es/bridge/bridgeHelpers/icpRosetta/types.d.ts.map +1 -0
  164. package/lib-es/bridge/bridgeHelpers/icpRosetta/types.js +2 -0
  165. package/lib-es/bridge/bridgeHelpers/icpRosetta/types.js.map +1 -0
  166. package/lib-es/bridge/bridgeHelpers/icpRosetta/utils.d.ts +17 -0
  167. package/lib-es/bridge/bridgeHelpers/icpRosetta/utils.d.ts.map +1 -0
  168. package/lib-es/bridge/bridgeHelpers/icpRosetta/utils.js +122 -0
  169. package/lib-es/bridge/bridgeHelpers/icpRosetta/utils.js.map +1 -0
  170. package/lib-es/bridge/broadcast.d.ts +4 -0
  171. package/lib-es/bridge/broadcast.d.ts.map +1 -0
  172. package/lib-es/bridge/broadcast.js +17 -0
  173. package/lib-es/bridge/broadcast.js.map +1 -0
  174. package/lib-es/bridge/buildOptimisticOperation.d.ts +4 -0
  175. package/lib-es/bridge/buildOptimisticOperation.d.ts.map +1 -0
  176. package/lib-es/bridge/buildOptimisticOperation.js +33 -0
  177. package/lib-es/bridge/buildOptimisticOperation.js.map +1 -0
  178. package/lib-es/bridge/createTransaction.d.ts +4 -0
  179. package/lib-es/bridge/createTransaction.d.ts.map +1 -0
  180. package/lib-es/bridge/createTransaction.js +13 -0
  181. package/lib-es/bridge/createTransaction.js.map +1 -0
  182. package/lib-es/bridge/deviceTransactionConfig.d.ts +11 -0
  183. package/lib-es/bridge/deviceTransactionConfig.d.ts.map +1 -0
  184. package/lib-es/bridge/deviceTransactionConfig.js +39 -0
  185. package/lib-es/bridge/deviceTransactionConfig.js.map +1 -0
  186. package/lib-es/bridge/estimateMaxSpendable.d.ts +4 -0
  187. package/lib-es/bridge/estimateMaxSpendable.d.ts.map +1 -0
  188. package/lib-es/bridge/estimateMaxSpendable.js +21 -0
  189. package/lib-es/bridge/estimateMaxSpendable.js.map +1 -0
  190. package/lib-es/bridge/getTransactionStatus.d.ts +4 -0
  191. package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -0
  192. package/lib-es/bridge/getTransactionStatus.js +67 -0
  193. package/lib-es/bridge/getTransactionStatus.js.map +1 -0
  194. package/lib-es/bridge/index.d.ts +8 -0
  195. package/lib-es/bridge/index.d.ts.map +1 -0
  196. package/lib-es/bridge/index.js +47 -0
  197. package/lib-es/bridge/index.js.map +1 -0
  198. package/lib-es/bridge/prepareTransaction.d.ts +4 -0
  199. package/lib-es/bridge/prepareTransaction.d.ts.map +1 -0
  200. package/lib-es/bridge/prepareTransaction.js +28 -0
  201. package/lib-es/bridge/prepareTransaction.js.map +1 -0
  202. package/lib-es/bridge/signOperation.d.ts +6 -0
  203. package/lib-es/bridge/signOperation.d.ts.map +1 -0
  204. package/lib-es/bridge/signOperation.js +49 -0
  205. package/lib-es/bridge/signOperation.js.map +1 -0
  206. package/lib-es/bridge/transaction.d.ts +14 -0
  207. package/lib-es/bridge/transaction.d.ts.map +1 -0
  208. package/lib-es/bridge/transaction.js +33 -0
  209. package/lib-es/bridge/transaction.js.map +1 -0
  210. package/lib-es/common-logic/index.d.ts +2 -0
  211. package/lib-es/common-logic/index.d.ts.map +1 -0
  212. package/lib-es/common-logic/index.js +2 -0
  213. package/lib-es/common-logic/index.js.map +1 -0
  214. package/lib-es/common-logic/utils.d.ts +9 -0
  215. package/lib-es/common-logic/utils.d.ts.map +1 -0
  216. package/lib-es/common-logic/utils.js +34 -0
  217. package/lib-es/common-logic/utils.js.map +1 -0
  218. package/lib-es/consts.d.ts +6 -0
  219. package/lib-es/consts.d.ts.map +1 -0
  220. package/lib-es/consts.js +9 -0
  221. package/lib-es/consts.js.map +1 -0
  222. package/lib-es/errors.d.ts +4 -0
  223. package/lib-es/errors.d.ts.map +1 -0
  224. package/lib-es/errors.js +6 -0
  225. package/lib-es/errors.js.map +1 -0
  226. package/lib-es/hw-signMessage.d.ts +12 -0
  227. package/lib-es/hw-signMessage.d.ts.map +1 -0
  228. package/lib-es/hw-signMessage.js +39 -0
  229. package/lib-es/hw-signMessage.js.map +1 -0
  230. package/lib-es/signer/getAddress.d.ts +6 -0
  231. package/lib-es/signer/getAddress.d.ts.map +1 -0
  232. package/lib-es/signer/getAddress.js +33 -0
  233. package/lib-es/signer/getAddress.js.map +1 -0
  234. package/lib-es/signer/index.d.ts +3 -0
  235. package/lib-es/signer/index.d.ts.map +1 -0
  236. package/lib-es/signer/index.js +3 -0
  237. package/lib-es/signer/index.js.map +1 -0
  238. package/lib-es/test/bot-specs.d.ts +7 -0
  239. package/lib-es/test/bot-specs.d.ts.map +1 -0
  240. package/lib-es/test/bot-specs.js +98 -0
  241. package/lib-es/test/bot-specs.js.map +1 -0
  242. package/lib-es/test/bridgeDatasetTest.d.ts +4 -0
  243. package/lib-es/test/bridgeDatasetTest.d.ts.map +1 -0
  244. package/lib-es/test/bridgeDatasetTest.js +135 -0
  245. package/lib-es/test/bridgeDatasetTest.js.map +1 -0
  246. package/lib-es/test/cli.d.ts +15 -0
  247. package/lib-es/test/cli.d.ts.map +1 -0
  248. package/lib-es/test/cli.js +21 -0
  249. package/lib-es/test/cli.js.map +1 -0
  250. package/lib-es/test/index.d.ts +4 -0
  251. package/lib-es/test/index.d.ts.map +1 -0
  252. package/lib-es/test/index.js +4 -0
  253. package/lib-es/test/index.js.map +1 -0
  254. package/lib-es/test/speculos-deviceActions.d.ts +4 -0
  255. package/lib-es/test/speculos-deviceActions.d.ts.map +1 -0
  256. package/lib-es/test/speculos-deviceActions.js +52 -0
  257. package/lib-es/test/speculos-deviceActions.js.map +1 -0
  258. package/lib-es/types/common.d.ts +21 -0
  259. package/lib-es/types/common.d.ts.map +1 -0
  260. package/lib-es/types/common.js +2 -0
  261. package/lib-es/types/common.js.map +1 -0
  262. package/lib-es/types/index.d.ts +3 -0
  263. package/lib-es/types/index.d.ts.map +1 -0
  264. package/lib-es/types/index.js +3 -0
  265. package/lib-es/types/index.js.map +1 -0
  266. package/lib-es/types/signer.d.ts +22 -0
  267. package/lib-es/types/signer.d.ts.map +1 -0
  268. package/lib-es/types/signer.js +2 -0
  269. package/lib-es/types/signer.js.map +1 -0
  270. package/package.json +128 -0
  271. package/src/api/api.ts +92 -0
  272. package/src/api/index.ts +1 -0
  273. package/src/bridge/bridgeHelpers/account.ts +134 -0
  274. package/src/bridge/bridgeHelpers/addresses.ts +33 -0
  275. package/src/bridge/bridgeHelpers/fee.ts +6 -0
  276. package/src/bridge/bridgeHelpers/icpRosetta/index.ts +154 -0
  277. package/src/bridge/bridgeHelpers/icpRosetta/types.ts +166 -0
  278. package/src/bridge/bridgeHelpers/icpRosetta/utils.ts +151 -0
  279. package/src/bridge/broadcast.ts +15 -0
  280. package/src/bridge/buildOptimisticOperation.ts +32 -0
  281. package/src/bridge/createTransaction.ts +15 -0
  282. package/src/bridge/deviceTransactionConfig.ts +53 -0
  283. package/src/bridge/estimateMaxSpendable.ts +19 -0
  284. package/src/bridge/getTransactionStatus.ts +75 -0
  285. package/src/bridge/index.ts +63 -0
  286. package/src/bridge/prepareTransaction.ts +28 -0
  287. package/src/bridge/signOperation.ts +59 -0
  288. package/src/bridge/transaction.ts +61 -0
  289. package/src/common-logic/index.ts +9 -0
  290. package/src/common-logic/utils.ts +47 -0
  291. package/src/consts.ts +11 -0
  292. package/src/errors.ts +6 -0
  293. package/src/hw-signMessage.ts +42 -0
  294. package/src/signer/getAddress.ts +34 -0
  295. package/src/signer/index.ts +3 -0
  296. package/src/test/bot-specs.ts +120 -0
  297. package/src/test/bridgeDatasetTest.ts +141 -0
  298. package/src/test/cli.ts +36 -0
  299. package/src/test/index.ts +3 -0
  300. package/src/test/speculos-deviceActions.ts +61 -0
  301. package/src/types/common.ts +31 -0
  302. package/src/types/index.ts +2 -0
  303. package/src/types/signer.ts +22 -0
  304. package/tsconfig.json +14 -0
@@ -0,0 +1,63 @@
1
+ import {
2
+ makeAccountBridgeReceive,
3
+ makeScanAccounts,
4
+ makeSync,
5
+ } from "@ledgerhq/coin-framework/bridge/jsHelpers";
6
+ import resolver from "../signer";
7
+ import getAddressWrapper from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
8
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
9
+ import type { Account, AccountBridge, CurrencyBridge } from "@ledgerhq/types-live";
10
+ import { defaultUpdateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers";
11
+ import type { Transaction, TransactionStatus, ICPSigner } from "../types";
12
+ import { getTransactionStatus } from "./getTransactionStatus";
13
+ import { estimateMaxSpendable } from "./estimateMaxSpendable";
14
+ import { prepareTransaction } from "./prepareTransaction";
15
+ import { createTransaction } from "./createTransaction";
16
+ import { getAccountShape } from "./bridgeHelpers/account";
17
+ import { buildSignOperation } from "./signOperation";
18
+ import { broadcast } from "./broadcast";
19
+
20
+ function buildCurrencyBridge(signerContext: SignerContext<ICPSigner>): CurrencyBridge {
21
+ const getAddress = resolver(signerContext);
22
+
23
+ const scanAccounts = makeScanAccounts({
24
+ getAccountShape,
25
+ getAddressFn: getAddressWrapper(getAddress),
26
+ });
27
+
28
+ return {
29
+ preload: () => Promise.resolve({}),
30
+ hydrate: () => {},
31
+ scanAccounts,
32
+ };
33
+ }
34
+
35
+ const sync = makeSync({ getAccountShape });
36
+
37
+ function buildAccountBridge(
38
+ signerContext: SignerContext<ICPSigner>,
39
+ ): AccountBridge<Transaction, Account, TransactionStatus> {
40
+ const getAddress = resolver(signerContext);
41
+
42
+ const receive = makeAccountBridgeReceive(getAddressWrapper(getAddress));
43
+ const signOperation = buildSignOperation(signerContext);
44
+
45
+ return {
46
+ estimateMaxSpendable,
47
+ createTransaction,
48
+ updateTransaction: defaultUpdateTransaction,
49
+ getTransactionStatus,
50
+ prepareTransaction,
51
+ sync,
52
+ receive,
53
+ signOperation,
54
+ broadcast,
55
+ };
56
+ }
57
+
58
+ export function createBridges(signerContext: SignerContext<ICPSigner>) {
59
+ return {
60
+ currencyBridge: buildCurrencyBridge(signerContext),
61
+ accountBridge: buildAccountBridge(signerContext),
62
+ };
63
+ }
@@ -0,0 +1,28 @@
1
+ import { AccountBridge } from "@ledgerhq/types-live";
2
+ import { Transaction } from "../types";
3
+ import { getAddress, validateAddress } from "./bridgeHelpers/addresses";
4
+
5
+ export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"] = async (
6
+ account,
7
+ transaction,
8
+ ) => {
9
+ // log("debug", "[prepareTransaction] start fn");
10
+
11
+ const { address } = getAddress(account);
12
+ const { recipient } = transaction;
13
+
14
+ let amount = transaction.amount;
15
+ if (recipient && address) {
16
+ // log("debug", "[prepareTransaction] fetching estimated fees");
17
+
18
+ if ((await validateAddress(recipient)).isValid && (await validateAddress(address)).isValid) {
19
+ if (transaction.useAllAmount) {
20
+ amount = account.spendableBalance.minus(transaction.fees);
21
+ return { ...transaction, amount };
22
+ }
23
+ }
24
+ }
25
+
26
+ // log("debug", "[prepareTransaction] finish fn");
27
+ return transaction;
28
+ };
@@ -0,0 +1,59 @@
1
+ import { Observable } from "rxjs";
2
+ import { Account, AccountBridge } from "@ledgerhq/types-live";
3
+ import { getAddress } from "./bridgeHelpers/addresses";
4
+ import {
5
+ getTxnExpirationDate,
6
+ getTxnMetadata,
7
+ getUnsignedTransaction,
8
+ signICPTransaction,
9
+ } from "./bridgeHelpers/icpRosetta";
10
+ import { buildOptimisticOperation } from "./buildOptimisticOperation";
11
+ import { Transaction } from "../types";
12
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
13
+ import { ICPSigner } from "../types";
14
+ import { getPath } from "../common-logic";
15
+
16
+ export const buildSignOperation =
17
+ (signerContext: SignerContext<ICPSigner>): AccountBridge<Transaction, Account>["signOperation"] =>
18
+ ({ account, transaction, deviceId }) =>
19
+ new Observable(o => {
20
+ async function main() {
21
+ const { xpub } = account;
22
+ const { derivationPath } = getAddress(account);
23
+ const { unsignedTxn, payloads } = await getUnsignedTransaction(transaction, account);
24
+
25
+ o.next({
26
+ type: "device-signature-requested",
27
+ });
28
+
29
+ const { signedTxn } = await signICPTransaction({
30
+ signerContext,
31
+ deviceId,
32
+ unsignedTxn,
33
+ path: getPath(derivationPath),
34
+ payloads,
35
+ pubkey: xpub ?? "",
36
+ });
37
+
38
+ o.next({
39
+ type: "device-signature-granted",
40
+ });
41
+
42
+ const { hash } = await getTxnMetadata(signedTxn);
43
+ const operation = await buildOptimisticOperation(account, transaction, hash);
44
+
45
+ o.next({
46
+ type: "signed",
47
+ signedOperation: {
48
+ operation,
49
+ signature: signedTxn,
50
+ expirationDate: getTxnExpirationDate(unsignedTxn),
51
+ },
52
+ });
53
+ }
54
+
55
+ main().then(
56
+ () => o.complete(),
57
+ e => o.error(e),
58
+ );
59
+ });
@@ -0,0 +1,61 @@
1
+ import { formatTransactionStatus } from "@ledgerhq/coin-framework/formatters";
2
+ import {
3
+ fromTransactionCommonRaw,
4
+ fromTransactionStatusRawCommon as fromTransactionStatusRaw,
5
+ toTransactionCommonRaw,
6
+ toTransactionStatusRawCommon as toTransactionStatusRaw,
7
+ } from "@ledgerhq/coin-framework/serialization";
8
+ import type { Account } from "@ledgerhq/types-live";
9
+ import { getAccountCurrency } from "@ledgerhq/coin-framework/account/index";
10
+ import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
11
+ import BigNumber from "bignumber.js";
12
+ import type { Transaction, TransactionRaw } from "../types";
13
+
14
+ export const formatTransaction = (
15
+ { recipient, useAllAmount, amount }: Transaction,
16
+ account: Account,
17
+ ): string => `
18
+ SEND ${
19
+ useAllAmount
20
+ ? "MAX"
21
+ : amount.isZero()
22
+ ? ""
23
+ : " " +
24
+ formatCurrencyUnit(getAccountCurrency(account).units[0], amount, {
25
+ showCode: true,
26
+ disableRounding: true,
27
+ })
28
+ }
29
+ TO ${recipient}`;
30
+
31
+ export const fromTransactionRaw = (tr: TransactionRaw): Transaction => {
32
+ const common = fromTransactionCommonRaw(tr);
33
+ return {
34
+ ...common,
35
+ family: tr.family,
36
+ fees: new BigNumber(tr.fees),
37
+ amount: new BigNumber(tr.amount),
38
+ memo: tr.memo,
39
+ };
40
+ };
41
+
42
+ const toTransactionRaw = (t: Transaction): TransactionRaw => {
43
+ const common = toTransactionCommonRaw(t);
44
+
45
+ return {
46
+ ...common,
47
+ family: t.family,
48
+ amount: t.amount.toFixed(),
49
+ fees: t.fees.toString(),
50
+ memo: t.memo,
51
+ };
52
+ };
53
+
54
+ export default {
55
+ formatTransaction,
56
+ fromTransactionRaw,
57
+ toTransactionRaw,
58
+ fromTransactionStatusRaw,
59
+ toTransactionStatusRaw,
60
+ formatTransactionStatus,
61
+ };
@@ -0,0 +1,9 @@
1
+ export {
2
+ getPath,
3
+ isValidHex,
4
+ isValidBase64,
5
+ methodToString,
6
+ getBufferFromString,
7
+ normalizeEpochTimestamp,
8
+ getRandomTransferID,
9
+ } from "./utils";
@@ -0,0 +1,47 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import { ICP_SEND_TXN_TYPE, MAX_MEMO_VALUE } from "../consts";
3
+
4
+ const validHexRegExp = new RegExp(/[0-9A-Fa-f]{6}/g);
5
+ const validBase64RegExp = new RegExp(
6
+ /^(?:[A-Za-z\d+/]{4})*(?:[A-Za-z\d+/]{3}=|[A-Za-z\d+/]{2}==)?$/,
7
+ );
8
+
9
+ export const getPath = (path: string): string =>
10
+ path && path.substr(0, 2) !== "m/" ? `m/${path}` : path;
11
+
12
+ export const isValidHex = (msg: string): boolean => validHexRegExp.test(msg);
13
+ export const isValidBase64 = (msg: string): boolean => validBase64RegExp.test(msg);
14
+
15
+ export const methodToString = (method: number): string => {
16
+ switch (method) {
17
+ case ICP_SEND_TXN_TYPE:
18
+ return "Send ICP";
19
+ default:
20
+ return "Unknown";
21
+ }
22
+ };
23
+
24
+ export const getBufferFromString = (message: string): Buffer =>
25
+ isValidHex(message)
26
+ ? Buffer.from(message, "hex")
27
+ : isValidBase64(message)
28
+ ? Buffer.from(message, "base64")
29
+ : Buffer.from(message);
30
+
31
+ export const normalizeEpochTimestamp = (timestamp: string): number => {
32
+ return parseInt(timestamp.slice(0, 13));
33
+ };
34
+
35
+ function randomIntFromInterval(min: any, max: any): string {
36
+ const minBig = new BigNumber(min);
37
+ const maxBig = new BigNumber(max);
38
+
39
+ const random = BigNumber.random().multipliedBy(maxBig.minus(minBig).plus(1)).plus(minBig);
40
+ const randomInt = random.integerValue(BigNumber.ROUND_FLOOR);
41
+
42
+ return randomInt.toString();
43
+ }
44
+
45
+ export function getRandomTransferID(): string {
46
+ return randomIntFromInterval(0, MAX_MEMO_VALUE);
47
+ }
package/src/consts.ts ADDED
@@ -0,0 +1,11 @@
1
+ export const ICP_SEND_TXN_TYPE = 0;
2
+
3
+ // ICP Rosetta ids
4
+ export const ICP_BLK_NAME_ROSETTA = "Internet Computer";
5
+ export const ICP_NET_ID_ROSETTA = "00000000000000020101";
6
+
7
+ // Mac ICP fees
8
+ export const ICP_FEES = 1e4;
9
+
10
+ // Max Memo value on ICP network
11
+ export const MAX_MEMO_VALUE = Number.MAX_SAFE_INTEGER;
package/src/errors.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { createCustomErrorClass } from "@ledgerhq/errors";
2
+
3
+ /*
4
+ * When the transferID/Memo is non number
5
+ */
6
+ export const InvalidMemoICP = createCustomErrorClass("InvalidMemoICP");
@@ -0,0 +1,42 @@
1
+ import { log } from "@ledgerhq/logs";
2
+ import { getBufferFromString } from "./common-logic/utils";
3
+ import { ICP_SEND_TXN_TYPE } from "./consts";
4
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
5
+ import { ICPSigner } from "./types";
6
+ import { Account, AnyMessage } from "@ledgerhq/types-live";
7
+
8
+ function bufferToArrayBuffer(buffer: Buffer): Buffer {
9
+ const sig = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
10
+ return Buffer.from(sig);
11
+ }
12
+
13
+ export const signMessage =
14
+ (signerContext: SignerContext<ICPSigner>) =>
15
+ async (deviceId: string, account: Account, { message }: AnyMessage) => {
16
+ log("debug", "start signMessage process");
17
+
18
+ if (!message) throw new Error("Message cannot be empty");
19
+ if (typeof message !== "string") throw new Error("Message must be a string");
20
+
21
+ const { r } = await signerContext(deviceId, async signer => {
22
+ const r = await signer.sign(
23
+ account.freshAddressPath,
24
+ getBufferFromString(message),
25
+ ICP_SEND_TXN_TYPE,
26
+ );
27
+ return { r };
28
+ });
29
+
30
+ if (!r.signatureRS) {
31
+ throw Error("Signing failed");
32
+ }
33
+
34
+ return {
35
+ rsv: {
36
+ r: "",
37
+ s: "",
38
+ v: 0,
39
+ },
40
+ signature: bufferToArrayBuffer(r.signatureRS).toString("hex"),
41
+ };
42
+ };
@@ -0,0 +1,34 @@
1
+ import { log } from "@ledgerhq/logs";
2
+
3
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
4
+ import { GetAddressFn } from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
5
+ import { GetAddressOptions } from "@ledgerhq/coin-framework/derivation";
6
+ import { ICPSigner } from "../types";
7
+
8
+ function resolver(signerContext: SignerContext<ICPSigner>): GetAddressFn {
9
+ return async (deviceId: string, { path, verify }: GetAddressOptions) => {
10
+ log("debug", "start getAddress process");
11
+
12
+ const { r } = await signerContext(deviceId, async signer => {
13
+ const r = verify
14
+ ? await signer.showAddressAndPubKey(path)
15
+ : await signer.getAddressAndPubKey(path);
16
+
17
+ return { r };
18
+ });
19
+
20
+ if (!r.address || !r.publicKey) {
21
+ console.error("Failed to get address from device");
22
+ throw Error("Failed to get address from device");
23
+ }
24
+
25
+ return {
26
+ path,
27
+ address: Buffer.from(r.address).toString("hex"),
28
+ principalText: r.principalText,
29
+ publicKey: Buffer.from(r.publicKey).toString("hex"),
30
+ };
31
+ };
32
+ }
33
+
34
+ export default resolver;
@@ -0,0 +1,3 @@
1
+ import resolver from "./getAddress";
2
+
3
+ export default resolver;
@@ -0,0 +1,120 @@
1
+ import invariant from "invariant";
2
+ import { DeviceModelId } from "@ledgerhq/devices";
3
+ import expect from "expect";
4
+ import BigNumber from "bignumber.js";
5
+ import type { Transaction } from "../types";
6
+ import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
7
+ import { genericTestDestination, pickSiblings, botTest } from "@ledgerhq/coin-framework/bot/specs";
8
+ import type { AppSpec } from "@ledgerhq/coin-framework/bot/types";
9
+ import { acceptTransaction } from "./speculos-deviceActions";
10
+ import { getRandomTransferID } from "../common-logic/utils";
11
+
12
+ const MIN_SAFE = new BigNumber(10);
13
+ const maxAccount = 6;
14
+
15
+ const internetComputerSpecs: AppSpec<Transaction> = {
16
+ name: "InternetComputer",
17
+ currency: getCryptoCurrencyById("internet_computer"),
18
+ appQuery: {
19
+ model: DeviceModelId.nanoS,
20
+ appName: "Internet Computer",
21
+ },
22
+ genericDeviceAction: acceptTransaction,
23
+ testTimeout: 6 * 60 * 1000,
24
+ minViableAmount: MIN_SAFE,
25
+ transactionCheck: ({ maxSpendable }) => {
26
+ invariant(maxSpendable.gt(MIN_SAFE), "balance is too low");
27
+ },
28
+ mutations: [
29
+ {
30
+ name: "Send ~50%",
31
+ maxRun: 1,
32
+ testDestination: genericTestDestination,
33
+ transaction: ({ account, siblings, bridge, maxSpendable }) => {
34
+ invariant(maxSpendable.gt(MIN_SAFE), "balance is too low");
35
+ const sibling = pickSiblings(siblings, maxAccount);
36
+ const recipient = sibling.freshAddress;
37
+ const amount = maxSpendable.div(2).integerValue();
38
+
39
+ const transaction = bridge.createTransaction(account);
40
+ const updates: Array<Partial<Transaction>> = [
41
+ {
42
+ recipient,
43
+ },
44
+ { amount },
45
+ ];
46
+
47
+ if (Math.random() < 0.5) {
48
+ updates.push({
49
+ memo: getRandomTransferID(),
50
+ });
51
+ }
52
+
53
+ return {
54
+ transaction,
55
+ updates,
56
+ };
57
+ },
58
+
59
+ test: ({ accountBeforeTransaction, operation, account, transaction }) => {
60
+ botTest("account spendable balance decreased with operation", () =>
61
+ expect(account.spendableBalance).toEqual(
62
+ accountBeforeTransaction.spendableBalance.minus(operation.value),
63
+ ),
64
+ );
65
+
66
+ if (transaction.memo) {
67
+ botTest("operation memo", () =>
68
+ expect(operation.extra).toMatchObject({
69
+ memo: transaction.memo,
70
+ }),
71
+ );
72
+ }
73
+ },
74
+ },
75
+ {
76
+ name: "Transfer Max",
77
+ maxRun: 1,
78
+ testDestination: genericTestDestination,
79
+ transaction: ({ account, siblings, bridge }) => {
80
+ const transaction = bridge.createTransaction(account);
81
+ const updates: Array<Partial<Transaction>> = [
82
+ {
83
+ recipient: pickSiblings(siblings, maxAccount).freshAddress,
84
+ },
85
+ {
86
+ useAllAmount: true,
87
+ },
88
+ ];
89
+
90
+ if (Math.random() < 0.5) {
91
+ updates.push({
92
+ memo: getRandomTransferID(),
93
+ });
94
+ }
95
+
96
+ return {
97
+ transaction,
98
+ updates,
99
+ };
100
+ },
101
+ test: ({ account, transaction, operation }) => {
102
+ botTest("account spendable balance is zero", () =>
103
+ expect(account.spendableBalance.toString()).toBe("0"),
104
+ );
105
+
106
+ if (transaction.memo) {
107
+ botTest("operation memo", () =>
108
+ expect(operation.extra).toMatchObject({
109
+ memo: transaction.memo,
110
+ }),
111
+ );
112
+ }
113
+ },
114
+ },
115
+ ],
116
+ };
117
+
118
+ export default {
119
+ internetComputerSpecs,
120
+ };
@@ -0,0 +1,141 @@
1
+ import type { CurrenciesData, DatasetTest } from "@ledgerhq/types-live";
2
+ import type { Transaction } from "../types";
3
+ import { fromTransactionRaw } from "../bridge/transaction";
4
+ import BigNumber from "bignumber.js";
5
+ import { AmountRequired, InvalidAddress, NotEnoughBalance } from "@ledgerhq/errors";
6
+ import { getEstimatedFees } from "../bridge/bridgeHelpers/fee";
7
+ import { InvalidMemoICP } from "../errors";
8
+
9
+ const SEED_IDENTIFIER =
10
+ "046f08828871028b6e3cb5c13b2e2a8fa6e93f0b3ca7379171f6b7b45877955a2430925f76ec69ccb3cd8738859a8e29dcd0f9a357f1d009d2b497c6c8f63aa7cf";
11
+
12
+ // const SEED_IDENTIFIER_ADDRESS = "e8a1474afbed438be8b019c4293b9e01b33075d72757ac715183ae7c7ba77e37";
13
+ const ACCOUNT_2 = "fdb7db0d3ae67368cb5010b7de7d98566c072f0a4eda871f45cd6582bf08aeb4";
14
+
15
+ const internet_computer: CurrenciesData<Transaction> = {
16
+ scanAccounts: [
17
+ {
18
+ name: "internet_computer seed 1",
19
+ apdus: `
20
+ => 11010000142c000080df000080000000800000000000000000
21
+ <= 046f08828871028b6e3cb5c13b2e2a8fa6e93f0b3ca7379171f6b7b45877955a2430925f76ec69ccb3cd8738859a8e29dcd0f9a357f1d009d2b497c6c8f63aa7cf182d2af0e048c8cf215fa86d7af7e2234f401679c7839dd3b1ae916a02e8a1474afbed438be8b019c4293b9e01b33075d72757ac715183ae7c7ba77e37793471646770797966757670627963697a646873637835696e763570707972646a3561626d366f68716f6f35686d6e6f73667661659000
22
+ => 11010000142c000080df000080000000800000000001000000
23
+ <= 043ad9dda46b25cbcf98b2d91f8aa289d08078fa960d13e7d77a571c625eedcb62b6c26a86408d30a6bbdea5ecad6f7603bc1ba11fbb62caa315789f333ece2c8cd785035623de419beb00247d11fbb4d3f77fbb466869fb01deac4f61021723b9a25b7cb1865caa6e633fc727c95cee6a84c52e5ca0f8752ecf66cdea4b6764756f79346f78717562766d69363669676e367761626570756937786e677436353733777274696e6835716478766d6a357171659000
24
+ `,
25
+ test: (expect, accounts) => {
26
+ for (const account of accounts) {
27
+ expect(account.derivationMode).toEqual("internet_computer");
28
+ }
29
+ },
30
+ },
31
+ ],
32
+ accounts: [
33
+ {
34
+ raw: {
35
+ id: `js:2:internet_computer:${SEED_IDENTIFIER}:`,
36
+ balance: "1000000",
37
+ currencyId: "internet_computer",
38
+ derivationMode: "internet_computer",
39
+ freshAddress: "",
40
+ freshAddressPath: "44'/223'/0'/0/0",
41
+ index: 0,
42
+ name: "Internet Computer 1",
43
+ operationsCount: 1,
44
+ blockHeight: 0,
45
+ pendingOperations: [],
46
+ operations: [],
47
+ lastSyncDate: "",
48
+ seedIdentifier: SEED_IDENTIFIER,
49
+ spendableBalance: "1000000",
50
+ swapHistory: [],
51
+ syncHash: undefined,
52
+ used: true,
53
+ xpub: SEED_IDENTIFIER,
54
+ },
55
+ transactions: [
56
+ {
57
+ name: "Not a valid address",
58
+ transaction: fromTransactionRaw({
59
+ family: "internet_computer",
60
+ recipient: "novalidaddress",
61
+ fees: getEstimatedFees().toString(),
62
+ amount: "1000",
63
+ }),
64
+ expectedStatus: {
65
+ errors: {
66
+ recipient: new InvalidAddress(),
67
+ },
68
+ warnings: {},
69
+ },
70
+ },
71
+ {
72
+ name: "Not enough balance",
73
+ transaction: fromTransactionRaw({
74
+ family: "internet_computer",
75
+ recipient: ACCOUNT_2,
76
+ fees: getEstimatedFees().toString(),
77
+ amount: (300 * 1e9).toString(),
78
+ }),
79
+ expectedStatus: {
80
+ errors: {
81
+ amount: new NotEnoughBalance(),
82
+ },
83
+ warnings: {},
84
+ },
85
+ },
86
+ {
87
+ name: "Invalid transferID/Memo",
88
+ transaction: fromTransactionRaw({
89
+ family: "internet_computer",
90
+ recipient: ACCOUNT_2,
91
+ fees: getEstimatedFees().toString(),
92
+ amount: "1000",
93
+ memo: "-1",
94
+ }),
95
+ expectedStatus: {
96
+ errors: {
97
+ transaction: new InvalidMemoICP(),
98
+ },
99
+ warnings: {},
100
+ },
101
+ },
102
+ {
103
+ name: "Amount Required",
104
+ transaction: fromTransactionRaw({
105
+ family: "internet_computer",
106
+ recipient: ACCOUNT_2,
107
+ amount: "0",
108
+ fees: getEstimatedFees().toString(),
109
+ }),
110
+ expectedStatus: {
111
+ errors: {
112
+ amount: new AmountRequired(),
113
+ },
114
+ warnings: {},
115
+ },
116
+ },
117
+ {
118
+ name: "New account and sufficient amount",
119
+ transaction: fromTransactionRaw({
120
+ family: "internet_computer",
121
+ recipient: ACCOUNT_2,
122
+ amount: "1000",
123
+ fees: getEstimatedFees().toString(),
124
+ }),
125
+ expectedStatus: {
126
+ amount: new BigNumber("1000"),
127
+ errors: {},
128
+ warnings: {},
129
+ },
130
+ },
131
+ ],
132
+ },
133
+ ],
134
+ };
135
+
136
+ export const dataset: DatasetTest<Transaction> = {
137
+ implementations: ["js"],
138
+ currencies: {
139
+ internet_computer,
140
+ },
141
+ };
@@ -0,0 +1,36 @@
1
+ import type { Account, AccountLike, AccountLikeArray } from "@ledgerhq/types-live";
2
+ import invariant from "invariant";
3
+ import flatMap from "lodash/flatMap";
4
+ import type { Transaction } from "../types";
5
+
6
+ function inferAccounts(account: Account): AccountLikeArray {
7
+ invariant(account.currency.family === "internet_computer", "internet computer family");
8
+
9
+ const accounts: Account[] = [account];
10
+ return accounts;
11
+ }
12
+
13
+ function inferTransactions(
14
+ transactions: Array<{
15
+ account: AccountLike;
16
+ transaction: Transaction;
17
+ mainAccount: Account;
18
+ }>,
19
+ ): Transaction[] {
20
+ return flatMap(transactions, ({ transaction }) => {
21
+ invariant(transaction.family === "internet_computer", "internet computer family");
22
+
23
+ return {
24
+ ...transaction,
25
+ family: "internet_computer",
26
+ } as Transaction;
27
+ });
28
+ }
29
+
30
+ export default function makeCliTools() {
31
+ return {
32
+ options: [],
33
+ inferAccounts,
34
+ inferTransactions,
35
+ };
36
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./bridgeDatasetTest";
2
+ export * from "./bot-specs";
3
+ export * from "./speculos-deviceActions";