@ledgerhq/coin-filecoin 1.3.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 (316) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.unimportedrc.json +21 -0
  3. package/CHANGELOG.md +19 -0
  4. package/LICENSE.txt +21 -0
  5. package/jest.config.js +8 -0
  6. package/lib/api/api.d.ts +9 -0
  7. package/lib/api/api.d.ts.map +1 -0
  8. package/lib/api/api.js +99 -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/broadcast.d.ts +4 -0
  15. package/lib/bridge/broadcast.d.ts.map +1 -0
  16. package/lib/bridge/broadcast.js +27 -0
  17. package/lib/bridge/broadcast.js.map +1 -0
  18. package/lib/bridge/buildOptimisticOperation.d.ts +5 -0
  19. package/lib/bridge/buildOptimisticOperation.d.ts.map +1 -0
  20. package/lib/bridge/buildOptimisticOperation.js +62 -0
  21. package/lib/bridge/buildOptimisticOperation.js.map +1 -0
  22. package/lib/bridge/createTransaction.d.ts +4 -0
  23. package/lib/bridge/createTransaction.d.ts.map +1 -0
  24. package/lib/bridge/createTransaction.js +24 -0
  25. package/lib/bridge/createTransaction.js.map +1 -0
  26. package/lib/bridge/deviceTransactionConfig.d.ts +33 -0
  27. package/lib/bridge/deviceTransactionConfig.d.ts.map +1 -0
  28. package/lib/bridge/deviceTransactionConfig.js +71 -0
  29. package/lib/bridge/deviceTransactionConfig.js.map +1 -0
  30. package/lib/bridge/estimateMaxSpendable.d.ts +4 -0
  31. package/lib/bridge/estimateMaxSpendable.d.ts.map +1 -0
  32. package/lib/bridge/estimateMaxSpendable.js +100 -0
  33. package/lib/bridge/estimateMaxSpendable.js.map +1 -0
  34. package/lib/bridge/getTransactionStatus.d.ts +4 -0
  35. package/lib/bridge/getTransactionStatus.d.ts.map +1 -0
  36. package/lib/bridge/getTransactionStatus.js +84 -0
  37. package/lib/bridge/getTransactionStatus.js.map +1 -0
  38. package/lib/bridge/index.d.ts +8 -0
  39. package/lib/bridge/index.d.ts.map +1 -0
  40. package/lib/bridge/index.js +54 -0
  41. package/lib/bridge/index.js.map +1 -0
  42. package/lib/bridge/prepareTransaction.d.ts +4 -0
  43. package/lib/bridge/prepareTransaction.d.ts.map +1 -0
  44. package/lib/bridge/prepareTransaction.js +75 -0
  45. package/lib/bridge/prepareTransaction.js.map +1 -0
  46. package/lib/bridge/serializer.d.ts +13 -0
  47. package/lib/bridge/serializer.d.ts.map +1 -0
  48. package/lib/bridge/serializer.js +65 -0
  49. package/lib/bridge/serializer.js.map +1 -0
  50. package/lib/bridge/signOperation.d.ts +5 -0
  51. package/lib/bridge/signOperation.d.ts.map +1 -0
  52. package/lib/bridge/signOperation.js +80 -0
  53. package/lib/bridge/signOperation.js.map +1 -0
  54. package/lib/bridge/transaction.d.ts +14 -0
  55. package/lib/bridge/transaction.d.ts.map +1 -0
  56. package/lib/bridge/transaction.js +41 -0
  57. package/lib/bridge/transaction.js.map +1 -0
  58. package/lib/bridge/utils.d.ts +26 -0
  59. package/lib/bridge/utils.d.ts.map +1 -0
  60. package/lib/bridge/utils.js +67 -0
  61. package/lib/bridge/utils.js.map +1 -0
  62. package/lib/bridge/utils.unit.test.d.ts +2 -0
  63. package/lib/bridge/utils.unit.test.d.ts.map +1 -0
  64. package/lib/bridge/utils.unit.test.js +23 -0
  65. package/lib/bridge/utils.unit.test.js.map +1 -0
  66. package/lib/common-logic/index.d.ts +2 -0
  67. package/lib/common-logic/index.d.ts.map +1 -0
  68. package/lib/common-logic/index.js +13 -0
  69. package/lib/common-logic/index.js.map +1 -0
  70. package/lib/common-logic/utils.d.ts +22 -0
  71. package/lib/common-logic/utils.d.ts.map +1 -0
  72. package/lib/common-logic/utils.js +189 -0
  73. package/lib/common-logic/utils.js.map +1 -0
  74. package/lib/erc20/ERC20.json +12 -0
  75. package/lib/erc20/tokenAccounts.d.ts +10 -0
  76. package/lib/erc20/tokenAccounts.d.ts.map +1 -0
  77. package/lib/erc20/tokenAccounts.js +169 -0
  78. package/lib/erc20/tokenAccounts.js.map +1 -0
  79. package/lib/errors.d.ts +7 -0
  80. package/lib/errors.d.ts.map +1 -0
  81. package/lib/errors.js +13 -0
  82. package/lib/errors.js.map +1 -0
  83. package/lib/hw-signMessage.d.ts +12 -0
  84. package/lib/hw-signMessage.d.ts.map +1 -0
  85. package/lib/hw-signMessage.js +32 -0
  86. package/lib/hw-signMessage.js.map +1 -0
  87. package/lib/index.d.ts +2 -0
  88. package/lib/index.d.ts.map +1 -0
  89. package/lib/index.js +6 -0
  90. package/lib/index.js.map +1 -0
  91. package/lib/network/addresses.d.ts +16 -0
  92. package/lib/network/addresses.d.ts.map +1 -0
  93. package/lib/network/addresses.js +75 -0
  94. package/lib/network/addresses.js.map +1 -0
  95. package/lib/network/index.d.ts +2 -0
  96. package/lib/network/index.d.ts.map +1 -0
  97. package/lib/network/index.js +18 -0
  98. package/lib/network/index.js.map +1 -0
  99. package/lib/signer/getAddress.d.ts +6 -0
  100. package/lib/signer/getAddress.d.ts.map +1 -0
  101. package/lib/signer/getAddress.js +30 -0
  102. package/lib/signer/getAddress.js.map +1 -0
  103. package/lib/signer/index.d.ts +3 -0
  104. package/lib/signer/index.d.ts.map +1 -0
  105. package/lib/signer/index.js +8 -0
  106. package/lib/signer/index.js.map +1 -0
  107. package/lib/test/bot-specs.d.ts +7 -0
  108. package/lib/test/bot-specs.d.ts.map +1 -0
  109. package/lib/test/bot-specs.js +151 -0
  110. package/lib/test/bot-specs.js.map +1 -0
  111. package/lib/test/bridgeDatasetTest.d.ts +4 -0
  112. package/lib/test/bridgeDatasetTest.d.ts.map +1 -0
  113. package/lib/test/bridgeDatasetTest.js +401 -0
  114. package/lib/test/bridgeDatasetTest.js.map +1 -0
  115. package/lib/test/cli.d.ts +19 -0
  116. package/lib/test/cli.d.ts.map +1 -0
  117. package/lib/test/cli.js +59 -0
  118. package/lib/test/cli.js.map +1 -0
  119. package/lib/test/index.d.ts +6 -0
  120. package/lib/test/index.d.ts.map +1 -0
  121. package/lib/test/index.js +26 -0
  122. package/lib/test/index.js.map +1 -0
  123. package/lib/test/speculos-deviceActions.d.ts +5 -0
  124. package/lib/test/speculos-deviceActions.d.ts.map +1 -0
  125. package/lib/test/speculos-deviceActions.js +159 -0
  126. package/lib/test/speculos-deviceActions.js.map +1 -0
  127. package/lib/types/bridge.d.ts +35 -0
  128. package/lib/types/bridge.d.ts.map +1 -0
  129. package/lib/types/bridge.js +3 -0
  130. package/lib/types/bridge.js.map +1 -0
  131. package/lib/types/common.d.ts +96 -0
  132. package/lib/types/common.d.ts.map +1 -0
  133. package/lib/types/common.js +10 -0
  134. package/lib/types/common.js.map +1 -0
  135. package/lib/types/index.d.ts +4 -0
  136. package/lib/types/index.d.ts.map +1 -0
  137. package/lib/types/index.js +20 -0
  138. package/lib/types/index.js.map +1 -0
  139. package/lib/types/signer.d.ts +19 -0
  140. package/lib/types/signer.d.ts.map +1 -0
  141. package/lib/types/signer.js +3 -0
  142. package/lib/types/signer.js.map +1 -0
  143. package/lib-es/api/api.d.ts +9 -0
  144. package/lib-es/api/api.d.ts.map +1 -0
  145. package/lib-es/api/api.js +87 -0
  146. package/lib-es/api/api.js.map +1 -0
  147. package/lib-es/api/index.d.ts +2 -0
  148. package/lib-es/api/index.d.ts.map +1 -0
  149. package/lib-es/api/index.js +2 -0
  150. package/lib-es/api/index.js.map +1 -0
  151. package/lib-es/bridge/broadcast.d.ts +4 -0
  152. package/lib-es/bridge/broadcast.d.ts.map +1 -0
  153. package/lib-es/bridge/broadcast.js +23 -0
  154. package/lib-es/bridge/broadcast.js.map +1 -0
  155. package/lib-es/bridge/buildOptimisticOperation.d.ts +5 -0
  156. package/lib-es/bridge/buildOptimisticOperation.d.ts.map +1 -0
  157. package/lib-es/bridge/buildOptimisticOperation.js +58 -0
  158. package/lib-es/bridge/buildOptimisticOperation.js.map +1 -0
  159. package/lib-es/bridge/createTransaction.d.ts +4 -0
  160. package/lib-es/bridge/createTransaction.d.ts.map +1 -0
  161. package/lib-es/bridge/createTransaction.js +17 -0
  162. package/lib-es/bridge/createTransaction.js.map +1 -0
  163. package/lib-es/bridge/deviceTransactionConfig.d.ts +33 -0
  164. package/lib-es/bridge/deviceTransactionConfig.d.ts.map +1 -0
  165. package/lib-es/bridge/deviceTransactionConfig.js +69 -0
  166. package/lib-es/bridge/deviceTransactionConfig.js.map +1 -0
  167. package/lib-es/bridge/estimateMaxSpendable.d.ts +4 -0
  168. package/lib-es/bridge/estimateMaxSpendable.d.ts.map +1 -0
  169. package/lib-es/bridge/estimateMaxSpendable.js +93 -0
  170. package/lib-es/bridge/estimateMaxSpendable.js.map +1 -0
  171. package/lib-es/bridge/getTransactionStatus.d.ts +4 -0
  172. package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -0
  173. package/lib-es/bridge/getTransactionStatus.js +80 -0
  174. package/lib-es/bridge/getTransactionStatus.js.map +1 -0
  175. package/lib-es/bridge/index.d.ts +8 -0
  176. package/lib-es/bridge/index.d.ts.map +1 -0
  177. package/lib-es/bridge/index.js +47 -0
  178. package/lib-es/bridge/index.js.map +1 -0
  179. package/lib-es/bridge/prepareTransaction.d.ts +4 -0
  180. package/lib-es/bridge/prepareTransaction.d.ts.map +1 -0
  181. package/lib-es/bridge/prepareTransaction.js +68 -0
  182. package/lib-es/bridge/prepareTransaction.js.map +1 -0
  183. package/lib-es/bridge/serializer.d.ts +13 -0
  184. package/lib-es/bridge/serializer.d.ts.map +1 -0
  185. package/lib-es/bridge/serializer.js +58 -0
  186. package/lib-es/bridge/serializer.js.map +1 -0
  187. package/lib-es/bridge/signOperation.d.ts +5 -0
  188. package/lib-es/bridge/signOperation.d.ts.map +1 -0
  189. package/lib-es/bridge/signOperation.js +76 -0
  190. package/lib-es/bridge/signOperation.js.map +1 -0
  191. package/lib-es/bridge/transaction.d.ts +14 -0
  192. package/lib-es/bridge/transaction.d.ts.map +1 -0
  193. package/lib-es/bridge/transaction.js +33 -0
  194. package/lib-es/bridge/transaction.js.map +1 -0
  195. package/lib-es/bridge/utils.d.ts +26 -0
  196. package/lib-es/bridge/utils.d.ts.map +1 -0
  197. package/lib-es/bridge/utils.js +57 -0
  198. package/lib-es/bridge/utils.js.map +1 -0
  199. package/lib-es/bridge/utils.unit.test.d.ts +2 -0
  200. package/lib-es/bridge/utils.unit.test.d.ts.map +1 -0
  201. package/lib-es/bridge/utils.unit.test.js +21 -0
  202. package/lib-es/bridge/utils.unit.test.js.map +1 -0
  203. package/lib-es/common-logic/index.d.ts +2 -0
  204. package/lib-es/common-logic/index.d.ts.map +1 -0
  205. package/lib-es/common-logic/index.js +2 -0
  206. package/lib-es/common-logic/index.js.map +1 -0
  207. package/lib-es/common-logic/utils.d.ts +22 -0
  208. package/lib-es/common-logic/utils.d.ts.map +1 -0
  209. package/lib-es/common-logic/utils.js +175 -0
  210. package/lib-es/common-logic/utils.js.map +1 -0
  211. package/lib-es/erc20/ERC20.json +12 -0
  212. package/lib-es/erc20/tokenAccounts.d.ts +10 -0
  213. package/lib-es/erc20/tokenAccounts.d.ts.map +1 -0
  214. package/lib-es/erc20/tokenAccounts.js +158 -0
  215. package/lib-es/erc20/tokenAccounts.js.map +1 -0
  216. package/lib-es/errors.d.ts +7 -0
  217. package/lib-es/errors.d.ts.map +1 -0
  218. package/lib-es/errors.js +10 -0
  219. package/lib-es/errors.js.map +1 -0
  220. package/lib-es/hw-signMessage.d.ts +12 -0
  221. package/lib-es/hw-signMessage.d.ts.map +1 -0
  222. package/lib-es/hw-signMessage.js +28 -0
  223. package/lib-es/hw-signMessage.js.map +1 -0
  224. package/lib-es/index.d.ts +2 -0
  225. package/lib-es/index.d.ts.map +1 -0
  226. package/lib-es/index.js +2 -0
  227. package/lib-es/index.js.map +1 -0
  228. package/lib-es/network/addresses.d.ts +16 -0
  229. package/lib-es/network/addresses.d.ts.map +1 -0
  230. package/lib-es/network/addresses.js +64 -0
  231. package/lib-es/network/addresses.js.map +1 -0
  232. package/lib-es/network/index.d.ts +2 -0
  233. package/lib-es/network/index.d.ts.map +1 -0
  234. package/lib-es/network/index.js +2 -0
  235. package/lib-es/network/index.js.map +1 -0
  236. package/lib-es/signer/getAddress.d.ts +6 -0
  237. package/lib-es/signer/getAddress.d.ts.map +1 -0
  238. package/lib-es/signer/getAddress.js +28 -0
  239. package/lib-es/signer/getAddress.js.map +1 -0
  240. package/lib-es/signer/index.d.ts +3 -0
  241. package/lib-es/signer/index.d.ts.map +1 -0
  242. package/lib-es/signer/index.js +3 -0
  243. package/lib-es/signer/index.js.map +1 -0
  244. package/lib-es/test/bot-specs.d.ts +7 -0
  245. package/lib-es/test/bot-specs.d.ts.map +1 -0
  246. package/lib-es/test/bot-specs.js +146 -0
  247. package/lib-es/test/bot-specs.js.map +1 -0
  248. package/lib-es/test/bridgeDatasetTest.d.ts +4 -0
  249. package/lib-es/test/bridgeDatasetTest.d.ts.map +1 -0
  250. package/lib-es/test/bridgeDatasetTest.js +395 -0
  251. package/lib-es/test/bridgeDatasetTest.js.map +1 -0
  252. package/lib-es/test/cli.d.ts +19 -0
  253. package/lib-es/test/cli.d.ts.map +1 -0
  254. package/lib-es/test/cli.js +53 -0
  255. package/lib-es/test/cli.js.map +1 -0
  256. package/lib-es/test/index.d.ts +6 -0
  257. package/lib-es/test/index.d.ts.map +1 -0
  258. package/lib-es/test/index.js +6 -0
  259. package/lib-es/test/index.js.map +1 -0
  260. package/lib-es/test/speculos-deviceActions.d.ts +5 -0
  261. package/lib-es/test/speculos-deviceActions.d.ts.map +1 -0
  262. package/lib-es/test/speculos-deviceActions.js +152 -0
  263. package/lib-es/test/speculos-deviceActions.js.map +1 -0
  264. package/lib-es/types/bridge.d.ts +35 -0
  265. package/lib-es/types/bridge.d.ts.map +1 -0
  266. package/lib-es/types/bridge.js +2 -0
  267. package/lib-es/types/bridge.js.map +1 -0
  268. package/lib-es/types/common.d.ts +96 -0
  269. package/lib-es/types/common.d.ts.map +1 -0
  270. package/lib-es/types/common.js +7 -0
  271. package/lib-es/types/common.js.map +1 -0
  272. package/lib-es/types/index.d.ts +4 -0
  273. package/lib-es/types/index.d.ts.map +1 -0
  274. package/lib-es/types/index.js +4 -0
  275. package/lib-es/types/index.js.map +1 -0
  276. package/lib-es/types/signer.d.ts +19 -0
  277. package/lib-es/types/signer.d.ts.map +1 -0
  278. package/lib-es/types/signer.js +2 -0
  279. package/lib-es/types/signer.js.map +1 -0
  280. package/package.json +135 -0
  281. package/src/api/api.ts +125 -0
  282. package/src/api/index.ts +1 -0
  283. package/src/bridge/broadcast.ts +20 -0
  284. package/src/bridge/buildOptimisticOperation.ts +58 -0
  285. package/src/bridge/createTransaction.ts +20 -0
  286. package/src/bridge/deviceTransactionConfig.ts +119 -0
  287. package/src/bridge/estimateMaxSpendable.ts +120 -0
  288. package/src/bridge/getTransactionStatus.ts +80 -0
  289. package/src/bridge/index.ts +63 -0
  290. package/src/bridge/prepareTransaction.ts +82 -0
  291. package/src/bridge/serializer.ts +63 -0
  292. package/src/bridge/signOperation.ts +97 -0
  293. package/src/bridge/transaction.ts +69 -0
  294. package/src/bridge/utils.ts +73 -0
  295. package/src/bridge/utils.unit.test.ts +27 -0
  296. package/src/common-logic/index.ts +10 -0
  297. package/src/common-logic/utils.ts +232 -0
  298. package/src/erc20/ERC20.json +12 -0
  299. package/src/erc20/tokenAccounts.ts +183 -0
  300. package/src/errors.ts +13 -0
  301. package/src/hw-signMessage.ts +27 -0
  302. package/src/index.ts +1 -0
  303. package/src/network/addresses.ts +93 -0
  304. package/src/network/index.ts +1 -0
  305. package/src/signer/getAddress.ts +28 -0
  306. package/src/signer/index.ts +3 -0
  307. package/src/test/bot-specs.ts +163 -0
  308. package/src/test/bridgeDatasetTest.ts +403 -0
  309. package/src/test/cli.ts +80 -0
  310. package/src/test/index.ts +6 -0
  311. package/src/test/speculos-deviceActions.ts +166 -0
  312. package/src/types/bridge.ts +42 -0
  313. package/src/types/common.ts +105 -0
  314. package/src/types/index.ts +3 -0
  315. package/src/types/signer.ts +19 -0
  316. package/tsconfig.json +14 -0
@@ -0,0 +1,97 @@
1
+ import { Observable } from "rxjs";
2
+ import { log } from "@ledgerhq/logs";
3
+ import { FeeNotLoaded } from "@ledgerhq/errors";
4
+ import { Account, AccountBridge, Operation } from "@ledgerhq/types-live";
5
+ import { buildOptimisticOperation } from "./buildOptimisticOperation";
6
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
7
+ import { toCBOR } from "./serializer";
8
+ import { getAddress, getSubAccount } from "../common-logic/utils";
9
+ import { AccountType } from "./utils";
10
+ import { Transaction, FilecoinSigner } from "../types";
11
+
12
+ export const buildSignOperation =
13
+ (
14
+ signerContext: SignerContext<FilecoinSigner>,
15
+ ): AccountBridge<Transaction, Account>["signOperation"] =>
16
+ ({ account, deviceId, transaction }) =>
17
+ new Observable(o => {
18
+ async function main() {
19
+ const { method, version, nonce, gasFeeCap, gasLimit, gasPremium } = transaction;
20
+ const { derivationPath } = getAddress(account);
21
+ const subAccount = getSubAccount(account, transaction);
22
+ const tokenAccountTxn = subAccount?.type === AccountType.TokenAccount;
23
+
24
+ if (!gasFeeCap.gt(0) || !gasLimit.gt(0)) {
25
+ log("debug", `signOperation missingData --> gasFeeCap=${gasFeeCap} gasLimit=${gasLimit}`);
26
+ throw new FeeNotLoaded();
27
+ }
28
+
29
+ o.next({
30
+ type: "device-signature-requested",
31
+ });
32
+
33
+ // Serialize tx
34
+ const toCBORResponse = await toCBOR(account, transaction);
35
+ const {
36
+ txPayload,
37
+ parsedSender,
38
+ recipientToBroadcast,
39
+ encodedParams,
40
+ amountToBroadcast: finalAmount,
41
+ } = toCBORResponse;
42
+
43
+ log("debug", `[signOperation] serialized CBOR tx: [${txPayload.toString("hex")}]`);
44
+
45
+ // Sign by device
46
+ const { r } = await signerContext(deviceId, async signer => {
47
+ const r = await signer.sign(derivationPath, txPayload);
48
+ return { r };
49
+ });
50
+
51
+ o.next({
52
+ type: "device-signature-granted",
53
+ });
54
+
55
+ if (!r.signature_compact) {
56
+ throw new Error("Signature compact is null");
57
+ }
58
+ // build signature on the correct format
59
+ const signature = `${Buffer.from(r.signature_compact).toString("base64")}`;
60
+
61
+ const operation: Operation = await buildOptimisticOperation(
62
+ account,
63
+ transaction,
64
+ toCBORResponse,
65
+ );
66
+
67
+ // Necessary for broadcast
68
+ const additionalTxFields = {
69
+ sender: parsedSender,
70
+ recipient: recipientToBroadcast,
71
+ params: encodedParams,
72
+ gasLimit,
73
+ gasFeeCap,
74
+ gasPremium,
75
+ method,
76
+ version,
77
+ nonce,
78
+ signatureType: 1,
79
+ tokenTransfer: tokenAccountTxn,
80
+ value: finalAmount.toString(),
81
+ };
82
+
83
+ o.next({
84
+ type: "signed",
85
+ signedOperation: {
86
+ operation,
87
+ signature,
88
+ rawData: additionalTxFields,
89
+ },
90
+ });
91
+ }
92
+
93
+ main().then(
94
+ () => o.complete(),
95
+ e => o.error(e),
96
+ );
97
+ });
@@ -0,0 +1,69 @@
1
+ import type { Transaction, TransactionRaw } from "../types";
2
+ import { formatTransactionStatus } from "@ledgerhq/coin-framework/formatters";
3
+ import {
4
+ fromTransactionCommonRaw,
5
+ fromTransactionStatusRawCommon as fromTransactionStatusRaw,
6
+ toTransactionCommonRaw,
7
+ toTransactionStatusRawCommon as toTransactionStatusRaw,
8
+ } from "@ledgerhq/coin-framework/serialization";
9
+ import type { Account } from "@ledgerhq/types-live";
10
+ import { getAccountCurrency } from "@ledgerhq/coin-framework/account/index";
11
+ import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
12
+ import BigNumber from "bignumber.js";
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
+ version: tr.version,
37
+ method: tr.method,
38
+ nonce: tr.nonce,
39
+ amount: new BigNumber(tr.amount),
40
+ gasFeeCap: new BigNumber(tr.gasFeeCap),
41
+ gasLimit: new BigNumber(tr.gasLimit),
42
+ gasPremium: new BigNumber(tr.gasPremium),
43
+ };
44
+ };
45
+
46
+ const toTransactionRaw = (t: Transaction): TransactionRaw => {
47
+ const common = toTransactionCommonRaw(t);
48
+
49
+ return {
50
+ ...common,
51
+ method: t.method,
52
+ version: t.version,
53
+ family: t.family,
54
+ nonce: t.nonce,
55
+ amount: t.amount.toFixed(),
56
+ gasFeeCap: t.gasFeeCap.toString(),
57
+ gasLimit: t.gasLimit.toNumber(),
58
+ gasPremium: t.gasPremium.toString(),
59
+ };
60
+ };
61
+
62
+ export default {
63
+ formatTransaction,
64
+ fromTransactionRaw,
65
+ toTransactionRaw,
66
+ fromTransactionStatusRaw,
67
+ toTransactionStatusRaw,
68
+ formatTransactionStatus,
69
+ };
@@ -0,0 +1,73 @@
1
+ import { AccountLike } from "@ledgerhq/types-live";
2
+ import { BigNumber } from "bignumber.js";
3
+ import { getEquivalentAddress } from "../network";
4
+
5
+ export enum Methods {
6
+ Transfer = 0,
7
+ ERC20Transfer = 1,
8
+ InvokeEVM = 3844450837,
9
+ }
10
+
11
+ export enum AccountType {
12
+ Account = "Account",
13
+ TokenAccount = "TokenAccount",
14
+ }
15
+
16
+ export enum BotScenario {
17
+ DEFAULT = "default",
18
+ ETH_RECIPIENT = "eth-recipient",
19
+ F4_RECIPIENT = "f4-recipient",
20
+ TOKEN_TRANSFER = "token-transfer",
21
+ }
22
+
23
+ const validHexRegExp = new RegExp(/^(0x)?[a-fA-F0-9]+$/);
24
+ const validBase64RegExp = new RegExp(
25
+ /^(?:[A-Za-z\d+/]{4})*(?:[A-Za-z\d+/]{3}=|[A-Za-z\d+/]{2}==)?$/,
26
+ );
27
+
28
+ // TODO Filecoin - Use the new package @zondax/ledger-utils instead
29
+
30
+ export const isValidHex = (msg: string) => validHexRegExp.test(msg) && msg.length % 2 === 0;
31
+ export const isValidBase64 = (msg: string) => validBase64RegExp.test(msg);
32
+
33
+ export const methodToString = (method: number): string => {
34
+ switch (method) {
35
+ case Methods.Transfer:
36
+ return "Transfer";
37
+ case Methods.InvokeEVM:
38
+ return "InvokeEVM (3844450837)";
39
+ case Methods.ERC20Transfer:
40
+ return "ERC20 Transfer";
41
+ default:
42
+ return "Unknown";
43
+ }
44
+ };
45
+
46
+ export const getBufferFromString = (message: string): Buffer =>
47
+ isValidHex(message)
48
+ ? Buffer.from(message, "hex")
49
+ : isValidBase64(message)
50
+ ? Buffer.from(message, "base64")
51
+ : Buffer.from(message);
52
+
53
+ export const calculateEstimatedFees = (gasFeeCap: BigNumber, gasLimit: BigNumber): BigNumber =>
54
+ gasFeeCap.multipliedBy(gasLimit);
55
+
56
+ export function getAccountUnit(account: AccountLike) {
57
+ if (account.type === AccountType.TokenAccount) {
58
+ return account.token.units[0];
59
+ }
60
+
61
+ return account.currency.units[0];
62
+ }
63
+
64
+ export const expectedToFieldForTokenTransfer = (recipient: string) => {
65
+ let value = recipient;
66
+ const equivalent = getEquivalentAddress(value);
67
+
68
+ if (equivalent && value != equivalent) {
69
+ value += ` / ${equivalent}`;
70
+ }
71
+
72
+ return value;
73
+ };
@@ -0,0 +1,27 @@
1
+ import { isValidBase64, isValidHex, methodToString } from "./utils";
2
+
3
+ test("methodToString", () => {
4
+ const str1 = methodToString(0);
5
+ expect(str1).toBe("Transfer");
6
+ const str2 = methodToString(3844450837);
7
+ expect(str2).toBe("InvokeEVM (3844450837)");
8
+ const str3 = methodToString(5649856);
9
+ expect(str3).toBe("Unknown");
10
+ });
11
+
12
+ test("isValidHex", () => {
13
+ expect(isValidHex("0x0001aaeeff")).toBeTruthy();
14
+ expect(isValidHex("0001aaeeff")).toBeTruthy();
15
+ expect(isValidHex("0x0001rreeta")).toBeFalsy();
16
+ expect(isValidHex("0x0001aaeef")).toBeFalsy();
17
+ });
18
+
19
+ test("isValidBase64", () => {
20
+ expect(isValidBase64("YXNkYWZhc2Rmc2Rm")).toBeTruthy();
21
+ expect(
22
+ isValidBase64(
23
+ "YXNmZHNhZGZzYWRmYXNkZnNhZGZzYWRmYXNkZnNhZGYyNTEyMzQxMjIzcjZmYXM0MmZhczJkMTNhc2M=",
24
+ ),
25
+ ).toBeTruthy();
26
+ expect(isValidBase64("asdasd````")).toBeFalsy();
27
+ });
@@ -0,0 +1,10 @@
1
+ export {
2
+ getUnit,
3
+ processTxs,
4
+ mapTxToOps,
5
+ getAddress,
6
+ getTxToBroadcast,
7
+ getAccountShape,
8
+ getSubAccount,
9
+ valueFromUnit,
10
+ } from "./utils";
@@ -0,0 +1,232 @@
1
+ import { Account, Operation } from "@ledgerhq/types-live";
2
+ import type { Unit } from "@ledgerhq/types-cryptoassets";
3
+ import { log } from "@ledgerhq/logs";
4
+ import { parseCurrencyUnit } from "@ledgerhq/coin-framework/currencies";
5
+ import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets";
6
+ import { BigNumber } from "bignumber.js";
7
+ import { BroadcastTransactionRequest, TransactionResponse, TxStatus, Transaction } from "../types";
8
+ import { GetAccountShape, AccountShapeInfo } from "@ledgerhq/coin-framework/bridge/jsHelpers";
9
+ import { fetchBalances, fetchBlockHeight, fetchTxs } from "../api/api";
10
+ import { encodeAccountId } from "@ledgerhq/coin-framework/account";
11
+ import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
12
+ import flatMap from "lodash/flatMap";
13
+ import { buildTokenAccounts } from "../erc20/tokenAccounts";
14
+
15
+ type TxsById = {
16
+ [id: string]:
17
+ | {
18
+ Send: TransactionResponse;
19
+ Fee?: TransactionResponse;
20
+ }
21
+ | {
22
+ InvokeContract: TransactionResponse;
23
+ Fee?: TransactionResponse;
24
+ };
25
+ };
26
+
27
+ export const getUnit = () => getCryptoCurrencyById("filecoin").units[0];
28
+
29
+ export const processTxs = (txs: TransactionResponse[]): TransactionResponse[] => {
30
+ // Group all tx types related to same tx cid into the same object
31
+ const txsByTxCid = txs.reduce((txsByTxCidResult: TxsById, currentTx) => {
32
+ const { hash: txCid, type: txType } = currentTx;
33
+ const txByType = txsByTxCidResult[txCid] || {};
34
+ switch (txType) {
35
+ case "Send":
36
+ (txByType as { Send: TransactionResponse }).Send = currentTx;
37
+ break;
38
+ case "InvokeContract":
39
+ (txByType as { InvokeContract: TransactionResponse }).InvokeContract = currentTx;
40
+ break;
41
+ case "Fee":
42
+ (txByType as { Fee?: TransactionResponse }).Fee = currentTx;
43
+ break;
44
+ default:
45
+ log("warn", `tx type [${txType}] on tx cid [${txCid}] was not recognized.`);
46
+ break;
47
+ }
48
+
49
+ txsByTxCidResult[txCid] = txByType;
50
+ return txsByTxCidResult;
51
+ }, {});
52
+
53
+ // Once all tx types have been grouped, we want to find
54
+ const processedTxs: TransactionResponse[] = [];
55
+ for (const txCid in txsByTxCid) {
56
+ const item = txsByTxCid[txCid];
57
+ const feeTx = item.Fee;
58
+ let mainTx: TransactionResponse | undefined;
59
+ if ("Send" in item) {
60
+ mainTx = item.Send;
61
+ } else if ("InvokeContract" in item) {
62
+ mainTx = item.InvokeContract;
63
+ } else {
64
+ log(
65
+ "warn",
66
+ `unexpected tx type, tx with cid [${txCid}] and payload [${JSON.stringify(item)}]`,
67
+ );
68
+ }
69
+
70
+ if (!mainTx) {
71
+ if (feeTx) {
72
+ log("warn", `feeTx [${feeTx.hash}] found without a mainTx linked to it.`);
73
+ }
74
+
75
+ continue;
76
+ }
77
+
78
+ if (feeTx) {
79
+ mainTx.fee = feeTx.amount;
80
+ }
81
+
82
+ processedTxs.push(mainTx);
83
+ }
84
+
85
+ return processedTxs;
86
+ };
87
+
88
+ export const mapTxToOps =
89
+ (accountId: string, { address }: AccountShapeInfo) =>
90
+ (tx: TransactionResponse): Operation[] => {
91
+ const { to, from, hash, timestamp, amount, fee, status } = tx;
92
+ const ops: Operation[] = [];
93
+ const date = new Date(timestamp * 1000);
94
+ const value = parseCurrencyUnit(getUnit(), amount.toString());
95
+ const feeToUse = parseCurrencyUnit(getUnit(), (fee || 0).toString());
96
+
97
+ const isSending = address === from;
98
+ const isReceiving = address === to;
99
+ const hasFailed = status !== TxStatus.Ok;
100
+
101
+ if (isSending) {
102
+ const type = value.eq(0) ? "FEES" : "OUT";
103
+ ops.push({
104
+ id: encodeOperationId(accountId, hash, type),
105
+ hash,
106
+ type,
107
+ value: value.plus(feeToUse),
108
+ fee: feeToUse,
109
+ blockHeight: tx.height,
110
+ blockHash: null,
111
+ accountId,
112
+ senders: [from],
113
+ recipients: [to],
114
+ date,
115
+ extra: {},
116
+ hasFailed,
117
+ });
118
+ }
119
+
120
+ if (isReceiving) {
121
+ const type = value.eq(0) ? "FEES" : "IN";
122
+ ops.push({
123
+ id: encodeOperationId(accountId, hash, type),
124
+ hash,
125
+ type,
126
+ value,
127
+ fee: feeToUse,
128
+ blockHeight: tx.height,
129
+ blockHash: null,
130
+ accountId,
131
+ senders: [from],
132
+ recipients: [to],
133
+ date,
134
+ extra: {},
135
+ hasFailed,
136
+ });
137
+ }
138
+
139
+ return ops;
140
+ };
141
+
142
+ export const getAddress = (
143
+ a: Account,
144
+ ): {
145
+ address: string;
146
+ derivationPath: string;
147
+ } => ({ address: a.freshAddress, derivationPath: a.freshAddressPath });
148
+
149
+ export const getTxToBroadcast = (
150
+ operation: Operation,
151
+ signature: string,
152
+ rawData: Record<string, any>,
153
+ ): BroadcastTransactionRequest => {
154
+ const {
155
+ sender,
156
+ recipient,
157
+ gasLimit,
158
+ gasFeeCap,
159
+ gasPremium,
160
+ method,
161
+ version,
162
+ nonce,
163
+ signatureType,
164
+ params,
165
+ value,
166
+ } = rawData;
167
+
168
+ return {
169
+ message: {
170
+ version,
171
+ method,
172
+ nonce,
173
+ params: params ?? "",
174
+ to: recipient,
175
+ from: sender,
176
+ gaslimit: gasLimit.toNumber(),
177
+ gaspremium: gasPremium.toString(),
178
+ gasfeecap: gasFeeCap.toString(),
179
+ value,
180
+ },
181
+ signature: {
182
+ type: signatureType,
183
+ data: signature,
184
+ },
185
+ };
186
+ };
187
+
188
+ export const getAccountShape: GetAccountShape = async info => {
189
+ const { address, currency, derivationMode } = info;
190
+
191
+ const accountId = encodeAccountId({
192
+ type: "js",
193
+ version: "2",
194
+ currencyId: currency.id,
195
+ xpubOrAddress: address,
196
+ derivationMode,
197
+ });
198
+
199
+ const blockHeight = await fetchBlockHeight();
200
+ const balance = await fetchBalances(address);
201
+ const rawTxs = await fetchTxs(address);
202
+ const tokenAccounts = await buildTokenAccounts(address, accountId, info.initialAccount);
203
+
204
+ const result: Partial<Account> = {
205
+ id: accountId,
206
+ subAccounts: tokenAccounts,
207
+ balance: new BigNumber(balance.total_balance),
208
+ spendableBalance: new BigNumber(balance.spendable_balance),
209
+ operations: flatMap(processTxs(rawTxs), mapTxToOps(accountId, info)).sort(
210
+ (a, b) => b.date.getTime() - a.date.getTime(),
211
+ ),
212
+ blockHeight: blockHeight.current_block_identifier.index,
213
+ };
214
+ return result;
215
+ };
216
+
217
+ export const getSubAccount = (account: Account, tx: Transaction) => {
218
+ const subAccount =
219
+ tx.subAccountId && account.subAccounts
220
+ ? account.subAccounts.find(sa => sa.id === tx.subAccountId)
221
+ : null;
222
+
223
+ return subAccount;
224
+ };
225
+
226
+ /**
227
+ * convert a value in a given unit to a normalized value
228
+ * For instance, for 1 BTC, valueFromUnit(1, btcUnit) returns 100000000
229
+ * @memberof countervalue
230
+ */
231
+ export const valueFromUnit = (valueInUnit: BigNumber, unit: Unit) =>
232
+ valueInUnit.times(new BigNumber(10).pow(unit.magnitude));
@@ -0,0 +1,12 @@
1
+ [
2
+ {
3
+ "inputs": [
4
+ { "internalType": "address", "name": "recipient", "type": "address" },
5
+ { "internalType": "uint256", "name": "amount", "type": "uint256" }
6
+ ],
7
+ "name": "transfer",
8
+ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
9
+ "stateMutability": "nonpayable",
10
+ "type": "function"
11
+ }
12
+ ]
@@ -0,0 +1,183 @@
1
+ import cbor from "@zondax/cbor";
2
+ import { Account, Operation, TokenAccount } from "@ledgerhq/types-live";
3
+ import { fetchERC20TokenBalance, fetchERC20Transactions } from "../api";
4
+ import invariant from "invariant";
5
+ import { ERC20Transfer, TxStatus } from "../types";
6
+ import { emptyHistoryCache, encodeTokenAccountId } from "@ledgerhq/coin-framework/account/index";
7
+ import { findTokenByAddressInCurrency } from "@ledgerhq/cryptoassets/tokens";
8
+ import { log } from "@ledgerhq/logs";
9
+ import BigNumber from "bignumber.js";
10
+ import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
11
+ import { convertAddressFilToEth } from "../network";
12
+ import { ethers } from "ethers";
13
+ import contractABI from "./ERC20.json";
14
+ import { RecipientRequired } from "@ledgerhq/errors";
15
+ import { Unit } from "@ledgerhq/types-cryptoassets";
16
+ import { AccountType } from "../bridge/utils";
17
+ import { valueFromUnit } from "../common-logic/utils";
18
+
19
+ export const erc20TxnToOperation = (
20
+ tx: ERC20Transfer,
21
+ address: string,
22
+ accountId: string,
23
+ unit: Unit,
24
+ ): Operation[] => {
25
+ try {
26
+ const { to, from, timestamp, tx_hash, tx_cid, amount, height, status } = tx;
27
+ const value = valueFromUnit(new BigNumber(amount), unit);
28
+
29
+ const isSending = address.toLowerCase() === from.toLowerCase();
30
+ const isReceiving = address.toLowerCase() === to.toLowerCase();
31
+
32
+ const fee = new BigNumber(0);
33
+
34
+ const date = new Date(timestamp * 1000);
35
+ const hash = tx_cid ?? tx_hash;
36
+ const hasFailed = status !== TxStatus.Ok;
37
+
38
+ const ops: Operation[] = [];
39
+ if (isSending) {
40
+ ops.push({
41
+ id: encodeOperationId(accountId, hash, "OUT"),
42
+ hash,
43
+ type: "OUT",
44
+ value: value,
45
+ fee,
46
+ blockHeight: height,
47
+ blockHash: "",
48
+ accountId,
49
+ senders: [from],
50
+ recipients: [to],
51
+ date,
52
+ hasFailed,
53
+ extra: {},
54
+ });
55
+ }
56
+
57
+ if (isReceiving) {
58
+ ops.push({
59
+ id: encodeOperationId(accountId, hash, "IN"),
60
+ hash,
61
+ type: "IN",
62
+ value,
63
+ fee,
64
+ blockHeight: height,
65
+ blockHash: "",
66
+ accountId,
67
+ senders: [from],
68
+ recipients: [to],
69
+ date,
70
+ hasFailed,
71
+ extra: {},
72
+ });
73
+ }
74
+
75
+ invariant(ops, "filecoin operation is not defined");
76
+
77
+ return ops;
78
+ } catch (e) {
79
+ log("error", "filecoin error converting erc20 transaction to operation", e);
80
+ return [];
81
+ }
82
+ };
83
+
84
+ export async function buildTokenAccounts(
85
+ filAddr: string,
86
+ parentAccountId: string,
87
+ initialAccount?: Account,
88
+ ): Promise<TokenAccount[]> {
89
+ try {
90
+ const transfers = await fetchERC20Transactions(filAddr);
91
+ const transfersUntangled: { [addr: string]: ERC20Transfer[] } = transfers.reduce(
92
+ (prev: { [addr: string]: ERC20Transfer[] }, curr: ERC20Transfer) => {
93
+ curr.contract_address = curr.contract_address.toLowerCase();
94
+ if (prev[curr.contract_address]) {
95
+ prev[curr.contract_address] = [...prev[curr.contract_address], curr];
96
+ } else {
97
+ prev[curr.contract_address] = [curr];
98
+ }
99
+ return prev;
100
+ },
101
+ {},
102
+ );
103
+
104
+ const subs: TokenAccount[] = [];
105
+ for (const [cAddr, txns] of Object.entries(transfersUntangled)) {
106
+ const token = findTokenByAddressInCurrency(cAddr, "filecoin");
107
+ if (!token) {
108
+ log("error", `filecoin token not found, addr: ${cAddr}`);
109
+ continue;
110
+ }
111
+
112
+ const balance = await fetchERC20TokenBalance(filAddr, cAddr);
113
+ const bnBalance = new BigNumber(balance.toString());
114
+ const tokenAccountId = encodeTokenAccountId(parentAccountId, token);
115
+
116
+ const operations = txns
117
+ .flatMap(txn => erc20TxnToOperation(txn, filAddr, tokenAccountId, token.units[0]))
118
+ .flat()
119
+ .sort((a, b) => b.date.getTime() - a.date.getTime());
120
+
121
+ if (operations.length === 0 && bnBalance.isZero()) {
122
+ continue;
123
+ }
124
+
125
+ const maybeExistingSubAccount =
126
+ initialAccount &&
127
+ initialAccount.subAccounts &&
128
+ initialAccount.subAccounts.find(a => a.id === tokenAccountId);
129
+
130
+ const sub: TokenAccount = {
131
+ type: AccountType.TokenAccount,
132
+ id: tokenAccountId,
133
+ parentId: parentAccountId,
134
+ token,
135
+ balance: bnBalance,
136
+ spendableBalance: bnBalance,
137
+ operationsCount: txns.length,
138
+ operations,
139
+ pendingOperations: maybeExistingSubAccount ? maybeExistingSubAccount.pendingOperations : [],
140
+ creationDate: operations.length > 0 ? operations[0].date : new Date(),
141
+ swapHistory: maybeExistingSubAccount ? maybeExistingSubAccount.swapHistory : [],
142
+ balanceHistoryCache: emptyHistoryCache, // calculated in the jsHelpers
143
+ };
144
+
145
+ subs.push(sub);
146
+ }
147
+
148
+ return subs;
149
+ } catch (e) {
150
+ log("error", "filecoin error building token accounts", e);
151
+ return [];
152
+ }
153
+ }
154
+
155
+ export const encodeTxnParams = (abiEncodedParams: string) => {
156
+ log("debug", `filecoin/abiEncodedParams: ${abiEncodedParams}`);
157
+ if (!abiEncodedParams) {
158
+ throw new Error("Cannot encode empty abi encoded params");
159
+ }
160
+
161
+ const buffer = Buffer.from(abiEncodedParams.slice(2), "hex"); // buffer/byte array
162
+ const dataEncoded = cbor.encode(buffer);
163
+
164
+ return dataEncoded.toString("base64");
165
+ };
166
+
167
+ export const abiEncodeTransferParams = (recipient: string, amount: string) => {
168
+ const contract = new ethers.utils.Interface(contractABI);
169
+ const data = contract.encodeFunctionData("transfer", [recipient, amount]);
170
+ return data;
171
+ };
172
+
173
+ export const generateTokenTxnParams = (recipient: string, amount: BigNumber) => {
174
+ log("debug", "generateTokenTxnParams", { recipient, amount: amount.toString() });
175
+
176
+ if (!recipient) {
177
+ throw new RecipientRequired();
178
+ }
179
+
180
+ recipient = convertAddressFilToEth(recipient);
181
+
182
+ return abiEncodeTransferParams(recipient, amount.toString());
183
+ };