@ledgerhq/coin-casper 1.4.0-next.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 +49 -0
  3. package/CHANGELOG.md +15 -0
  4. package/LICENSE.txt +21 -0
  5. package/jest.config.js +8 -0
  6. package/lib/api/index.d.ts +11 -0
  7. package/lib/api/index.d.ts.map +1 -0
  8. package/lib/api/index.js +129 -0
  9. package/lib/api/index.js.map +1 -0
  10. package/lib/api/types.d.ts +105 -0
  11. package/lib/api/types.d.ts.map +1 -0
  12. package/lib/api/types.js +3 -0
  13. package/lib/api/types.js.map +1 -0
  14. package/lib/bridge/bridgeHelpers/accountShape.d.ts +3 -0
  15. package/lib/bridge/bridgeHelpers/accountShape.d.ts.map +1 -0
  16. package/lib/bridge/bridgeHelpers/accountShape.js +38 -0
  17. package/lib/bridge/bridgeHelpers/accountShape.js.map +1 -0
  18. package/lib/bridge/bridgeHelpers/addresses.d.ts +18 -0
  19. package/lib/bridge/bridgeHelpers/addresses.d.ts.map +1 -0
  20. package/lib/bridge/bridgeHelpers/addresses.js +83 -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/transferId.d.ts +2 -0
  27. package/lib/bridge/bridgeHelpers/transferId.d.ts.map +1 -0
  28. package/lib/bridge/bridgeHelpers/transferId.js +14 -0
  29. package/lib/bridge/bridgeHelpers/transferId.js.map +1 -0
  30. package/lib/bridge/bridgeHelpers/txn.d.ts +9 -0
  31. package/lib/bridge/bridgeHelpers/txn.d.ts.map +1 -0
  32. package/lib/bridge/bridgeHelpers/txn.js +100 -0
  33. package/lib/bridge/bridgeHelpers/txn.js.map +1 -0
  34. package/lib/bridge/broadcast.d.ts +4 -0
  35. package/lib/bridge/broadcast.d.ts.map +1 -0
  36. package/lib/bridge/broadcast.js +15 -0
  37. package/lib/bridge/broadcast.js.map +1 -0
  38. package/lib/bridge/buildOptimisticOperation.d.ts +4 -0
  39. package/lib/bridge/buildOptimisticOperation.d.ts.map +1 -0
  40. package/lib/bridge/buildOptimisticOperation.js +27 -0
  41. package/lib/bridge/buildOptimisticOperation.js.map +1 -0
  42. package/lib/bridge/createTransaction.d.ts +4 -0
  43. package/lib/bridge/createTransaction.d.ts.map +1 -0
  44. package/lib/bridge/createTransaction.js +19 -0
  45. package/lib/bridge/createTransaction.js.map +1 -0
  46. package/lib/bridge/deviceTransactionConfig.d.ts +18 -0
  47. package/lib/bridge/deviceTransactionConfig.d.ts.map +1 -0
  48. package/lib/bridge/deviceTransactionConfig.js +26 -0
  49. package/lib/bridge/deviceTransactionConfig.js.map +1 -0
  50. package/lib/bridge/estimateMaxSpendable.d.ts +4 -0
  51. package/lib/bridge/estimateMaxSpendable.d.ts.map +1 -0
  52. package/lib/bridge/estimateMaxSpendable.js +23 -0
  53. package/lib/bridge/estimateMaxSpendable.js.map +1 -0
  54. package/lib/bridge/getTransactionStatus.d.ts +4 -0
  55. package/lib/bridge/getTransactionStatus.d.ts.map +1 -0
  56. package/lib/bridge/getTransactionStatus.js +75 -0
  57. package/lib/bridge/getTransactionStatus.js.map +1 -0
  58. package/lib/bridge/index.d.ts +8 -0
  59. package/lib/bridge/index.d.ts.map +1 -0
  60. package/lib/bridge/index.js +54 -0
  61. package/lib/bridge/index.js.map +1 -0
  62. package/lib/bridge/prepareTransaction.d.ts +4 -0
  63. package/lib/bridge/prepareTransaction.d.ts.map +1 -0
  64. package/lib/bridge/prepareTransaction.js +16 -0
  65. package/lib/bridge/prepareTransaction.js.map +1 -0
  66. package/lib/bridge/signOperation.d.ts +6 -0
  67. package/lib/bridge/signOperation.d.ts.map +1 -0
  68. package/lib/bridge/signOperation.js +47 -0
  69. package/lib/bridge/signOperation.js.map +1 -0
  70. package/lib/bridge/transaction.d.ts +14 -0
  71. package/lib/bridge/transaction.d.ts.map +1 -0
  72. package/lib/bridge/transaction.js +53 -0
  73. package/lib/bridge/transaction.js.map +1 -0
  74. package/lib/common-logic/index.d.ts +2 -0
  75. package/lib/common-logic/index.d.ts.map +1 -0
  76. package/lib/common-logic/index.js +13 -0
  77. package/lib/common-logic/index.js.map +1 -0
  78. package/lib/common-logic/utils.d.ts +14 -0
  79. package/lib/common-logic/utils.d.ts.map +1 -0
  80. package/lib/common-logic/utils.js +53 -0
  81. package/lib/common-logic/utils.js.map +1 -0
  82. package/lib/common-logic/utils.unit.test.d.ts +2 -0
  83. package/lib/common-logic/utils.unit.test.d.ts.map +1 -0
  84. package/lib/common-logic/utils.unit.test.js +50 -0
  85. package/lib/common-logic/utils.unit.test.js.map +1 -0
  86. package/lib/consts.d.ts +10 -0
  87. package/lib/consts.d.ts.map +1 -0
  88. package/lib/consts.js +18 -0
  89. package/lib/consts.js.map +1 -0
  90. package/lib/errors.d.ts +10 -0
  91. package/lib/errors.d.ts.map +1 -0
  92. package/lib/errors.js +8 -0
  93. package/lib/errors.js.map +1 -0
  94. package/lib/hw-signMessage.d.ts +23 -0
  95. package/lib/hw-signMessage.d.ts.map +1 -0
  96. package/lib/hw-signMessage.js +24 -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 +25 -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 +110 -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 +177 -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 +30 -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 +53 -0
  125. package/lib/test/speculos-deviceActions.js.map +1 -0
  126. package/lib/types/common.d.ts +23 -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 +21 -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/index.d.ts +11 -0
  139. package/lib-es/api/index.d.ts.map +1 -0
  140. package/lib-es/api/index.js +118 -0
  141. package/lib-es/api/index.js.map +1 -0
  142. package/lib-es/api/types.d.ts +105 -0
  143. package/lib-es/api/types.d.ts.map +1 -0
  144. package/lib-es/api/types.js +2 -0
  145. package/lib-es/api/types.js.map +1 -0
  146. package/lib-es/bridge/bridgeHelpers/accountShape.d.ts +3 -0
  147. package/lib-es/bridge/bridgeHelpers/accountShape.d.ts.map +1 -0
  148. package/lib-es/bridge/bridgeHelpers/accountShape.js +31 -0
  149. package/lib-es/bridge/bridgeHelpers/accountShape.js.map +1 -0
  150. package/lib-es/bridge/bridgeHelpers/addresses.d.ts +18 -0
  151. package/lib-es/bridge/bridgeHelpers/addresses.d.ts.map +1 -0
  152. package/lib-es/bridge/bridgeHelpers/addresses.js +74 -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/transferId.d.ts +2 -0
  159. package/lib-es/bridge/bridgeHelpers/transferId.d.ts.map +1 -0
  160. package/lib-es/bridge/bridgeHelpers/transferId.js +10 -0
  161. package/lib-es/bridge/bridgeHelpers/transferId.js.map +1 -0
  162. package/lib-es/bridge/bridgeHelpers/txn.d.ts +9 -0
  163. package/lib-es/bridge/bridgeHelpers/txn.d.ts.map +1 -0
  164. package/lib-es/bridge/bridgeHelpers/txn.js +91 -0
  165. package/lib-es/bridge/bridgeHelpers/txn.js.map +1 -0
  166. package/lib-es/bridge/broadcast.d.ts +4 -0
  167. package/lib-es/bridge/broadcast.d.ts.map +1 -0
  168. package/lib-es/bridge/broadcast.js +11 -0
  169. package/lib-es/bridge/broadcast.js.map +1 -0
  170. package/lib-es/bridge/buildOptimisticOperation.d.ts +4 -0
  171. package/lib-es/bridge/buildOptimisticOperation.d.ts.map +1 -0
  172. package/lib-es/bridge/buildOptimisticOperation.js +23 -0
  173. package/lib-es/bridge/buildOptimisticOperation.js.map +1 -0
  174. package/lib-es/bridge/createTransaction.d.ts +4 -0
  175. package/lib-es/bridge/createTransaction.d.ts.map +1 -0
  176. package/lib-es/bridge/createTransaction.js +12 -0
  177. package/lib-es/bridge/createTransaction.js.map +1 -0
  178. package/lib-es/bridge/deviceTransactionConfig.d.ts +18 -0
  179. package/lib-es/bridge/deviceTransactionConfig.d.ts.map +1 -0
  180. package/lib-es/bridge/deviceTransactionConfig.js +24 -0
  181. package/lib-es/bridge/deviceTransactionConfig.js.map +1 -0
  182. package/lib-es/bridge/estimateMaxSpendable.d.ts +4 -0
  183. package/lib-es/bridge/estimateMaxSpendable.d.ts.map +1 -0
  184. package/lib-es/bridge/estimateMaxSpendable.js +16 -0
  185. package/lib-es/bridge/estimateMaxSpendable.js.map +1 -0
  186. package/lib-es/bridge/getTransactionStatus.d.ts +4 -0
  187. package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -0
  188. package/lib-es/bridge/getTransactionStatus.js +68 -0
  189. package/lib-es/bridge/getTransactionStatus.js.map +1 -0
  190. package/lib-es/bridge/index.d.ts +8 -0
  191. package/lib-es/bridge/index.d.ts.map +1 -0
  192. package/lib-es/bridge/index.js +47 -0
  193. package/lib-es/bridge/index.js.map +1 -0
  194. package/lib-es/bridge/prepareTransaction.d.ts +4 -0
  195. package/lib-es/bridge/prepareTransaction.d.ts.map +1 -0
  196. package/lib-es/bridge/prepareTransaction.js +12 -0
  197. package/lib-es/bridge/prepareTransaction.js.map +1 -0
  198. package/lib-es/bridge/signOperation.d.ts +6 -0
  199. package/lib-es/bridge/signOperation.d.ts.map +1 -0
  200. package/lib-es/bridge/signOperation.js +43 -0
  201. package/lib-es/bridge/signOperation.js.map +1 -0
  202. package/lib-es/bridge/transaction.d.ts +14 -0
  203. package/lib-es/bridge/transaction.d.ts.map +1 -0
  204. package/lib-es/bridge/transaction.js +45 -0
  205. package/lib-es/bridge/transaction.js.map +1 -0
  206. package/lib-es/common-logic/index.d.ts +2 -0
  207. package/lib-es/common-logic/index.d.ts.map +1 -0
  208. package/lib-es/common-logic/index.js +2 -0
  209. package/lib-es/common-logic/index.js.map +1 -0
  210. package/lib-es/common-logic/utils.d.ts +14 -0
  211. package/lib-es/common-logic/utils.d.ts.map +1 -0
  212. package/lib-es/common-logic/utils.js +39 -0
  213. package/lib-es/common-logic/utils.js.map +1 -0
  214. package/lib-es/common-logic/utils.unit.test.d.ts +2 -0
  215. package/lib-es/common-logic/utils.unit.test.d.ts.map +1 -0
  216. package/lib-es/common-logic/utils.unit.test.js +48 -0
  217. package/lib-es/common-logic/utils.unit.test.js.map +1 -0
  218. package/lib-es/consts.d.ts +10 -0
  219. package/lib-es/consts.d.ts.map +1 -0
  220. package/lib-es/consts.js +15 -0
  221. package/lib-es/consts.js.map +1 -0
  222. package/lib-es/errors.d.ts +10 -0
  223. package/lib-es/errors.d.ts.map +1 -0
  224. package/lib-es/errors.js +5 -0
  225. package/lib-es/errors.js.map +1 -0
  226. package/lib-es/hw-signMessage.d.ts +23 -0
  227. package/lib-es/hw-signMessage.d.ts.map +1 -0
  228. package/lib-es/hw-signMessage.js +20 -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 +23 -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 +105 -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 +171 -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 +24 -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 +50 -0
  257. package/lib-es/test/speculos-deviceActions.js.map +1 -0
  258. package/lib-es/types/common.d.ts +23 -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 +21 -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 +127 -0
  271. package/src/api/index.ts +166 -0
  272. package/src/api/types.ts +113 -0
  273. package/src/bridge/bridgeHelpers/accountShape.ts +39 -0
  274. package/src/bridge/bridgeHelpers/addresses.ts +94 -0
  275. package/src/bridge/bridgeHelpers/fee.ts +6 -0
  276. package/src/bridge/bridgeHelpers/transferId.ts +9 -0
  277. package/src/bridge/bridgeHelpers/txn.ts +121 -0
  278. package/src/bridge/broadcast.ts +18 -0
  279. package/src/bridge/buildOptimisticOperation.ts +31 -0
  280. package/src/bridge/createTransaction.ts +15 -0
  281. package/src/bridge/deviceTransactionConfig.ts +46 -0
  282. package/src/bridge/estimateMaxSpendable.ts +26 -0
  283. package/src/bridge/getTransactionStatus.ts +96 -0
  284. package/src/bridge/index.ts +65 -0
  285. package/src/bridge/prepareTransaction.ts +19 -0
  286. package/src/bridge/signOperation.ts +73 -0
  287. package/src/bridge/transaction.ts +61 -0
  288. package/src/common-logic/index.ts +10 -0
  289. package/src/common-logic/utils.ts +53 -0
  290. package/src/common-logic/utils.unit.test.ts +75 -0
  291. package/src/consts.ts +18 -0
  292. package/src/errors.ts +5 -0
  293. package/src/hw-signMessage.ts +30 -0
  294. package/src/signer/getAddress.ts +31 -0
  295. package/src/signer/index.ts +3 -0
  296. package/src/test/bot-specs.ts +127 -0
  297. package/src/test/bridgeDatasetTest.ts +178 -0
  298. package/src/test/cli.ts +36 -0
  299. package/src/test/index.ts +3 -0
  300. package/src/test/speculos-deviceActions.ts +54 -0
  301. package/src/types/common.ts +38 -0
  302. package/src/types/index.ts +2 -0
  303. package/src/types/signer.ts +20 -0
  304. package/tsconfig.json +15 -0
@@ -0,0 +1,31 @@
1
+ import { OperationType } from "@ledgerhq/types-live";
2
+ import { getAddress } from "./bridgeHelpers/addresses";
3
+ import { CasperAccount, CasperOperation, Transaction } from "../types";
4
+ import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
5
+
6
+ export const buildOptimisticOperation = (
7
+ account: CasperAccount,
8
+ transaction: Transaction,
9
+ hash: string,
10
+ operationType: OperationType = "OUT",
11
+ ): CasperOperation => {
12
+ const { id: accountId } = account;
13
+ const { address } = getAddress(account);
14
+
15
+ return {
16
+ id: encodeOperationId(accountId, hash, operationType),
17
+ hash,
18
+ type: operationType,
19
+ senders: [address],
20
+ recipients: [transaction.recipient],
21
+ accountId,
22
+ value: transaction.amount.plus(transaction.fees),
23
+ fee: transaction.fees,
24
+ blockHash: null,
25
+ blockHeight: null,
26
+ date: new Date(),
27
+ extra: {
28
+ transferId: transaction.transferId,
29
+ },
30
+ };
31
+ };
@@ -0,0 +1,15 @@
1
+ import BigNumber from "bignumber.js";
2
+ import { AccountBridge } from "@ledgerhq/types-live";
3
+ import { Transaction } from "../types";
4
+
5
+ export const createTransaction: AccountBridge<Transaction>["createTransaction"] = () => {
6
+ // log("debug", "[createTransaction] creating base tx");
7
+
8
+ return {
9
+ family: "casper",
10
+ amount: new BigNumber(0),
11
+ fees: new BigNumber(0),
12
+ recipient: "",
13
+ useAllAmount: false,
14
+ };
15
+ };
@@ -0,0 +1,46 @@
1
+ import { log } from "@ledgerhq/logs";
2
+ import { Account, AccountLike } from "@ledgerhq/types-live";
3
+ import type { CommonDeviceTransactionField } from "@ledgerhq/coin-framework/transaction/common";
4
+ import { Transaction, TransactionStatus } from "../types";
5
+ import { methodToString } from "../common-logic";
6
+ import BigNumber from "bignumber.js";
7
+
8
+ export type ExtraDeviceTransactionField = {
9
+ type: "casper.extendedAmount";
10
+ label: string;
11
+ value: number | BigNumber;
12
+ };
13
+
14
+ type DeviceTransactionField = CommonDeviceTransactionField | ExtraDeviceTransactionField;
15
+
16
+ function getDeviceTransactionConfig({
17
+ transaction,
18
+ }: {
19
+ account: AccountLike;
20
+ parentAccount: Account | null | undefined;
21
+ transaction: Transaction;
22
+ status: TransactionStatus;
23
+ }): Array<DeviceTransactionField> {
24
+ const fields: Array<DeviceTransactionField> = [];
25
+ fields.push({
26
+ type: "text",
27
+ label: "Type",
28
+ value: methodToString(0),
29
+ });
30
+ fields.push({
31
+ type: "casper.extendedAmount",
32
+ label: "Fee",
33
+ value: transaction.fees,
34
+ });
35
+ fields.push({
36
+ type: "casper.extendedAmount",
37
+ label: "Amount",
38
+ value: transaction.amount,
39
+ });
40
+
41
+ log("debug", `Transaction config ${JSON.stringify(fields)}`);
42
+
43
+ return fields;
44
+ }
45
+
46
+ export default getDeviceTransactionConfig;
@@ -0,0 +1,26 @@
1
+ import BigNumber from "bignumber.js";
2
+ import { AccountBridge } from "@ledgerhq/types-live";
3
+ import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
4
+ import { getEstimatedFees } from "./bridgeHelpers/fee";
5
+ import { Transaction } from "../types";
6
+
7
+ export const estimateMaxSpendable: AccountBridge<Transaction>["estimateMaxSpendable"] = async ({
8
+ account,
9
+ parentAccount,
10
+ transaction,
11
+ }) => {
12
+ const mainAccount = getMainAccount(account, parentAccount);
13
+ let balance = mainAccount.spendableBalance;
14
+
15
+ if (balance.eq(0)) return balance;
16
+
17
+ const estimatedFees = transaction?.fees ?? getEstimatedFees();
18
+
19
+ if (balance.lte(estimatedFees)) return new BigNumber(0);
20
+
21
+ balance = balance.minus(estimatedFees);
22
+
23
+ // log("debug", "[estimateMaxSpendable] finish fn");
24
+
25
+ return balance;
26
+ };
@@ -0,0 +1,96 @@
1
+ import BigNumber from "bignumber.js";
2
+ import { AccountBridge } from "@ledgerhq/types-live";
3
+ import {
4
+ AmountRequired,
5
+ InvalidAddress,
6
+ InvalidAddressBecauseDestinationIsAlsoSource,
7
+ NotEnoughBalance,
8
+ RecipientRequired,
9
+ } from "@ledgerhq/errors";
10
+ import { getAddress, isAddressValid } from "./bridgeHelpers/addresses";
11
+ import { CasperAccount, Transaction, TransactionStatus } from "../types";
12
+ import { isTransferIdValid } from "./bridgeHelpers/transferId";
13
+ import { CasperInvalidTransferId } from "../errors";
14
+ import {
15
+ CASPER_MINIMUM_VALID_AMOUNT_MOTES,
16
+ CASPER_MAX_TRANSFER_ID,
17
+ MayBlockAccountError,
18
+ InvalidMinimumAmountError,
19
+ } from "../consts";
20
+
21
+ export const getTransactionStatus: AccountBridge<
22
+ Transaction,
23
+ CasperAccount,
24
+ TransactionStatus
25
+ >["getTransactionStatus"] = async (account, transaction) => {
26
+ const errors: TransactionStatus["errors"] = {};
27
+ const warnings: TransactionStatus["warnings"] = {};
28
+
29
+ const { balance, spendableBalance } = account;
30
+ const { address } = getAddress(account);
31
+ const { recipient, useAllAmount } = transaction;
32
+ let { amount } = transaction;
33
+
34
+ if (!recipient) {
35
+ errors.recipient = new RecipientRequired();
36
+ } else if (!isAddressValid(recipient)) {
37
+ errors.recipient = new InvalidAddress("", {
38
+ currencyName: account.currency.name,
39
+ });
40
+ } else if (recipient.toLowerCase() === address.toLowerCase()) {
41
+ errors.recipient = new InvalidAddressBecauseDestinationIsAlsoSource();
42
+ }
43
+
44
+ if (!isAddressValid(address)) {
45
+ errors.sender = new InvalidAddress("", {
46
+ currencyName: account.currency.name,
47
+ });
48
+ } else if (!isTransferIdValid(transaction.transferId)) {
49
+ errors.sender = new CasperInvalidTransferId("", {
50
+ maxTransferId: CASPER_MAX_TRANSFER_ID,
51
+ });
52
+ }
53
+
54
+ const estimatedFees = transaction.fees;
55
+
56
+ let totalSpent = new BigNumber(0);
57
+
58
+ if (useAllAmount) {
59
+ totalSpent = account.spendableBalance;
60
+ amount = totalSpent.minus(estimatedFees);
61
+ if (amount.lte(0) || totalSpent.gt(balance)) {
62
+ errors.amount = new NotEnoughBalance();
63
+ }
64
+ }
65
+
66
+ if (!useAllAmount) {
67
+ totalSpent = amount.plus(estimatedFees);
68
+ if (amount.eq(0)) {
69
+ errors.amount = new AmountRequired();
70
+ }
71
+
72
+ if (totalSpent.gt(account.spendableBalance)) {
73
+ errors.amount = new NotEnoughBalance();
74
+ }
75
+ }
76
+
77
+ if (amount.lt(CASPER_MINIMUM_VALID_AMOUNT_MOTES) && !errors.amount) {
78
+ errors.amount = InvalidMinimumAmountError;
79
+ }
80
+
81
+ if (
82
+ spendableBalance.minus(totalSpent).minus(estimatedFees).lt(CASPER_MINIMUM_VALID_AMOUNT_MOTES)
83
+ ) {
84
+ warnings.amount = MayBlockAccountError;
85
+ }
86
+
87
+ // log("debug", "[getTransactionStatus] finish fn");
88
+
89
+ return {
90
+ errors,
91
+ warnings,
92
+ estimatedFees,
93
+ amount,
94
+ totalSpent,
95
+ };
96
+ };
@@ -0,0 +1,65 @@
1
+ import {
2
+ getSerializedAddressParameters,
3
+ makeAccountBridgeReceive,
4
+ makeScanAccounts,
5
+ makeSync,
6
+ updateTransaction,
7
+ } from "@ledgerhq/coin-framework/bridge/jsHelpers";
8
+ import resolver from "../signer";
9
+ import getAddressWrapper from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
10
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
11
+ import type { Account, AccountBridge, CurrencyBridge } from "@ledgerhq/types-live";
12
+ import type { Transaction, TransactionStatus, CasperSigner } from "../types";
13
+ import { getTransactionStatus } from "./getTransactionStatus";
14
+ import { estimateMaxSpendable } from "./estimateMaxSpendable";
15
+ import { prepareTransaction } from "./prepareTransaction";
16
+ import { createTransaction } from "./createTransaction";
17
+ import { getAccountShape } from "./bridgeHelpers/accountShape";
18
+ import { buildSignOperation } from "./signOperation";
19
+ import { broadcast } from "./broadcast";
20
+
21
+ function buildCurrencyBridge(signerContext: SignerContext<CasperSigner>): CurrencyBridge {
22
+ const getAddress = resolver(signerContext);
23
+
24
+ const scanAccounts = makeScanAccounts({
25
+ getAccountShape,
26
+ getAddressFn: getAddressWrapper(getAddress),
27
+ });
28
+
29
+ return {
30
+ preload: () => Promise.resolve({}),
31
+ hydrate: () => {},
32
+ scanAccounts,
33
+ };
34
+ }
35
+
36
+ const sync = makeSync({ getAccountShape });
37
+
38
+ function buildAccountBridge(
39
+ signerContext: SignerContext<CasperSigner>,
40
+ ): AccountBridge<Transaction, Account, TransactionStatus> {
41
+ const getAddress = resolver(signerContext);
42
+
43
+ const receive = makeAccountBridgeReceive(getAddressWrapper(getAddress));
44
+ const signOperation = buildSignOperation(signerContext);
45
+
46
+ return {
47
+ estimateMaxSpendable,
48
+ createTransaction,
49
+ updateTransaction,
50
+ getTransactionStatus,
51
+ prepareTransaction,
52
+ sync,
53
+ receive,
54
+ signOperation,
55
+ broadcast,
56
+ getSerializedAddressParameters,
57
+ };
58
+ }
59
+
60
+ export function createBridges(signerContext: SignerContext<CasperSigner>) {
61
+ return {
62
+ currencyBridge: buildCurrencyBridge(signerContext),
63
+ accountBridge: buildAccountBridge(signerContext),
64
+ };
65
+ }
@@ -0,0 +1,19 @@
1
+ import { AccountBridge } from "@ledgerhq/types-live";
2
+ import { updateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers";
3
+ import { getEstimatedFees } from "./bridgeHelpers/fee";
4
+ import { Transaction } from "../types";
5
+
6
+ export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"] = async (
7
+ account,
8
+ transaction,
9
+ ): Promise<Transaction> => {
10
+ // log("debug", "[prepareTransaction] start fn");
11
+ const fees = getEstimatedFees();
12
+
13
+ const amount = transaction.useAllAmount
14
+ ? account.spendableBalance.minus(transaction.fees)
15
+ : transaction.amount;
16
+
17
+ // log("debug", "[prepareTransaction] finish fn");
18
+ return updateTransaction(transaction, { fees, amount });
19
+ };
@@ -0,0 +1,73 @@
1
+ import { Observable } from "rxjs";
2
+ import { log } from "@ledgerhq/logs";
3
+ import { DeployUtil } from "casper-js-sdk";
4
+ import { Account, AccountBridge } from "@ledgerhq/types-live";
5
+ import { casperGetCLPublicKey, getAddress } from "../bridge/bridgeHelpers/addresses";
6
+ import { createNewDeploy } from "../bridge/bridgeHelpers/txn";
7
+ import { Transaction } from "../types";
8
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
9
+ import { CasperSigner } from "../types";
10
+ import { buildOptimisticOperation } from "./buildOptimisticOperation";
11
+
12
+ export const buildSignOperation =
13
+ (
14
+ signerContext: SignerContext<CasperSigner>,
15
+ ): AccountBridge<Transaction, Account>["signOperation"] =>
16
+ ({ account, transaction, deviceId }) =>
17
+ new Observable(o => {
18
+ async function main() {
19
+ // log("debug", "[signOperation] start fn");
20
+
21
+ const { recipient } = transaction;
22
+ const { address, derivationPath } = getAddress(account);
23
+ const deploy = createNewDeploy(
24
+ address,
25
+ recipient,
26
+ transaction.amount,
27
+ transaction.fees,
28
+ transaction.transferId,
29
+ );
30
+
31
+ // Serialize tx
32
+ const deployBytes = DeployUtil.deployToBytes(deploy);
33
+ log("debug", `[signOperation] serialized deploy: [${deployBytes.toString()}]`);
34
+ o.next({
35
+ type: "device-signature-requested",
36
+ });
37
+
38
+ // Sign by device
39
+ const { r } = await signerContext(deviceId, async signer => {
40
+ const r = await signer.sign(derivationPath, Buffer.from(deployBytes));
41
+ return { r };
42
+ });
43
+
44
+ o.next({
45
+ type: "device-signature-granted",
46
+ });
47
+
48
+ // signature verification
49
+ const deployHash = deploy.hash.toString();
50
+ const signature = r.signatureRS;
51
+
52
+ // sign deploy object
53
+ const signedDeploy = DeployUtil.setSignature(
54
+ deploy,
55
+ signature,
56
+ casperGetCLPublicKey(address),
57
+ );
58
+
59
+ const operation = buildOptimisticOperation(account, transaction, deployHash);
60
+
61
+ o.next({
62
+ type: "signed",
63
+ signedOperation: {
64
+ operation,
65
+ signature: JSON.stringify(DeployUtil.deployToJson(signedDeploy)),
66
+ },
67
+ });
68
+ }
69
+ main().then(
70
+ () => o.complete(),
71
+ e => o.error(e),
72
+ );
73
+ });
@@ -0,0 +1,61 @@
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
+ fees: new BigNumber(tr.fees),
37
+ amount: new BigNumber(tr.amount),
38
+ transferId: tr.transferId,
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
+ transferId: t.transferId,
51
+ };
52
+ };
53
+
54
+ export default {
55
+ formatTransaction,
56
+ fromTransactionRaw,
57
+ toTransactionRaw,
58
+ fromTransactionStatusRaw,
59
+ toTransactionStatusRaw,
60
+ formatTransactionStatus,
61
+ };
@@ -0,0 +1,10 @@
1
+ export {
2
+ isNoErrorReturnCode,
3
+ getPath,
4
+ isValidHex,
5
+ isValidBase64,
6
+ isError,
7
+ methodToString,
8
+ getBufferFromString,
9
+ getRandomTransferID,
10
+ } from "./utils";
@@ -0,0 +1,53 @@
1
+ import BigNumber from "bignumber.js";
2
+
3
+ const validHexRegExp = new RegExp(/[0-9A-Fa-f]{6}/g);
4
+ const validBase64RegExp = new RegExp(
5
+ /^(?:[A-Za-z\d+/]{4})*(?:[A-Za-z\d+/]{3}=|[A-Za-z\d+/]{2}==)?$/,
6
+ );
7
+
8
+ export const isNoErrorReturnCode = (code: number): boolean => code === 0x9000;
9
+
10
+ export const getPath = (path: string): string =>
11
+ path && path.substring(0, 2) !== "m/" ? `m/${path}` : path;
12
+
13
+ export const isValidHex = (msg: string): boolean => validHexRegExp.test(msg);
14
+ export const isValidBase64 = (msg: string): boolean => validBase64RegExp.test(msg);
15
+
16
+ export const isError = (r: { returnCode: number; errorMessage: string }): void => {
17
+ if (!isNoErrorReturnCode(r.returnCode)) throw new Error(`${r.returnCode} - ${r.errorMessage}`);
18
+ };
19
+
20
+ export const methodToString = (method: number): string => {
21
+ switch (method) {
22
+ case 0:
23
+ return "Token transfer";
24
+ default:
25
+ return "Unknown";
26
+ }
27
+ };
28
+
29
+ export const getBufferFromString = (message: string): Buffer => {
30
+ if (isValidHex(message)) {
31
+ return Buffer.from(message, "hex");
32
+ }
33
+
34
+ if (isValidBase64(message)) {
35
+ return Buffer.from(message, "base64");
36
+ }
37
+
38
+ return Buffer.from(message);
39
+ };
40
+
41
+ function randomIntFromInterval(min: number, max: number): string {
42
+ const minBig = new BigNumber(min);
43
+ const maxBig = new BigNumber(max);
44
+
45
+ const random = BigNumber.random().multipliedBy(maxBig.minus(minBig).plus(1)).plus(minBig);
46
+ const randomInt = random.integerValue(BigNumber.ROUND_FLOOR);
47
+
48
+ return randomInt.toString();
49
+ }
50
+
51
+ export function getRandomTransferID(): string {
52
+ return randomIntFromInterval(0, Number.MAX_SAFE_INTEGER);
53
+ }
@@ -0,0 +1,75 @@
1
+ import { CLPublicKeyTag } from "casper-js-sdk";
2
+ import { casperAddressFromPubKey, isAddressValid } from "../bridge/bridgeHelpers/addresses";
3
+
4
+ describe("Casper addresses", () => {
5
+ const pubKeys = {
6
+ // valid
7
+ validSecp256k1: "0203a17118ec0e64c4e4fdbdbee0ea14d118c9aaf08c6c81bbb776cae607ceb84ecb",
8
+ validEd25519: "016470ae57b0a3ad5a679d2e0422909bfb9ded445e20cbe6b4c9806f844c94d401",
9
+ validSecp256k1Checksum: "0203A17118eC0e64c4e4FdbDbEe0eA14D118C9aAf08C6c81bbB776Cae607cEB84EcB", // Checksummed
10
+ validEd25519Checksum: "016470AE57b0a3aD5A679d2e0422909Bfb9dEd445e20cbE6B4c9806f844c94d401", // Checksummed
11
+ // invalid
12
+ invalidSecp256k1: "0203A17118ec0e64c4e4fdbdbee0ea14d118c9aaf08c6c81bbc776cae607ceb84ecb",
13
+ invalidEd25519: "016470ae57b0a3ad5a679d2e0422909bfb9ded445e20cbe6b8c9806f844c94D401",
14
+ invalidAddresstype: "036470ae57b0a3ad5a679d2e0422909bfb9ded445e20cbe6b8c9806f844c94d401", // Invalid address type
15
+ invalidLength: "12345", // Invalid length
16
+ invalidCharacter: "xyz123", // Contains non-hex characters
17
+ invalidChecksum: "016470ae57b0a3ad5a679d2e0422909bfb9ded445e20cbe6b4c9806f844c94D400", // Invalid checksum
18
+ };
19
+
20
+ test("Check if valid addresses are valid", () => {
21
+ expect(isAddressValid(pubKeys.validEd25519)).toBe(true);
22
+ expect(isAddressValid(pubKeys.validSecp256k1)).toBe(true);
23
+ });
24
+
25
+ test("Check if invalid addresses are invalid", () => {
26
+ expect(isAddressValid(pubKeys.invalidEd25519)).toBe(false);
27
+ expect(isAddressValid(pubKeys.invalidSecp256k1)).toBe(false);
28
+ expect(isAddressValid(pubKeys.invalidLength)).toBe(false);
29
+ expect(isAddressValid(pubKeys.invalidCharacter)).toBe(false);
30
+ expect(isAddressValid(pubKeys.invalidChecksum)).toBe(false);
31
+ });
32
+
33
+ test("Get the address from the publick key", () => {
34
+ /**
35
+ * Extracts the public key and key signature from a given Casper address.
36
+ *
37
+ * @param {string} address - The Casper address from which to extract the public key and key signature.
38
+ * @returns {{ pubkey: Buffer, keySig: CLPublicKeyTag }} An object containing the public key as a Buffer and the key signature as a CLPublicKeyTag.
39
+ */
40
+ function casperPubKeyFromAddress(address: string): {
41
+ pubkey: Buffer;
42
+ keySig: CLPublicKeyTag;
43
+ } {
44
+ const keySig = parseInt(address.slice(0, 2), 10) as CLPublicKeyTag;
45
+ const pubkeyHex = address.slice(2);
46
+ const pubkey = Buffer.from(pubkeyHex, "hex");
47
+ return { pubkey, keySig };
48
+ }
49
+
50
+ expect(
51
+ casperAddressFromPubKey(
52
+ casperPubKeyFromAddress(pubKeys.validSecp256k1).pubkey,
53
+ CLPublicKeyTag.SECP256K1,
54
+ ),
55
+ ).toBe(pubKeys.validSecp256k1);
56
+ expect(
57
+ casperAddressFromPubKey(
58
+ casperPubKeyFromAddress(pubKeys.validSecp256k1Checksum).pubkey,
59
+ CLPublicKeyTag.SECP256K1,
60
+ ),
61
+ ).toBe(pubKeys.validSecp256k1Checksum.toLowerCase());
62
+ expect(
63
+ casperAddressFromPubKey(
64
+ casperPubKeyFromAddress(pubKeys.validEd25519).pubkey,
65
+ CLPublicKeyTag.ED25519,
66
+ ),
67
+ ).toBe(pubKeys.validEd25519);
68
+ expect(
69
+ casperAddressFromPubKey(
70
+ casperPubKeyFromAddress(pubKeys.validEd25519Checksum).pubkey,
71
+ CLPublicKeyTag.ED25519,
72
+ ),
73
+ ).toBe(pubKeys.validEd25519Checksum.toLowerCase());
74
+ });
75
+ });
package/src/consts.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { InvalidMinimumAmount, MayBlockAccount } from "./errors";
2
+
3
+ export const CASPER_FEES_MOTES = 0.1 * 1e9;
4
+ export const CASPER_FEES_CSPR = 0.1;
5
+ export const CASPER_MINIMUM_VALID_AMOUNT_MOTES = 2.5 * 1e9;
6
+ export const CASPER_MINIMUM_VALID_AMOUNT_CSPR = 2.5;
7
+ export const CASPER_NETWORK = "casper";
8
+ export const CASPER_CHECKSUM_HEX_LEN = 32;
9
+
10
+ export const CASPER_MAX_TRANSFER_ID = "18446744073709551615";
11
+
12
+ export const MayBlockAccountError = new MayBlockAccount("", {
13
+ minAmount: `${CASPER_MINIMUM_VALID_AMOUNT_CSPR + CASPER_FEES_CSPR} CSPR`,
14
+ });
15
+
16
+ export const InvalidMinimumAmountError = new InvalidMinimumAmount("", {
17
+ minAmount: `${CASPER_MINIMUM_VALID_AMOUNT_CSPR} CSPR`,
18
+ });
package/src/errors.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { createCustomErrorClass } from "@ledgerhq/errors";
2
+
3
+ export const CasperInvalidTransferId = createCustomErrorClass("CasperInvalidTransferId");
4
+ export const InvalidMinimumAmount = createCustomErrorClass("InvalidMinimumAmount");
5
+ export const MayBlockAccount = createCustomErrorClass("MayBlockAccount");
@@ -0,0 +1,30 @@
1
+ import { log } from "@ledgerhq/logs";
2
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
3
+ import { CasperSigner } from "./types";
4
+ import { getBufferFromString } from "./common-logic/utils";
5
+ import { Account, AnyMessage } from "@ledgerhq/types-live";
6
+
7
+ export const signMessage =
8
+ (signerContext: SignerContext<CasperSigner>) =>
9
+ async (deviceId: string, account: Account, { message }: AnyMessage) => {
10
+ log("debug", "start signMessage process");
11
+
12
+ if (!message) throw new Error(`Message cannot be empty`);
13
+ if (typeof message !== "string") throw new Error(`Signing EIP712Message not supported`);
14
+
15
+ const r = await signerContext(
16
+ deviceId,
17
+ async signer => await signer.sign(account.freshAddressPath, getBufferFromString(message)),
18
+ );
19
+
20
+ return {
21
+ rsv: {
22
+ r: Buffer.from(r.signature_compact.slice(0, 32)).toString("hex"),
23
+ s: Buffer.from(r.signature_compact.slice(32, 64)).toString("hex"),
24
+ v: parseInt(Buffer.from(r.signature_compact.slice(64, 65)).toString("hex"), 16),
25
+ },
26
+ signature: `0x${Buffer.from(r.signature_compact).toString("hex")}`,
27
+ };
28
+ };
29
+
30
+ export default { signMessage };
@@ -0,0 +1,31 @@
1
+ import { log } from "@ledgerhq/logs";
2
+ import { GetAddressFn } from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
3
+ import { GetAddressOptions } from "@ledgerhq/coin-framework/derivation";
4
+ import { SignerContext } from "@ledgerhq/coin-framework/signer";
5
+ import { CLPublicKeyTag } from "casper-js-sdk";
6
+ import { casperAddressFromPubKey } from "../bridge/bridgeHelpers/addresses";
7
+ import { CasperSigner } from "../types";
8
+
9
+ function resolver(signerContext: SignerContext<CasperSigner>): GetAddressFn {
10
+ return async (deviceId: string, { path, verify }: GetAddressOptions) => {
11
+ log("debug", "start getAddress process");
12
+
13
+ const { r } = await signerContext(deviceId, async signer => {
14
+ const r = verify
15
+ ? await signer.showAddressAndPubKey(path)
16
+ : await signer.getAddressAndPubKey(path);
17
+
18
+ return { r };
19
+ });
20
+
21
+ return {
22
+ path,
23
+ address: r.Address.length
24
+ ? r.Address.toString().toLowerCase()
25
+ : casperAddressFromPubKey(r.publicKey, CLPublicKeyTag.SECP256K1),
26
+ publicKey: r.publicKey.toString("hex"),
27
+ };
28
+ };
29
+ }
30
+
31
+ export default resolver;
@@ -0,0 +1,3 @@
1
+ import resolver from "./getAddress";
2
+
3
+ export default resolver;