@ledgerhq/coin-stellar 6.26.0 → 6.26.1

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 (271) hide show
  1. package/.oxlintrc.json +7 -0
  2. package/CHANGELOG.md +6 -0
  3. package/LICENSE +194 -0
  4. package/knip.json +12 -0
  5. package/lib/api/index.d.ts +5 -5
  6. package/lib/api/index.d.ts.map +1 -1
  7. package/lib/api/index.js +12 -10
  8. package/lib/api/index.js.map +1 -1
  9. package/lib/config.d.ts +1 -1
  10. package/lib/config.d.ts.map +1 -1
  11. package/lib/config.js +2 -0
  12. package/lib/config.js.map +1 -1
  13. package/lib/constants.d.ts.map +1 -1
  14. package/lib/constants.js +3 -1
  15. package/lib/constants.js.map +1 -1
  16. package/lib/logic/broadcast.d.ts.map +1 -1
  17. package/lib/logic/broadcast.js +2 -0
  18. package/lib/logic/broadcast.js.map +1 -1
  19. package/lib/logic/combine.d.ts +1 -1
  20. package/lib/logic/combine.d.ts.map +1 -1
  21. package/lib/logic/combine.js +2 -0
  22. package/lib/logic/combine.js.map +1 -1
  23. package/lib/logic/common.d.ts +1 -1
  24. package/lib/logic/common.d.ts.map +1 -1
  25. package/lib/logic/common.js +4 -2
  26. package/lib/logic/common.js.map +1 -1
  27. package/lib/logic/craftTransaction.d.ts +1 -1
  28. package/lib/logic/craftTransaction.d.ts.map +1 -1
  29. package/lib/logic/craftTransaction.js +10 -8
  30. package/lib/logic/craftTransaction.js.map +1 -1
  31. package/lib/logic/estimateFees.d.ts.map +1 -1
  32. package/lib/logic/estimateFees.js +2 -0
  33. package/lib/logic/estimateFees.js.map +1 -1
  34. package/lib/logic/getBalance.d.ts +1 -1
  35. package/lib/logic/getBalance.d.ts.map +1 -1
  36. package/lib/logic/getBalance.js +4 -2
  37. package/lib/logic/getBalance.js.map +1 -1
  38. package/lib/logic/getBlock.d.ts +1 -1
  39. package/lib/logic/getBlock.d.ts.map +1 -1
  40. package/lib/logic/getBlock.js +39 -34
  41. package/lib/logic/getBlock.js.map +1 -1
  42. package/lib/logic/getBlockInfo.d.ts +1 -1
  43. package/lib/logic/getBlockInfo.d.ts.map +1 -1
  44. package/lib/logic/getBlockInfo.js +2 -0
  45. package/lib/logic/getBlockInfo.js.map +1 -1
  46. package/lib/logic/index.d.ts +12 -12
  47. package/lib/logic/index.d.ts.map +1 -1
  48. package/lib/logic/index.js +2 -0
  49. package/lib/logic/index.js.map +1 -1
  50. package/lib/logic/lastBlock.d.ts +1 -1
  51. package/lib/logic/lastBlock.d.ts.map +1 -1
  52. package/lib/logic/lastBlock.js +2 -0
  53. package/lib/logic/lastBlock.js.map +1 -1
  54. package/lib/logic/listOperations.d.ts +1 -1
  55. package/lib/logic/listOperations.d.ts.map +1 -1
  56. package/lib/logic/listOperations.js +6 -4
  57. package/lib/logic/listOperations.js.map +1 -1
  58. package/lib/logic/sdkWrapper.d.ts +1 -1
  59. package/lib/logic/sdkWrapper.d.ts.map +1 -1
  60. package/lib/logic/sdkWrapper.js +2 -0
  61. package/lib/logic/sdkWrapper.js.map +1 -1
  62. package/lib/logic/utils.d.ts.map +1 -1
  63. package/lib/logic/utils.js +4 -2
  64. package/lib/logic/utils.js.map +1 -1
  65. package/lib/logic/validateAddress.d.ts +1 -1
  66. package/lib/logic/validateAddress.d.ts.map +1 -1
  67. package/lib/logic/validateAddress.js +2 -0
  68. package/lib/logic/validateAddress.js.map +1 -1
  69. package/lib/logic/validateIntent.d.ts +2 -2
  70. package/lib/logic/validateIntent.d.ts.map +1 -1
  71. package/lib/logic/validateIntent.js +21 -19
  72. package/lib/logic/validateIntent.js.map +1 -1
  73. package/lib/logic/validateMemo.d.ts +1 -1
  74. package/lib/logic/validateMemo.d.ts.map +1 -1
  75. package/lib/logic/validateMemo.js +7 -5
  76. package/lib/logic/validateMemo.js.map +1 -1
  77. package/lib/network/horizon.d.ts +6 -7
  78. package/lib/network/horizon.d.ts.map +1 -1
  79. package/lib/network/horizon.js +71 -68
  80. package/lib/network/horizon.js.map +1 -1
  81. package/lib/network/horizonLedgerErrors.d.ts.map +1 -1
  82. package/lib/network/horizonLedgerErrors.js +5 -3
  83. package/lib/network/horizonLedgerErrors.js.map +1 -1
  84. package/lib/network/index.d.ts +1 -1
  85. package/lib/network/index.d.ts.map +1 -1
  86. package/lib/network/index.js +2 -0
  87. package/lib/network/index.js.map +1 -1
  88. package/lib/network/serialization.d.ts +6 -4
  89. package/lib/network/serialization.d.ts.map +1 -1
  90. package/lib/network/serialization.js +95 -91
  91. package/lib/network/serialization.js.map +1 -1
  92. package/lib/polyfill.d.ts.map +1 -1
  93. package/lib/polyfill.js +6 -4
  94. package/lib/polyfill.js.map +1 -1
  95. package/lib/supportedFeatures.d.ts +1 -1
  96. package/lib/supportedFeatures.d.ts.map +1 -1
  97. package/lib/supportedFeatures.js +3 -1
  98. package/lib/supportedFeatures.js.map +1 -1
  99. package/lib/types/errors.d.ts.map +1 -1
  100. package/lib/types/errors.js +14 -12
  101. package/lib/types/errors.js.map +1 -1
  102. package/lib/types/index.d.ts +2 -2
  103. package/lib/types/index.d.ts.map +1 -1
  104. package/lib/types/index.js +2 -0
  105. package/lib/types/index.js.map +1 -1
  106. package/lib/types/model.d.ts +6 -6
  107. package/lib/types/model.d.ts.map +1 -1
  108. package/lib/types/model.js +7 -5
  109. package/lib/types/model.js.map +1 -1
  110. package/lib-es/api/index.d.ts +5 -5
  111. package/lib-es/api/index.d.ts.map +1 -1
  112. package/lib-es/api/index.js +20 -18
  113. package/lib-es/api/index.js.map +1 -1
  114. package/lib-es/config.d.ts +1 -1
  115. package/lib-es/config.d.ts.map +1 -1
  116. package/lib-es/config.js +3 -1
  117. package/lib-es/config.js.map +1 -1
  118. package/lib-es/constants.d.ts.map +1 -1
  119. package/lib-es/constants.js +3 -1
  120. package/lib-es/constants.js.map +1 -1
  121. package/lib-es/logic/broadcast.d.ts.map +1 -1
  122. package/lib-es/logic/broadcast.js +3 -1
  123. package/lib-es/logic/broadcast.js.map +1 -1
  124. package/lib-es/logic/combine.d.ts +1 -1
  125. package/lib-es/logic/combine.d.ts.map +1 -1
  126. package/lib-es/logic/combine.js +3 -1
  127. package/lib-es/logic/combine.js.map +1 -1
  128. package/lib-es/logic/common.d.ts +1 -1
  129. package/lib-es/logic/common.d.ts.map +1 -1
  130. package/lib-es/logic/common.js +5 -3
  131. package/lib-es/logic/common.js.map +1 -1
  132. package/lib-es/logic/craftTransaction.d.ts +1 -1
  133. package/lib-es/logic/craftTransaction.d.ts.map +1 -1
  134. package/lib-es/logic/craftTransaction.js +15 -13
  135. package/lib-es/logic/craftTransaction.js.map +1 -1
  136. package/lib-es/logic/estimateFees.d.ts.map +1 -1
  137. package/lib-es/logic/estimateFees.js +3 -1
  138. package/lib-es/logic/estimateFees.js.map +1 -1
  139. package/lib-es/logic/getBalance.d.ts +1 -1
  140. package/lib-es/logic/getBalance.d.ts.map +1 -1
  141. package/lib-es/logic/getBalance.js +5 -3
  142. package/lib-es/logic/getBalance.js.map +1 -1
  143. package/lib-es/logic/getBlock.d.ts +1 -1
  144. package/lib-es/logic/getBlock.d.ts.map +1 -1
  145. package/lib-es/logic/getBlock.js +42 -37
  146. package/lib-es/logic/getBlock.js.map +1 -1
  147. package/lib-es/logic/getBlockInfo.d.ts +1 -1
  148. package/lib-es/logic/getBlockInfo.d.ts.map +1 -1
  149. package/lib-es/logic/getBlockInfo.js +3 -1
  150. package/lib-es/logic/getBlockInfo.js.map +1 -1
  151. package/lib-es/logic/index.d.ts +12 -12
  152. package/lib-es/logic/index.d.ts.map +1 -1
  153. package/lib-es/logic/index.js +14 -12
  154. package/lib-es/logic/index.js.map +1 -1
  155. package/lib-es/logic/lastBlock.d.ts +1 -1
  156. package/lib-es/logic/lastBlock.d.ts.map +1 -1
  157. package/lib-es/logic/lastBlock.js +3 -1
  158. package/lib-es/logic/lastBlock.js.map +1 -1
  159. package/lib-es/logic/listOperations.d.ts +1 -1
  160. package/lib-es/logic/listOperations.d.ts.map +1 -1
  161. package/lib-es/logic/listOperations.js +7 -5
  162. package/lib-es/logic/listOperations.js.map +1 -1
  163. package/lib-es/logic/sdkWrapper.d.ts +1 -1
  164. package/lib-es/logic/sdkWrapper.d.ts.map +1 -1
  165. package/lib-es/logic/sdkWrapper.js +4 -2
  166. package/lib-es/logic/sdkWrapper.js.map +1 -1
  167. package/lib-es/logic/utils.d.ts.map +1 -1
  168. package/lib-es/logic/utils.js +6 -4
  169. package/lib-es/logic/utils.js.map +1 -1
  170. package/lib-es/logic/validateAddress.d.ts +1 -1
  171. package/lib-es/logic/validateAddress.d.ts.map +1 -1
  172. package/lib-es/logic/validateAddress.js +3 -1
  173. package/lib-es/logic/validateAddress.js.map +1 -1
  174. package/lib-es/logic/validateIntent.d.ts +2 -2
  175. package/lib-es/logic/validateIntent.d.ts.map +1 -1
  176. package/lib-es/logic/validateIntent.js +30 -28
  177. package/lib-es/logic/validateIntent.js.map +1 -1
  178. package/lib-es/logic/validateMemo.d.ts +1 -1
  179. package/lib-es/logic/validateMemo.d.ts.map +1 -1
  180. package/lib-es/logic/validateMemo.js +8 -6
  181. package/lib-es/logic/validateMemo.js.map +1 -1
  182. package/lib-es/network/horizon.d.ts +6 -7
  183. package/lib-es/network/horizon.d.ts.map +1 -1
  184. package/lib-es/network/horizon.js +80 -77
  185. package/lib-es/network/horizon.js.map +1 -1
  186. package/lib-es/network/horizonLedgerErrors.d.ts.map +1 -1
  187. package/lib-es/network/horizonLedgerErrors.js +7 -5
  188. package/lib-es/network/horizonLedgerErrors.js.map +1 -1
  189. package/lib-es/network/index.d.ts +1 -1
  190. package/lib-es/network/index.d.ts.map +1 -1
  191. package/lib-es/network/index.js +3 -1
  192. package/lib-es/network/index.js.map +1 -1
  193. package/lib-es/network/serialization.d.ts +6 -4
  194. package/lib-es/network/serialization.d.ts.map +1 -1
  195. package/lib-es/network/serialization.js +97 -95
  196. package/lib-es/network/serialization.js.map +1 -1
  197. package/lib-es/polyfill.d.ts.map +1 -1
  198. package/lib-es/polyfill.js +7 -5
  199. package/lib-es/polyfill.js.map +1 -1
  200. package/lib-es/supportedFeatures.d.ts +1 -1
  201. package/lib-es/supportedFeatures.d.ts.map +1 -1
  202. package/lib-es/supportedFeatures.js +3 -1
  203. package/lib-es/supportedFeatures.js.map +1 -1
  204. package/lib-es/types/errors.d.ts.map +1 -1
  205. package/lib-es/types/errors.js +15 -13
  206. package/lib-es/types/errors.js.map +1 -1
  207. package/lib-es/types/index.d.ts +2 -2
  208. package/lib-es/types/index.d.ts.map +1 -1
  209. package/lib-es/types/index.js +4 -2
  210. package/lib-es/types/index.js.map +1 -1
  211. package/lib-es/types/model.d.ts +6 -6
  212. package/lib-es/types/model.d.ts.map +1 -1
  213. package/lib-es/types/model.js +7 -5
  214. package/lib-es/types/model.js.map +1 -1
  215. package/package.json +13 -16
  216. package/src/api/index.integ.test.ts +165 -162
  217. package/src/api/index.test.ts +106 -103
  218. package/src/api/index.ts +49 -46
  219. package/src/api/index_error.test.ts +48 -25
  220. package/src/config.ts +15 -12
  221. package/src/constants.ts +4 -1
  222. package/src/globals.d.ts +7 -5
  223. package/src/logic/broadcast.integ.test.ts +22 -19
  224. package/src/logic/broadcast.ts +5 -2
  225. package/src/logic/combine.test.ts +18 -15
  226. package/src/logic/combine.ts +8 -5
  227. package/src/logic/common.ts +9 -6
  228. package/src/logic/craftTransaction.test.ts +76 -75
  229. package/src/logic/craftTransaction.ts +46 -43
  230. package/src/logic/estimateFees.ts +6 -3
  231. package/src/logic/getBalance.test.ts +31 -28
  232. package/src/logic/getBalance.ts +13 -10
  233. package/src/logic/getBlock.integ.test.ts +40 -39
  234. package/src/logic/getBlock.test.ts +462 -415
  235. package/src/logic/getBlock.ts +142 -127
  236. package/src/logic/getBlockInfo.test.ts +72 -69
  237. package/src/logic/getBlockInfo.ts +15 -12
  238. package/src/logic/index.ts +15 -12
  239. package/src/logic/lastBlock.ts +6 -3
  240. package/src/logic/listOperations.ts +14 -11
  241. package/src/logic/listOperations.unit.test.ts +212 -209
  242. package/src/logic/networkWrappers.test.ts +32 -29
  243. package/src/logic/sdkWrapper.ts +19 -16
  244. package/src/logic/utils.ts +13 -10
  245. package/src/logic/validateAddress.test.ts +21 -18
  246. package/src/logic/validateAddress.ts +7 -4
  247. package/src/logic/validateIntent.test.ts +62 -59
  248. package/src/logic/validateIntent.ts +87 -84
  249. package/src/logic/validateMemo.test.ts +50 -47
  250. package/src/logic/validateMemo.ts +16 -13
  251. package/src/network/broadcastTransaction.test.ts +60 -60
  252. package/src/network/fetchLedgerOperations.unit.test.ts +155 -0
  253. package/src/network/horizon.integ.test.ts +45 -42
  254. package/src/network/horizon.test.ts +17 -14
  255. package/src/network/horizon.ts +279 -281
  256. package/src/network/horizon.unit.test.ts +238 -237
  257. package/src/network/horizonLedgerErrors.test.ts +81 -78
  258. package/src/network/horizonLedgerErrors.ts +22 -19
  259. package/src/network/index.ts +4 -1
  260. package/src/network/registerHorizonInterceptors.test.ts +163 -160
  261. package/src/network/serialization.ts +232 -227
  262. package/src/network/serialization.unit.test.ts +801 -798
  263. package/src/polyfill.ts +18 -15
  264. package/src/supportedFeatures.ts +6 -3
  265. package/src/types/errors.ts +33 -32
  266. package/src/types/index.ts +5 -2
  267. package/src/types/model.ts +55 -52
  268. package/tsconfig.json +1 -1
  269. package/.unimportedrc.json +0 -17
  270. package/LICENSE.txt +0 -21
  271. package/src/network/fetchLedgerOperations.nock.unit.test.ts +0 -156
@@ -1,163 +1,166 @@
1
- import { BalanceOptions, TransactionIntent } from "@ledgerhq/coin-module-framework/api/types";
2
- import { InvalidParameterError } from "@ledgerhq/errors";
3
- import { StellarMemo } from "../types";
4
- import { createApi, envelopeFromAnyXDR } from "./index";
1
+ // SPDX-FileCopyrightText: © 2026 LEDGER SAS
2
+ // SPDX-License-Identifier: Apache-2.0
5
3
 
6
- const mockGetOperations = jest.fn();
4
+ import { BalanceOptions, TransactionIntent } from '@ledgerhq/coin-module-framework/api/types'
5
+ import { InvalidParameterError } from '@ledgerhq/errors'
6
+ import { StellarMemo } from '../types'
7
+ import { createApi, envelopeFromAnyXDR } from './index'
7
8
 
8
- jest.mock("../logic/listOperations", () => ({
9
+ const mockGetOperations = jest.fn()
10
+
11
+ jest.mock('../logic/listOperations', () => ({
9
12
  listOperations: () => mockGetOperations(),
10
- }));
13
+ }))
11
14
 
12
- const CUSTOM_FEES = 300n;
13
- const estimateFeesMock = jest.fn(() => CUSTOM_FEES);
14
- jest.mock("../logic/estimateFees", () => ({
15
+ const CUSTOM_FEES = 300n
16
+ const estimateFeesMock = jest.fn(() => CUSTOM_FEES)
17
+ jest.mock('../logic/estimateFees', () => ({
15
18
  estimateFees: () => estimateFeesMock(),
16
- }));
19
+ }))
17
20
 
18
21
  const logicCraftTransactionMock = jest.fn((_account: unknown, _transaction: { fee: bigint }) => {
19
- return { xdr: undefined };
20
- });
21
- jest.mock("../logic/craftTransaction", () => ({
22
+ return { xdr: undefined }
23
+ })
24
+ jest.mock('../logic/craftTransaction', () => ({
22
25
  craftTransaction: (account: unknown, transaction: { fee: bigint }) =>
23
26
  logicCraftTransactionMock(account, transaction),
24
- }));
27
+ }))
25
28
 
26
29
  const api = createApi({
27
30
  explorer: {
28
- url: "explorer.com",
31
+ url: 'explorer.com',
29
32
  fetchLimit: 200,
30
33
  },
31
34
  useStaticFees: true,
32
35
  enableNetworkLogs: false,
33
- });
36
+ })
34
37
 
35
- const fromGenesisMinHeight = 0;
36
- const fromGenesisOrder = "asc" as const;
38
+ const fromGenesisMinHeight = 0
39
+ const fromGenesisOrder = 'asc' as const
37
40
 
38
- describe("operations", () => {
41
+ describe('operations', () => {
39
42
  beforeEach(() => {
40
- jest.clearAllMocks();
41
- });
43
+ jest.clearAllMocks()
44
+ })
42
45
 
43
46
  const mockOperation = {
44
- asset: { type: "native" },
47
+ asset: { type: 'native' },
45
48
  tx: {
46
- hash: "e035a56c32003e3b0e4c9c5499b0750d71d98233ae6ae94323ff0a458b05a30b",
49
+ hash: 'e035a56c32003e3b0e4c9c5499b0750d71d98233ae6ae94323ff0a458b05a30b',
47
50
  fees: 0.0291,
48
51
  block: {
49
- hash: "hash",
50
- time: new Date("2024-03-20T10:00:00Z"),
52
+ hash: 'hash',
53
+ time: new Date('2024-03-20T10:00:00Z'),
51
54
  height: 10,
52
55
  },
53
- date: new Date("2024-03-20T10:00:00Z"),
56
+ date: new Date('2024-03-20T10:00:00Z'),
54
57
  },
55
- type: "Operation",
58
+ type: 'Operation',
56
59
  value: 200,
57
- senders: ["addr"],
58
- recipients: ["recipient"],
59
- };
60
+ senders: ['addr'],
61
+ recipients: ['recipient'],
62
+ }
60
63
 
61
- it("should return 0 operations for a valid account", async () => {
62
- mockGetOperations.mockResolvedValue({ items: [], next: "" });
64
+ it('should return 0 operations for a valid account', async () => {
65
+ mockGetOperations.mockResolvedValue({ items: [], next: '' })
63
66
 
64
67
  // When
65
- const operations = await api.listOperations("addr", {
68
+ const operations = await api.listOperations('addr', {
66
69
  minHeight: fromGenesisMinHeight,
67
70
  order: fromGenesisOrder,
68
- });
71
+ })
69
72
 
70
73
  // Then
71
- expect(operations).toEqual({ items: [], next: undefined });
72
- expect(mockGetOperations).toHaveBeenCalledTimes(1);
73
- });
74
+ expect(operations).toEqual({ items: [], next: undefined })
75
+ expect(mockGetOperations).toHaveBeenCalledTimes(1)
76
+ })
74
77
 
75
- it("should return 1 operation for a valid account", async () => {
76
- mockGetOperations.mockResolvedValue({ items: [mockOperation], next: "" });
78
+ it('should return 1 operation for a valid account', async () => {
79
+ mockGetOperations.mockResolvedValue({ items: [mockOperation], next: '' })
77
80
 
78
81
  // When
79
- const operations = await api.listOperations("addr", {
82
+ const operations = await api.listOperations('addr', {
80
83
  minHeight: fromGenesisMinHeight,
81
84
  order: fromGenesisOrder,
82
- });
85
+ })
83
86
 
84
87
  // Then
85
- expect(operations).toEqual({ items: [mockOperation], next: undefined });
86
- expect(mockGetOperations).toHaveBeenCalledTimes(1);
87
- });
88
+ expect(operations).toEqual({ items: [mockOperation], next: undefined })
89
+ expect(mockGetOperations).toHaveBeenCalledTimes(1)
90
+ })
88
91
 
89
- it("should return cursor for caller-driven pagination", async () => {
90
- mockGetOperations.mockResolvedValueOnce({ items: [mockOperation], next: "cursor-abc" });
92
+ it('should return cursor for caller-driven pagination', async () => {
93
+ mockGetOperations.mockResolvedValueOnce({ items: [mockOperation], next: 'cursor-abc' })
91
94
 
92
95
  // When
93
- const operations = await api.listOperations("addr", {
96
+ const operations = await api.listOperations('addr', {
94
97
  minHeight: fromGenesisMinHeight,
95
98
  order: fromGenesisOrder,
96
- });
99
+ })
97
100
 
98
- expect(operations).toEqual({ items: [mockOperation], next: "cursor-abc" });
99
- expect(mockGetOperations).toHaveBeenCalledTimes(1);
100
- });
101
- });
101
+ expect(operations).toEqual({ items: [mockOperation], next: 'cursor-abc' })
102
+ expect(mockGetOperations).toHaveBeenCalledTimes(1)
103
+ })
104
+ })
102
105
 
103
- describe("Testing craftTransaction function", () => {
106
+ describe('Testing craftTransaction function', () => {
104
107
  beforeEach(() => {
105
- estimateFeesMock.mockClear();
106
- logicCraftTransactionMock.mockClear();
107
- });
108
+ estimateFeesMock.mockClear()
109
+ logicCraftTransactionMock.mockClear()
110
+ })
108
111
 
109
- it("should use estimated fees when user does not provide them for crafting a transaction", async () => {
110
- await api.craftTransaction({ asset: {} } as TransactionIntent<StellarMemo>);
111
- expect(estimateFeesMock).toHaveBeenCalledTimes(1);
112
+ it('should use estimated fees when user does not provide them for crafting a transaction', async () => {
113
+ await api.craftTransaction({ asset: {} } as TransactionIntent<StellarMemo>)
114
+ expect(estimateFeesMock).toHaveBeenCalledTimes(1)
112
115
  expect(logicCraftTransactionMock).toHaveBeenCalledWith(
113
116
  expect.any(Object),
114
- expect.objectContaining({ fee: CUSTOM_FEES }),
115
- );
116
- });
117
+ expect.objectContaining({ fee: CUSTOM_FEES })
118
+ )
119
+ })
117
120
 
118
121
  it.each([[1n], [50n], [99n]])(
119
- "should use custom user fees when user provide them for crafting a transaction",
122
+ 'should use custom user fees when user provide them for crafting a transaction',
120
123
  async (fees: bigint) => {
121
- await api.craftTransaction({ asset: {} } as TransactionIntent<StellarMemo>, { value: fees });
122
- expect(estimateFeesMock).toHaveBeenCalledTimes(0);
124
+ await api.craftTransaction({ asset: {} } as TransactionIntent<StellarMemo>, { value: fees })
125
+ expect(estimateFeesMock).toHaveBeenCalledTimes(0)
123
126
  expect(logicCraftTransactionMock).toHaveBeenCalledWith(
124
127
  expect.any(Object),
125
- expect.objectContaining({ fee: fees }),
126
- );
127
- },
128
- );
129
- });
130
-
131
- describe("Testing transaction loading functions", () => {
132
- it("should deserialize a transaction as expected", async () => {
128
+ expect.objectContaining({ fee: fees })
129
+ )
130
+ }
131
+ )
132
+ })
133
+
134
+ describe('Testing transaction loading functions', () => {
135
+ it('should deserialize a transaction as expected', async () => {
133
136
  const transactionPayloadXDR =
134
- "esM5l1ROMXXSZr0CJDmyLNsWUIwBFj8m5csqPhBFqXkAAAACAAAAAEFMhHdla/OhHE2CYrF1VVPnLgBThGuzpNFZyYMh" +
135
- "8L6XAAAAZAAAJ/cAAAkYAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAABHRlc3QAAAABAAAAAAAAAAAAAAAA/QIumXyU" +
136
- "+Nq3dDZfGCXjgxYI7uvPElz8zGb0gN+vWD8AAAAAAA9CQAAAAAA=";
137
+ 'esM5l1ROMXXSZr0CJDmyLNsWUIwBFj8m5csqPhBFqXkAAAACAAAAAEFMhHdla/OhHE2CYrF1VVPnLgBThGuzpNFZyYMh' +
138
+ '8L6XAAAAZAAAJ/cAAAkYAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAABHRlc3QAAAABAAAAAAAAAAAAAAAA/QIumXyU' +
139
+ '+Nq3dDZfGCXjgxYI7uvPElz8zGb0gN+vWD8AAAAAAA9CQAAAAAA='
137
140
  const transactionEnvelopeXDR =
138
- "AAAAAgAAAABBTIR3ZWvzoRxNgmKxdVVT5y4AU4Rrs6TRWcmDIfC+lwAAAGQAACf3AAAJGAAAAAEAAAAAAAAAAAAAAAAA" +
139
- "AAAAAAAAAQAAAAR0ZXN0AAAAAQAAAAAAAAAAAAAAAP0CLpl8lPjat3Q2Xxgl44MWCO7rzxJc/Mxm9IDfr1g/AAAAAAAP" +
140
- "QkAAAAAAAAAAAA==";
141
- const txFromSignaturePayload = envelopeFromAnyXDR(transactionPayloadXDR, "base64");
142
- const txFromEnvelope = envelopeFromAnyXDR(transactionEnvelopeXDR, "base64");
143
- expect(txFromEnvelope).toEqual(txFromSignaturePayload);
144
- expect(txFromEnvelope.toXDR("base64")).toEqual(transactionEnvelopeXDR);
145
- expect(txFromSignaturePayload.toXDR("base64")).toEqual(transactionEnvelopeXDR);
146
- });
147
-
148
- it("throw expected error when deserializing an invalid transaction", async () => {
149
- expect(() => envelopeFromAnyXDR("lulz", "base64")).toThrow(
150
- "Failed decoding transaction as an envelope (TypeError: XDR Read Error: attempt to read outside the boundary of" +
151
- " the buffer) or as a signature base: (TypeError: XDR Read Error: attempt to read outside the boundary of the" +
152
- " buffer)",
153
- );
154
- });
155
- });
156
-
157
- describe("getBalance", () => {
158
- it("should throw an exception when options is provided", async () => {
159
- await expect(api.getBalance("random address", {} as unknown as BalanceOptions)).rejects.toThrow(
160
- InvalidParameterError,
161
- );
162
- });
163
- });
141
+ 'AAAAAgAAAABBTIR3ZWvzoRxNgmKxdVVT5y4AU4Rrs6TRWcmDIfC+lwAAAGQAACf3AAAJGAAAAAEAAAAAAAAAAAAAAAAA' +
142
+ 'AAAAAAAAAQAAAAR0ZXN0AAAAAQAAAAAAAAAAAAAAAP0CLpl8lPjat3Q2Xxgl44MWCO7rzxJc/Mxm9IDfr1g/AAAAAAAP' +
143
+ 'QkAAAAAAAAAAAA=='
144
+ const txFromSignaturePayload = envelopeFromAnyXDR(transactionPayloadXDR, 'base64')
145
+ const txFromEnvelope = envelopeFromAnyXDR(transactionEnvelopeXDR, 'base64')
146
+ expect(txFromEnvelope).toEqual(txFromSignaturePayload)
147
+ expect(txFromEnvelope.toXDR('base64')).toEqual(transactionEnvelopeXDR)
148
+ expect(txFromSignaturePayload.toXDR('base64')).toEqual(transactionEnvelopeXDR)
149
+ })
150
+
151
+ it('throw expected error when deserializing an invalid transaction', async () => {
152
+ expect(() => envelopeFromAnyXDR('lulz', 'base64')).toThrow(
153
+ 'Failed decoding transaction as an envelope (TypeError: XDR Read Error: attempt to read outside the boundary of' +
154
+ ' the buffer) or as a signature base: (TypeError: XDR Read Error: attempt to read outside the boundary of the' +
155
+ ' buffer)'
156
+ )
157
+ })
158
+ })
159
+
160
+ describe('getBalance', () => {
161
+ it('should throw an exception when options is provided', async () => {
162
+ await expect(api.getBalance('random address', {} as unknown as BalanceOptions)).rejects.toThrow(
163
+ InvalidParameterError
164
+ )
165
+ })
166
+ })
package/src/api/index.ts CHANGED
@@ -1,4 +1,7 @@
1
- import { rejectBalanceOptions } from "@ledgerhq/coin-module-framework/api/getBalance/rejectBalanceOptions";
1
+ // SPDX-FileCopyrightText: © 2026 LEDGER SAS
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { rejectBalanceOptions } from '@ledgerhq/coin-module-framework/api/getBalance/rejectBalanceOptions'
2
5
  import {
3
6
  CoinModuleApi,
4
7
  BalanceOptions,
@@ -12,10 +15,10 @@ import {
12
15
  Stake,
13
16
  TransactionIntent,
14
17
  Validator,
15
- } from "@ledgerhq/coin-module-framework/api/index";
16
- import { craftTransactionData } from "@ledgerhq/coin-module-framework/logic/craftTransactionData";
17
- import { xdr } from "@stellar/stellar-sdk";
18
- import coinConfig, { type StellarConfig } from "../config";
18
+ } from '@ledgerhq/coin-module-framework/api/index'
19
+ import { craftTransactionData } from '@ledgerhq/coin-module-framework/logic/craftTransactionData'
20
+ import { xdr } from '@stellar/stellar-sdk'
21
+ import coinConfig, { type StellarConfig } from '../config'
19
22
  import {
20
23
  broadcast,
21
24
  combine,
@@ -26,15 +29,15 @@ import {
26
29
  getBlockInfo,
27
30
  lastBlock,
28
31
  validateIntent,
29
- } from "../logic";
30
- import { listOperations } from "../logic";
31
- import { validateAddress } from "../logic/validateAddress";
32
- import { fetchSequence, registerHorizonInterceptors } from "../network";
33
- import { StellarMemo } from "../types";
32
+ } from '../logic'
33
+ import { listOperations } from '../logic'
34
+ import { validateAddress } from '../logic/validateAddress'
35
+ import { fetchSequence, registerHorizonInterceptors } from '../network'
36
+ import { StellarMemo } from '../types'
34
37
 
35
38
  export function createApi(config: StellarConfig): CoinModuleApi<StellarMemo> {
36
- coinConfig.setCoinConfig(() => ({ ...config, status: { type: "active" } }));
37
- registerHorizonInterceptors();
39
+ coinConfig.setCoinConfig(() => ({ ...config, status: { type: 'active' } }))
40
+ registerHorizonInterceptors()
38
41
 
39
42
  return {
40
43
  broadcast,
@@ -44,9 +47,9 @@ export function createApi(config: StellarConfig): CoinModuleApi<StellarMemo> {
44
47
  _transaction: string,
45
48
  _sender: string,
46
49
  _publicKey: string,
47
- _sequence: bigint,
50
+ _sequence: bigint
48
51
  ): Promise<CraftedTransaction> => {
49
- throw new Error("craftRawTransaction is not supported");
52
+ throw new Error('craftRawTransaction is not supported')
50
53
  },
51
54
  estimateFees: estimate,
52
55
  getBalance: (address: string, options?: BalanceOptions) =>
@@ -56,36 +59,36 @@ export function createApi(config: StellarConfig): CoinModuleApi<StellarMemo> {
56
59
  getBlock,
57
60
  getBlockInfo,
58
61
  getStakes(_address: string, _cursor?: Cursor): Promise<Page<Stake>> {
59
- throw new Error("getStakes is not supported");
62
+ throw new Error('getStakes is not supported')
60
63
  },
61
64
  getRewards(_address: string, _cursor?: Cursor): Promise<Page<Reward>> {
62
- throw new Error("getRewards is not supported");
65
+ throw new Error('getRewards is not supported')
63
66
  },
64
67
  validateIntent,
65
68
  getNextSequence: async (address: string) => {
66
- const sequence = await fetchSequence(address);
67
- return BigInt(sequence.plus(1).toFixed());
69
+ const sequence = await fetchSequence(address)
70
+ return BigInt(sequence.plus(1).toFixed())
68
71
  },
69
72
  getValidators(_cursor?: Cursor): Promise<Page<Validator>> {
70
- throw new Error("getValidators is not supported");
73
+ throw new Error('getValidators is not supported')
71
74
  },
72
75
  validateAddress,
73
76
  craftTransactionData,
74
- };
77
+ }
75
78
  }
76
79
 
77
80
  async function craft(
78
81
  transactionIntent: TransactionIntent<StellarMemo>,
79
- customFees?: FeeEstimation,
82
+ customFees?: FeeEstimation
80
83
  ): Promise<CraftedTransaction> {
81
- const fees = customFees?.value || (await estimateFees());
84
+ const fees = customFees?.value || (await estimateFees())
82
85
 
83
86
  // NOTE: check how many memos, throw if more than one?
84
87
  // if (transactionIntent.memos && transactionIntent.memos.length > 1) {
85
88
  // throw new Error("Stellar only supports one memo per transaction.");
86
89
  // }
87
- const memo = "memo" in transactionIntent ? transactionIntent.memo : undefined;
88
- const hasMemoValue = memo && memo.type !== "NO_MEMO";
90
+ const memo = 'memo' in transactionIntent ? transactionIntent.memo : undefined
91
+ const hasMemoValue = memo && memo.type !== 'NO_MEMO'
89
92
  const tx = await craftTransaction(
90
93
  { address: transactionIntent.sender },
91
94
  {
@@ -93,7 +96,7 @@ async function craft(
93
96
  recipient: transactionIntent.recipient,
94
97
  amount: transactionIntent.amount,
95
98
  fee: fees,
96
- ...(transactionIntent.asset.type !== "native" && "assetReference" in transactionIntent.asset
99
+ ...(transactionIntent.asset.type !== 'native' && 'assetReference' in transactionIntent.asset
97
100
  ? {
98
101
  assetCode: transactionIntent.asset.assetReference,
99
102
  assetIssuer: transactionIntent.asset.assetOwner,
@@ -101,32 +104,32 @@ async function craft(
101
104
  : {}),
102
105
  memoType: memo?.type,
103
106
  ...(hasMemoValue ? { memoValue: (memo as { value: string }).value } : {}),
104
- },
105
- );
107
+ }
108
+ )
106
109
 
107
110
  // Note: the API returns the signature base, not the full XDR, see BACK-8727 for more context
108
- return { transaction: tx.signatureBase };
111
+ return { transaction: tx.signatureBase }
109
112
  }
110
113
 
111
114
  function compose(tx: string, signature: string, pubkey?: string): string {
112
115
  if (!pubkey) {
113
- throw new Error("Missing pubkey");
116
+ throw new Error('Missing pubkey')
114
117
  }
115
118
  // note: accept here `TransactionEnvelope` or `TransactionSignaturePayload`, see BACK-8727 for more context
116
- return combine(envelopeFromAnyXDR(tx, "base64"), signature, pubkey);
119
+ return combine(envelopeFromAnyXDR(tx, 'base64'), signature, pubkey)
117
120
  }
118
121
 
119
122
  async function estimate(_transactionIntent: TransactionIntent): Promise<FeeEstimation> {
120
- const value = await estimateFees();
121
- return { value };
123
+ const value = await estimateFees()
124
+ return { value }
122
125
  }
123
126
 
124
127
  async function operations(
125
128
  address: string,
126
- options: ListOperationsOptions,
129
+ options: ListOperationsOptions
127
130
  ): Promise<Page<Operation>> {
128
- const { items, next } = await listOperations(address, options);
129
- return { items, next: next || undefined };
131
+ const { items, next } = await listOperations(address, options)
132
+ return { items, next: next || undefined }
130
133
  }
131
134
 
132
135
  /**
@@ -137,17 +140,17 @@ async function operations(
137
140
  */
138
141
  export function envelopeFromAnyXDR(
139
142
  input: string,
140
- format: "hex" | "base64",
143
+ format: 'hex' | 'base64'
141
144
  ): xdr.TransactionEnvelope {
142
145
  try {
143
- return xdr.TransactionEnvelope.fromXDR(input, format);
146
+ return xdr.TransactionEnvelope.fromXDR(input, format)
144
147
  } catch (envelopeError) {
145
148
  try {
146
- return signatureBaseToEnvelope(xdr.TransactionSignaturePayload.fromXDR(input, format));
149
+ return signatureBaseToEnvelope(xdr.TransactionSignaturePayload.fromXDR(input, format))
147
150
  } catch (signatureBaseError) {
148
151
  throw new Error(
149
- `Failed decoding transaction as an envelope (${envelopeError}) or as a signature base: (${signatureBaseError})`,
150
- );
152
+ `Failed decoding transaction as an envelope (${envelopeError}) or as a signature base: (${signatureBaseError})`
153
+ )
151
154
  }
152
155
  }
153
156
  }
@@ -158,16 +161,16 @@ export function envelopeFromAnyXDR(
158
161
  * @param signatureBase deserialized `TransactionSignaturePayload`
159
162
  */
160
163
  function signatureBaseToEnvelope(
161
- signatureBase: xdr.TransactionSignaturePayload,
164
+ signatureBase: xdr.TransactionSignaturePayload
162
165
  ): xdr.TransactionEnvelope {
163
- const tx = signatureBase.taggedTransaction().value();
166
+ const tx = signatureBase.taggedTransaction().value()
164
167
  if (tx instanceof xdr.Transaction) {
165
168
  return xdr.TransactionEnvelope.envelopeTypeTx(
166
- new xdr.TransactionV1Envelope({ tx, signatures: [] }),
167
- );
169
+ new xdr.TransactionV1Envelope({ tx, signatures: [] })
170
+ )
168
171
  } else {
169
172
  return xdr.TransactionEnvelope.envelopeTypeTxFeeBump(
170
- new xdr.FeeBumpTransactionEnvelope({ tx, signatures: [] }),
171
- );
173
+ new xdr.FeeBumpTransactionEnvelope({ tx, signatures: [] })
174
+ )
172
175
  }
173
176
  }
@@ -1,32 +1,55 @@
1
- import type { CoinModuleApi } from "@ledgerhq/coin-module-framework/api/index";
2
- import nock from "nock";
3
- import { LedgerAPI4xx } from "@ledgerhq/errors";
4
- import { StellarMemo } from "../types";
5
- import { createApi } from ".";
1
+ // SPDX-FileCopyrightText: © 2026 LEDGER SAS
2
+ // SPDX-License-Identifier: Apache-2.0
6
3
 
7
- describe("Stellar Api", () => {
8
- let module: CoinModuleApi<StellarMemo>;
9
- const ADDRESS = "GBAUZBDXMVV7HII4JWBGFMLVKVJ6OLQAKOCGXM5E2FM4TAZB6C7JO2L7";
4
+ import type { CoinModuleApi } from '@ledgerhq/coin-module-framework/api/index'
5
+ import { Horizon } from '@stellar/stellar-sdk'
6
+ import { StellarMemo } from '../types'
7
+ import { createApi } from '.'
10
8
 
11
- beforeAll(() => {
12
- nock("https://horizon-testnet.stellar.org")
13
- .get(/.*/)
14
- .reply(() => {
15
- return [429, { error: "whatever, only status code is important" }];
16
- });
9
+ /**
10
+ * Minimal chainable stub of a Horizon call builder: every builder method returns
11
+ * the builder itself, and `call()` rejects with the configured error.
12
+ */
13
+ function rejectingBuilder(error: unknown): unknown {
14
+ const builder: unknown = new Proxy(
15
+ {},
16
+ {
17
+ get(_target, prop) {
18
+ if (prop === 'call') return () => Promise.reject(error)
19
+ return () => builder
20
+ },
21
+ }
22
+ )
23
+ return builder
24
+ }
25
+
26
+ describe('Stellar Api', () => {
27
+ let module: CoinModuleApi<StellarMemo>
28
+ const ADDRESS = 'GBAUZBDXMVV7HII4JWBGFMLVKVJ6OLQAKOCGXM5E2FM4TAZB6C7JO2L7'
17
29
 
30
+ beforeAll(() => {
18
31
  module = createApi({
19
32
  explorer: {
20
- url: "https://horizon-testnet.stellar.org/",
33
+ url: 'https://horizon-testnet.stellar.org/',
21
34
  },
22
- });
23
- });
35
+ })
36
+ })
37
+
38
+ afterEach(() => {
39
+ jest.restoreAllMocks()
40
+ })
41
+
42
+ describe('listOperations propagates 429 errors to caller', () => {
43
+ it('throws LedgerAPI4xx on rate limit', async () => {
44
+ // Horizon surfaces a 429 as a NetworkError whose message is the "Too Many Requests"
45
+ // status text, which fetchOperations maps to the rate-limit-specific LedgerAPI4xx.
46
+ jest
47
+ .spyOn(Horizon.Server.prototype, 'operations')
48
+ .mockReturnValue(rejectingBuilder(new Error('Too Many Requests')) as never)
24
49
 
25
- describe("listOperations propagates 429 errors to caller", () => {
26
- it("throws LedgerAPI4xx on rate limit", async () => {
27
- await expect(module.listOperations(ADDRESS, { minHeight: 0, order: "asc" })).rejects.toThrow(
28
- LedgerAPI4xx,
29
- );
30
- });
31
- });
32
- });
50
+ await expect(
51
+ module.listOperations(ADDRESS, { minHeight: 0, order: 'asc' })
52
+ ).rejects.toMatchObject({ name: 'LedgerAPI4xx', status: 429 })
53
+ })
54
+ })
55
+ })
package/src/config.ts CHANGED
@@ -1,22 +1,25 @@
1
+ // SPDX-FileCopyrightText: © 2026 LEDGER SAS
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
1
4
  import buildCoinConfig, {
2
5
  type CoinConfig,
3
6
  type CurrencyConfig,
4
- } from "@ledgerhq/coin-module-framework/config";
7
+ } from '@ledgerhq/coin-module-framework/config'
5
8
 
6
9
  export type StellarConfig = {
7
10
  explorer: {
8
- url: string;
9
- fetchLimit?: number;
10
- };
11
- useStaticFees?: boolean;
12
- enableNetworkLogs?: boolean;
13
- };
11
+ url: string
12
+ fetchLimit?: number
13
+ }
14
+ useStaticFees?: boolean
15
+ enableNetworkLogs?: boolean
16
+ }
14
17
 
15
- export type StellarCoinConfig = CurrencyConfig & StellarConfig;
18
+ export type StellarCoinConfig = CurrencyConfig & StellarConfig
16
19
 
17
20
  const coinConfig: {
18
- setCoinConfig: (config: CoinConfig<StellarCoinConfig>) => void;
19
- getCoinConfig: (currencyId?: string) => StellarCoinConfig;
20
- } = buildCoinConfig<StellarCoinConfig>();
21
+ setCoinConfig: (config: CoinConfig<StellarCoinConfig>) => void
22
+ getCoinConfig: (currencyId?: string) => StellarCoinConfig
23
+ } = buildCoinConfig<StellarCoinConfig>()
21
24
 
22
- export default coinConfig;
25
+ export default coinConfig
package/src/constants.ts CHANGED
@@ -1 +1,4 @@
1
- export const STELLAR_DUMMY_ADDRESS = "GDYPMQMYW2JTLPWAUAHIDY3E4VHP5SGTFC5SMA45L7ZPOTHWQ2PHEW3E";
1
+ // SPDX-FileCopyrightText: © 2026 LEDGER SAS
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export const STELLAR_DUMMY_ADDRESS = 'GDYPMQMYW2JTLPWAUAHIDY3E4VHP5SGTFC5SMA45L7ZPOTHWQ2PHEW3E'
package/src/globals.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- /* eslint-disable no-var */
1
+ // SPDX-FileCopyrightText: © 2026 LEDGER SAS
2
+ // SPDX-License-Identifier: Apache-2.0
2
3
 
3
- export {};
4
+ /* eslint-disable no-var */
4
5
 
5
- declare global {
6
- var HermesInternal: any | undefined;
7
- }
6
+ // Ambient global declaration (script file, no imports/exports) so `global.HermesInternal`
7
+ // resolves on `typeof globalThis`. Kept export-free on purpose: an `export {}` module marker
8
+ // gets stripped by oxfmt, which would break the augmentation.
9
+ declare var HermesInternal: any | undefined