@ledgerhq/coin-stellar 6.26.0 → 6.26.2

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 (281) hide show
  1. package/.oxlintrc.json +7 -0
  2. package/CHANGELOG.md +12 -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 +48 -95
  80. package/lib/network/horizon.js.map +1 -1
  81. package/lib/network/horizonErrorBody.d.ts +29 -0
  82. package/lib/network/horizonErrorBody.d.ts.map +1 -0
  83. package/lib/network/horizonErrorBody.js +139 -0
  84. package/lib/network/horizonErrorBody.js.map +1 -0
  85. package/lib/network/horizonLedgerErrors.d.ts.map +1 -1
  86. package/lib/network/horizonLedgerErrors.js +28 -4
  87. package/lib/network/horizonLedgerErrors.js.map +1 -1
  88. package/lib/network/index.d.ts +1 -1
  89. package/lib/network/index.d.ts.map +1 -1
  90. package/lib/network/index.js +2 -0
  91. package/lib/network/index.js.map +1 -1
  92. package/lib/network/serialization.d.ts +6 -4
  93. package/lib/network/serialization.d.ts.map +1 -1
  94. package/lib/network/serialization.js +95 -91
  95. package/lib/network/serialization.js.map +1 -1
  96. package/lib/polyfill.d.ts.map +1 -1
  97. package/lib/polyfill.js +6 -4
  98. package/lib/polyfill.js.map +1 -1
  99. package/lib/supportedFeatures.d.ts +1 -1
  100. package/lib/supportedFeatures.d.ts.map +1 -1
  101. package/lib/supportedFeatures.js +3 -1
  102. package/lib/supportedFeatures.js.map +1 -1
  103. package/lib/types/errors.d.ts.map +1 -1
  104. package/lib/types/errors.js +14 -12
  105. package/lib/types/errors.js.map +1 -1
  106. package/lib/types/index.d.ts +2 -2
  107. package/lib/types/index.d.ts.map +1 -1
  108. package/lib/types/index.js +2 -0
  109. package/lib/types/index.js.map +1 -1
  110. package/lib/types/model.d.ts +6 -6
  111. package/lib/types/model.d.ts.map +1 -1
  112. package/lib/types/model.js +7 -5
  113. package/lib/types/model.js.map +1 -1
  114. package/lib-es/api/index.d.ts +5 -5
  115. package/lib-es/api/index.d.ts.map +1 -1
  116. package/lib-es/api/index.js +20 -18
  117. package/lib-es/api/index.js.map +1 -1
  118. package/lib-es/config.d.ts +1 -1
  119. package/lib-es/config.d.ts.map +1 -1
  120. package/lib-es/config.js +3 -1
  121. package/lib-es/config.js.map +1 -1
  122. package/lib-es/constants.d.ts.map +1 -1
  123. package/lib-es/constants.js +3 -1
  124. package/lib-es/constants.js.map +1 -1
  125. package/lib-es/logic/broadcast.d.ts.map +1 -1
  126. package/lib-es/logic/broadcast.js +3 -1
  127. package/lib-es/logic/broadcast.js.map +1 -1
  128. package/lib-es/logic/combine.d.ts +1 -1
  129. package/lib-es/logic/combine.d.ts.map +1 -1
  130. package/lib-es/logic/combine.js +3 -1
  131. package/lib-es/logic/combine.js.map +1 -1
  132. package/lib-es/logic/common.d.ts +1 -1
  133. package/lib-es/logic/common.d.ts.map +1 -1
  134. package/lib-es/logic/common.js +5 -3
  135. package/lib-es/logic/common.js.map +1 -1
  136. package/lib-es/logic/craftTransaction.d.ts +1 -1
  137. package/lib-es/logic/craftTransaction.d.ts.map +1 -1
  138. package/lib-es/logic/craftTransaction.js +15 -13
  139. package/lib-es/logic/craftTransaction.js.map +1 -1
  140. package/lib-es/logic/estimateFees.d.ts.map +1 -1
  141. package/lib-es/logic/estimateFees.js +3 -1
  142. package/lib-es/logic/estimateFees.js.map +1 -1
  143. package/lib-es/logic/getBalance.d.ts +1 -1
  144. package/lib-es/logic/getBalance.d.ts.map +1 -1
  145. package/lib-es/logic/getBalance.js +5 -3
  146. package/lib-es/logic/getBalance.js.map +1 -1
  147. package/lib-es/logic/getBlock.d.ts +1 -1
  148. package/lib-es/logic/getBlock.d.ts.map +1 -1
  149. package/lib-es/logic/getBlock.js +42 -37
  150. package/lib-es/logic/getBlock.js.map +1 -1
  151. package/lib-es/logic/getBlockInfo.d.ts +1 -1
  152. package/lib-es/logic/getBlockInfo.d.ts.map +1 -1
  153. package/lib-es/logic/getBlockInfo.js +3 -1
  154. package/lib-es/logic/getBlockInfo.js.map +1 -1
  155. package/lib-es/logic/index.d.ts +12 -12
  156. package/lib-es/logic/index.d.ts.map +1 -1
  157. package/lib-es/logic/index.js +14 -12
  158. package/lib-es/logic/index.js.map +1 -1
  159. package/lib-es/logic/lastBlock.d.ts +1 -1
  160. package/lib-es/logic/lastBlock.d.ts.map +1 -1
  161. package/lib-es/logic/lastBlock.js +3 -1
  162. package/lib-es/logic/lastBlock.js.map +1 -1
  163. package/lib-es/logic/listOperations.d.ts +1 -1
  164. package/lib-es/logic/listOperations.d.ts.map +1 -1
  165. package/lib-es/logic/listOperations.js +7 -5
  166. package/lib-es/logic/listOperations.js.map +1 -1
  167. package/lib-es/logic/sdkWrapper.d.ts +1 -1
  168. package/lib-es/logic/sdkWrapper.d.ts.map +1 -1
  169. package/lib-es/logic/sdkWrapper.js +4 -2
  170. package/lib-es/logic/sdkWrapper.js.map +1 -1
  171. package/lib-es/logic/utils.d.ts.map +1 -1
  172. package/lib-es/logic/utils.js +6 -4
  173. package/lib-es/logic/utils.js.map +1 -1
  174. package/lib-es/logic/validateAddress.d.ts +1 -1
  175. package/lib-es/logic/validateAddress.d.ts.map +1 -1
  176. package/lib-es/logic/validateAddress.js +3 -1
  177. package/lib-es/logic/validateAddress.js.map +1 -1
  178. package/lib-es/logic/validateIntent.d.ts +2 -2
  179. package/lib-es/logic/validateIntent.d.ts.map +1 -1
  180. package/lib-es/logic/validateIntent.js +30 -28
  181. package/lib-es/logic/validateIntent.js.map +1 -1
  182. package/lib-es/logic/validateMemo.d.ts +1 -1
  183. package/lib-es/logic/validateMemo.d.ts.map +1 -1
  184. package/lib-es/logic/validateMemo.js +8 -6
  185. package/lib-es/logic/validateMemo.js.map +1 -1
  186. package/lib-es/network/horizon.d.ts +6 -7
  187. package/lib-es/network/horizon.d.ts.map +1 -1
  188. package/lib-es/network/horizon.js +57 -104
  189. package/lib-es/network/horizon.js.map +1 -1
  190. package/lib-es/network/horizonErrorBody.d.ts +29 -0
  191. package/lib-es/network/horizonErrorBody.d.ts.map +1 -0
  192. package/lib-es/network/horizonErrorBody.js +134 -0
  193. package/lib-es/network/horizonErrorBody.js.map +1 -0
  194. package/lib-es/network/horizonLedgerErrors.d.ts.map +1 -1
  195. package/lib-es/network/horizonLedgerErrors.js +30 -6
  196. package/lib-es/network/horizonLedgerErrors.js.map +1 -1
  197. package/lib-es/network/index.d.ts +1 -1
  198. package/lib-es/network/index.d.ts.map +1 -1
  199. package/lib-es/network/index.js +3 -1
  200. package/lib-es/network/index.js.map +1 -1
  201. package/lib-es/network/serialization.d.ts +6 -4
  202. package/lib-es/network/serialization.d.ts.map +1 -1
  203. package/lib-es/network/serialization.js +97 -95
  204. package/lib-es/network/serialization.js.map +1 -1
  205. package/lib-es/polyfill.d.ts.map +1 -1
  206. package/lib-es/polyfill.js +7 -5
  207. package/lib-es/polyfill.js.map +1 -1
  208. package/lib-es/supportedFeatures.d.ts +1 -1
  209. package/lib-es/supportedFeatures.d.ts.map +1 -1
  210. package/lib-es/supportedFeatures.js +3 -1
  211. package/lib-es/supportedFeatures.js.map +1 -1
  212. package/lib-es/types/errors.d.ts.map +1 -1
  213. package/lib-es/types/errors.js +15 -13
  214. package/lib-es/types/errors.js.map +1 -1
  215. package/lib-es/types/index.d.ts +2 -2
  216. package/lib-es/types/index.d.ts.map +1 -1
  217. package/lib-es/types/index.js +4 -2
  218. package/lib-es/types/index.js.map +1 -1
  219. package/lib-es/types/model.d.ts +6 -6
  220. package/lib-es/types/model.d.ts.map +1 -1
  221. package/lib-es/types/model.js +7 -5
  222. package/lib-es/types/model.js.map +1 -1
  223. package/package.json +13 -16
  224. package/src/api/index.integ.test.ts +168 -163
  225. package/src/api/index.test.ts +106 -103
  226. package/src/api/index.ts +49 -46
  227. package/src/api/index_error.test.ts +48 -25
  228. package/src/config.ts +15 -12
  229. package/src/constants.ts +4 -1
  230. package/src/globals.d.ts +7 -5
  231. package/src/logic/broadcast.integ.test.ts +22 -19
  232. package/src/logic/broadcast.ts +5 -2
  233. package/src/logic/combine.test.ts +18 -15
  234. package/src/logic/combine.ts +8 -5
  235. package/src/logic/common.ts +9 -6
  236. package/src/logic/craftTransaction.test.ts +76 -75
  237. package/src/logic/craftTransaction.ts +46 -43
  238. package/src/logic/estimateFees.ts +6 -3
  239. package/src/logic/getBalance.test.ts +31 -28
  240. package/src/logic/getBalance.ts +13 -10
  241. package/src/logic/getBlock.integ.test.ts +40 -39
  242. package/src/logic/getBlock.test.ts +462 -415
  243. package/src/logic/getBlock.ts +142 -127
  244. package/src/logic/getBlockInfo.test.ts +72 -69
  245. package/src/logic/getBlockInfo.ts +15 -12
  246. package/src/logic/index.ts +15 -12
  247. package/src/logic/lastBlock.ts +6 -3
  248. package/src/logic/listOperations.ts +14 -11
  249. package/src/logic/listOperations.unit.test.ts +212 -209
  250. package/src/logic/networkWrappers.test.ts +32 -29
  251. package/src/logic/sdkWrapper.ts +19 -16
  252. package/src/logic/utils.ts +13 -10
  253. package/src/logic/validateAddress.test.ts +21 -18
  254. package/src/logic/validateAddress.ts +7 -4
  255. package/src/logic/validateIntent.test.ts +62 -59
  256. package/src/logic/validateIntent.ts +87 -84
  257. package/src/logic/validateMemo.test.ts +50 -47
  258. package/src/logic/validateMemo.ts +16 -13
  259. package/src/network/broadcastTransaction.test.ts +83 -63
  260. package/src/network/fetchLedgerOperations.unit.test.ts +155 -0
  261. package/src/network/horizon.integ.test.ts +45 -42
  262. package/src/network/horizon.test.ts +17 -14
  263. package/src/network/horizon.ts +244 -314
  264. package/src/network/horizon.unit.test.ts +238 -237
  265. package/src/network/horizonErrorBody.test.ts +133 -0
  266. package/src/network/horizonErrorBody.ts +178 -0
  267. package/src/network/horizonLedgerErrors.test.ts +150 -78
  268. package/src/network/horizonLedgerErrors.ts +47 -20
  269. package/src/network/index.ts +4 -1
  270. package/src/network/registerHorizonInterceptors.test.ts +163 -160
  271. package/src/network/serialization.ts +232 -227
  272. package/src/network/serialization.unit.test.ts +801 -798
  273. package/src/polyfill.ts +18 -15
  274. package/src/supportedFeatures.ts +6 -3
  275. package/src/types/errors.ts +33 -32
  276. package/src/types/index.ts +5 -2
  277. package/src/types/model.ts +55 -52
  278. package/tsconfig.json +1 -1
  279. package/.unimportedrc.json +0 -17
  280. package/LICENSE.txt +0 -21
  281. package/src/network/fetchLedgerOperations.nock.unit.test.ts +0 -156
@@ -1,653 +1,700 @@
1
- import type { Horizon } from "@stellar/stellar-sdk";
2
- import BigNumber from "bignumber.js";
3
- import * as network from "../network";
4
- import type { RawOperation } from "../types";
5
- import { parseAPIValue } from "./common";
6
- import { getBlock } from "./getBlock";
7
-
8
- jest.mock("../network", () => ({
9
- ...jest.requireActual<typeof import("../network")>("../network"),
1
+ // SPDX-FileCopyrightText: © 2026 LEDGER SAS
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { RawOperation } from '../types'
5
+ import type { Horizon } from '@stellar/stellar-sdk'
6
+ import BigNumber from 'bignumber.js'
7
+ import * as network from '../network'
8
+ import { parseAPIValue } from './common'
9
+ import { getBlock } from './getBlock'
10
+
11
+ jest.mock('../network', () => ({
12
+ ...jest.requireActual<typeof import('../network')>('../network'),
10
13
  fetchLedgerRecord: jest.fn(),
11
14
  fetchAllLedgerOperations: jest.fn(),
12
- }));
15
+ }))
13
16
 
14
17
  const fetchLedgerRecordMock = network.fetchLedgerRecord as jest.MockedFunction<
15
18
  typeof network.fetchLedgerRecord
16
- >;
19
+ >
17
20
  const fetchAllLedgerOperationsMock = network.fetchAllLedgerOperations as jest.MockedFunction<
18
21
  typeof network.fetchAllLedgerOperations
19
- >;
22
+ >
20
23
 
21
24
  function txRecord(
22
- overrides: Partial<Horizon.ServerApi.TransactionRecord> = {},
25
+ overrides: Partial<Horizon.ServerApi.TransactionRecord> = {}
23
26
  ): Horizon.ServerApi.TransactionRecord {
24
27
  return {
25
- fee_charged: "100",
26
- source_account: "GSOURCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
28
+ fee_charged: '100',
29
+ source_account: 'GSOURCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
27
30
  fee_account: undefined,
28
31
  ledger_attr: 42,
29
- memo_type: "none",
32
+ memo_type: 'none',
30
33
  ...overrides,
31
- } as Horizon.ServerApi.TransactionRecord;
34
+ } as Horizon.ServerApi.TransactionRecord
32
35
  }
33
36
 
34
37
  function rawOp(
35
38
  base: Record<string, unknown> & {
36
- type: string;
37
- transaction_hash: string;
38
- transactionRecord?: Horizon.ServerApi.TransactionRecord;
39
- },
39
+ type: string
40
+ transaction_hash: string
41
+ transactionRecord?: Horizon.ServerApi.TransactionRecord
42
+ }
40
43
  ): RawOperation {
41
- const tr = base.transactionRecord ?? txRecord();
42
- const { transactionRecord: _t, ...rest } = base;
44
+ const tr = base.transactionRecord ?? txRecord()
45
+ const { transactionRecord: _t, ...rest } = base
43
46
  return {
44
- id: "1",
45
- paging_token: "pt",
46
- source_account: "GSOURCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
47
+ id: '1',
48
+ paging_token: 'pt',
49
+ source_account: 'GSOURCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
47
50
  transaction_successful: true,
48
- created_at: "2020-01-01T00:00:00Z",
51
+ created_at: '2020-01-01T00:00:00Z',
49
52
  ...rest,
50
53
  transaction: () => Promise.resolve(tr),
51
- } as RawOperation;
54
+ } as RawOperation
52
55
  }
53
56
 
54
- describe("getBlock", () => {
57
+ describe('getBlock', () => {
55
58
  beforeEach(() => {
56
- jest.clearAllMocks();
59
+ jest.clearAllMocks()
57
60
  fetchLedgerRecordMock.mockImplementation(
58
61
  async (seq: number) =>
59
62
  ({
60
63
  sequence: seq,
61
64
  hash: `LEDGER-HASH-${seq}`,
62
- closed_at: "2018-09-15T15:40:05Z",
65
+ closed_at: '2018-09-15T15:40:05Z',
63
66
  ...(seq > 1 && { prev_hash: `LEDGER-HASH-${seq - 1}` }),
64
- }) as Awaited<ReturnType<typeof network.fetchLedgerRecord>>,
65
- );
66
- });
67
+ }) as Awaited<ReturnType<typeof network.fetchLedgerRecord>>
68
+ )
69
+ })
67
70
 
68
- describe("height validation", () => {
69
- it("rejects height 0", async () => {
71
+ describe('height validation', () => {
72
+ it('rejects height 0', async () => {
70
73
  await expect(getBlock(0)).rejects.toThrow(
71
- "getBlock: height must be a positive integer, got 0",
72
- );
73
- });
74
+ 'getBlock: height must be a positive integer, got 0'
75
+ )
76
+ })
74
77
 
75
- it("rejects negative height", async () => {
78
+ it('rejects negative height', async () => {
76
79
  await expect(getBlock(-1)).rejects.toThrow(
77
- "getBlock: height must be a positive integer, got -1",
78
- );
79
- });
80
+ 'getBlock: height must be a positive integer, got -1'
81
+ )
82
+ })
80
83
 
81
- it("rejects non-integer height", async () => {
84
+ it('rejects non-integer height', async () => {
82
85
  await expect(getBlock(2.5)).rejects.toThrow(
83
- "getBlock: height must be a positive integer, got 2.5",
84
- );
85
- });
86
+ 'getBlock: height must be a positive integer, got 2.5'
87
+ )
88
+ })
86
89
 
87
- it("rejects NaN", async () => {
90
+ it('rejects NaN', async () => {
88
91
  await expect(getBlock(Number.NaN)).rejects.toThrow(
89
- "getBlock: height must be a positive integer, got NaN",
90
- );
91
- });
92
+ 'getBlock: height must be a positive integer, got NaN'
93
+ )
94
+ })
92
95
 
93
- it("rejects Infinity", async () => {
96
+ it('rejects Infinity', async () => {
94
97
  await expect(getBlock(Number.POSITIVE_INFINITY)).rejects.toThrow(
95
- "getBlock: height must be a positive integer, got Infinity",
96
- );
97
- });
98
- });
98
+ 'getBlock: height must be a positive integer, got Infinity'
99
+ )
100
+ })
101
+ })
99
102
 
100
- it("maps a native payment with two transfer operations", async () => {
103
+ it('maps a native payment with two transfer operations', async () => {
101
104
  fetchAllLedgerOperationsMock.mockResolvedValue([
102
105
  rawOp({
103
- type: "payment",
104
- transaction_hash: "txpay1",
105
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
106
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
107
- amount: "1.0000000",
108
- asset_type: "native",
109
- transactionRecord: txRecord({ fee_charged: "200" }),
106
+ type: 'payment',
107
+ transaction_hash: 'txpay1',
108
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
109
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
110
+ amount: '1.0000000',
111
+ asset_type: 'native',
112
+ transactionRecord: txRecord({ fee_charged: '200' }),
110
113
  }),
111
- ]);
114
+ ])
112
115
 
113
- const block = await getBlock(20000000);
116
+ const block = await getBlock(20000000)
114
117
 
115
- expect(block.info.height).toBe(20000000);
116
- expect(block.info.hash).toBe("LEDGER-HASH-20000000");
118
+ expect(block.info.height).toBe(20000000)
119
+ expect(block.info.hash).toBe('LEDGER-HASH-20000000')
117
120
  expect(block.info.parent).toEqual({
118
121
  height: 19999999,
119
- hash: "LEDGER-HASH-19999999",
120
- });
121
-
122
- expect(block.transactions).toHaveLength(1);
123
- const tx0 = block.transactions[0];
124
- expect(tx0.hash).toBe("txpay1");
125
- expect(tx0.failed).toBe(false);
126
- expect(tx0.fees).toBe(200n);
127
- expect(tx0.feesPayer).toBe("GSOURCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
122
+ hash: 'LEDGER-HASH-19999999',
123
+ })
124
+
125
+ expect(block.transactions).toHaveLength(1)
126
+ const tx0 = block.transactions[0]
127
+ expect(tx0.hash).toBe('txpay1')
128
+ expect(tx0.failed).toBe(false)
129
+ expect(tx0.fees).toBe(200n)
130
+ expect(tx0.feesPayer).toBe('GSOURCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')
128
131
  expect(tx0.operations).toEqual(
129
132
  expect.arrayContaining([
130
133
  expect.objectContaining({
131
- type: "transfer",
132
- address: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
134
+ type: 'transfer',
135
+ address: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
133
136
  amount: -10000000n,
134
137
  }),
135
138
  expect.objectContaining({
136
- type: "transfer",
137
- address: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
139
+ type: 'transfer',
140
+ address: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
138
141
  amount: 10000000n,
139
142
  }),
140
- ]),
141
- );
142
- });
143
+ ])
144
+ )
145
+ })
143
146
 
144
- it("uses fee_account as feesPayer when present (fee bump)", async () => {
147
+ it('uses fee_account as feesPayer when present (fee bump)', async () => {
145
148
  fetchAllLedgerOperationsMock.mockResolvedValue([
146
149
  rawOp({
147
- type: "payment",
148
- transaction_hash: "txfeebump",
149
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
150
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
151
- amount: "2.0000000",
152
- asset_type: "native",
150
+ type: 'payment',
151
+ transaction_hash: 'txfeebump',
152
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
153
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
154
+ amount: '2.0000000',
155
+ asset_type: 'native',
153
156
  transactionRecord: txRecord({
154
- fee_charged: "500",
155
- source_account: "GINNERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
156
- fee_account: "GFEEPAYERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
157
+ fee_charged: '500',
158
+ source_account: 'GINNERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
159
+ fee_account: 'GFEEPAYERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
157
160
  }),
158
161
  }),
159
- ]);
162
+ ])
160
163
 
161
- const block = await getBlock(10);
162
- expect(block.transactions[0].feesPayer).toBe(
163
- "GFEEPAYERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
164
- );
165
- });
164
+ const block = await getBlock(10)
165
+ expect(block.transactions[0].feesPayer).toBe('GFEEPAYERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')
166
+ })
166
167
 
167
- it("marks failed transactions with empty operations but keeps fees", async () => {
168
+ it('marks failed transactions with empty operations but keeps fees', async () => {
168
169
  fetchAllLedgerOperationsMock.mockResolvedValue([
169
170
  rawOp({
170
- type: "payment",
171
- transaction_hash: "txfail",
172
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
173
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
174
- amount: "1.0000000",
175
- asset_type: "native",
171
+ type: 'payment',
172
+ transaction_hash: 'txfail',
173
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
174
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
175
+ amount: '1.0000000',
176
+ asset_type: 'native',
176
177
  transaction_successful: false,
177
- transactionRecord: txRecord({ fee_charged: "400" }),
178
+ transactionRecord: txRecord({ fee_charged: '400' }),
178
179
  }),
179
- ]);
180
+ ])
180
181
 
181
- const block = await getBlock(10);
182
+ const block = await getBlock(10)
182
183
  expect(block.transactions[0]).toMatchObject({
183
- hash: "txfail",
184
+ hash: 'txfail',
184
185
  failed: true,
185
186
  fees: 400n,
186
187
  operations: [],
187
- });
188
- });
188
+ })
189
+ })
189
190
 
190
- it("groups multiple allowlisted operations under the same transaction hash", async () => {
191
- const sharedTx = txRecord({ fee_charged: "300" });
191
+ it('groups multiple allowlisted operations under the same transaction hash', async () => {
192
+ const sharedTx = txRecord({ fee_charged: '300' })
192
193
  fetchAllLedgerOperationsMock.mockResolvedValue([
193
194
  rawOp({
194
- id: "1",
195
- type: "payment",
196
- transaction_hash: "txmulti",
197
- from: "GA",
198
- to: "GB",
199
- amount: "1.0000000",
200
- asset_type: "native",
195
+ id: '1',
196
+ type: 'payment',
197
+ transaction_hash: 'txmulti',
198
+ from: 'GA',
199
+ to: 'GB',
200
+ amount: '1.0000000',
201
+ asset_type: 'native',
201
202
  transactionRecord: sharedTx,
202
203
  }),
203
204
  rawOp({
204
- id: "2",
205
- type: "payment",
206
- transaction_hash: "txmulti",
207
- from: "GB",
208
- to: "GC",
209
- amount: "0.5000000",
210
- asset_type: "native",
205
+ id: '2',
206
+ type: 'payment',
207
+ transaction_hash: 'txmulti',
208
+ from: 'GB',
209
+ to: 'GC',
210
+ amount: '0.5000000',
211
+ asset_type: 'native',
211
212
  transactionRecord: sharedTx,
212
213
  }),
213
- ]);
214
+ ])
214
215
 
215
- const block = await getBlock(10);
216
- expect(block.transactions).toHaveLength(1);
217
- expect(block.transactions[0].operations.length).toBeGreaterThanOrEqual(2);
218
- });
216
+ const block = await getBlock(10)
217
+ expect(block.transactions).toHaveLength(1)
218
+ expect(block.transactions[0].operations.length).toBeGreaterThanOrEqual(2)
219
+ })
219
220
 
220
- it("maps token payments using assetReference and assetOwner", async () => {
221
+ it('maps token payments using assetReference and assetOwner', async () => {
221
222
  fetchAllLedgerOperationsMock.mockResolvedValue([
222
223
  rawOp({
223
- type: "payment",
224
- transaction_hash: "txtok",
225
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
226
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
227
- amount: "10.0000000",
228
- asset_type: "credit_alphanum4",
229
- asset_code: "USD",
230
- asset_issuer: "GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
224
+ type: 'payment',
225
+ transaction_hash: 'txtok',
226
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
227
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
228
+ amount: '10.0000000',
229
+ asset_type: 'credit_alphanum4',
230
+ asset_code: 'USD',
231
+ asset_issuer: 'GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
231
232
  transactionRecord: txRecord(),
232
233
  }),
233
- ]);
234
+ ])
234
235
 
235
- const block = await getBlock(10);
236
- const transfers = block.transactions[0].operations.filter(o => o.type === "transfer");
236
+ const block = await getBlock(10)
237
+ const transfers = block.transactions[0].operations.filter((o) => o.type === 'transfer')
237
238
  expect(transfers[0]).toMatchObject({
238
239
  asset: {
239
- type: "token",
240
- assetReference: "USD",
241
- assetOwner: "GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
240
+ type: 'token',
241
+ assetReference: 'USD',
242
+ assetOwner: 'GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
242
243
  },
243
- });
244
- });
244
+ })
245
+ })
245
246
 
246
- it("maps create_account to two native transfers", async () => {
247
+ it('maps create_account to two native transfers', async () => {
247
248
  fetchAllLedgerOperationsMock.mockResolvedValue([
248
249
  rawOp({
249
- type: "create_account",
250
- transaction_hash: "txcreate",
251
- funder: "GFUNDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
252
- account: "GNEWACCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
253
- starting_balance: "2.0000000",
254
- transactionRecord: txRecord({ fee_charged: "100" }),
250
+ type: 'create_account',
251
+ transaction_hash: 'txcreate',
252
+ funder: 'GFUNDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
253
+ account: 'GNEWACCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
254
+ starting_balance: '2.0000000',
255
+ transactionRecord: txRecord({ fee_charged: '100' }),
255
256
  }),
256
- ]);
257
+ ])
257
258
 
258
- const block = await getBlock(10);
259
+ const block = await getBlock(10)
259
260
  expect(block.transactions[0].operations).toEqual(
260
261
  expect.arrayContaining([
261
262
  expect.objectContaining({
262
- type: "transfer",
263
- address: "GFUNDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
263
+ type: 'transfer',
264
+ address: 'GFUNDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
264
265
  amount: -20000000n,
265
266
  }),
266
267
  expect.objectContaining({
267
- type: "transfer",
268
- address: "GNEWACCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
268
+ type: 'transfer',
269
+ address: 'GNEWACCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
269
270
  amount: 20000000n,
270
271
  }),
271
- ]),
272
- );
273
- });
272
+ ])
273
+ )
274
+ })
274
275
 
275
- it("maps change_trust to other operations", async () => {
276
+ it('maps change_trust to other operations', async () => {
276
277
  fetchAllLedgerOperationsMock.mockResolvedValue([
277
278
  rawOp({
278
- type: "change_trust",
279
- transaction_hash: "txtrust",
280
- trustor: "GTRUSTORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
281
- asset_code: "ABC",
282
- asset_issuer: "GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
283
- limit: "1000.0000000",
284
- transactionRecord: txRecord(),
279
+ type: 'change_trust',
280
+ transaction_hash: 'txtrust',
281
+ trustor: 'GTRUSTORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
282
+ asset_code: 'ABC',
283
+ asset_issuer: 'GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
284
+ limit: '1000.0000000',
285
+ transactionRecord: txRecord({ source_account_sequence: '12345' }),
285
286
  }),
286
- ]);
287
+ ])
287
288
 
288
- const block = await getBlock(10);
289
+ const block = await getBlock(10)
289
290
  expect(block.transactions[0].operations[0]).toMatchObject({
290
- type: "other",
291
- ledgerOpType: "OPT_IN",
292
- trustor: "GTRUSTORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
293
- });
294
- });
291
+ type: 'other',
292
+ ledgerOpType: 'OPT_IN',
293
+ assetAmount: '100',
294
+ memo: { type: 'NO_MEMO' },
295
+ sequence: '12345',
296
+ })
297
+ })
298
+
299
+ it('decodes MEMO_HASH from base64 to hex in change_trust details', async () => {
300
+ const base64Hash = Buffer.from('abcdef1234567890', 'hex').toString('base64')
301
+ fetchAllLedgerOperationsMock.mockResolvedValue([
302
+ rawOp({
303
+ type: 'change_trust',
304
+ transaction_hash: 'txhash',
305
+ asset_code: 'USD',
306
+ asset_issuer: 'GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
307
+ limit: '500.0000000',
308
+ transactionRecord: txRecord({ memo_type: 'hash', memo: base64Hash }),
309
+ }),
310
+ ])
295
311
 
296
- it("omits successful transactions that only contain unsupported operation types", async () => {
312
+ const block = await getBlock(10)
313
+ expect(block.transactions[0].operations[0]).toMatchObject({
314
+ memo: { type: 'MEMO_HASH', value: 'abcdef1234567890' },
315
+ })
316
+ })
317
+
318
+ it('decodes MEMO_RETURN from base64 to hex in change_trust details', async () => {
319
+ const base64Hash = Buffer.from('deadbeef', 'hex').toString('base64')
297
320
  fetchAllLedgerOperationsMock.mockResolvedValue([
298
321
  rawOp({
299
- type: "manage_sell_offer",
300
- transaction_hash: "txoffer",
322
+ type: 'change_trust',
323
+ transaction_hash: 'txreturn',
324
+ asset_code: 'EUR',
325
+ asset_issuer: 'GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
326
+ limit: '100.0000000',
327
+ transactionRecord: txRecord({ memo_type: 'return', memo: base64Hash }),
328
+ }),
329
+ ])
330
+
331
+ const block = await getBlock(10)
332
+ expect(block.transactions[0].operations[0]).toMatchObject({
333
+ memo: { type: 'MEMO_RETURN', value: 'deadbeef' },
334
+ })
335
+ })
336
+
337
+ it('keeps successful transactions with only unsupported operation types for fee tracking', async () => {
338
+ fetchAllLedgerOperationsMock.mockResolvedValue([
339
+ rawOp({
340
+ type: 'manage_sell_offer',
341
+ transaction_hash: 'txoffer',
301
342
  transactionRecord: txRecord(),
302
343
  }),
303
- ]);
344
+ ])
304
345
 
305
- const block = await getBlock(10);
306
- expect(block.transactions).toHaveLength(0);
307
- });
346
+ const block = await getBlock(10)
347
+ expect(block.transactions).toHaveLength(1)
348
+ expect(block.transactions[0].operations).toHaveLength(0)
349
+ expect(block.transactions[0].fees).toBe(100n)
350
+ })
308
351
 
309
- it("maps path_payment_strict_send with distinct source and destination assets", async () => {
352
+ it('maps path_payment_strict_send with distinct source and destination assets', async () => {
310
353
  fetchAllLedgerOperationsMock.mockResolvedValue([
311
354
  rawOp({
312
- type: "path_payment_strict_send",
313
- transaction_hash: "txpathsend",
314
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
315
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
316
- amount: "0.0033586",
317
- asset_type: "credit_alphanum12",
318
- asset_code: "Shitcoinz",
319
- asset_issuer: "GBVYKIM4QGW7NK3Q5S76GWMZMLAWYB6FB43JQ4J7ZOXHAA3LEZZGYHSD",
320
- source_amount: "0.0130225",
321
- source_asset_type: "native",
355
+ type: 'path_payment_strict_send',
356
+ transaction_hash: 'txpathsend',
357
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
358
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
359
+ amount: '0.0033586',
360
+ asset_type: 'credit_alphanum12',
361
+ asset_code: 'Shitcoinz',
362
+ asset_issuer: 'GBVYKIM4QGW7NK3Q5S76GWMZMLAWYB6FB43JQ4J7ZOXHAA3LEZZGYHSD',
363
+ source_amount: '0.0130225',
364
+ source_asset_type: 'native',
322
365
  transactionRecord: txRecord(),
323
366
  }),
324
- ]);
367
+ ])
325
368
 
326
- const block = await getBlock(10);
327
- const ops = block.transactions[0].operations;
328
- expect(ops).toHaveLength(2);
329
- expect(ops[0]).toMatchObject({ type: "transfer", asset: { type: "native" } });
330
- expect(typeof ops[0].amount).toBe("bigint");
369
+ const block = await getBlock(10)
370
+ const ops = block.transactions[0].operations
371
+ expect(ops).toHaveLength(2)
372
+ expect(ops[0]).toMatchObject({ type: 'transfer', asset: { type: 'native' } })
373
+ expect(typeof ops[0].amount).toBe('bigint')
331
374
  expect(ops[1]).toMatchObject({
332
- type: "transfer",
333
- asset: { type: "token", assetReference: "Shitcoinz" },
334
- });
335
- expect(typeof ops[1].amount).toBe("bigint");
336
- });
337
-
338
- it("path_payment_strict_receive debits source_amount when both send_max and source_amount are present", async () => {
339
- const sourceAmountStr = "0.0100000";
340
- const sendMaxStr = "5.0000000";
375
+ type: 'transfer',
376
+ asset: { type: 'token', assetReference: 'Shitcoinz' },
377
+ })
378
+ expect(typeof ops[1].amount).toBe('bigint')
379
+ })
380
+
381
+ it('path_payment_strict_receive debits source_amount when both send_max and source_amount are present', async () => {
382
+ const sourceAmountStr = '0.0100000'
383
+ const sendMaxStr = '5.0000000'
341
384
  const expectedDebit = BigInt(
342
- parseAPIValue(sourceAmountStr).integerValue(BigNumber.ROUND_FLOOR).toFixed(0),
343
- );
385
+ parseAPIValue(sourceAmountStr).integerValue(BigNumber.ROUND_FLOOR).toFixed(0)
386
+ )
344
387
 
345
388
  fetchAllLedgerOperationsMock.mockResolvedValue([
346
389
  rawOp({
347
- type: "path_payment_strict_receive",
348
- transaction_hash: "txpathrecv",
349
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
350
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
351
- amount: "0.0033586",
352
- asset_type: "credit_alphanum12",
353
- asset_code: "Shitcoinz",
354
- asset_issuer: "GBVYKIM4QGW7NK3Q5S76GWMZMLAWYB6FB43JQ4J7ZOXHAA3LEZZGYHSD",
390
+ type: 'path_payment_strict_receive',
391
+ transaction_hash: 'txpathrecv',
392
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
393
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
394
+ amount: '0.0033586',
395
+ asset_type: 'credit_alphanum12',
396
+ asset_code: 'Shitcoinz',
397
+ asset_issuer: 'GBVYKIM4QGW7NK3Q5S76GWMZMLAWYB6FB43JQ4J7ZOXHAA3LEZZGYHSD',
355
398
  send_max: sendMaxStr,
356
399
  source_amount: sourceAmountStr,
357
- source_asset_type: "native",
400
+ source_asset_type: 'native',
358
401
  transactionRecord: txRecord(),
359
402
  }),
360
- ]);
403
+ ])
361
404
 
362
- const block = await getBlock(10);
363
- const ops = block.transactions[0].operations;
364
- expect(ops).toHaveLength(2);
405
+ const block = await getBlock(10)
406
+ const ops = block.transactions[0].operations
407
+ expect(ops).toHaveLength(2)
365
408
  expect(ops[0]).toMatchObject({
366
- type: "transfer",
367
- address: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
368
- asset: { type: "native" },
409
+ type: 'transfer',
410
+ address: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
411
+ asset: { type: 'native' },
369
412
  amount: -expectedDebit,
370
- });
413
+ })
371
414
  const wrongDebit = BigInt(
372
- parseAPIValue(sendMaxStr).integerValue(BigNumber.ROUND_FLOOR).toFixed(0),
373
- );
374
- expect(ops[0].amount).not.toBe(-wrongDebit);
375
- });
415
+ parseAPIValue(sendMaxStr).integerValue(BigNumber.ROUND_FLOOR).toFixed(0)
416
+ )
417
+ expect(ops[0].amount).not.toBe(-wrongDebit)
418
+ })
376
419
 
377
- it("omits parent in block info for ledger height 1", async () => {
420
+ it('omits parent in block info for ledger height 1', async () => {
378
421
  fetchLedgerRecordMock.mockImplementation(
379
422
  async (seq: number) =>
380
423
  ({
381
424
  sequence: seq,
382
425
  hash: `LEDGER-HASH-${seq}`,
383
- closed_at: "2018-09-15T15:40:05Z",
384
- }) as Awaited<ReturnType<typeof network.fetchLedgerRecord>>,
385
- );
386
- fetchAllLedgerOperationsMock.mockResolvedValue([]);
426
+ closed_at: '2018-09-15T15:40:05Z',
427
+ }) as Awaited<ReturnType<typeof network.fetchLedgerRecord>>
428
+ )
429
+ fetchAllLedgerOperationsMock.mockResolvedValue([])
387
430
 
388
- const block = await getBlock(1);
389
- expect(block.info.height).toBe(1);
390
- expect(block.info.parent).toBeUndefined();
391
- });
431
+ const block = await getBlock(1)
432
+ expect(block.info.height).toBe(1)
433
+ expect(block.info.parent).toBeUndefined()
434
+ })
392
435
 
393
- it("omits feesPayer when fee_account and source_account are absent", async () => {
436
+ it('omits feesPayer when fee_account and source_account are absent', async () => {
394
437
  fetchAllLedgerOperationsMock.mockResolvedValue([
395
438
  rawOp({
396
- type: "payment",
397
- transaction_hash: "txnopayer",
398
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
399
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
400
- amount: "1.0000000",
401
- asset_type: "native",
439
+ type: 'payment',
440
+ transaction_hash: 'txnopayer',
441
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
442
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
443
+ amount: '1.0000000',
444
+ asset_type: 'native',
402
445
  transactionRecord: txRecord({
403
- fee_charged: "100",
404
- source_account: "",
405
- } as Partial<Horizon.ServerApi.TransactionRecord>),
446
+ fee_charged: '100',
447
+ source_account: '',
448
+ }),
406
449
  }),
407
- ]);
450
+ ])
408
451
 
409
- const block = await getBlock(10);
410
- expect(block.transactions[0]).not.toHaveProperty("feesPayer");
411
- });
452
+ const block = await getBlock(10)
453
+ expect(block.transactions[0]).not.toHaveProperty('feesPayer')
454
+ })
412
455
 
413
- it("maps create_account with zero starting balance to no operations", async () => {
456
+ it('maps create_account with zero starting balance to empty operations but keeps tx for fees', async () => {
414
457
  fetchAllLedgerOperationsMock.mockResolvedValue([
415
458
  rawOp({
416
- type: "create_account",
417
- transaction_hash: "txcreatezero",
418
- funder: "GFUNDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
419
- account: "GNEWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
420
- starting_balance: "0.0000000",
459
+ type: 'create_account',
460
+ transaction_hash: 'txcreatezero',
461
+ funder: 'GFUNDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
462
+ account: 'GNEWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
463
+ starting_balance: '0.0000000',
421
464
  transactionRecord: txRecord(),
422
465
  }),
423
- ]);
466
+ ])
424
467
 
425
- const block = await getBlock(10);
426
- expect(block.transactions).toHaveLength(0);
427
- });
468
+ const block = await getBlock(10)
469
+ expect(block.transactions).toHaveLength(1)
470
+ expect(block.transactions[0].operations).toHaveLength(0)
471
+ expect(block.transactions[0].fees).toBe(100n)
472
+ })
428
473
 
429
- it("maps payment using to_muxed when to is absent", async () => {
474
+ it('maps payment using to_muxed when to is absent', async () => {
430
475
  fetchAllLedgerOperationsMock.mockResolvedValue([
431
476
  rawOp({
432
- type: "payment",
433
- transaction_hash: "txmuxed",
434
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
477
+ type: 'payment',
478
+ transaction_hash: 'txmuxed',
479
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
435
480
  to: undefined,
436
- to_muxed: "GTO_MUXEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
437
- amount: "0.5000000",
438
- asset_type: "native",
481
+ to_muxed: 'GTO_MUXEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
482
+ amount: '0.5000000',
483
+ asset_type: 'native',
439
484
  transactionRecord: txRecord(),
440
485
  }),
441
- ]);
486
+ ])
442
487
 
443
- const block = await getBlock(10);
444
- const transfers = block.transactions[0].operations.filter(o => o.type === "transfer");
488
+ const block = await getBlock(10)
489
+ const transfers = block.transactions[0].operations.filter((o) => o.type === 'transfer')
445
490
  expect(
446
491
  transfers.some(
447
- o => "peer" in o && o.peer === "GTO_MUXEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
448
- ),
449
- ).toBe(true);
450
- });
492
+ (o) => 'peer' in o && o.peer === 'GTO_MUXEDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
493
+ )
494
+ ).toBe(true)
495
+ })
451
496
 
452
- it("maps change_trust with zero limit as OPT_OUT", async () => {
497
+ it('maps change_trust with zero limit as OPT_OUT', async () => {
453
498
  fetchAllLedgerOperationsMock.mockResolvedValue([
454
499
  rawOp({
455
- type: "change_trust",
456
- transaction_hash: "txoptout",
457
- trustor: "GTRUSTORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
458
- asset_code: "ABC",
459
- asset_issuer: "GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
460
- limit: "0.0000000",
500
+ type: 'change_trust',
501
+ transaction_hash: 'txoptout',
502
+ trustor: 'GTRUSTORAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
503
+ asset_code: 'ABC',
504
+ asset_issuer: 'GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
505
+ limit: '0.0000000',
461
506
  transactionRecord: txRecord(),
462
507
  }),
463
- ]);
508
+ ])
464
509
 
465
- const block = await getBlock(10);
510
+ const block = await getBlock(10)
466
511
  expect(block.transactions[0].operations[0]).toMatchObject({
467
- type: "other",
468
- ledgerOpType: "OPT_OUT",
469
- });
470
- });
512
+ type: 'other',
513
+ ledgerOpType: 'OPT_OUT',
514
+ })
515
+ })
471
516
 
472
- it("path_payment_strict_send with zero amounts omits the transaction row", async () => {
517
+ it('path_payment_strict_send with zero amounts keeps tx for fees', async () => {
473
518
  fetchAllLedgerOperationsMock.mockResolvedValue([
474
519
  rawOp({
475
- type: "path_payment_strict_send",
476
- transaction_hash: "txpathzero",
477
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
478
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
479
- amount: "0.0000000",
480
- asset_type: "native",
481
- source_amount: "0.0000000",
482
- source_asset_type: "native",
520
+ type: 'path_payment_strict_send',
521
+ transaction_hash: 'txpathzero',
522
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
523
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
524
+ amount: '0.0000000',
525
+ asset_type: 'native',
526
+ source_amount: '0.0000000',
527
+ source_asset_type: 'native',
483
528
  transactionRecord: txRecord(),
484
529
  }),
485
- ]);
530
+ ])
486
531
 
487
- const block = await getBlock(10);
488
- expect(block.transactions).toHaveLength(0);
489
- });
532
+ const block = await getBlock(10)
533
+ expect(block.transactions).toHaveLength(1)
534
+ expect(block.transactions[0].operations).toHaveLength(0)
535
+ expect(block.transactions[0].fees).toBe(100n)
536
+ })
490
537
 
491
- it("path_payment_strict_receive uses send_max when source_amount is absent", async () => {
492
- const sendMaxStr = "0.0200000";
538
+ it('path_payment_strict_receive uses send_max when source_amount is absent', async () => {
539
+ const sendMaxStr = '0.0200000'
493
540
  const expected = BigInt(
494
- parseAPIValue(sendMaxStr).integerValue(BigNumber.ROUND_FLOOR).toFixed(0),
495
- );
541
+ parseAPIValue(sendMaxStr).integerValue(BigNumber.ROUND_FLOOR).toFixed(0)
542
+ )
496
543
  fetchAllLedgerOperationsMock.mockResolvedValue([
497
544
  rawOp({
498
- type: "path_payment_strict_receive",
499
- transaction_hash: "txrecvmax",
500
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
501
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
502
- amount: "0.0010000",
503
- asset_type: "native",
545
+ type: 'path_payment_strict_receive',
546
+ transaction_hash: 'txrecvmax',
547
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
548
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
549
+ amount: '0.0010000',
550
+ asset_type: 'native',
504
551
  send_max: sendMaxStr,
505
- source_asset_type: "native",
552
+ source_asset_type: 'native',
506
553
  transactionRecord: txRecord(),
507
554
  }),
508
- ]);
555
+ ])
509
556
 
510
- const block = await getBlock(10);
557
+ const block = await getBlock(10)
511
558
  const sender = block.transactions[0].operations.find(
512
- o =>
513
- o.type === "transfer" && o.address === "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
514
- );
515
- expect(sender?.amount).toBe(-expected);
516
- });
559
+ (o) =>
560
+ o.type === 'transfer' && o.address === 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
561
+ )
562
+ expect(sender?.amount).toBe(-expected)
563
+ })
517
564
 
518
- it("path_payment_strict_receive with no source_amount nor send_max only maps destination leg", async () => {
565
+ it('path_payment_strict_receive with no source_amount nor send_max only maps destination leg', async () => {
519
566
  fetchAllLedgerOperationsMock.mockResolvedValue([
520
567
  rawOp({
521
- type: "path_payment_strict_receive",
522
- transaction_hash: "txrecvnodebit",
523
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
524
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
525
- amount: "0.5000000",
526
- asset_type: "native",
527
- source_asset_type: "native",
568
+ type: 'path_payment_strict_receive',
569
+ transaction_hash: 'txrecvnodebit',
570
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
571
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
572
+ amount: '0.5000000',
573
+ asset_type: 'native',
574
+ source_asset_type: 'native',
528
575
  transactionRecord: txRecord(),
529
576
  }),
530
- ]);
577
+ ])
531
578
 
532
- const block = await getBlock(10);
533
- expect(block.transactions[0].operations).toHaveLength(1);
579
+ const block = await getBlock(10)
580
+ expect(block.transactions[0].operations).toHaveLength(1)
534
581
  expect(block.transactions[0].operations[0]).toMatchObject({
535
- type: "transfer",
536
- address: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
537
- asset: { type: "native" },
582
+ type: 'transfer',
583
+ address: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
584
+ asset: { type: 'native' },
538
585
  amount: 5000000n,
539
- });
540
- });
586
+ })
587
+ })
541
588
 
542
- it("path_payment_strict_send with zero source_amount maps only destination leg", async () => {
589
+ it('path_payment_strict_send with zero source_amount maps only destination leg', async () => {
543
590
  fetchAllLedgerOperationsMock.mockResolvedValue([
544
591
  rawOp({
545
- type: "path_payment_strict_send",
546
- transaction_hash: "txpathsenddestonly",
547
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
548
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
549
- amount: "0.2500000",
550
- asset_type: "native",
551
- source_amount: "0.0000000",
552
- source_asset_type: "native",
592
+ type: 'path_payment_strict_send',
593
+ transaction_hash: 'txpathsenddestonly',
594
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
595
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
596
+ amount: '0.2500000',
597
+ asset_type: 'native',
598
+ source_amount: '0.0000000',
599
+ source_asset_type: 'native',
553
600
  transactionRecord: txRecord(),
554
601
  }),
555
- ]);
602
+ ])
556
603
 
557
- const block = await getBlock(10);
558
- expect(block.transactions[0].operations).toHaveLength(1);
604
+ const block = await getBlock(10)
605
+ expect(block.transactions[0].operations).toHaveLength(1)
559
606
  expect(block.transactions[0].operations[0]).toMatchObject({
560
- type: "transfer",
561
- address: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
607
+ type: 'transfer',
608
+ address: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
562
609
  amount: 2500000n,
563
- });
564
- });
610
+ })
611
+ })
565
612
 
566
- it("path_payment_strict_send with zero amount maps only source leg", async () => {
613
+ it('path_payment_strict_send with zero amount maps only source leg', async () => {
567
614
  fetchAllLedgerOperationsMock.mockResolvedValue([
568
615
  rawOp({
569
- type: "path_payment_strict_send",
570
- transaction_hash: "txpathsendsourceonly",
571
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
572
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
573
- amount: "0.0000000",
574
- asset_type: "native",
575
- source_amount: "1.0000000",
576
- source_asset_type: "native",
616
+ type: 'path_payment_strict_send',
617
+ transaction_hash: 'txpathsendsourceonly',
618
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
619
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
620
+ amount: '0.0000000',
621
+ asset_type: 'native',
622
+ source_amount: '1.0000000',
623
+ source_asset_type: 'native',
577
624
  transactionRecord: txRecord(),
578
625
  }),
579
- ]);
626
+ ])
580
627
 
581
- const block = await getBlock(10);
582
- expect(block.transactions[0].operations).toHaveLength(1);
628
+ const block = await getBlock(10)
629
+ expect(block.transactions[0].operations).toHaveLength(1)
583
630
  expect(block.transactions[0].operations[0]).toMatchObject({
584
- type: "transfer",
585
- address: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
631
+ type: 'transfer',
632
+ address: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
586
633
  amount: -10000000n,
587
- });
588
- });
634
+ })
635
+ })
589
636
 
590
- it("maps payment with only to address as single incoming transfer", async () => {
637
+ it('maps payment with only to address as single incoming transfer', async () => {
591
638
  fetchAllLedgerOperationsMock.mockResolvedValue([
592
639
  rawOp({
593
- type: "payment",
594
- transaction_hash: "txtoonly",
595
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
596
- amount: "3.0000000",
597
- asset_type: "native",
640
+ type: 'payment',
641
+ transaction_hash: 'txtoonly',
642
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
643
+ amount: '3.0000000',
644
+ asset_type: 'native',
598
645
  transactionRecord: txRecord(),
599
646
  }),
600
- ]);
647
+ ])
601
648
 
602
- const block = await getBlock(10);
649
+ const block = await getBlock(10)
603
650
  expect(block.transactions[0].operations).toEqual([
604
651
  expect.objectContaining({
605
- type: "transfer",
606
- address: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
652
+ type: 'transfer',
653
+ address: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
607
654
  amount: 30000000n,
608
655
  }),
609
- ]);
610
- });
656
+ ])
657
+ })
611
658
 
612
- it("maps payment with only from address as single outgoing transfer", async () => {
659
+ it('maps payment with only from address as single outgoing transfer', async () => {
613
660
  fetchAllLedgerOperationsMock.mockResolvedValue([
614
661
  rawOp({
615
- type: "payment",
616
- transaction_hash: "txfromonly",
617
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
618
- amount: "0.2500000",
619
- asset_type: "native",
662
+ type: 'payment',
663
+ transaction_hash: 'txfromonly',
664
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
665
+ amount: '0.2500000',
666
+ asset_type: 'native',
620
667
  transactionRecord: txRecord(),
621
668
  }),
622
- ]);
669
+ ])
623
670
 
624
- const block = await getBlock(10);
671
+ const block = await getBlock(10)
625
672
  expect(block.transactions[0].operations).toEqual([
626
673
  expect.objectContaining({
627
- type: "transfer",
628
- address: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
674
+ type: 'transfer',
675
+ address: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
629
676
  amount: -2500000n,
630
677
  }),
631
- ]);
632
- });
678
+ ])
679
+ })
633
680
 
634
- it("treats payment with missing asset_type as native when mapping asset", async () => {
681
+ it('treats payment with missing asset_type as native when mapping asset', async () => {
635
682
  fetchAllLedgerOperationsMock.mockResolvedValue([
636
683
  rawOp({
637
- type: "payment",
638
- transaction_hash: "txnoassettype",
639
- from: "GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
640
- to: "GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
641
- amount: "1.0000000",
684
+ type: 'payment',
685
+ transaction_hash: 'txnoassettype',
686
+ from: 'GFROMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
687
+ to: 'GTOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
688
+ amount: '1.0000000',
642
689
  asset_type: undefined,
643
- asset_code: "USD",
644
- asset_issuer: "GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
690
+ asset_code: 'USD',
691
+ asset_issuer: 'GISSUERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
645
692
  transactionRecord: txRecord(),
646
693
  }),
647
- ]);
694
+ ])
648
695
 
649
- const block = await getBlock(10);
650
- const transfers = block.transactions[0].operations.filter(o => o.type === "transfer");
651
- expect(transfers.every(t => t.type === "transfer" && t.asset.type === "native")).toBe(true);
652
- });
653
- });
696
+ const block = await getBlock(10)
697
+ const transfers = block.transactions[0].operations.filter((o) => o.type === 'transfer')
698
+ expect(transfers.every((t) => t.type === 'transfer' && t.asset.type === 'native')).toBe(true)
699
+ })
700
+ })