@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,339 @@
1
+ import BigNumber from "bignumber.js";
2
+ import { getUnit, mapTxToOps } from "./txn";
3
+ import { casperAccountHashFromPublicKey, isAddressValid } from "./addresses";
4
+ import * as fixtures from "../../test/fixtures";
5
+ import { ITxnHistoryData } from "../../api/types";
6
+ import { createNewTransaction as testCreateNewTransaction } from "./txn";
7
+
8
+ // Import Casper SDK mock for direct access to mocks
9
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
10
+ const mockCasperSDK = require("casper-js-sdk");
11
+
12
+ // Mock the entire Casper SDK
13
+ jest.mock("casper-js-sdk", () => {
14
+ const mockTransaction = { id: "mock-transaction" };
15
+ const mockHelper = {
16
+ createTransferTransaction: jest.fn().mockReturnValue(mockTransaction),
17
+ };
18
+
19
+ return {
20
+ CasperNetwork: {
21
+ create: jest.fn().mockResolvedValue(mockHelper),
22
+ },
23
+ PublicKey: {
24
+ fromHex: jest.fn().mockReturnValue({ value: "mocked-public-key" }),
25
+ },
26
+ Transaction: jest.fn().mockImplementation(() => mockTransaction),
27
+ };
28
+ });
29
+
30
+ jest.mock("@ledgerhq/coin-framework/operation", () => ({
31
+ encodeOperationId: jest.fn(
32
+ (accountId: string, hash: string, type: string) => `${accountId}-${hash}-${type}`,
33
+ ),
34
+ }));
35
+
36
+ jest.mock("./addresses", () => ({
37
+ casperAccountHashFromPublicKey: jest.fn((key: string) => `account-hash-${key}`),
38
+ isAddressValid: jest.fn(),
39
+ }));
40
+
41
+ jest.mock("../../api", () => ({
42
+ getCasperNodeRpcClient: jest.fn(),
43
+ }));
44
+
45
+ describe("txn", () => {
46
+ // Reset mocks between tests
47
+ beforeEach(() => {
48
+ jest.clearAllMocks();
49
+ });
50
+
51
+ describe("getUnit", () => {
52
+ test("should return the first unit of casper currency", () => {
53
+ const unit = getUnit();
54
+ expect(unit).toBeDefined();
55
+ expect(unit.name).toBe("CSPR");
56
+ expect(unit.code).toBe("CSPR");
57
+ expect(unit.magnitude).toBe(9);
58
+ });
59
+ });
60
+
61
+ describe("mapTxToOps", () => {
62
+ const { mockAccountId } = fixtures.createMockAccountShapeData();
63
+ const fees = new BigNumber("100000000");
64
+ const mockTimestamp = "2023-01-01T12:00:00Z";
65
+
66
+ beforeEach(() => {
67
+ (casperAccountHashFromPublicKey as jest.Mock).mockImplementation(
68
+ (key: string) => `account-hash-${key}`,
69
+ );
70
+ });
71
+
72
+ test("should map an outgoing transaction to operation", () => {
73
+ // Use a modified version of the fixture tx data
74
+ const fixtureData = fixtures.createMockAccountShapeData();
75
+ const txData: ITxnHistoryData = {
76
+ ...fixtureData.mockTxs[0],
77
+ timestamp: mockTimestamp,
78
+ caller_public_key: "owner-public-key",
79
+ args: {
80
+ target: {
81
+ cl_type: "PublicKey",
82
+ parsed: "recipient-public-key",
83
+ },
84
+ amount: {
85
+ parsed: "5000000000",
86
+ cl_type: "U512",
87
+ },
88
+ id: {
89
+ parsed: 12345,
90
+ cl_type: {
91
+ Option: "U64",
92
+ },
93
+ },
94
+ },
95
+ deploy_hash: "test-deploy-hash",
96
+ status: "success",
97
+ amount: "5000000000",
98
+ };
99
+
100
+ // Set up the owner address hash to match the from account hash
101
+ (casperAccountHashFromPublicKey as jest.Mock).mockReturnValueOnce(
102
+ "account-hash-owner-public-key",
103
+ );
104
+ (casperAccountHashFromPublicKey as jest.Mock).mockReturnValueOnce(
105
+ "account-hash-recipient-public-key",
106
+ );
107
+
108
+ const mapper = mapTxToOps(mockAccountId, "account-hash-owner-public-key", fees);
109
+ const operations = mapper(txData);
110
+
111
+ expect(operations).toHaveLength(1);
112
+ expect(operations[0]).toEqual({
113
+ id: `${mockAccountId}-${txData.deploy_hash}-OUT`,
114
+ hash: txData.deploy_hash,
115
+ type: "OUT",
116
+ value: new BigNumber("5000000000").plus(fees),
117
+ fee: fees,
118
+ blockHeight: 1,
119
+ hasFailed: false,
120
+ blockHash: null,
121
+ accountId: mockAccountId,
122
+ senders: ["account-hash-owner-public-key"],
123
+ recipients: ["account-hash-recipient-public-key"],
124
+ date: new Date(mockTimestamp),
125
+ extra: {
126
+ transferId: "12345",
127
+ },
128
+ });
129
+ });
130
+
131
+ test("should map an incoming transaction to operation", () => {
132
+ const recipientAddressHash = "account-hash-owner-public-key";
133
+ // Use a modified version of the fixture tx data
134
+ const fixtureData = fixtures.createMockAccountShapeData();
135
+ const txData: ITxnHistoryData = {
136
+ ...fixtureData.mockTxs[0],
137
+ timestamp: mockTimestamp,
138
+ caller_public_key: "sender-public-key",
139
+ args: {
140
+ target: {
141
+ cl_type: "PublicKey",
142
+ parsed: "owner-public-key",
143
+ },
144
+ amount: {
145
+ parsed: "5000000000",
146
+ cl_type: "U512",
147
+ },
148
+ id: {
149
+ parsed: 12345,
150
+ cl_type: {
151
+ Option: "U64",
152
+ },
153
+ },
154
+ },
155
+ deploy_hash: "test-deploy-hash",
156
+ status: "success",
157
+ amount: "5000000000",
158
+ };
159
+
160
+ (casperAccountHashFromPublicKey as jest.Mock).mockReturnValueOnce(
161
+ "account-hash-sender-public-key",
162
+ );
163
+ (casperAccountHashFromPublicKey as jest.Mock).mockReturnValueOnce(recipientAddressHash);
164
+
165
+ const mapper = mapTxToOps(mockAccountId, recipientAddressHash, fees);
166
+ const operations = mapper(txData);
167
+
168
+ expect(operations).toHaveLength(1);
169
+ expect(operations[0]).toEqual({
170
+ id: `${mockAccountId}-${txData.deploy_hash}-IN`,
171
+ hash: txData.deploy_hash,
172
+ type: "IN",
173
+ value: new BigNumber("5000000000"),
174
+ fee: fees,
175
+ blockHeight: 1,
176
+ hasFailed: false,
177
+ blockHash: null,
178
+ accountId: mockAccountId,
179
+ senders: ["account-hash-sender-public-key"],
180
+ recipients: [recipientAddressHash],
181
+ date: new Date(mockTimestamp),
182
+ extra: {
183
+ transferId: "12345",
184
+ },
185
+ });
186
+ });
187
+
188
+ test("should map a failed transaction correctly", () => {
189
+ // Use a modified version of the fixture tx data
190
+ const fixtureData = fixtures.createMockAccountShapeData();
191
+ const txData: ITxnHistoryData = {
192
+ ...fixtureData.mockTxs[0],
193
+ timestamp: mockTimestamp,
194
+ caller_public_key: "owner-public-key",
195
+ args: {
196
+ target: {
197
+ cl_type: "PublicKey",
198
+ parsed: "recipient-public-key",
199
+ },
200
+ amount: {
201
+ parsed: "5000000000",
202
+ cl_type: "U512",
203
+ },
204
+ id: {
205
+ parsed: 12345,
206
+ cl_type: {
207
+ Option: "U64",
208
+ },
209
+ },
210
+ },
211
+ deploy_hash: "test-deploy-hash",
212
+ error_message: "Transaction failed due to insufficient funds",
213
+ status: "failure",
214
+ amount: "5000000000",
215
+ };
216
+
217
+ (casperAccountHashFromPublicKey as jest.Mock).mockReturnValueOnce(
218
+ "account-hash-owner-public-key",
219
+ );
220
+ (casperAccountHashFromPublicKey as jest.Mock).mockReturnValueOnce(
221
+ "account-hash-recipient-public-key",
222
+ );
223
+
224
+ const mapper = mapTxToOps(mockAccountId, "account-hash-owner-public-key", fees);
225
+ const operations = mapper(txData);
226
+
227
+ expect(operations).toHaveLength(1);
228
+ expect(operations[0].hasFailed).toBe(true);
229
+ });
230
+
231
+ test("should handle target as account hash string directly", () => {
232
+ // Use a modified version of the fixture tx data
233
+ const fixtureData = fixtures.createMockAccountShapeData();
234
+ const txData: ITxnHistoryData = {
235
+ ...fixtureData.mockTxs[0],
236
+ timestamp: mockTimestamp,
237
+ caller_public_key: "owner-public-key",
238
+ args: {
239
+ target: {
240
+ cl_type: {
241
+ ByteArray: 32,
242
+ },
243
+ parsed: "account-hash-direct-address",
244
+ },
245
+ amount: {
246
+ parsed: "5000000000",
247
+ cl_type: "U512",
248
+ },
249
+ id: {
250
+ parsed: 12345,
251
+ cl_type: {
252
+ Option: "U64",
253
+ },
254
+ },
255
+ },
256
+ deploy_hash: "test-deploy-hash",
257
+ status: "success",
258
+ amount: "5000000000",
259
+ };
260
+
261
+ (casperAccountHashFromPublicKey as jest.Mock).mockReturnValueOnce(
262
+ "account-hash-owner-public-key",
263
+ );
264
+
265
+ const mapper = mapTxToOps(mockAccountId, "account-hash-owner-public-key", fees);
266
+ const operations = mapper(txData);
267
+
268
+ expect(operations).toHaveLength(1);
269
+ expect(operations[0].recipients).toEqual(["account-hash-direct-address"]);
270
+ });
271
+
272
+ test("should catch and log errors when mapping fails", () => {
273
+ const txData = {
274
+ timestamp: mockTimestamp,
275
+ caller_public_key: "owner-public-key",
276
+ args: {
277
+ // Intentionally missing the target field to cause an error
278
+ amount: {
279
+ parsed: "5000000000",
280
+ cl_type: "U512",
281
+ },
282
+ },
283
+ deploy_hash: "test-deploy-hash",
284
+ block_hash: "block-hash-1",
285
+ execution_type_id: 1,
286
+ cost: "100000",
287
+ payment_amount: "100000000",
288
+ status: "success",
289
+ amount: "5000000000",
290
+ };
291
+
292
+ const mapper = mapTxToOps(mockAccountId, "account-hash-owner-public-key", fees);
293
+ const operations = mapper(txData as any);
294
+
295
+ expect(operations).toEqual([]);
296
+ });
297
+ });
298
+
299
+ describe("createNewTransaction", () => {
300
+ const { mockAddress: mockSender } = fixtures.createMockAccountShapeData();
301
+ const mockRecipient = fixtures.TEST_ADDRESSES.RECIPIENT_SECP256K1;
302
+ const mockAmount = new BigNumber("5000000000");
303
+ const mockFees = new BigNumber("100000000");
304
+ const mockTransferId = fixtures.TEST_TRANSFER_IDS.VALID;
305
+
306
+ // Direct access to the mocks from jest.mock
307
+ const mockCreateNetwork = mockCasperSDK.CasperNetwork.create;
308
+ const mockPublicKeyFromHex = mockCasperSDK.PublicKey.fromHex;
309
+
310
+ beforeEach(() => {
311
+ (isAddressValid as jest.Mock).mockReturnValue(true);
312
+ });
313
+
314
+ test("should throw error if recipient address is invalid", async () => {
315
+ (isAddressValid as jest.Mock).mockReturnValue(false);
316
+
317
+ await expect(
318
+ testCreateNewTransaction(mockSender, mockRecipient, mockAmount, mockFees),
319
+ ).rejects.toThrow();
320
+ });
321
+
322
+ test("should create a new transaction with valid parameters", async () => {
323
+ const expectedTransaction = { id: "mock-transaction" };
324
+
325
+ const result = await testCreateNewTransaction(
326
+ mockSender,
327
+ mockRecipient,
328
+ mockAmount,
329
+ mockFees,
330
+ mockTransferId,
331
+ );
332
+
333
+ expect(result).toEqual(expectedTransaction);
334
+ expect(mockCreateNetwork).toHaveBeenCalled();
335
+ expect(mockPublicKeyFromHex).toHaveBeenCalledWith(mockSender);
336
+ expect(mockPublicKeyFromHex).toHaveBeenCalledWith(mockRecipient);
337
+ });
338
+ });
339
+ });
@@ -3,14 +3,15 @@ import { InvalidAddress } from "@ledgerhq/errors";
3
3
  import { log } from "@ledgerhq/logs";
4
4
  import { Unit } from "@ledgerhq/types-cryptoassets";
5
5
  import BigNumber from "bignumber.js";
6
- import { DeployUtil } from "casper-js-sdk";
6
+ import { CasperNetwork, PublicKey, Transaction } from "casper-js-sdk";
7
7
  import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
8
- import { CASPER_NETWORK } from "../../consts";
9
- import { casperAccountHashFromPublicKey, casperGetCLPublicKey, isAddressValid } from "./addresses";
8
+ import { CASPER_DEFAULT_TTL, CASPER_NETWORK } from "../../consts";
9
+ import { casperAccountHashFromPublicKey, isAddressValid } from "./addresses";
10
10
  import { ITxnHistoryData } from "../../api/types";
11
11
  import { getEstimatedFees } from "./fee";
12
12
  import { CasperOperation } from "../../types";
13
13
  import invariant from "invariant";
14
+ import { getCasperNodeRpcClient } from "../../api";
14
15
 
15
16
  export const getUnit = (): Unit => getCryptoCurrencyById("casper").units[0];
16
17
 
@@ -89,33 +90,32 @@ export function mapTxToOps(
89
90
  };
90
91
  }
91
92
 
92
- export const createNewDeploy = (
93
+ export const createNewTransaction = async (
93
94
  sender: string,
94
95
  recipient: string,
95
96
  amount: BigNumber,
96
97
  fees: BigNumber,
97
98
  transferId?: string,
98
99
  network = CASPER_NETWORK,
99
- ): DeployUtil.Deploy => {
100
- log("debug", `Creating new Deploy: ${sender}, ${recipient}, ${network}`);
100
+ ): Promise<Transaction> => {
101
+ log("debug", `Creating new Transaction: ${sender}, ${recipient}, ${network}`);
101
102
 
102
103
  if (recipient && !isAddressValid(recipient)) {
103
104
  throw InvalidAddress(`Invalid recipient Address ${recipient}`);
104
105
  }
105
106
 
106
- const deployParams = new DeployUtil.DeployParams(casperGetCLPublicKey(sender), network);
107
+ const client = getCasperNodeRpcClient();
108
+ const helper = await CasperNetwork.create(client);
107
109
 
108
- const session = DeployUtil.ExecutableDeployItem.newTransferWithOptionalTransferId(
109
- amount?.toNumber() ?? 0,
110
- casperGetCLPublicKey(recipient),
111
- undefined,
112
- transferId,
110
+ const tx = helper.createTransferTransaction(
111
+ PublicKey.fromHex(sender),
112
+ PublicKey.fromHex(recipient),
113
+ network,
114
+ amount.toString(),
115
+ fees.toNumber(),
116
+ CASPER_DEFAULT_TTL,
117
+ parseInt(transferId ?? "0"),
113
118
  );
114
119
 
115
- const payment = DeployUtil.standardPayment(fees.toString());
116
- const deploy = DeployUtil.makeDeploy(deployParams, session, payment);
117
- const txnRaw = DeployUtil.deployToJson(deploy);
118
- const txnFromRaw = DeployUtil.deployFromJson(txnRaw).unwrap();
119
-
120
- return txnFromRaw;
120
+ return tx;
121
121
  };
@@ -0,0 +1,89 @@
1
+ import { Transaction as CasperTransaction, PublicKey } from "casper-js-sdk";
2
+ import { broadcast } from "./broadcast";
3
+ import { broadcastTx } from "../api";
4
+ import {
5
+ createMockAccount,
6
+ createMockTransaction,
7
+ createMockSignedOperation,
8
+ } from "../test/fixtures";
9
+ import { patchOperationWithHash } from "@ledgerhq/coin-framework/lib/operation";
10
+
11
+ // Mock the dependencies
12
+ jest.mock("casper-js-sdk", () => {
13
+ return {
14
+ Transaction: {
15
+ fromJSON: jest.fn().mockReturnValue({
16
+ setSignature: jest.fn(),
17
+ }),
18
+ },
19
+ PublicKey: {
20
+ fromHex: jest.fn().mockReturnValue("mockedPublicKey"),
21
+ },
22
+ };
23
+ });
24
+
25
+ jest.mock("../api", () => ({
26
+ broadcastTx: jest.fn().mockResolvedValue("mockedTxHash"),
27
+ }));
28
+
29
+ describe("broadcast", () => {
30
+ // Create test fixtures
31
+ const mockAccount = createMockAccount();
32
+ const mockTransaction = createMockTransaction();
33
+ const mockSignedOperation = createMockSignedOperation(mockAccount, mockTransaction, {
34
+ signature: "deadbeef",
35
+ rawTxJson: { hash: "mockTxHash" },
36
+ });
37
+
38
+ afterEach(() => {
39
+ jest.clearAllMocks();
40
+ });
41
+
42
+ test("should successfully broadcast a transaction", async () => {
43
+ const result = await broadcast({
44
+ account: mockAccount,
45
+ signedOperation: mockSignedOperation,
46
+ });
47
+
48
+ // Assert the transaction was constructed and signed correctly
49
+ expect(CasperTransaction.fromJSON).toHaveBeenCalledWith(mockSignedOperation.rawData.tx);
50
+ expect(PublicKey.fromHex).toHaveBeenCalledWith(mockAccount.freshAddress);
51
+
52
+ // Assert the transaction was broadcast
53
+ expect(broadcastTx).toHaveBeenCalled();
54
+
55
+ // Assert the operation was patched with the hash
56
+ expect(result.hash).toBe("mockedTxHash");
57
+ expect(result).toEqual({
58
+ ...patchOperationWithHash(mockSignedOperation.operation, "mockedTxHash"),
59
+ hash: "mockedTxHash",
60
+ });
61
+ });
62
+
63
+ test("should throw if rawData is missing", async () => {
64
+ // Create a type-safe but invalid signed operation for testing
65
+ const invalidSignedOperation = {
66
+ ...mockSignedOperation,
67
+ rawData: null as any, // Force type assertion for test
68
+ };
69
+
70
+ await expect(
71
+ broadcast({
72
+ account: mockAccount,
73
+ signedOperation: invalidSignedOperation,
74
+ }),
75
+ ).rejects.toThrow("casper: rawData is required");
76
+ });
77
+
78
+ test("should throw if broadcast fails to return a hash", async () => {
79
+ // Mock broadcastTx to return null (failed broadcast)
80
+ (broadcastTx as jest.Mock).mockResolvedValueOnce(null);
81
+
82
+ await expect(
83
+ broadcast({
84
+ account: mockAccount,
85
+ signedOperation: mockSignedOperation,
86
+ }),
87
+ ).rejects.toThrow("casper: failed to broadcast transaction and get transaction hash");
88
+ });
89
+ });
@@ -1,4 +1,4 @@
1
- import { DeployUtil } from "casper-js-sdk";
1
+ import { Transaction as CasperTransaction, PublicKey } from "casper-js-sdk";
2
2
  import { AccountBridge } from "@ledgerhq/types-live";
3
3
  import { patchOperationWithHash } from "@ledgerhq/coin-framework/operation";
4
4
  import { Transaction } from "../types";
@@ -6,15 +6,17 @@ import { broadcastTx } from "../api";
6
6
  import invariant from "invariant";
7
7
 
8
8
  export const broadcast: AccountBridge<Transaction>["broadcast"] = async ({
9
- signedOperation: { signature, operation },
9
+ account,
10
+ signedOperation: { signature, operation, rawData },
10
11
  }) => {
11
- const tx = DeployUtil.deployFromJson(JSON.parse(signature)).unwrap();
12
+ invariant(rawData, "casper: rawData is required");
13
+ const tx = CasperTransaction.fromJSON(rawData.tx);
14
+ tx.setSignature(Buffer.from(signature, "hex"), PublicKey.fromHex(account.freshAddress));
12
15
 
13
- const resp = await broadcastTx(tx);
14
- invariant(resp.deploy_hash, "casper: failed to broadcast transaction and get deploy hash");
15
- const { deploy_hash } = resp;
16
+ const hash = await broadcastTx(tx);
17
+ invariant(hash, "casper: failed to broadcast transaction and get transaction hash");
16
18
 
17
- const result = patchOperationWithHash(operation, deploy_hash);
19
+ const result = patchOperationWithHash(operation, hash);
18
20
 
19
21
  return result;
20
22
  };
@@ -0,0 +1,89 @@
1
+ import { buildOptimisticOperation } from "./buildOptimisticOperation";
2
+ import { getAddress } from "./bridgeHelpers/addresses";
3
+ import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
4
+ import { createMockAccount, createMockTransaction, TEST_TRANSFER_IDS } from "../test/fixtures";
5
+
6
+ // Mock dependencies
7
+ jest.mock("./bridgeHelpers/addresses", () => ({
8
+ getAddress: jest.fn(),
9
+ }));
10
+
11
+ jest.mock("@ledgerhq/coin-framework/operation", () => ({
12
+ encodeOperationId: jest.fn(),
13
+ }));
14
+
15
+ describe("buildOptimisticOperation", () => {
16
+ // Create test fixtures using helper functions
17
+ const mockAccount = createMockAccount();
18
+ const mockTransaction = createMockTransaction();
19
+
20
+ const mockHash = "mockedTransactionHash";
21
+ const mockAddress = "01abcdef1234567890";
22
+ const mockOperationId = "mockOperationId";
23
+
24
+ beforeEach(() => {
25
+ jest.clearAllMocks();
26
+ (getAddress as jest.Mock).mockReturnValue({ address: mockAddress });
27
+ (encodeOperationId as jest.Mock).mockReturnValue(mockOperationId);
28
+ });
29
+
30
+ test("should build an optimistic operation for an outgoing transaction", () => {
31
+ const operation = buildOptimisticOperation(mockAccount, mockTransaction, mockHash);
32
+
33
+ expect(getAddress).toHaveBeenCalledWith(mockAccount);
34
+ expect(encodeOperationId).toHaveBeenCalledWith(mockAccount.id, mockHash, "OUT");
35
+
36
+ expect(operation).toEqual({
37
+ id: mockOperationId,
38
+ hash: mockHash,
39
+ type: "OUT",
40
+ senders: [mockAddress],
41
+ recipients: [mockTransaction.recipient],
42
+ accountId: mockAccount.id,
43
+ value: mockTransaction.amount.plus(mockTransaction.fees),
44
+ fee: mockTransaction.fees,
45
+ blockHash: null,
46
+ blockHeight: null,
47
+ date: expect.any(Date),
48
+ extra: {
49
+ transferId: mockTransaction.transferId,
50
+ },
51
+ nftOperations: [],
52
+ subOperations: [],
53
+ });
54
+ });
55
+
56
+ test("should build an optimistic operation with a custom operation type", () => {
57
+ const customType = "IN";
58
+ const operation = buildOptimisticOperation(mockAccount, mockTransaction, mockHash, customType);
59
+
60
+ expect(encodeOperationId).toHaveBeenCalledWith(mockAccount.id, mockHash, customType);
61
+ expect(operation.type).toBe(customType);
62
+ });
63
+
64
+ test("should include transferId in the extra field when present", () => {
65
+ const txWithTransferId = {
66
+ ...mockTransaction,
67
+ transferId: TEST_TRANSFER_IDS.VALID,
68
+ };
69
+
70
+ const operation = buildOptimisticOperation(mockAccount, txWithTransferId, mockHash);
71
+
72
+ expect(operation.extra).toEqual({
73
+ transferId: TEST_TRANSFER_IDS.VALID,
74
+ });
75
+ });
76
+
77
+ test("should handle transaction without transferId", () => {
78
+ const txWithoutTransferId = {
79
+ ...mockTransaction,
80
+ transferId: undefined,
81
+ };
82
+
83
+ const operation = buildOptimisticOperation(mockAccount, txWithoutTransferId, mockHash);
84
+
85
+ expect(operation.extra).toEqual({
86
+ transferId: undefined,
87
+ });
88
+ });
89
+ });
@@ -27,5 +27,7 @@ export const buildOptimisticOperation = (
27
27
  extra: {
28
28
  transferId: transaction.transferId,
29
29
  },
30
+ nftOperations: [],
31
+ subOperations: [],
30
32
  };
31
33
  };
@@ -0,0 +1,43 @@
1
+ import BigNumber from "bignumber.js";
2
+ import { createTransaction } from "./createTransaction";
3
+ import { Transaction } from "../types";
4
+ import { Account, AccountLike } from "@ledgerhq/types-live";
5
+
6
+ describe("createTransaction", () => {
7
+ it("should create a transaction with default values", () => {
8
+ const transaction = createTransaction({} as AccountLike<Account>);
9
+ const expectedTransaction: Transaction = {
10
+ family: "casper",
11
+ amount: new BigNumber(0),
12
+ fees: new BigNumber(0),
13
+ recipient: "",
14
+ useAllAmount: false,
15
+ };
16
+ expect(transaction).toEqual(expectedTransaction);
17
+ });
18
+
19
+ it("should create a transaction with the correct family", () => {
20
+ const transaction = createTransaction({} as AccountLike<Account>);
21
+ expect(transaction.family).toBe("casper");
22
+ });
23
+
24
+ it("should create a transaction with default amount set to zero", () => {
25
+ const transaction = createTransaction({} as AccountLike<Account>);
26
+ expect(transaction.amount.isEqualTo(new BigNumber(0))).toBe(true);
27
+ });
28
+
29
+ it("should create a transaction with default fees set to zero", () => {
30
+ const transaction = createTransaction({} as AccountLike<Account>);
31
+ expect(transaction.fees.isEqualTo(new BigNumber(0))).toBe(true);
32
+ });
33
+
34
+ it("should create a transaction with empty recipient", () => {
35
+ const transaction = createTransaction({} as AccountLike<Account>);
36
+ expect(transaction.recipient).toBe("");
37
+ });
38
+
39
+ it("should create a transaction with useAllAmount set to false", () => {
40
+ const transaction = createTransaction({} as AccountLike<Account>);
41
+ expect(transaction.useAllAmount).toBe(false);
42
+ });
43
+ });