@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,171 @@
1
+ import { log } from "@ledgerhq/logs";
2
+ import getDeviceTransactionConfig from "./deviceTransactionConfig";
3
+ import { createMockAccount, createMockTransaction } from "../test/fixtures";
4
+ import { CASPER_NETWORK } from "../consts";
5
+ import { methodToString } from "../common-logic";
6
+ import { TransactionStatus, Transaction } from "../types";
7
+ import BigNumber from "bignumber.js";
8
+
9
+ // Mock the log function to prevent console output during tests
10
+ jest.mock("@ledgerhq/logs", () => ({
11
+ log: jest.fn(),
12
+ }));
13
+
14
+ /**
15
+ * Tests for the getDeviceTransactionConfig function
16
+ * Validates the correct display fields are generated for Ledger devices
17
+ */
18
+ describe("getDeviceTransactionConfig", () => {
19
+ // Common test objects
20
+ const MOCK_AMOUNT = new BigNumber("1000000000"); // 1 CSPR
21
+ const TRANSFER_ID = "12345678";
22
+
23
+ /**
24
+ * Creates a mock transaction status for testing
25
+ * @returns A valid TransactionStatus object
26
+ */
27
+ const createMockStatus = (): TransactionStatus => ({
28
+ errors: {},
29
+ warnings: {},
30
+ estimatedFees: new BigNumber(0),
31
+ amount: new BigNumber(0),
32
+ totalSpent: new BigNumber(0),
33
+ });
34
+
35
+ /**
36
+ * Helper to get config fields
37
+ */
38
+ const getConfigFields = (transaction: Transaction, account = createMockAccount()) =>
39
+ getDeviceTransactionConfig({
40
+ account,
41
+ parentAccount: null,
42
+ transaction,
43
+ status: createMockStatus(),
44
+ });
45
+
46
+ beforeEach(() => {
47
+ jest.clearAllMocks();
48
+ });
49
+
50
+ test("should display chain ID, transaction type and amount fields for standard transactions", () => {
51
+ // Create mock transaction
52
+ const mockTransaction = createMockTransaction({
53
+ amount: MOCK_AMOUNT,
54
+ });
55
+
56
+ // Get display fields
57
+ const fields = getConfigFields(mockTransaction);
58
+
59
+ // Verify the results
60
+ expect(fields).toHaveLength(4);
61
+ // Check Type field
62
+ expect(fields[0]).toEqual({
63
+ type: "text",
64
+ label: "Type",
65
+ value: methodToString(0), // 0 = "transfer"
66
+ });
67
+
68
+ // Check Chain ID field
69
+ expect(fields[1]).toEqual({
70
+ type: "text",
71
+ label: "Chain ID",
72
+ value: CASPER_NETWORK,
73
+ });
74
+
75
+ // Check Fee field
76
+ expect(fields[2]).toEqual({
77
+ type: "casper.extendedAmount",
78
+ label: "Fee",
79
+ value: new BigNumber(100000000),
80
+ });
81
+
82
+ // Check Amount field
83
+ expect(fields[3]).toEqual({
84
+ type: "casper.extendedAmount",
85
+ label: "Amount",
86
+ value: MOCK_AMOUNT,
87
+ });
88
+
89
+ // Verify logging
90
+ expect(log).toHaveBeenCalledWith("debug", expect.stringContaining("Transaction config"));
91
+ });
92
+
93
+ test("should include transferId field when provided in transaction", () => {
94
+ // Create mock transaction with transferId
95
+ const mockTransaction = createMockTransaction({
96
+ amount: MOCK_AMOUNT,
97
+ transferId: TRANSFER_ID,
98
+ });
99
+
100
+ // Get display fields
101
+ const fields = getConfigFields(mockTransaction);
102
+
103
+ // Verify the results
104
+ expect(fields).toHaveLength(5); // Chain ID, Type, Amount, Transfer ID fields
105
+
106
+ // Check all fields are present
107
+ const fieldLabels = fields.map(field => field.label);
108
+ expect(fieldLabels).toEqual(["Type", "Chain ID", "Fee", "Amount", "Transfer ID"]);
109
+
110
+ // Check Transfer ID field specifically
111
+ expect(fields[4]).toEqual({
112
+ type: "text",
113
+ label: "Transfer ID",
114
+ value: TRANSFER_ID,
115
+ });
116
+ });
117
+
118
+ test("should not include transferId field when undefined in transaction", () => {
119
+ // Create mock transaction with explicitly undefined transferId
120
+ const mockTransaction = createMockTransaction({
121
+ amount: MOCK_AMOUNT,
122
+ transferId: undefined,
123
+ });
124
+
125
+ // Get display fields
126
+ const fields = getConfigFields(mockTransaction);
127
+
128
+ // Verify no transferId field is present
129
+ expect(fields).toHaveLength(4);
130
+ expect(fields.map(field => field.label)).not.toContain("Transfer ID");
131
+ });
132
+
133
+ test("should handle zero amount transactions correctly", () => {
134
+ // Create mock transaction with zero amount
135
+ const mockTransaction = createMockTransaction({
136
+ amount: new BigNumber(0),
137
+ });
138
+
139
+ // Get display fields
140
+ const fields = getConfigFields(mockTransaction);
141
+
142
+ // Verify amount field has zero value
143
+ const amountField = fields.find(field => field.label === "Amount");
144
+ expect(amountField).toBeDefined();
145
+ expect(amountField).toEqual({
146
+ type: "casper.extendedAmount",
147
+ label: "Amount",
148
+ value: new BigNumber(0),
149
+ });
150
+ });
151
+
152
+ test("should maintain consistent order of fields regardless of transaction properties", () => {
153
+ // Create two transactions - one with transferId, one without
154
+ const txWithTransferId = createMockTransaction({
155
+ amount: MOCK_AMOUNT,
156
+ transferId: TRANSFER_ID,
157
+ });
158
+
159
+ const txWithoutTransferId = createMockTransaction({
160
+ amount: MOCK_AMOUNT,
161
+ });
162
+
163
+ const fieldsWithId = getConfigFields(txWithTransferId);
164
+ const fieldsWithoutId = getConfigFields(txWithoutTransferId);
165
+
166
+ // Verify field order consistency for common fields
167
+ for (let i = 0; i < fieldsWithoutId.length; i++) {
168
+ expect(fieldsWithId[i].label).toEqual(fieldsWithoutId[i].label);
169
+ }
170
+ });
171
+ });
@@ -4,6 +4,7 @@ import type { CommonDeviceTransactionField } from "@ledgerhq/coin-framework/tran
4
4
  import { Transaction, TransactionStatus } from "../types";
5
5
  import { methodToString } from "../common-logic";
6
6
  import BigNumber from "bignumber.js";
7
+ import { CASPER_NETWORK } from "../consts";
7
8
 
8
9
  export type ExtraDeviceTransactionField = {
9
10
  type: "casper.extendedAmount";
@@ -27,6 +28,11 @@ function getDeviceTransactionConfig({
27
28
  label: "Type",
28
29
  value: methodToString(0),
29
30
  });
31
+ fields.push({
32
+ type: "text",
33
+ label: "Chain ID",
34
+ value: CASPER_NETWORK,
35
+ });
30
36
  fields.push({
31
37
  type: "casper.extendedAmount",
32
38
  label: "Fee",
@@ -38,6 +44,14 @@ function getDeviceTransactionConfig({
38
44
  value: transaction.amount,
39
45
  });
40
46
 
47
+ if (transaction.transferId) {
48
+ fields.push({
49
+ type: "text",
50
+ label: "Transfer ID",
51
+ value: transaction.transferId,
52
+ });
53
+ }
54
+
41
55
  log("debug", `Transaction config ${JSON.stringify(fields)}`);
42
56
 
43
57
  return fields;
@@ -0,0 +1,155 @@
1
+ import { Account } from "@ledgerhq/types-live";
2
+ import { BigNumber } from "bignumber.js";
3
+ import { estimateMaxSpendable } from "./estimateMaxSpendable";
4
+ import { getEstimatedFees } from "./bridgeHelpers/fee";
5
+ import { Transaction } from "../types";
6
+ import { createMockAccount } from "../test/fixtures";
7
+
8
+ // Mock the fee helper
9
+ jest.mock("./bridgeHelpers/fee", () => ({
10
+ getEstimatedFees: jest.fn().mockReturnValue(new BigNumber(1000000)),
11
+ }));
12
+
13
+ describe("estimateMaxSpendable", () => {
14
+ const mockAccount: Partial<Account> = {
15
+ id: "casper:0:testAccount",
16
+ type: "Account",
17
+ spendableBalance: new BigNumber(10000000),
18
+ };
19
+
20
+ afterEach(() => {
21
+ jest.clearAllMocks();
22
+ });
23
+
24
+ test("should return zero when balance is zero", async () => {
25
+ const zeroBalanceAccount = {
26
+ ...mockAccount,
27
+ spendableBalance: new BigNumber(0),
28
+ };
29
+
30
+ const result = await estimateMaxSpendable({
31
+ account: zeroBalanceAccount as Account,
32
+ parentAccount: undefined,
33
+ });
34
+
35
+ expect(result.toNumber()).toBe(0);
36
+ expect(getEstimatedFees).not.toHaveBeenCalled();
37
+ });
38
+
39
+ test("should return balance minus fees when no transaction is provided", async () => {
40
+ const result = await estimateMaxSpendable({
41
+ account: mockAccount as Account,
42
+ parentAccount: undefined,
43
+ });
44
+
45
+ const expectedFees = new BigNumber(1000000);
46
+ const expectedMaxSpendable = mockAccount.spendableBalance!.minus(expectedFees);
47
+
48
+ expect(result.toString()).toBe(expectedMaxSpendable.toString());
49
+ expect(getEstimatedFees).toHaveBeenCalled();
50
+ });
51
+
52
+ test("should use transaction fees when transaction is provided", async () => {
53
+ const transactionFees = new BigNumber(500000);
54
+ const mockTransaction: Partial<Transaction> = {
55
+ fees: transactionFees,
56
+ };
57
+
58
+ const result = await estimateMaxSpendable({
59
+ account: mockAccount as Account,
60
+ parentAccount: undefined,
61
+ transaction: mockTransaction as Transaction,
62
+ });
63
+
64
+ const expectedMaxSpendable = mockAccount.spendableBalance!.minus(transactionFees);
65
+
66
+ expect(result.toString()).toBe(expectedMaxSpendable.toString());
67
+ expect(getEstimatedFees).not.toHaveBeenCalled();
68
+ });
69
+
70
+ test("should return zero when balance is less than fees", async () => {
71
+ const lowBalanceAccount = {
72
+ ...mockAccount,
73
+ spendableBalance: new BigNumber(500000), // Less than default fee of 1000000
74
+ };
75
+
76
+ const result = await estimateMaxSpendable({
77
+ account: lowBalanceAccount as Account,
78
+ parentAccount: undefined,
79
+ });
80
+
81
+ expect(result.toString()).toBe("0");
82
+ });
83
+
84
+ test("should use main account when parentAccount is provided", async () => {
85
+ const parentAccount = {
86
+ id: "casper:parent",
87
+ spendableBalance: new BigNumber(0),
88
+ };
89
+
90
+ const result = await estimateMaxSpendable({
91
+ account: mockAccount as Account,
92
+ parentAccount: parentAccount as Account,
93
+ });
94
+
95
+ const expectedFees = new BigNumber(1000000);
96
+ const expectedMaxSpendable = mockAccount.spendableBalance!.minus(expectedFees);
97
+
98
+ expect(result.toString()).toBe(expectedMaxSpendable.toString());
99
+ });
100
+ });
101
+
102
+ // Add test cases from fixtures
103
+ describe("estimateMaxSpendable with standard test cases", () => {
104
+ const standardFees = new BigNumber("1000000");
105
+
106
+ beforeEach(() => {
107
+ (getEstimatedFees as jest.Mock).mockReturnValue(standardFees);
108
+ });
109
+
110
+ test.each([
111
+ {
112
+ name: "Standard account",
113
+ account: createMockAccount(),
114
+ expectedResult: new BigNumber("10000000000").minus(standardFees),
115
+ },
116
+ {
117
+ name: "Empty account",
118
+ account: createMockAccount({
119
+ balance: new BigNumber("0"),
120
+ spendableBalance: new BigNumber("0"),
121
+ }),
122
+ expectedResult: new BigNumber("0"),
123
+ },
124
+ {
125
+ name: "Account with balance less than fees",
126
+ account: createMockAccount({
127
+ balance: standardFees.div(2),
128
+ spendableBalance: standardFees.div(2),
129
+ }),
130
+ expectedResult: new BigNumber("0"),
131
+ },
132
+ {
133
+ name: "Account with balance equal to fees",
134
+ account: createMockAccount({
135
+ balance: standardFees,
136
+ spendableBalance: standardFees,
137
+ }),
138
+ expectedResult: new BigNumber("0"),
139
+ },
140
+ {
141
+ name: "Account with high balance",
142
+ account: createMockAccount({
143
+ balance: new BigNumber("100000000000000"),
144
+ spendableBalance: new BigNumber("100000000000000"),
145
+ }),
146
+ expectedResult: new BigNumber("100000000000000").minus(standardFees),
147
+ },
148
+ ])("should handle $name", async ({ account, expectedResult }) => {
149
+ const result = await estimateMaxSpendable({
150
+ account: account,
151
+ parentAccount: undefined,
152
+ });
153
+ expect(result.toString()).toBe(expectedResult.toString());
154
+ });
155
+ });
@@ -0,0 +1,264 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import { getTransactionStatus } from "./getTransactionStatus";
3
+ import {
4
+ CASPER_MINIMUM_VALID_AMOUNT_MOTES,
5
+ MayBlockAccountError,
6
+ InvalidMinimumAmountError,
7
+ } from "../consts";
8
+ import {
9
+ AmountRequired,
10
+ InvalidAddress,
11
+ InvalidAddressBecauseDestinationIsAlsoSource,
12
+ NotEnoughBalance,
13
+ RecipientRequired,
14
+ } from "@ledgerhq/errors";
15
+ import { CasperInvalidTransferId } from "../errors";
16
+ import { createMockAccount, createMockTransaction, TEST_ADDRESSES } from "../test/fixtures";
17
+
18
+ describe("getTransactionStatus", () => {
19
+ // Create fixtures
20
+ const mockAccount = createMockAccount();
21
+ const validTransaction = createMockTransaction();
22
+
23
+ beforeEach(() => {
24
+ jest.clearAllMocks();
25
+ });
26
+
27
+ test("should validate a valid transaction", async () => {
28
+ const status = await getTransactionStatus(mockAccount, validTransaction);
29
+
30
+ expect(status.errors).toEqual({});
31
+ expect(status.warnings).toEqual({});
32
+ expect(status.estimatedFees).toEqual(validTransaction.fees);
33
+ expect(status.amount).toEqual(validTransaction.amount);
34
+ expect(status.totalSpent).toEqual(validTransaction.amount.plus(validTransaction.fees));
35
+ });
36
+
37
+ test("should return error when recipient is missing", async () => {
38
+ const txWithoutRecipient = {
39
+ ...validTransaction,
40
+ recipient: "",
41
+ };
42
+
43
+ const status = await getTransactionStatus(mockAccount, txWithoutRecipient);
44
+
45
+ expect(status.errors.recipient).toBeInstanceOf(RecipientRequired);
46
+ });
47
+
48
+ test("should return error when recipient is invalid", async () => {
49
+ const txWithInvalidRecipient = {
50
+ ...validTransaction,
51
+ recipient: TEST_ADDRESSES.INVALID,
52
+ };
53
+
54
+ const status = await getTransactionStatus(mockAccount, txWithInvalidRecipient);
55
+
56
+ expect(status.errors.recipient).toBeInstanceOf(InvalidAddress);
57
+ });
58
+
59
+ test("should return error when recipient is same as sender", async () => {
60
+ const txToSelf = {
61
+ ...validTransaction,
62
+ recipient: mockAccount.freshAddress,
63
+ };
64
+
65
+ const status = await getTransactionStatus(mockAccount, txToSelf);
66
+
67
+ expect(status.errors.recipient).toBeInstanceOf(InvalidAddressBecauseDestinationIsAlsoSource);
68
+ });
69
+
70
+ test("should return error when transfer ID is invalid", async () => {
71
+ const txWithInvalidTransferId = {
72
+ ...validTransaction,
73
+ transferId: "invalid-id",
74
+ };
75
+
76
+ const status = await getTransactionStatus(mockAccount, txWithInvalidTransferId);
77
+
78
+ expect(status.errors.sender).toBeInstanceOf(CasperInvalidTransferId);
79
+ });
80
+
81
+ test("should handle useAllAmount correctly", async () => {
82
+ const useAllAmountTx = {
83
+ ...validTransaction,
84
+ useAllAmount: true,
85
+ };
86
+
87
+ const status = await getTransactionStatus(mockAccount, useAllAmountTx);
88
+
89
+ expect(status.amount).toEqual(mockAccount.spendableBalance.minus(useAllAmountTx.fees));
90
+ expect(status.totalSpent).toEqual(mockAccount.spendableBalance);
91
+ expect(status.errors).toEqual({});
92
+ });
93
+
94
+ test("should return error when useAllAmount but not enough balance for fees", async () => {
95
+ const lowBalanceAccount = createMockAccount({
96
+ spendableBalance: new BigNumber(500000), // Less than the fee
97
+ });
98
+
99
+ const useAllAmountTx = {
100
+ ...validTransaction,
101
+ useAllAmount: true,
102
+ fees: new BigNumber(1000000),
103
+ };
104
+
105
+ const status = await getTransactionStatus(lowBalanceAccount, useAllAmountTx);
106
+
107
+ expect(status.errors.amount).toBeInstanceOf(NotEnoughBalance);
108
+ });
109
+
110
+ test("should return error when amount is zero", async () => {
111
+ const zeroAmountTx = {
112
+ ...validTransaction,
113
+ amount: new BigNumber(0),
114
+ };
115
+
116
+ const status = await getTransactionStatus(mockAccount, zeroAmountTx);
117
+
118
+ expect(status.errors.amount).toBeInstanceOf(AmountRequired);
119
+ });
120
+
121
+ test("should return error when amount is below minimum", async () => {
122
+ const lowAmountTx = {
123
+ ...validTransaction,
124
+ amount: new BigNumber(CASPER_MINIMUM_VALID_AMOUNT_MOTES).minus(1),
125
+ };
126
+
127
+ const status = await getTransactionStatus(mockAccount, lowAmountTx);
128
+
129
+ expect(status.errors.amount).toBe(InvalidMinimumAmountError);
130
+ });
131
+
132
+ test("should return error when not enough balance for transaction", async () => {
133
+ const lowBalanceAccount = createMockAccount({
134
+ spendableBalance: new BigNumber(5000000),
135
+ });
136
+
137
+ const expensiveTx = {
138
+ ...validTransaction,
139
+ amount: new BigNumber(5000000),
140
+ fees: new BigNumber(1000000),
141
+ };
142
+
143
+ const status = await getTransactionStatus(lowBalanceAccount, expensiveTx);
144
+
145
+ expect(status.errors.amount).toBeInstanceOf(NotEnoughBalance);
146
+ });
147
+
148
+ test("should return warning when spending more than 90% of balance", async () => {
149
+ const expensiveTx = {
150
+ ...validTransaction,
151
+ amount: mockAccount.spendableBalance.multipliedBy(0.95), // 95% of balance
152
+ };
153
+
154
+ const status = await getTransactionStatus(mockAccount, expensiveTx);
155
+
156
+ expect(status.warnings.amount).toBe(MayBlockAccountError);
157
+ });
158
+
159
+ // Test using the predefined test cases
160
+ describe("transaction status test cases", () => {
161
+ const testCases = [
162
+ {
163
+ name: "Valid transaction",
164
+ account: createMockAccount(),
165
+ transaction: createMockTransaction(),
166
+ expectedStatus: { errors: {}, warnings: {}, estimatedFees: createMockTransaction().fees },
167
+ },
168
+ {
169
+ name: "Invalid recipient",
170
+ account: createMockAccount(),
171
+ transaction: createMockTransaction({ recipient: TEST_ADDRESSES.INVALID }),
172
+ expectedStatus: {
173
+ errors: { recipient: new InvalidAddress() },
174
+ warnings: {},
175
+ estimatedFees: createMockTransaction().fees,
176
+ },
177
+ },
178
+ {
179
+ name: "Zero amount",
180
+ account: createMockAccount(),
181
+ transaction: createMockTransaction({ amount: new BigNumber("0") }),
182
+ expectedStatus: {
183
+ errors: { amount: new AmountRequired() },
184
+ warnings: {},
185
+ },
186
+ },
187
+ {
188
+ name: "High amount (warning)",
189
+ account: createMockAccount(),
190
+ transaction: createMockTransaction({
191
+ amount: new BigNumber(
192
+ createMockAccount().balance.minus(createMockTransaction().fees).toString(),
193
+ ),
194
+ }),
195
+ expectedStatus: {
196
+ errors: {},
197
+ warnings: { amount: MayBlockAccountError },
198
+ },
199
+ },
200
+ {
201
+ name: "Insufficient funds",
202
+ account: createMockAccount({
203
+ balance: new BigNumber("2000000"), // 0.002 CSPR
204
+ spendableBalance: new BigNumber("2000000"),
205
+ }),
206
+ transaction: createMockTransaction({
207
+ amount: new BigNumber("2000000"),
208
+ }),
209
+ expectedStatus: {
210
+ errors: { amount: new NotEnoughBalance() },
211
+ warnings: { amount: MayBlockAccountError },
212
+ },
213
+ },
214
+ {
215
+ name: "Empty account",
216
+ account: createMockAccount({
217
+ balance: new BigNumber("0"),
218
+ spendableBalance: new BigNumber("0"),
219
+ }),
220
+ transaction: createMockTransaction(),
221
+ expectedStatus: {
222
+ errors: { amount: new NotEnoughBalance() },
223
+ warnings: { amount: MayBlockAccountError },
224
+ },
225
+ },
226
+ ];
227
+
228
+ testCases.forEach(testCase => {
229
+ test(`should handle ${testCase.name}`, async () => {
230
+ const status = await getTransactionStatus(testCase.account, testCase.transaction);
231
+
232
+ // Check if errors match expected errors
233
+ if (Object.keys(testCase.expectedStatus.errors).length) {
234
+ // Simplified error checking
235
+ expect(Object.keys(status.errors).length).toBeGreaterThan(0);
236
+
237
+ // Check only specific known error keys
238
+ if ("recipient" in testCase.expectedStatus.errors) {
239
+ expect(status.errors.recipient).toBeTruthy();
240
+ }
241
+
242
+ if ("amount" in testCase.expectedStatus.errors) {
243
+ expect(status.errors.amount).toBeTruthy();
244
+ }
245
+ } else {
246
+ expect(Object.keys(status.errors).length).toBe(0);
247
+ }
248
+
249
+ // Check if warnings match expected warnings
250
+ if (Object.keys(testCase.expectedStatus.warnings).length) {
251
+ // Simplified warning checking
252
+ expect(Object.keys(status.warnings).length).toBeGreaterThan(0);
253
+
254
+ // Check only specific known warning keys
255
+ if ("amount" in testCase.expectedStatus.warnings) {
256
+ expect(status.warnings.amount).toBeTruthy();
257
+ }
258
+ } else {
259
+ expect(Object.keys(status.warnings).length).toBe(0);
260
+ }
261
+ });
262
+ });
263
+ });
264
+ });
@@ -17,6 +17,8 @@ import { createTransaction } from "./createTransaction";
17
17
  import { getAccountShape } from "./bridgeHelpers/accountShape";
18
18
  import { buildSignOperation } from "./signOperation";
19
19
  import { broadcast } from "./broadcast";
20
+ import { CasperCoinConfig } from "../config";
21
+ import { setCoinConfig } from "../config";
20
22
 
21
23
  function buildCurrencyBridge(signerContext: SignerContext<CasperSigner>): CurrencyBridge {
22
24
  const getAddress = resolver(signerContext);
@@ -57,7 +59,12 @@ function buildAccountBridge(
57
59
  };
58
60
  }
59
61
 
60
- export function createBridges(signerContext: SignerContext<CasperSigner>) {
62
+ export function createBridges(
63
+ signerContext: SignerContext<CasperSigner>,
64
+ coinConfig: CasperCoinConfig,
65
+ ) {
66
+ setCoinConfig(coinConfig);
67
+
61
68
  return {
62
69
  currencyBridge: buildCurrencyBridge(signerContext),
63
70
  accountBridge: buildAccountBridge(signerContext),