@ledgerhq/coin-casper 1.7.3 → 2.0.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 (278) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.unimportedrc.json +11 -35
  3. package/CHANGELOG.md +14 -0
  4. package/jest.config.js +2 -5
  5. package/lib/api/index.d.ts +8 -6
  6. package/lib/api/index.d.ts.map +1 -1
  7. package/lib/api/index.integ.test.js +12 -3
  8. package/lib/api/index.integ.test.js.map +1 -1
  9. package/lib/api/index.js +53 -91
  10. package/lib/api/index.js.map +1 -1
  11. package/lib/api/index.test.d.ts +2 -0
  12. package/lib/api/index.test.d.ts.map +1 -0
  13. package/lib/api/index.test.js +274 -0
  14. package/lib/api/index.test.js.map +1 -0
  15. package/lib/api/types.d.ts +2 -67
  16. package/lib/api/types.d.ts.map +1 -1
  17. package/lib/bridge/bridgeHelpers/accountShape.d.ts.map +1 -1
  18. package/lib/bridge/bridgeHelpers/accountShape.js +5 -7
  19. package/lib/bridge/bridgeHelpers/accountShape.js.map +1 -1
  20. package/lib/bridge/bridgeHelpers/accountShape.test.d.ts +2 -0
  21. package/lib/bridge/bridgeHelpers/accountShape.test.d.ts.map +1 -0
  22. package/lib/bridge/bridgeHelpers/accountShape.test.js +94 -0
  23. package/lib/bridge/bridgeHelpers/accountShape.test.js.map +1 -0
  24. package/lib/bridge/bridgeHelpers/addresses.d.ts +3 -9
  25. package/lib/bridge/bridgeHelpers/addresses.d.ts.map +1 -1
  26. package/lib/bridge/bridgeHelpers/addresses.js +5 -62
  27. package/lib/bridge/bridgeHelpers/addresses.js.map +1 -1
  28. package/lib/bridge/bridgeHelpers/txn.d.ts +2 -2
  29. package/lib/bridge/bridgeHelpers/txn.d.ts.map +1 -1
  30. package/lib/bridge/bridgeHelpers/txn.js +9 -11
  31. package/lib/bridge/bridgeHelpers/txn.js.map +1 -1
  32. package/lib/bridge/bridgeHelpers/txn.test.d.ts +2 -0
  33. package/lib/bridge/bridgeHelpers/txn.test.d.ts.map +1 -0
  34. package/lib/bridge/bridgeHelpers/txn.test.js +306 -0
  35. package/lib/bridge/bridgeHelpers/txn.test.js.map +1 -0
  36. package/lib/bridge/broadcast.d.ts.map +1 -1
  37. package/lib/bridge/broadcast.js +7 -6
  38. package/lib/bridge/broadcast.js.map +1 -1
  39. package/lib/bridge/broadcast.test.d.ts +2 -0
  40. package/lib/bridge/broadcast.test.d.ts.map +1 -0
  41. package/lib/bridge/broadcast.test.js +72 -0
  42. package/lib/bridge/broadcast.test.js.map +1 -0
  43. package/lib/bridge/buildOptimisticOperation.d.ts.map +1 -1
  44. package/lib/bridge/buildOptimisticOperation.js +2 -0
  45. package/lib/bridge/buildOptimisticOperation.js.map +1 -1
  46. package/lib/bridge/buildOptimisticOperation.test.d.ts +2 -0
  47. package/lib/bridge/buildOptimisticOperation.test.d.ts.map +1 -0
  48. package/lib/bridge/buildOptimisticOperation.test.js +76 -0
  49. package/lib/bridge/buildOptimisticOperation.test.js.map +1 -0
  50. package/lib/bridge/createTransaction.test.d.ts +2 -0
  51. package/lib/bridge/createTransaction.test.d.ts.map +1 -0
  52. package/lib/bridge/createTransaction.test.js +41 -0
  53. package/lib/bridge/createTransaction.test.js.map +1 -0
  54. package/lib/bridge/deviceTransactionConfig.d.ts.map +1 -1
  55. package/lib/bridge/deviceTransactionConfig.js +13 -0
  56. package/lib/bridge/deviceTransactionConfig.js.map +1 -1
  57. package/lib/bridge/deviceTransactionConfig.test.d.ts +2 -0
  58. package/lib/bridge/deviceTransactionConfig.test.d.ts.map +1 -0
  59. package/lib/bridge/deviceTransactionConfig.test.js +148 -0
  60. package/lib/bridge/deviceTransactionConfig.test.js.map +1 -0
  61. package/lib/bridge/estimateMaxSpendable.test.d.ts +2 -0
  62. package/lib/bridge/estimateMaxSpendable.test.d.ts.map +1 -0
  63. package/lib/bridge/estimateMaxSpendable.test.js +133 -0
  64. package/lib/bridge/estimateMaxSpendable.test.js.map +1 -0
  65. package/lib/bridge/getTransactionStatus.test.d.ts +2 -0
  66. package/lib/bridge/getTransactionStatus.test.d.ts.map +1 -0
  67. package/lib/bridge/getTransactionStatus.test.js +214 -0
  68. package/lib/bridge/getTransactionStatus.test.js.map +1 -0
  69. package/lib/bridge/index.d.ts +2 -1
  70. package/lib/bridge/index.d.ts.map +1 -1
  71. package/lib/bridge/index.js +3 -1
  72. package/lib/bridge/index.js.map +1 -1
  73. package/lib/bridge/prepareTransaction.js +1 -1
  74. package/lib/bridge/prepareTransaction.js.map +1 -1
  75. package/lib/bridge/prepareTransaction.test.d.ts +2 -0
  76. package/lib/bridge/prepareTransaction.test.d.ts.map +1 -0
  77. package/lib/bridge/prepareTransaction.test.js +159 -0
  78. package/lib/bridge/prepareTransaction.test.js.map +1 -0
  79. package/lib/bridge/signOperation.d.ts.map +1 -1
  80. package/lib/bridge/signOperation.js +14 -12
  81. package/lib/bridge/signOperation.js.map +1 -1
  82. package/lib/bridge/transaction.test.d.ts +2 -0
  83. package/lib/bridge/transaction.test.d.ts.map +1 -0
  84. package/lib/bridge/transaction.test.js +179 -0
  85. package/lib/bridge/transaction.test.js.map +1 -0
  86. package/lib/common-logic/utils.additional.test.d.ts +2 -0
  87. package/lib/common-logic/utils.additional.test.d.ts.map +1 -0
  88. package/lib/common-logic/utils.additional.test.js +58 -0
  89. package/lib/common-logic/utils.additional.test.js.map +1 -0
  90. package/lib/common-logic/utils.unit.test.js +6 -4
  91. package/lib/common-logic/utils.unit.test.js.map +1 -1
  92. package/lib/config.d.ts +10 -0
  93. package/lib/config.d.ts.map +1 -0
  94. package/lib/config.js +16 -0
  95. package/lib/config.js.map +1 -0
  96. package/lib/consts.d.ts +3 -0
  97. package/lib/consts.d.ts.map +1 -1
  98. package/lib/consts.js +5 -1
  99. package/lib/consts.js.map +1 -1
  100. package/lib/hw-signMessage.test.d.ts +2 -0
  101. package/lib/hw-signMessage.test.d.ts.map +1 -0
  102. package/lib/hw-signMessage.test.js +80 -0
  103. package/lib/hw-signMessage.test.js.map +1 -0
  104. package/lib/signer/getAddress.js +1 -1
  105. package/lib/signer/getAddress.js.map +1 -1
  106. package/lib/signer/getAddress.test.d.ts +2 -0
  107. package/lib/signer/getAddress.test.d.ts.map +1 -0
  108. package/lib/signer/getAddress.test.js +133 -0
  109. package/lib/signer/getAddress.test.js.map +1 -0
  110. package/lib/test/bot-specs.d.ts.map +1 -1
  111. package/lib/test/bot-specs.js +1 -0
  112. package/lib/test/bot-specs.js.map +1 -1
  113. package/lib/test/fixtures.d.ts +131 -0
  114. package/lib/test/fixtures.d.ts.map +1 -0
  115. package/lib/test/fixtures.js +395 -0
  116. package/lib/test/fixtures.js.map +1 -0
  117. package/lib/test/index.d.ts +2 -0
  118. package/lib/test/index.d.ts.map +1 -1
  119. package/lib/test/index.js +2 -0
  120. package/lib/test/index.js.map +1 -1
  121. package/lib/test/speculos-deviceActions.d.ts.map +1 -1
  122. package/lib/test/speculos-deviceActions.js +4 -3
  123. package/lib/test/speculos-deviceActions.js.map +1 -1
  124. package/lib-es/api/index.d.ts +8 -6
  125. package/lib-es/api/index.d.ts.map +1 -1
  126. package/lib-es/api/index.integ.test.js +13 -4
  127. package/lib-es/api/index.integ.test.js.map +1 -1
  128. package/lib-es/api/index.js +51 -90
  129. package/lib-es/api/index.js.map +1 -1
  130. package/lib-es/api/index.test.d.ts +2 -0
  131. package/lib-es/api/index.test.d.ts.map +1 -0
  132. package/lib-es/api/index.test.js +269 -0
  133. package/lib-es/api/index.test.js.map +1 -0
  134. package/lib-es/api/types.d.ts +2 -67
  135. package/lib-es/api/types.d.ts.map +1 -1
  136. package/lib-es/bridge/bridgeHelpers/accountShape.d.ts.map +1 -1
  137. package/lib-es/bridge/bridgeHelpers/accountShape.js +6 -8
  138. package/lib-es/bridge/bridgeHelpers/accountShape.js.map +1 -1
  139. package/lib-es/bridge/bridgeHelpers/accountShape.test.d.ts +2 -0
  140. package/lib-es/bridge/bridgeHelpers/accountShape.test.d.ts.map +1 -0
  141. package/lib-es/bridge/bridgeHelpers/accountShape.test.js +89 -0
  142. package/lib-es/bridge/bridgeHelpers/accountShape.test.js.map +1 -0
  143. package/lib-es/bridge/bridgeHelpers/addresses.d.ts +3 -9
  144. package/lib-es/bridge/bridgeHelpers/addresses.d.ts.map +1 -1
  145. package/lib-es/bridge/bridgeHelpers/addresses.js +5 -60
  146. package/lib-es/bridge/bridgeHelpers/addresses.js.map +1 -1
  147. package/lib-es/bridge/bridgeHelpers/txn.d.ts +2 -2
  148. package/lib-es/bridge/bridgeHelpers/txn.d.ts.map +1 -1
  149. package/lib-es/bridge/bridgeHelpers/txn.js +10 -12
  150. package/lib-es/bridge/bridgeHelpers/txn.js.map +1 -1
  151. package/lib-es/bridge/bridgeHelpers/txn.test.d.ts +2 -0
  152. package/lib-es/bridge/bridgeHelpers/txn.test.d.ts.map +1 -0
  153. package/lib-es/bridge/bridgeHelpers/txn.test.js +278 -0
  154. package/lib-es/bridge/bridgeHelpers/txn.test.js.map +1 -0
  155. package/lib-es/bridge/broadcast.d.ts.map +1 -1
  156. package/lib-es/bridge/broadcast.js +8 -7
  157. package/lib-es/bridge/broadcast.js.map +1 -1
  158. package/lib-es/bridge/broadcast.test.d.ts +2 -0
  159. package/lib-es/bridge/broadcast.test.d.ts.map +1 -0
  160. package/lib-es/bridge/broadcast.test.js +70 -0
  161. package/lib-es/bridge/broadcast.test.js.map +1 -0
  162. package/lib-es/bridge/buildOptimisticOperation.d.ts.map +1 -1
  163. package/lib-es/bridge/buildOptimisticOperation.js +2 -0
  164. package/lib-es/bridge/buildOptimisticOperation.js.map +1 -1
  165. package/lib-es/bridge/buildOptimisticOperation.test.d.ts +2 -0
  166. package/lib-es/bridge/buildOptimisticOperation.test.d.ts.map +1 -0
  167. package/lib-es/bridge/buildOptimisticOperation.test.js +74 -0
  168. package/lib-es/bridge/buildOptimisticOperation.test.js.map +1 -0
  169. package/lib-es/bridge/createTransaction.test.d.ts +2 -0
  170. package/lib-es/bridge/createTransaction.test.d.ts.map +1 -0
  171. package/lib-es/bridge/createTransaction.test.js +36 -0
  172. package/lib-es/bridge/createTransaction.test.js.map +1 -0
  173. package/lib-es/bridge/deviceTransactionConfig.d.ts.map +1 -1
  174. package/lib-es/bridge/deviceTransactionConfig.js +13 -0
  175. package/lib-es/bridge/deviceTransactionConfig.js.map +1 -1
  176. package/lib-es/bridge/deviceTransactionConfig.test.d.ts +2 -0
  177. package/lib-es/bridge/deviceTransactionConfig.test.d.ts.map +1 -0
  178. package/lib-es/bridge/deviceTransactionConfig.test.js +143 -0
  179. package/lib-es/bridge/deviceTransactionConfig.test.js.map +1 -0
  180. package/lib-es/bridge/estimateMaxSpendable.test.d.ts +2 -0
  181. package/lib-es/bridge/estimateMaxSpendable.test.d.ts.map +1 -0
  182. package/lib-es/bridge/estimateMaxSpendable.test.js +131 -0
  183. package/lib-es/bridge/estimateMaxSpendable.test.js.map +1 -0
  184. package/lib-es/bridge/getTransactionStatus.test.d.ts +2 -0
  185. package/lib-es/bridge/getTransactionStatus.test.d.ts.map +1 -0
  186. package/lib-es/bridge/getTransactionStatus.test.js +212 -0
  187. package/lib-es/bridge/getTransactionStatus.test.js.map +1 -0
  188. package/lib-es/bridge/index.d.ts +2 -1
  189. package/lib-es/bridge/index.d.ts.map +1 -1
  190. package/lib-es/bridge/index.js +3 -1
  191. package/lib-es/bridge/index.js.map +1 -1
  192. package/lib-es/bridge/prepareTransaction.js +1 -1
  193. package/lib-es/bridge/prepareTransaction.js.map +1 -1
  194. package/lib-es/bridge/prepareTransaction.test.d.ts +2 -0
  195. package/lib-es/bridge/prepareTransaction.test.d.ts.map +1 -0
  196. package/lib-es/bridge/prepareTransaction.test.js +157 -0
  197. package/lib-es/bridge/prepareTransaction.test.js.map +1 -0
  198. package/lib-es/bridge/signOperation.d.ts.map +1 -1
  199. package/lib-es/bridge/signOperation.js +16 -14
  200. package/lib-es/bridge/signOperation.js.map +1 -1
  201. package/lib-es/bridge/transaction.test.d.ts +2 -0
  202. package/lib-es/bridge/transaction.test.d.ts.map +1 -0
  203. package/lib-es/bridge/transaction.test.js +154 -0
  204. package/lib-es/bridge/transaction.test.js.map +1 -0
  205. package/lib-es/common-logic/utils.additional.test.d.ts +2 -0
  206. package/lib-es/common-logic/utils.additional.test.d.ts.map +1 -0
  207. package/lib-es/common-logic/utils.additional.test.js +56 -0
  208. package/lib-es/common-logic/utils.additional.test.js.map +1 -0
  209. package/lib-es/common-logic/utils.unit.test.js +7 -5
  210. package/lib-es/common-logic/utils.unit.test.js.map +1 -1
  211. package/lib-es/config.d.ts +10 -0
  212. package/lib-es/config.d.ts.map +1 -0
  213. package/lib-es/config.js +11 -0
  214. package/lib-es/config.js.map +1 -0
  215. package/lib-es/consts.d.ts +3 -0
  216. package/lib-es/consts.d.ts.map +1 -1
  217. package/lib-es/consts.js +4 -0
  218. package/lib-es/consts.js.map +1 -1
  219. package/lib-es/hw-signMessage.test.d.ts +2 -0
  220. package/lib-es/hw-signMessage.test.d.ts.map +1 -0
  221. package/lib-es/hw-signMessage.test.js +78 -0
  222. package/lib-es/hw-signMessage.test.js.map +1 -0
  223. package/lib-es/signer/getAddress.js +2 -2
  224. package/lib-es/signer/getAddress.js.map +1 -1
  225. package/lib-es/signer/getAddress.test.d.ts +2 -0
  226. package/lib-es/signer/getAddress.test.d.ts.map +1 -0
  227. package/lib-es/signer/getAddress.test.js +105 -0
  228. package/lib-es/signer/getAddress.test.js.map +1 -0
  229. package/lib-es/test/bot-specs.d.ts.map +1 -1
  230. package/lib-es/test/bot-specs.js +1 -0
  231. package/lib-es/test/bot-specs.js.map +1 -1
  232. package/lib-es/test/fixtures.d.ts +131 -0
  233. package/lib-es/test/fixtures.d.ts.map +1 -0
  234. package/lib-es/test/fixtures.js +381 -0
  235. package/lib-es/test/fixtures.js.map +1 -0
  236. package/lib-es/test/index.d.ts +2 -0
  237. package/lib-es/test/index.d.ts.map +1 -1
  238. package/lib-es/test/index.js +2 -0
  239. package/lib-es/test/index.js.map +1 -1
  240. package/lib-es/test/speculos-deviceActions.d.ts.map +1 -1
  241. package/lib-es/test/speculos-deviceActions.js +5 -4
  242. package/lib-es/test/speculos-deviceActions.js.map +1 -1
  243. package/package.json +17 -12
  244. package/src/api/index.integ.test.ts +14 -4
  245. package/src/api/index.test.ts +386 -0
  246. package/src/api/index.ts +59 -117
  247. package/src/api/types.ts +2 -75
  248. package/src/bridge/bridgeHelpers/accountShape.test.ts +122 -0
  249. package/src/bridge/bridgeHelpers/accountShape.ts +7 -9
  250. package/src/bridge/bridgeHelpers/addresses.ts +6 -73
  251. package/src/bridge/bridgeHelpers/txn.test.ts +339 -0
  252. package/src/bridge/bridgeHelpers/txn.ts +18 -18
  253. package/src/bridge/broadcast.test.ts +89 -0
  254. package/src/bridge/broadcast.ts +9 -7
  255. package/src/bridge/buildOptimisticOperation.test.ts +89 -0
  256. package/src/bridge/buildOptimisticOperation.ts +2 -0
  257. package/src/bridge/createTransaction.test.ts +43 -0
  258. package/src/bridge/deviceTransactionConfig.test.ts +171 -0
  259. package/src/bridge/deviceTransactionConfig.ts +14 -0
  260. package/src/bridge/estimateMaxSpendable.test.ts +155 -0
  261. package/src/bridge/getTransactionStatus.test.ts +264 -0
  262. package/src/bridge/index.ts +8 -1
  263. package/src/bridge/prepareTransaction.test.ts +174 -0
  264. package/src/bridge/prepareTransaction.ts +1 -1
  265. package/src/bridge/signOperation.ts +16 -25
  266. package/src/bridge/transaction.test.ts +182 -0
  267. package/src/common-logic/utils.additional.test.ts +75 -0
  268. package/src/common-logic/utils.unit.test.ts +9 -7
  269. package/src/config.ts +22 -0
  270. package/src/consts.ts +5 -0
  271. package/src/hw-signMessage.test.ts +123 -0
  272. package/src/signer/getAddress.test.ts +134 -0
  273. package/src/signer/getAddress.ts +2 -2
  274. package/src/test/bot-specs.ts +1 -0
  275. package/src/test/fixtures.ts +448 -0
  276. package/src/test/index.ts +2 -0
  277. package/src/test/speculos-deviceActions.ts +6 -4
  278. package/tsconfig.json +1 -4
@@ -0,0 +1,174 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import { prepareTransaction } from "./prepareTransaction";
3
+ import { getEstimatedFees } from "./bridgeHelpers/fee";
4
+ import { updateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers";
5
+ import { createMockAccount, createMockTransaction } from "../test/fixtures";
6
+
7
+ // Mock dependencies
8
+ jest.mock("./bridgeHelpers/fee", () => ({
9
+ getEstimatedFees: jest.fn(),
10
+ }));
11
+
12
+ jest.mock("@ledgerhq/coin-framework/bridge/jsHelpers", () => ({
13
+ updateTransaction: jest.fn((tx, updates) => ({ ...tx, ...updates })),
14
+ }));
15
+
16
+ describe("prepareTransaction", () => {
17
+ const mockAccount = createMockAccount({
18
+ id: "casper:0:testAccount",
19
+ spendableBalance: new BigNumber(10000000),
20
+ });
21
+
22
+ const mockTransaction = createMockTransaction({
23
+ recipient: "01fedcba0987654321",
24
+ amount: new BigNumber(5000000),
25
+ useAllAmount: false,
26
+ fees: new BigNumber(1000000),
27
+ transferId: "1",
28
+ });
29
+
30
+ const mockEstimatedFees = new BigNumber(1000000);
31
+
32
+ beforeEach(() => {
33
+ jest.clearAllMocks();
34
+ (getEstimatedFees as jest.Mock).mockReturnValue(mockEstimatedFees);
35
+ });
36
+
37
+ test("should prepare a regular transaction with estimated fees", async () => {
38
+ const result = await prepareTransaction(mockAccount, mockTransaction);
39
+
40
+ expect(getEstimatedFees).toHaveBeenCalled();
41
+ expect(updateTransaction).toHaveBeenCalledWith(mockTransaction, {
42
+ fees: mockEstimatedFees,
43
+ amount: mockTransaction.amount,
44
+ });
45
+
46
+ expect(result).toEqual({
47
+ ...mockTransaction,
48
+ fees: mockEstimatedFees,
49
+ });
50
+ });
51
+
52
+ test("should calculate correct amount for useAllAmount transactions", async () => {
53
+ const useAllAmountTx = createMockTransaction({
54
+ ...mockTransaction,
55
+ useAllAmount: true,
56
+ });
57
+
58
+ const result = await prepareTransaction(mockAccount, useAllAmountTx);
59
+
60
+ const expectedAmount = mockAccount.spendableBalance.minus(mockEstimatedFees);
61
+
62
+ expect(updateTransaction).toHaveBeenCalledWith(useAllAmountTx, {
63
+ fees: mockEstimatedFees,
64
+ amount: expectedAmount,
65
+ });
66
+
67
+ expect(result).toEqual({
68
+ ...useAllAmountTx,
69
+ fees: mockEstimatedFees,
70
+ amount: expectedAmount,
71
+ });
72
+ });
73
+
74
+ test("should recalculate amount for useAllAmount transactions after fee update", async () => {
75
+ const useAllAmountTx = createMockTransaction({
76
+ ...mockTransaction,
77
+ useAllAmount: true,
78
+ });
79
+
80
+ const result = await prepareTransaction(mockAccount, useAllAmountTx);
81
+
82
+ const expectedAmount = mockAccount.spendableBalance.minus(mockEstimatedFees);
83
+
84
+ expect(result.amount).toEqual(expectedAmount);
85
+ });
86
+
87
+ // Using parameterized testing with fixtures
88
+ describe("with test case fixtures", () => {
89
+ // Define test cases inline for controlled fee values
90
+ test.each([
91
+ {
92
+ name: "Standard transaction",
93
+ account: createMockAccount({
94
+ spendableBalance: new BigNumber("10000000000"),
95
+ }),
96
+ transaction: createMockTransaction({
97
+ amount: new BigNumber("1000000000"),
98
+ useAllAmount: false,
99
+ }),
100
+ expectedResult: {
101
+ fees: mockEstimatedFees,
102
+ amount: new BigNumber("1000000000"),
103
+ },
104
+ },
105
+ {
106
+ name: "Use all amount transaction",
107
+ account: createMockAccount({
108
+ spendableBalance: new BigNumber("10000000000"),
109
+ }),
110
+ transaction: createMockTransaction({
111
+ useAllAmount: true,
112
+ }),
113
+ expectedResult: {
114
+ fees: mockEstimatedFees,
115
+ amount: new BigNumber("10000000000").minus(mockEstimatedFees),
116
+ },
117
+ },
118
+ {
119
+ name: "Low balance account",
120
+ account: createMockAccount({
121
+ spendableBalance: new BigNumber(mockEstimatedFees.div(2)),
122
+ }),
123
+ transaction: createMockTransaction({
124
+ useAllAmount: true,
125
+ }),
126
+ expectedResult: {
127
+ fees: mockEstimatedFees,
128
+ // For low balance, amount should be negative (will be handled in the test)
129
+ amount: new BigNumber(mockEstimatedFees.div(2)).minus(mockEstimatedFees),
130
+ },
131
+ },
132
+ {
133
+ name: "Exactly enough for fees",
134
+ account: createMockAccount({
135
+ spendableBalance: mockEstimatedFees,
136
+ }),
137
+ transaction: createMockTransaction({
138
+ useAllAmount: true,
139
+ }),
140
+ expectedResult: {
141
+ fees: mockEstimatedFees,
142
+ // For exact fee balance, amount should be zero
143
+ amount: new BigNumber("0"),
144
+ },
145
+ },
146
+ {
147
+ name: "Custom fee override",
148
+ account: createMockAccount({
149
+ spendableBalance: new BigNumber("10000000000"),
150
+ }),
151
+ transaction: createMockTransaction({
152
+ fees: new BigNumber("2000000"),
153
+ useAllAmount: true,
154
+ }),
155
+ expectedResult: {
156
+ fees: mockEstimatedFees,
157
+ amount: new BigNumber("10000000000").minus(mockEstimatedFees),
158
+ },
159
+ },
160
+ ])("$name", async ({ account, transaction, expectedResult }) => {
161
+ const result = await prepareTransaction(account, transaction);
162
+ expect(result.fees).toEqual(expectedResult.fees);
163
+
164
+ // For negative balance scenarios, just check they're less than or equal to zero
165
+ if (account.spendableBalance.lt(mockEstimatedFees) && transaction.useAllAmount) {
166
+ expect(result.amount.lte(new BigNumber("0"))).toBe(true);
167
+ } else if (account.spendableBalance.eq(mockEstimatedFees) && transaction.useAllAmount) {
168
+ expect(result.amount.eq(new BigNumber("0"))).toBe(true);
169
+ } else {
170
+ expect(result.amount).toEqual(expectedResult.amount);
171
+ }
172
+ });
173
+ });
174
+ });
@@ -11,7 +11,7 @@ export const prepareTransaction: AccountBridge<Transaction>["prepareTransaction"
11
11
  const fees = getEstimatedFees();
12
12
 
13
13
  const amount = transaction.useAllAmount
14
- ? account.spendableBalance.minus(transaction.fees)
14
+ ? account.spendableBalance.minus(fees)
15
15
  : transaction.amount;
16
16
 
17
17
  // log("debug", "[prepareTransaction] finish fn");
@@ -1,13 +1,13 @@
1
1
  import { Observable } from "rxjs";
2
2
  import { log } from "@ledgerhq/logs";
3
- import { DeployUtil } from "casper-js-sdk";
4
3
  import { Account, AccountBridge } from "@ledgerhq/types-live";
5
- import { casperGetCLPublicKey, getAddress } from "../bridge/bridgeHelpers/addresses";
6
- import { createNewDeploy } from "../bridge/bridgeHelpers/txn";
4
+ import { getAddress } from "../bridge/bridgeHelpers/addresses";
5
+ import { createNewTransaction } from "../bridge/bridgeHelpers/txn";
7
6
  import { Transaction } from "../types";
8
7
  import { SignerContext } from "@ledgerhq/coin-framework/signer";
9
8
  import { CasperSigner } from "../types";
10
9
  import { buildOptimisticOperation } from "./buildOptimisticOperation";
10
+ import { KeyAlgorithm } from "casper-js-sdk";
11
11
 
12
12
  export const buildSignOperation =
13
13
  (
@@ -18,26 +18,20 @@ export const buildSignOperation =
18
18
  async function main() {
19
19
  // log("debug", "[signOperation] start fn");
20
20
 
21
- const { recipient } = transaction;
21
+ const { recipient, amount, fees, transferId } = transaction;
22
22
  const { address, derivationPath } = getAddress(account);
23
- const deploy = createNewDeploy(
24
- address,
25
- recipient,
26
- transaction.amount,
27
- transaction.fees,
28
- transaction.transferId,
29
- );
23
+ const casperTx = await createNewTransaction(address, recipient, amount, fees, transferId);
30
24
 
31
25
  // Serialize tx
32
- const deployBytes = DeployUtil.deployToBytes(deploy);
33
- log("debug", `[signOperation] serialized deploy: [${deployBytes.toString()}]`);
26
+ const txBytes = casperTx.toBytes();
27
+ log("debug", `[signOperation] serialized transaction: [${txBytes.toString()}]`);
34
28
  o.next({
35
29
  type: "device-signature-requested",
36
30
  });
37
31
 
38
32
  // Sign by device
39
33
  const { r } = await signerContext(deviceId, async signer => {
40
- const r = await signer.sign(derivationPath, Buffer.from(deployBytes));
34
+ const r = await signer.sign(derivationPath, Buffer.from(txBytes));
41
35
  return { r };
42
36
  });
43
37
 
@@ -46,23 +40,20 @@ export const buildSignOperation =
46
40
  });
47
41
 
48
42
  // signature verification
49
- const deployHash = deploy.hash.toString();
50
- const signature = r.signatureRS;
43
+ const txHash = casperTx.hash.getHash()?.toHex() ?? "";
44
+ const signature = Buffer.concat([Buffer.from([KeyAlgorithm.SECP256K1]), r.signatureRS]);
51
45
 
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);
46
+ const operation = buildOptimisticOperation(account, transaction, txHash);
47
+ const txJson = casperTx.toJSON();
60
48
 
61
49
  o.next({
62
50
  type: "signed",
63
51
  signedOperation: {
64
52
  operation,
65
- signature: JSON.stringify(DeployUtil.deployToJson(signedDeploy)),
53
+ signature: Buffer.from(signature).toString("hex"),
54
+ rawData: {
55
+ tx: JSON.stringify(txJson),
56
+ },
66
57
  },
67
58
  });
68
59
  }
@@ -0,0 +1,182 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import transaction, { fromTransactionRaw, formatTransaction } from "./transaction";
3
+ import { TransactionRaw } from "../types";
4
+ import {
5
+ createMockAccount,
6
+ createMockTransaction,
7
+ TEST_ADDRESSES,
8
+ TEST_TRANSFER_IDS,
9
+ } from "../test/fixtures";
10
+
11
+ describe("transaction", () => {
12
+ // Using the createMockAccount function from fixtures
13
+ const account = createMockAccount({
14
+ id: "casper:0:testAccount",
15
+ balance: new BigNumber(100000000),
16
+ spendableBalance: new BigNumber(100000000),
17
+ blockHeight: 123456,
18
+ freshAddress: "0123456789",
19
+ freshAddressPath: "44'/506'/0'/0/0",
20
+ lastSyncDate: new Date(),
21
+ });
22
+
23
+ describe("formatTransaction", () => {
24
+ test("should format a transaction with amount", () => {
25
+ const tx = createMockTransaction({
26
+ recipient: TEST_ADDRESSES.RECIPIENT_SECP256K1,
27
+ useAllAmount: false,
28
+ amount: new BigNumber(50000000),
29
+ fees: new BigNumber(1000000),
30
+ transferId: "1",
31
+ });
32
+
33
+ const result = formatTransaction(tx, account);
34
+ expect(result).toContain("SEND");
35
+ expect(result).toContain("0.05");
36
+ expect(result).toContain("CSPR");
37
+ expect(result).toContain(`TO ${TEST_ADDRESSES.RECIPIENT_SECP256K1}`);
38
+ });
39
+
40
+ test("should format a transaction with useAllAmount", () => {
41
+ const tx = createMockTransaction({
42
+ recipient: TEST_ADDRESSES.RECIPIENT_SECP256K1,
43
+ useAllAmount: true,
44
+ amount: new BigNumber(0),
45
+ fees: new BigNumber(1000000),
46
+ transferId: "1",
47
+ });
48
+
49
+ const result = formatTransaction(tx, account);
50
+ expect(result).toContain("SEND MAX");
51
+ expect(result).toContain(`TO ${TEST_ADDRESSES.RECIPIENT_SECP256K1}`);
52
+ });
53
+
54
+ test("should format a transaction with zero amount", () => {
55
+ const tx = createMockTransaction({
56
+ recipient: TEST_ADDRESSES.RECIPIENT_SECP256K1,
57
+ useAllAmount: false,
58
+ amount: new BigNumber(0),
59
+ fees: new BigNumber(1000000),
60
+ transferId: "1",
61
+ });
62
+
63
+ const result = formatTransaction(tx, account);
64
+ expect(result).toContain("SEND");
65
+ expect(result).not.toContain("MAX");
66
+ expect(result).not.toContain("CSPR");
67
+ expect(result).toContain(`TO ${TEST_ADDRESSES.RECIPIENT_SECP256K1}`);
68
+ });
69
+
70
+ test("should format a transaction with different address formats", () => {
71
+ // Test with ED25519 address format
72
+ const tx = createMockTransaction({
73
+ recipient: TEST_ADDRESSES.RECIPIENT_ED25519,
74
+ amount: new BigNumber(50000000),
75
+ });
76
+
77
+ const result = formatTransaction(tx, account);
78
+ expect(result).toContain(`TO ${TEST_ADDRESSES.RECIPIENT_ED25519}`);
79
+ });
80
+
81
+ test("should format a transaction with transfer ID", () => {
82
+ const tx = createMockTransaction({
83
+ recipient: TEST_ADDRESSES.RECIPIENT_SECP256K1,
84
+ amount: new BigNumber(50000000),
85
+ transferId: TEST_TRANSFER_IDS.VALID,
86
+ });
87
+
88
+ const result = formatTransaction(tx, account);
89
+ expect(result).toContain("0.05");
90
+ expect(result).toContain("CSPR");
91
+ expect(result).toContain(`TO ${TEST_ADDRESSES.RECIPIENT_SECP256K1}`);
92
+ });
93
+ });
94
+
95
+ describe("fromTransactionRaw", () => {
96
+ test("should convert a transaction raw to a transaction", () => {
97
+ const raw: TransactionRaw = {
98
+ family: "casper",
99
+ recipient: TEST_ADDRESSES.RECIPIENT_SECP256K1,
100
+ useAllAmount: false,
101
+ amount: "50000000",
102
+ fees: "1000000",
103
+ transferId: TEST_TRANSFER_IDS.VALID,
104
+ };
105
+
106
+ const result = fromTransactionRaw(raw);
107
+ expect(result.family).toBe("casper");
108
+ expect(result.recipient).toBe(TEST_ADDRESSES.RECIPIENT_SECP256K1);
109
+ expect(result.useAllAmount).toBe(false);
110
+ expect(result.amount).toEqual(new BigNumber(50000000));
111
+ expect(result.fees).toEqual(new BigNumber(1000000));
112
+ expect(result.transferId).toBe(TEST_TRANSFER_IDS.VALID);
113
+ });
114
+
115
+ test("should handle transaction raw without optional fields", () => {
116
+ const raw: TransactionRaw = {
117
+ family: "casper",
118
+ recipient: TEST_ADDRESSES.RECIPIENT_SECP256K1,
119
+ useAllAmount: false,
120
+ amount: "50000000",
121
+ fees: "1000000",
122
+ };
123
+
124
+ const result = fromTransactionRaw(raw);
125
+ expect(result.family).toBe("casper");
126
+ expect(result.transferId).toBeUndefined();
127
+ });
128
+ });
129
+
130
+ describe("toTransactionRaw", () => {
131
+ test("should convert a transaction to a transaction raw", () => {
132
+ const tx = createMockTransaction({
133
+ recipient: TEST_ADDRESSES.RECIPIENT_SECP256K1,
134
+ useAllAmount: false,
135
+ amount: new BigNumber(50000000),
136
+ fees: new BigNumber(1000000),
137
+ transferId: TEST_TRANSFER_IDS.VALID,
138
+ });
139
+
140
+ const result = transaction.toTransactionRaw(tx);
141
+ expect(result.family).toBe("casper");
142
+ expect(result.recipient).toBe(TEST_ADDRESSES.RECIPIENT_SECP256K1);
143
+ expect(result.useAllAmount).toBe(false);
144
+ expect(result.amount).toBe("50000000");
145
+ expect(result.fees).toBe("1000000");
146
+ expect(result.transferId).toBe(TEST_TRANSFER_IDS.VALID);
147
+ });
148
+
149
+ test("should handle transaction without optional fields", () => {
150
+ const tx = createMockTransaction({
151
+ recipient: TEST_ADDRESSES.RECIPIENT_SECP256K1,
152
+ useAllAmount: false,
153
+ amount: new BigNumber(50000000),
154
+ fees: new BigNumber(1000000),
155
+ transferId: undefined,
156
+ });
157
+
158
+ const result = transaction.toTransactionRaw(tx);
159
+ expect(result.transferId).toBeUndefined();
160
+ });
161
+
162
+ test("should handle different transaction scenarios", () => {
163
+ // Test with useAllAmount = true
164
+ const maxTx = createMockTransaction({
165
+ useAllAmount: true,
166
+ amount: new BigNumber(0),
167
+ });
168
+
169
+ const maxResult = transaction.toTransactionRaw(maxTx);
170
+ expect(maxResult.useAllAmount).toBe(true);
171
+ expect(maxResult.amount).toBe("0");
172
+
173
+ // Test with very large amount
174
+ const largeTx = createMockTransaction({
175
+ amount: new BigNumber("9999000000000"), // 9,999 CSPR
176
+ });
177
+
178
+ const largeResult = transaction.toTransactionRaw(largeTx);
179
+ expect(largeResult.amount).toBe("9999000000000");
180
+ });
181
+ });
182
+ });
@@ -0,0 +1,75 @@
1
+ import {
2
+ isNoErrorReturnCode,
3
+ getPath,
4
+ isError,
5
+ methodToString,
6
+ getRandomTransferID,
7
+ } from "./utils";
8
+
9
+ describe("Casper utils", () => {
10
+ describe("isNoErrorReturnCode", () => {
11
+ test("should return true for code 0x9000", () => {
12
+ expect(isNoErrorReturnCode(0x9000)).toBe(true);
13
+ });
14
+
15
+ test("should return false for other codes", () => {
16
+ expect(isNoErrorReturnCode(0x6984)).toBe(false);
17
+ expect(isNoErrorReturnCode(0x6a80)).toBe(false);
18
+ expect(isNoErrorReturnCode(0)).toBe(false);
19
+ });
20
+ });
21
+
22
+ describe("getPath", () => {
23
+ test("should add m/ prefix if not present", () => {
24
+ expect(getPath("44'/506'/0'/0/0")).toBe("m/44'/506'/0'/0/0");
25
+ });
26
+
27
+ test("should not modify path if m/ prefix is already present", () => {
28
+ expect(getPath("m/44'/506'/0'/0/0")).toBe("m/44'/506'/0'/0/0");
29
+ });
30
+
31
+ test("should handle empty path", () => {
32
+ expect(getPath("")).toBe("");
33
+ });
34
+ });
35
+
36
+ describe("isError", () => {
37
+ test("should not throw for successful return code", () => {
38
+ expect(() => isError({ returnCode: 0x9000, errorMessage: "Success" })).not.toThrow();
39
+ });
40
+
41
+ test("should throw for error return codes", () => {
42
+ expect(() => isError({ returnCode: 0x6a80, errorMessage: "Bad data" })).toThrow(
43
+ "27264 - Bad data",
44
+ );
45
+ });
46
+ });
47
+
48
+ describe("methodToString", () => {
49
+ test("should return 'Token transfer' for method 0", () => {
50
+ expect(methodToString(0)).toBe("Token transfer");
51
+ });
52
+
53
+ test("should return 'Unknown' for other methods", () => {
54
+ expect(methodToString(1)).toBe("Unknown");
55
+ expect(methodToString(999)).toBe("Unknown");
56
+ });
57
+ });
58
+
59
+ describe("getRandomTransferID", () => {
60
+ test("should return a string containing a number", () => {
61
+ const result = getRandomTransferID();
62
+ expect(typeof result).toBe("string");
63
+ expect(Number.isNaN(parseInt(result, 10))).toBe(false);
64
+ });
65
+
66
+ test("should generate different IDs on multiple calls", () => {
67
+ const id1 = getRandomTransferID();
68
+ const id2 = getRandomTransferID();
69
+ const id3 = getRandomTransferID();
70
+
71
+ // There's a very small chance these could be the same, but it's extremely unlikely
72
+ expect(new Set([id1, id2, id3]).size).toBeGreaterThan(0);
73
+ });
74
+ });
75
+ });
@@ -1,4 +1,4 @@
1
- import { CLPublicKeyTag } from "casper-js-sdk";
1
+ import { KeyAlgorithm } from "casper-js-sdk";
2
2
  import { casperAddressFromPubKey, isAddressValid } from "../bridge/bridgeHelpers/addresses";
3
3
 
4
4
  describe("Casper addresses", () => {
@@ -20,6 +20,8 @@ describe("Casper addresses", () => {
20
20
  test("Check if valid addresses are valid", () => {
21
21
  expect(isAddressValid(pubKeys.validEd25519)).toBe(true);
22
22
  expect(isAddressValid(pubKeys.validSecp256k1)).toBe(true);
23
+ expect(isAddressValid(pubKeys.validSecp256k1Checksum)).toBe(true);
24
+ expect(isAddressValid(pubKeys.validEd25519Checksum)).toBe(true);
23
25
  });
24
26
 
25
27
  test("Check if invalid addresses are invalid", () => {
@@ -39,9 +41,9 @@ describe("Casper addresses", () => {
39
41
  */
40
42
  function casperPubKeyFromAddress(address: string): {
41
43
  pubkey: Buffer;
42
- keySig: CLPublicKeyTag;
44
+ keySig: KeyAlgorithm;
43
45
  } {
44
- const keySig = parseInt(address.slice(0, 2), 10) as CLPublicKeyTag;
46
+ const keySig = parseInt(address.slice(0, 2), 10) as KeyAlgorithm;
45
47
  const pubkeyHex = address.slice(2);
46
48
  const pubkey = Buffer.from(pubkeyHex, "hex");
47
49
  return { pubkey, keySig };
@@ -50,25 +52,25 @@ describe("Casper addresses", () => {
50
52
  expect(
51
53
  casperAddressFromPubKey(
52
54
  casperPubKeyFromAddress(pubKeys.validSecp256k1).pubkey,
53
- CLPublicKeyTag.SECP256K1,
55
+ KeyAlgorithm.SECP256K1,
54
56
  ),
55
57
  ).toBe(pubKeys.validSecp256k1);
56
58
  expect(
57
59
  casperAddressFromPubKey(
58
60
  casperPubKeyFromAddress(pubKeys.validSecp256k1Checksum).pubkey,
59
- CLPublicKeyTag.SECP256K1,
61
+ KeyAlgorithm.SECP256K1,
60
62
  ),
61
63
  ).toBe(pubKeys.validSecp256k1Checksum.toLowerCase());
62
64
  expect(
63
65
  casperAddressFromPubKey(
64
66
  casperPubKeyFromAddress(pubKeys.validEd25519).pubkey,
65
- CLPublicKeyTag.ED25519,
67
+ KeyAlgorithm.ED25519,
66
68
  ),
67
69
  ).toBe(pubKeys.validEd25519);
68
70
  expect(
69
71
  casperAddressFromPubKey(
70
72
  casperPubKeyFromAddress(pubKeys.validEd25519Checksum).pubkey,
71
- CLPublicKeyTag.ED25519,
73
+ KeyAlgorithm.ED25519,
72
74
  ),
73
75
  ).toBe(pubKeys.validEd25519Checksum.toLowerCase());
74
76
  });
package/src/config.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { CurrencyConfig } from "@ledgerhq/coin-framework/config";
2
+
3
+ export type CasperCoinConfig = () => CurrencyConfig & {
4
+ infra: {
5
+ API_CASPER_NODE_ENDPOINT: string;
6
+ API_CASPER_INDEXER: string;
7
+ };
8
+ };
9
+
10
+ let coinConfig: CasperCoinConfig | undefined;
11
+
12
+ export const setCoinConfig = (config: CasperCoinConfig): void => {
13
+ coinConfig = config;
14
+ };
15
+
16
+ export const getCoinConfig = (): ReturnType<CasperCoinConfig> => {
17
+ if (!coinConfig?.()) {
18
+ throw new Error("Casper module config not set");
19
+ }
20
+
21
+ return coinConfig();
22
+ };
package/src/consts.ts CHANGED
@@ -6,6 +6,7 @@ export const CASPER_MINIMUM_VALID_AMOUNT_MOTES = 2.5 * 1e9;
6
6
  export const CASPER_MINIMUM_VALID_AMOUNT_CSPR = 2.5;
7
7
  export const CASPER_NETWORK = "casper";
8
8
  export const CASPER_CHECKSUM_HEX_LEN = 32;
9
+ export const CASPER_DEFAULT_TTL = 1800000;
9
10
 
10
11
  export const CASPER_MAX_TRANSFER_ID = "18446744073709551615";
11
12
 
@@ -16,3 +17,7 @@ export const MayBlockAccountError = new MayBlockAccount("", {
16
17
  export const InvalidMinimumAmountError = new InvalidMinimumAmount("", {
17
18
  minAmount: `${CASPER_MINIMUM_VALID_AMOUNT_CSPR} CSPR`,
18
19
  });
20
+
21
+ // Known Error Codes
22
+ export const NodeErrorCodeAccountNotFound = -32009;
23
+ export const NodeErrorCodeQueryFailed = -32003;