@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,43 +1,46 @@
1
- import type { Horizon } from "@stellar/stellar-sdk";
2
- import type { BalanceAsset, RawOperation } from "../types";
1
+ // SPDX-FileCopyrightText: © 2026 LEDGER SAS
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { BalanceAsset, RawOperation } from '../types'
5
+ import type { Horizon } from '@stellar/stellar-sdk'
3
6
  import {
4
7
  BASE_RESERVE,
5
8
  MIN_BALANCE,
6
9
  getReservedBalance,
7
10
  rawOperationsToOperations,
8
- } from "./serialization";
11
+ } from './serialization'
9
12
 
10
- const ADDR = "GBADDR";
11
- const OTHER_ADDR = "GBOTHER";
12
- const THIRD_ADDR = "GBTHIRD";
13
- const ACCOUNT_ID = "stellar:GBADDR";
14
- const TX_HASH = "txh";
15
- const BLOCK_HASH = "block-hash";
16
- const BLOCK_TIME = "2025-06-01T12:00:00Z";
17
- const CREATED_AT = "2025-06-01T12:00:00Z";
13
+ const ADDR = 'GBADDR'
14
+ const OTHER_ADDR = 'GBOTHER'
15
+ const THIRD_ADDR = 'GBTHIRD'
16
+ const ACCOUNT_ID = 'stellar:GBADDR'
17
+ const TX_HASH = 'txh'
18
+ const BLOCK_HASH = 'block-hash'
19
+ const BLOCK_TIME = '2025-06-01T12:00:00Z'
20
+ const CREATED_AT = '2025-06-01T12:00:00Z'
18
21
 
19
22
  type TxOverrides = Partial<{
20
- ledger_attr: number;
21
- fee_charged: string;
22
- fee_account: string;
23
- source_account_sequence: string;
24
- memo_type: string;
25
- memo: string | undefined;
26
- ledger_hash: string;
27
- ledger_closed_at: string;
28
- }>;
23
+ ledger_attr: number
24
+ fee_charged: string
25
+ fee_account: string
26
+ source_account_sequence: string
27
+ memo_type: string
28
+ memo: string | undefined
29
+ ledger_hash: string
30
+ ledger_closed_at: string
31
+ }>
29
32
 
30
33
  function makeTx(overrides: TxOverrides = {}) {
31
34
  const {
32
35
  ledger_attr = 100,
33
- fee_charged = "100",
36
+ fee_charged = '100',
34
37
  fee_account,
35
- source_account_sequence = "42",
36
- memo_type = "none",
38
+ source_account_sequence = '42',
39
+ memo_type = 'none',
37
40
  memo,
38
41
  ledger_hash = BLOCK_HASH,
39
42
  ledger_closed_at = BLOCK_TIME,
40
- } = overrides;
43
+ } = overrides
41
44
 
42
45
  return {
43
46
  ledger_attr,
@@ -50,1147 +53,1147 @@ function makeTx(overrides: TxOverrides = {}) {
50
53
  hash: ledger_hash,
51
54
  closed_at: ledger_closed_at,
52
55
  }),
53
- };
56
+ }
54
57
  }
55
58
 
56
59
  // `RawOperation.type` is constrained to a narrow union of Horizon operation type
57
60
  // literals which makes building fixtures with plain strings impractical, so we
58
61
  // accept any string and cast at the construction site.
59
- type RawOpInput = { type: string } & Record<string, unknown>;
62
+ type RawOpInput = { type: string } & Record<string, unknown>
60
63
 
61
64
  function makeOp(rawOpOverrides: RawOpInput, txOverrides: TxOverrides = {}): RawOperation {
62
65
  return {
63
- id: "op-1",
64
- paging_token: "pt-1",
66
+ id: 'op-1',
67
+ paging_token: 'pt-1',
65
68
  source_account: ADDR,
66
69
  transaction_hash: TX_HASH,
67
70
  transaction_successful: true,
68
71
  created_at: CREATED_AT,
69
72
  transaction: jest.fn().mockResolvedValue(makeTx(txOverrides)),
70
73
  ...rawOpOverrides,
71
- } as unknown as RawOperation;
74
+ } as unknown as RawOperation
72
75
  }
73
76
 
74
- describe("constants", () => {
75
- it("exports BASE_RESERVE equal to 0.5 (stellar protocol base reserve in XLM)", () => {
76
- expect(BASE_RESERVE).toBe(0.5);
77
- });
77
+ describe('constants', () => {
78
+ it('exports BASE_RESERVE equal to 0.5 (stellar protocol base reserve in XLM)', () => {
79
+ expect(BASE_RESERVE).toBe(0.5)
80
+ })
78
81
 
79
- it("exports MIN_BALANCE equal to 1 (minimum stellar account balance in XLM)", () => {
80
- expect(MIN_BALANCE).toBe(1);
81
- });
82
- });
82
+ it('exports MIN_BALANCE equal to 1 (minimum stellar account balance in XLM)', () => {
83
+ expect(MIN_BALANCE).toBe(1)
84
+ })
85
+ })
83
86
 
84
- describe("getReservedBalance", () => {
87
+ describe('getReservedBalance', () => {
85
88
  type AccountInput = Partial<{
86
- num_sponsoring: string;
87
- num_sponsored: string;
88
- subentry_count: number;
89
- balances: Array<Partial<BalanceAsset>>;
90
- }>;
89
+ num_sponsoring: string
90
+ num_sponsored: string
91
+ subentry_count: number
92
+ balances: Array<Partial<BalanceAsset>>
93
+ }>
91
94
 
92
95
  function makeAccount(overrides: AccountInput = {}): Horizon.ServerApi.AccountRecord {
93
96
  return {
94
- num_sponsoring: "0",
95
- num_sponsored: "0",
97
+ num_sponsoring: '0',
98
+ num_sponsored: '0',
96
99
  subentry_count: 0,
97
- balances: [{ asset_type: "native", selling_liabilities: "0" }],
100
+ balances: [{ asset_type: 'native', selling_liabilities: '0' }],
98
101
  ...overrides,
99
- } as unknown as Horizon.ServerApi.AccountRecord;
102
+ } as unknown as Horizon.ServerApi.AccountRecord
100
103
  }
101
104
 
102
- it("should return 1 XLM (the minimum reserve) when account has no subentries, sponsors or liabilities", () => {
103
- expect(getReservedBalance(makeAccount()).toNumber()).toBe(1);
104
- });
105
+ it('should return 1 XLM (the minimum reserve) when account has no subentries, sponsors or liabilities', () => {
106
+ expect(getReservedBalance(makeAccount()).toNumber()).toBe(1)
107
+ })
105
108
 
106
- it("should add 0.5 XLM per subentry", () => {
107
- expect(getReservedBalance(makeAccount({ subentry_count: 4 })).toNumber()).toBe(3);
108
- });
109
+ it('should add 0.5 XLM per subentry', () => {
110
+ expect(getReservedBalance(makeAccount({ subentry_count: 4 })).toNumber()).toBe(3)
111
+ })
109
112
 
110
- it("should add 0.5 XLM per sponsoring entry", () => {
111
- expect(getReservedBalance(makeAccount({ num_sponsoring: "2" })).toNumber()).toBe(2);
112
- });
113
+ it('should add 0.5 XLM per sponsoring entry', () => {
114
+ expect(getReservedBalance(makeAccount({ num_sponsoring: '2' })).toNumber()).toBe(2)
115
+ })
113
116
 
114
- it("should subtract 0.5 XLM per sponsored entry", () => {
117
+ it('should subtract 0.5 XLM per sponsored entry', () => {
115
118
  expect(
116
- getReservedBalance(makeAccount({ num_sponsoring: "4", num_sponsored: "2" })).toNumber(),
117
- ).toBe(2);
118
- });
119
+ getReservedBalance(makeAccount({ num_sponsoring: '4', num_sponsored: '2' })).toNumber()
120
+ ).toBe(2)
121
+ })
119
122
 
120
- it("should add native selling_liabilities on top of the entry reserve", () => {
123
+ it('should add native selling_liabilities on top of the entry reserve', () => {
121
124
  expect(
122
125
  getReservedBalance(
123
- makeAccount({ balances: [{ asset_type: "native", selling_liabilities: "10.5" }] }),
124
- ).toNumber(),
125
- ).toBe(11.5);
126
- });
126
+ makeAccount({ balances: [{ asset_type: 'native', selling_liabilities: '10.5' }] })
127
+ ).toNumber()
128
+ ).toBe(11.5)
129
+ })
127
130
 
128
- it("should ignore non-native selling_liabilities (only the native balance contributes)", () => {
131
+ it('should ignore non-native selling_liabilities (only the native balance contributes)', () => {
129
132
  expect(
130
133
  getReservedBalance(
131
134
  makeAccount({
132
135
  balances: [
133
- { asset_type: "credit_alphanum4", selling_liabilities: "100", asset_code: "USDC" },
134
- { asset_type: "native", selling_liabilities: "2" },
136
+ { asset_type: 'credit_alphanum4', selling_liabilities: '100', asset_code: 'USDC' },
137
+ { asset_type: 'native', selling_liabilities: '2' },
135
138
  ],
136
- }),
137
- ).toNumber(),
138
- ).toBe(3);
139
- });
139
+ })
140
+ ).toNumber()
141
+ ).toBe(3)
142
+ })
140
143
 
141
- it("should fall back to 0 selling_liabilities when no native balance entry exists", () => {
142
- expect(getReservedBalance(makeAccount({ balances: [] })).toNumber()).toBe(1);
143
- });
144
+ it('should fall back to 0 selling_liabilities when no native balance entry exists', () => {
145
+ expect(getReservedBalance(makeAccount({ balances: [] })).toNumber()).toBe(1)
146
+ })
144
147
 
145
- it("should treat undefined selling_liabilities on the native balance as 0", () => {
148
+ it('should treat undefined selling_liabilities on the native balance as 0', () => {
146
149
  expect(
147
- getReservedBalance(makeAccount({ balances: [{ asset_type: "native" }] })).toNumber(),
148
- ).toBe(1);
149
- });
150
+ getReservedBalance(makeAccount({ balances: [{ asset_type: 'native' }] })).toNumber()
151
+ ).toBe(1)
152
+ })
150
153
 
151
- it("should combine subentries, sponsoring/sponsored entries and selling_liabilities", () => {
154
+ it('should combine subentries, sponsoring/sponsored entries and selling_liabilities', () => {
152
155
  // (2 + 3 + 2 - 1) * 0.5 + 4.5 = 6 * 0.5 + 4.5 = 7.5
153
156
  expect(
154
157
  getReservedBalance(
155
158
  makeAccount({
156
159
  subentry_count: 3,
157
- num_sponsoring: "2",
158
- num_sponsored: "1",
159
- balances: [{ asset_type: "native", selling_liabilities: "4.5" }],
160
- }),
161
- ).toNumber(),
162
- ).toBe(7.5);
163
- });
164
- });
165
-
166
- describe("rawOperationsToOperations", () => {
167
- describe("address filtering", () => {
168
- it("should exclude operations not involving the address", async () => {
160
+ num_sponsoring: '2',
161
+ num_sponsored: '1',
162
+ balances: [{ asset_type: 'native', selling_liabilities: '4.5' }],
163
+ })
164
+ ).toNumber()
165
+ ).toBe(7.5)
166
+ })
167
+ })
168
+
169
+ describe('rawOperationsToOperations', () => {
170
+ describe('address filtering', () => {
171
+ it('should exclude operations not involving the address', async () => {
169
172
  const op = makeOp({
170
- type: "payment",
173
+ type: 'payment',
171
174
  from: OTHER_ADDR,
172
175
  to: THIRD_ADDR,
173
- amount: "10",
176
+ amount: '10',
174
177
  source_account: OTHER_ADDR,
175
- });
176
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
177
- expect(result).toHaveLength(0);
178
- });
178
+ })
179
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
180
+ expect(result).toHaveLength(0)
181
+ })
179
182
 
180
- it("should include operations where `from` equals the address", async () => {
183
+ it('should include operations where `from` equals the address', async () => {
181
184
  const op = makeOp({
182
- type: "payment",
185
+ type: 'payment',
183
186
  from: ADDR,
184
187
  to: OTHER_ADDR,
185
- amount: "10",
186
- });
187
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
188
- expect(result).toHaveLength(1);
189
- });
188
+ amount: '10',
189
+ })
190
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
191
+ expect(result).toHaveLength(1)
192
+ })
190
193
 
191
- it("should include operations where `to` equals the address", async () => {
194
+ it('should include operations where `to` equals the address', async () => {
192
195
  const op = makeOp({
193
- type: "payment",
196
+ type: 'payment',
194
197
  from: OTHER_ADDR,
195
198
  to: ADDR,
196
- amount: "10",
199
+ amount: '10',
197
200
  source_account: OTHER_ADDR,
198
- });
199
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
200
- expect(result).toHaveLength(1);
201
- });
201
+ })
202
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
203
+ expect(result).toHaveLength(1)
204
+ })
202
205
 
203
- it("should include operations where `funder` equals the address", async () => {
206
+ it('should include operations where `funder` equals the address', async () => {
204
207
  const op = makeOp({
205
- type: "create_account",
208
+ type: 'create_account',
206
209
  funder: ADDR,
207
210
  account: OTHER_ADDR,
208
- starting_balance: "10",
209
- });
210
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
211
- expect(result).toHaveLength(1);
212
- });
211
+ starting_balance: '10',
212
+ })
213
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
214
+ expect(result).toHaveLength(1)
215
+ })
213
216
 
214
- it("should include operations where `account` equals the address", async () => {
217
+ it('should include operations where `account` equals the address', async () => {
215
218
  const op = makeOp({
216
- type: "create_account",
219
+ type: 'create_account',
217
220
  funder: OTHER_ADDR,
218
221
  account: ADDR,
219
- starting_balance: "10",
222
+ starting_balance: '10',
220
223
  source_account: OTHER_ADDR,
221
- });
222
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
223
- expect(result).toHaveLength(1);
224
- });
224
+ })
225
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
226
+ expect(result).toHaveLength(1)
227
+ })
225
228
 
226
- it("should include operations where `trustor` equals the address", async () => {
229
+ it('should include operations where `trustor` equals the address', async () => {
227
230
  const op = makeOp({
228
- type: "change_trust",
231
+ type: 'change_trust',
229
232
  trustor: ADDR,
230
- limit: "1000",
231
- asset_code: "USDC",
232
- asset_issuer: "GISSUER",
233
+ limit: '1000',
234
+ asset_code: 'USDC',
235
+ asset_issuer: 'GISSUER',
233
236
  source_account: OTHER_ADDR,
234
- });
235
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
236
- expect(result).toHaveLength(1);
237
- });
237
+ })
238
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
239
+ expect(result).toHaveLength(1)
240
+ })
238
241
 
239
- it("should include operations where `source_account` equals the address", async () => {
242
+ it('should include operations where `source_account` equals the address', async () => {
240
243
  const op = makeOp({
241
- type: "change_trust",
244
+ type: 'change_trust',
242
245
  trustor: OTHER_ADDR,
243
- limit: "1000",
244
- asset_code: "USDC",
245
- asset_issuer: "GISSUER",
246
+ limit: '1000',
247
+ asset_code: 'USDC',
248
+ asset_issuer: 'GISSUER',
246
249
  source_account: ADDR,
247
- });
248
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
249
- expect(result).toHaveLength(1);
250
- });
251
- });
252
-
253
- describe("operation type filtering", () => {
254
- it.each(["manage_offer", "set_options", "allow_trust", "manage_data", "bump_sequence"])(
255
- "should not surface a typed Operation for unsupported %s operation",
256
- async type => {
250
+ })
251
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
252
+ expect(result).toHaveLength(1)
253
+ })
254
+ })
255
+
256
+ describe('operation type filtering', () => {
257
+ it.each(['manage_offer', 'set_options', 'allow_trust', 'manage_data', 'bump_sequence'])(
258
+ 'should not surface a typed Operation for unsupported %s operation',
259
+ async (type) => {
257
260
  const op = makeOp({
258
261
  type,
259
262
  source_account: ADDR,
260
- });
261
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
263
+ })
264
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
262
265
  // No typed Operation (OUT/IN/OPT_IN/...) is emitted for unsupported types
263
- expect(result.find(o => o.type !== "FEES")).toBeUndefined();
264
- },
265
- );
266
+ expect(result.find((o) => o.type !== 'FEES')).toBeUndefined()
267
+ }
268
+ )
266
269
 
267
270
  it.each([
268
- ["create_account", { funder: ADDR, account: OTHER_ADDR, starting_balance: "1" }],
269
- ["payment", { from: ADDR, to: OTHER_ADDR, amount: "1" }],
270
- ["path_payment_strict_send", { from: ADDR, to: OTHER_ADDR, amount: "1" }],
271
- ["path_payment_strict_receive", { from: ADDR, to: OTHER_ADDR, amount: "1" }],
271
+ ['create_account', { funder: ADDR, account: OTHER_ADDR, starting_balance: '1' }],
272
+ ['payment', { from: ADDR, to: OTHER_ADDR, amount: '1' }],
273
+ ['path_payment_strict_send', { from: ADDR, to: OTHER_ADDR, amount: '1' }],
274
+ ['path_payment_strict_receive', { from: ADDR, to: OTHER_ADDR, amount: '1' }],
272
275
  [
273
- "change_trust",
274
- { trustor: ADDR, limit: "1000", asset_code: "USDC", asset_issuer: "GISSUER" },
276
+ 'change_trust',
277
+ { trustor: ADDR, limit: '1000', asset_code: 'USDC', asset_issuer: 'GISSUER' },
275
278
  ],
276
- ])("should include supported %s operation", async (type, extra) => {
277
- const op = makeOp({ type, ...extra } as RawOpInput);
278
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
279
- expect(result).toHaveLength(1);
280
- });
281
- });
282
-
283
- describe("fee-only operations", () => {
279
+ ])('should include supported %s operation', async (type, extra) => {
280
+ const op = makeOp({ type, ...extra } as RawOpInput)
281
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
282
+ expect(result).toHaveLength(1)
283
+ })
284
+ })
285
+
286
+ describe('fee-only operations', () => {
284
287
  // Non-fee-bump Stellar transactions have `fee_account === source_account`,
285
288
  // which is what most of these fixtures model.
286
- it.each(["set_options", "manage_offer", "manage_data", "bump_sequence", "allow_trust"])(
287
- "emits a single FEES Operation for unsupported %s when address paid the fee",
288
- async type => {
289
+ it.each(['set_options', 'manage_offer', 'manage_data', 'bump_sequence', 'allow_trust'])(
290
+ 'emits a single FEES Operation for unsupported %s when address paid the fee',
291
+ async (type) => {
289
292
  const op = makeOp(
290
293
  { type, source_account: ADDR, transaction_hash: `tx-${type}` },
291
- { fee_account: ADDR, fee_charged: "150" },
292
- );
293
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
294
- expect(result).toHaveLength(1);
294
+ { fee_account: ADDR, fee_charged: '150' }
295
+ )
296
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
297
+ expect(result).toHaveLength(1)
295
298
  expect(result[0]).toMatchObject({
296
- type: "FEES",
299
+ type: 'FEES',
297
300
  value: 0n,
298
- asset: { type: "native" },
301
+ asset: { type: 'native' },
299
302
  senders: [ADDR],
300
303
  recipients: [],
301
304
  tx: { hash: `tx-${type}`, fees: 150n, feesPayer: ADDR, failed: false },
302
- });
303
- expect(result[0].details).toMatchObject({ ledgerOpType: "FEES" });
304
- expect(result[0].id).toBe(`${ACCOUNT_ID}-tx-${type}-FEES`);
305
- },
306
- );
305
+ })
306
+ expect(result[0].details).toMatchObject({ ledgerOpType: 'FEES' })
307
+ expect(result[0].id).toBe(`${ACCOUNT_ID}-tx-${type}-FEES`)
308
+ }
309
+ )
307
310
 
308
- it("emits a FEES Operation for create_claimable_balance when address is the sponsor", async () => {
311
+ it('emits a FEES Operation for create_claimable_balance when address is the sponsor', async () => {
309
312
  const op = makeOp(
310
313
  {
311
- type: "create_claimable_balance",
314
+ type: 'create_claimable_balance',
312
315
  source_account: ADDR,
313
- asset: "USDC:GISSUER",
314
- amount: "100",
316
+ asset: 'USDC:GISSUER',
317
+ amount: '100',
315
318
  sponsor: ADDR,
316
- transaction_hash: "tx-ccb",
319
+ transaction_hash: 'tx-ccb',
317
320
  },
318
- { fee_account: ADDR, fee_charged: "100" },
319
- );
320
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
321
- expect(out.type).toBe("FEES");
322
- expect(out.tx.fees).toBe(100n);
321
+ { fee_account: ADDR, fee_charged: '100' }
322
+ )
323
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
324
+ expect(out.type).toBe('FEES')
325
+ expect(out.tx.fees).toBe(100n)
323
326
  // The token amount locked in the claimable balance is intentionally NOT
324
327
  // exposed on the FEES op; only the XLM fee deduction is.
325
- expect(out.value).toBe(0n);
326
- expect(out.asset).toEqual({ type: "native" });
327
- });
328
+ expect(out.value).toBe(0n)
329
+ expect(out.asset).toEqual({ type: 'native' })
330
+ })
328
331
 
329
- it("does NOT emit a FEES Operation when address is not the fee payer (fee-bump or unrelated)", async () => {
332
+ it('does NOT emit a FEES Operation when address is not the fee payer (fee-bump or unrelated)', async () => {
330
333
  const op = makeOp(
331
334
  {
332
- type: "set_options",
335
+ type: 'set_options',
333
336
  source_account: ADDR,
334
- transaction_hash: "tx-fee-bumped",
337
+ transaction_hash: 'tx-fee-bumped',
335
338
  },
336
339
  // fee bumped by another account
337
- { fee_account: OTHER_ADDR, fee_charged: "150" },
338
- );
339
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
340
- expect(result).toHaveLength(0);
341
- });
340
+ { fee_account: OTHER_ADDR, fee_charged: '150' }
341
+ )
342
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
343
+ expect(result).toHaveLength(0)
344
+ })
342
345
 
343
- it("does NOT emit a FEES Operation when the tx already has a surfaced Operation (avoids double-counting)", async () => {
346
+ it('does NOT emit a FEES Operation when the tx already has a surfaced Operation (avoids double-counting)', async () => {
344
347
  // Multi-op transaction: one supported (change_trust, OPT_IN) + one
345
348
  // unsupported (set_options). Only the supported op is surfaced; the
346
349
  // unsupported one does not produce an extra FEES row since the tx fee is
347
350
  // already carried on the OPT_IN op's `tx.fees`.
348
351
  const supportedOp = makeOp(
349
352
  {
350
- type: "change_trust",
353
+ type: 'change_trust',
351
354
  trustor: ADDR,
352
- limit: "1000",
353
- asset_code: "BTC",
354
- asset_issuer: "GISSUER",
355
+ limit: '1000',
356
+ asset_code: 'BTC',
357
+ asset_issuer: 'GISSUER',
355
358
  source_account: ADDR,
356
- transaction_hash: "tx-mixed",
357
- id: "op-1",
358
- paging_token: "pt-1",
359
+ transaction_hash: 'tx-mixed',
360
+ id: 'op-1',
361
+ paging_token: 'pt-1',
359
362
  },
360
- { fee_account: ADDR, fee_charged: "100" },
361
- );
363
+ { fee_account: ADDR, fee_charged: '100' }
364
+ )
362
365
  const unsupportedOp = makeOp(
363
366
  {
364
- type: "set_options",
367
+ type: 'set_options',
365
368
  source_account: ADDR,
366
- transaction_hash: "tx-mixed",
367
- id: "op-2",
368
- paging_token: "pt-2",
369
+ transaction_hash: 'tx-mixed',
370
+ id: 'op-2',
371
+ paging_token: 'pt-2',
369
372
  },
370
- { fee_account: ADDR, fee_charged: "100" },
371
- );
373
+ { fee_account: ADDR, fee_charged: '100' }
374
+ )
372
375
  const result = await rawOperationsToOperations(
373
376
  [supportedOp, unsupportedOp],
374
377
  ADDR,
375
378
  ACCOUNT_ID,
376
- 0,
377
- );
378
- expect(result).toHaveLength(1);
379
- expect(result[0].type).toBe("OPT_IN");
380
- expect(result[0].tx.fees).toBe(100n);
381
- });
382
-
383
- it("emits a single FEES Operation per tx even when multiple unsupported ops share the same tx hash", async () => {
379
+ 0
380
+ )
381
+ expect(result).toHaveLength(1)
382
+ expect(result[0].type).toBe('OPT_IN')
383
+ expect(result[0].tx.fees).toBe(100n)
384
+ })
385
+
386
+ it('emits a single FEES Operation per tx even when multiple unsupported ops share the same tx hash', async () => {
384
387
  const opA = makeOp(
385
388
  {
386
- type: "set_options",
389
+ type: 'set_options',
387
390
  source_account: ADDR,
388
- transaction_hash: "tx-multi",
389
- id: "op-a",
390
- paging_token: "pt-a",
391
+ transaction_hash: 'tx-multi',
392
+ id: 'op-a',
393
+ paging_token: 'pt-a',
391
394
  },
392
- { fee_account: ADDR, fee_charged: "100" },
393
- );
395
+ { fee_account: ADDR, fee_charged: '100' }
396
+ )
394
397
  const opB = makeOp(
395
398
  {
396
- type: "manage_data",
399
+ type: 'manage_data',
397
400
  source_account: ADDR,
398
- transaction_hash: "tx-multi",
399
- id: "op-b",
400
- paging_token: "pt-b",
401
+ transaction_hash: 'tx-multi',
402
+ id: 'op-b',
403
+ paging_token: 'pt-b',
401
404
  },
402
- { fee_account: ADDR, fee_charged: "100" },
403
- );
404
- const result = await rawOperationsToOperations([opA, opB], ADDR, ACCOUNT_ID, 0);
405
- expect(result).toHaveLength(1);
406
- expect(result[0].type).toBe("FEES");
407
- expect(result[0].tx.hash).toBe("tx-multi");
405
+ { fee_account: ADDR, fee_charged: '100' }
406
+ )
407
+ const result = await rawOperationsToOperations([opA, opB], ADDR, ACCOUNT_ID, 0)
408
+ expect(result).toHaveLength(1)
409
+ expect(result[0].type).toBe('FEES')
410
+ expect(result[0].tx.hash).toBe('tx-multi')
408
411
  // The FEES op anchors at the first raw op's index/pagingToken so the
409
412
  // descending Horizon page order is preserved.
410
- expect(result[0].details).toMatchObject({ index: "op-a", pagingToken: "pt-a" });
411
- });
413
+ expect(result[0].details).toMatchObject({ index: 'op-a', pagingToken: 'pt-a' })
414
+ })
412
415
 
413
- it("honors minHeight for fee-only operations", async () => {
416
+ it('honors minHeight for fee-only operations', async () => {
414
417
  const op = makeOp(
415
- { type: "set_options", source_account: ADDR },
416
- { fee_account: ADDR, fee_charged: "100", ledger_attr: 99 },
417
- );
418
- expect(await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 100)).toHaveLength(0);
419
- });
418
+ { type: 'set_options', source_account: ADDR },
419
+ { fee_account: ADDR, fee_charged: '100', ledger_attr: 99 }
420
+ )
421
+ expect(await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 100)).toHaveLength(0)
422
+ })
420
423
 
421
- it("marks the FEES Operation as failed when the transaction failed", async () => {
424
+ it('marks the FEES Operation as failed when the transaction failed', async () => {
422
425
  const op = makeOp(
423
426
  {
424
- type: "set_options",
427
+ type: 'set_options',
425
428
  source_account: ADDR,
426
429
  transaction_successful: false,
427
- transaction_hash: "tx-failed",
430
+ transaction_hash: 'tx-failed',
428
431
  },
429
- { fee_account: ADDR, fee_charged: "100" },
430
- );
431
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
432
- expect(out.type).toBe("FEES");
433
- expect(out.tx.failed).toBe(true);
434
- expect(out.tx.fees).toBe(100n);
435
- });
436
- });
437
-
438
- describe("minHeight filtering", () => {
439
- it("should exclude operations from blocks strictly below minHeight", async () => {
432
+ { fee_account: ADDR, fee_charged: '100' }
433
+ )
434
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
435
+ expect(out.type).toBe('FEES')
436
+ expect(out.tx.failed).toBe(true)
437
+ expect(out.tx.fees).toBe(100n)
438
+ })
439
+ })
440
+
441
+ describe('minHeight filtering', () => {
442
+ it('should exclude operations from blocks strictly below minHeight', async () => {
440
443
  const op = makeOp(
441
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "5" },
442
- { ledger_attr: 99 },
443
- );
444
- expect(await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 100)).toHaveLength(0);
445
- });
444
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '5' },
445
+ { ledger_attr: 99 }
446
+ )
447
+ expect(await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 100)).toHaveLength(0)
448
+ })
446
449
 
447
- it("should include operations at minHeight", async () => {
450
+ it('should include operations at minHeight', async () => {
448
451
  const op = makeOp(
449
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "5" },
450
- { ledger_attr: 100 },
451
- );
452
- expect(await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 100)).toHaveLength(1);
453
- });
454
- });
455
-
456
- describe("operation type determination", () => {
457
- it("should mark create_account as OUT when funder is the address", async () => {
452
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '5' },
453
+ { ledger_attr: 100 }
454
+ )
455
+ expect(await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 100)).toHaveLength(1)
456
+ })
457
+ })
458
+
459
+ describe('operation type determination', () => {
460
+ it('should mark create_account as OUT when funder is the address', async () => {
458
461
  const op = makeOp({
459
- type: "create_account",
462
+ type: 'create_account',
460
463
  funder: ADDR,
461
464
  account: OTHER_ADDR,
462
- starting_balance: "10",
463
- });
464
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
465
- expect(out.type).toBe("OUT");
466
- });
465
+ starting_balance: '10',
466
+ })
467
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
468
+ expect(out.type).toBe('OUT')
469
+ })
467
470
 
468
- it("should mark create_account as IN when account is the address", async () => {
471
+ it('should mark create_account as IN when account is the address', async () => {
469
472
  const op = makeOp({
470
- type: "create_account",
473
+ type: 'create_account',
471
474
  funder: OTHER_ADDR,
472
475
  account: ADDR,
473
- starting_balance: "10",
476
+ starting_balance: '10',
474
477
  source_account: OTHER_ADDR,
475
- });
476
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
477
- expect(out.type).toBe("IN");
478
- });
479
-
480
- it("should mark payment as OUT when from is the address and recipient differs", async () => {
481
- const op = makeOp({ type: "payment", from: ADDR, to: OTHER_ADDR, amount: "5" });
482
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
483
- expect(out.type).toBe("OUT");
484
- });
485
-
486
- it("should mark payment as IN when the address is the recipient", async () => {
478
+ })
479
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
480
+ expect(out.type).toBe('IN')
481
+ })
482
+
483
+ it('should mark payment as OUT when from is the address and recipient differs', async () => {
484
+ const op = makeOp({ type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '5' })
485
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
486
+ expect(out.type).toBe('OUT')
487
+ })
488
+
489
+ it('should mark payment as IN when the address is the recipient', async () => {
487
490
  const op = makeOp({
488
- type: "payment",
491
+ type: 'payment',
489
492
  from: OTHER_ADDR,
490
493
  to: ADDR,
491
- amount: "5",
494
+ amount: '5',
492
495
  source_account: OTHER_ADDR,
493
- });
494
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
495
- expect(out.type).toBe("IN");
496
- });
497
-
498
- it("should mark self-payments (from=to=address) as IN", async () => {
499
- const op = makeOp({ type: "payment", from: ADDR, to: ADDR, amount: "5" });
500
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
501
- expect(out.type).toBe("IN");
502
- });
503
-
504
- it("should mark path_payment_strict_send as OUT when address is not the recipient", async () => {
496
+ })
497
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
498
+ expect(out.type).toBe('IN')
499
+ })
500
+
501
+ it('should mark self-payments (from=to=address) as IN', async () => {
502
+ const op = makeOp({ type: 'payment', from: ADDR, to: ADDR, amount: '5' })
503
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
504
+ expect(out.type).toBe('IN')
505
+ })
506
+
507
+ it('should mark path_payment_strict_send as OUT when address is not the recipient', async () => {
505
508
  const op = makeOp({
506
- type: "path_payment_strict_send",
509
+ type: 'path_payment_strict_send',
507
510
  from: ADDR,
508
511
  to: OTHER_ADDR,
509
- amount: "5",
510
- });
511
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
512
- expect(out.type).toBe("OUT");
513
- });
512
+ amount: '5',
513
+ })
514
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
515
+ expect(out.type).toBe('OUT')
516
+ })
514
517
 
515
- it("should mark path_payment_strict_send as IN when address is the recipient", async () => {
518
+ it('should mark path_payment_strict_send as IN when address is the recipient', async () => {
516
519
  const op = makeOp({
517
- type: "path_payment_strict_send",
520
+ type: 'path_payment_strict_send',
518
521
  from: OTHER_ADDR,
519
522
  to: ADDR,
520
- amount: "5",
523
+ amount: '5',
521
524
  source_account: OTHER_ADDR,
522
- });
523
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
524
- expect(out.type).toBe("IN");
525
- });
525
+ })
526
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
527
+ expect(out.type).toBe('IN')
528
+ })
526
529
 
527
- it("should mark path_payment_strict_receive as OUT when address is the source", async () => {
530
+ it('should mark path_payment_strict_receive as OUT when address is the source', async () => {
528
531
  const op = makeOp({
529
- type: "path_payment_strict_receive",
532
+ type: 'path_payment_strict_receive',
530
533
  from: ADDR,
531
534
  to: OTHER_ADDR,
532
- amount: "5",
533
- });
534
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
535
- expect(out.type).toBe("OUT");
536
- });
535
+ amount: '5',
536
+ })
537
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
538
+ expect(out.type).toBe('OUT')
539
+ })
537
540
 
538
- it("should mark path_payment_strict_receive as IN when address is the recipient", async () => {
541
+ it('should mark path_payment_strict_receive as IN when address is the recipient', async () => {
539
542
  const op = makeOp({
540
- type: "path_payment_strict_receive",
543
+ type: 'path_payment_strict_receive',
541
544
  from: OTHER_ADDR,
542
545
  to: ADDR,
543
- amount: "5",
546
+ amount: '5',
544
547
  source_account: OTHER_ADDR,
545
- });
546
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
547
- expect(out.type).toBe("IN");
548
- });
548
+ })
549
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
550
+ expect(out.type).toBe('IN')
551
+ })
549
552
 
550
- it("should mark change_trust as OPT_IN when limit is non-zero", async () => {
553
+ it('should mark change_trust as OPT_IN when limit is non-zero', async () => {
551
554
  const op = makeOp({
552
- type: "change_trust",
555
+ type: 'change_trust',
553
556
  trustor: ADDR,
554
- limit: "1000",
555
- asset_code: "USDC",
556
- asset_issuer: "GISSUER",
557
- });
558
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
559
- expect(out.type).toBe("OPT_IN");
560
- });
561
-
562
- it("should mark change_trust as OPT_OUT when limit is zero", async () => {
557
+ limit: '1000',
558
+ asset_code: 'USDC',
559
+ asset_issuer: 'GISSUER',
560
+ })
561
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
562
+ expect(out.type).toBe('OPT_IN')
563
+ })
564
+
565
+ it('should mark change_trust as OPT_OUT when limit is zero', async () => {
563
566
  const op = makeOp({
564
- type: "change_trust",
567
+ type: 'change_trust',
565
568
  trustor: ADDR,
566
- limit: "0",
567
- asset_code: "USDC",
568
- asset_issuer: "GISSUER",
569
- });
570
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
571
- expect(out.type).toBe("OPT_OUT");
572
- });
573
- });
574
-
575
- describe("memo handling", () => {
569
+ limit: '0',
570
+ asset_code: 'USDC',
571
+ asset_issuer: 'GISSUER',
572
+ })
573
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
574
+ expect(out.type).toBe('OPT_OUT')
575
+ })
576
+ })
577
+
578
+ describe('memo handling', () => {
576
579
  it("should set NO_MEMO when memo_type is 'none'", async () => {
577
580
  const op = makeOp(
578
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
579
- { memo_type: "none" },
580
- );
581
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
582
- expect(out.details).toMatchObject({ memo: { type: "NO_MEMO" } });
583
- });
581
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
582
+ { memo_type: 'none' }
583
+ )
584
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
585
+ expect(out.details).toMatchObject({ memo: { type: 'NO_MEMO' } })
586
+ })
584
587
 
585
588
  it("should set MEMO_ID with raw memo when memo_type is 'id'", async () => {
586
589
  const op = makeOp(
587
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
588
- { memo_type: "id", memo: "12345" },
589
- );
590
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
591
- expect(out.details).toMatchObject({ memo: { type: "MEMO_ID", value: "12345" } });
592
- });
590
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
591
+ { memo_type: 'id', memo: '12345' }
592
+ )
593
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
594
+ expect(out.details).toMatchObject({ memo: { type: 'MEMO_ID', value: '12345' } })
595
+ })
593
596
 
594
597
  it("should set MEMO_TEXT with raw memo when memo_type is 'text'", async () => {
595
598
  const op = makeOp(
596
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
597
- { memo_type: "text", memo: "hello" },
598
- );
599
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
600
- expect(out.details).toMatchObject({ memo: { type: "MEMO_TEXT", value: "hello" } });
601
- });
602
-
603
- it("should convert MEMO_RETURN from base64 to hex", async () => {
604
- const memoBase64 = Buffer.from("deadbeef", "hex").toString("base64");
599
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
600
+ { memo_type: 'text', memo: 'hello' }
601
+ )
602
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
603
+ expect(out.details).toMatchObject({ memo: { type: 'MEMO_TEXT', value: 'hello' } })
604
+ })
605
+
606
+ it('should convert MEMO_RETURN from base64 to hex', async () => {
607
+ const memoBase64 = Buffer.from('deadbeef', 'hex').toString('base64')
605
608
  const op = makeOp(
606
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
607
- { memo_type: "return", memo: memoBase64 },
608
- );
609
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
609
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
610
+ { memo_type: 'return', memo: memoBase64 }
611
+ )
612
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
610
613
  expect(out.details).toMatchObject({
611
- memo: { type: "MEMO_RETURN", value: "deadbeef" },
612
- });
613
- });
614
+ memo: { type: 'MEMO_RETURN', value: 'deadbeef' },
615
+ })
616
+ })
614
617
 
615
- it("should convert MEMO_HASH from base64 to hex", async () => {
616
- const memoBase64 = Buffer.from("cafebabe", "hex").toString("base64");
618
+ it('should convert MEMO_HASH from base64 to hex', async () => {
619
+ const memoBase64 = Buffer.from('cafebabe', 'hex').toString('base64')
617
620
  const op = makeOp(
618
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
619
- { memo_type: "hash", memo: memoBase64 },
620
- );
621
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
621
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
622
+ { memo_type: 'hash', memo: memoBase64 }
623
+ )
624
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
622
625
  expect(out.details).toMatchObject({
623
- memo: { type: "MEMO_HASH", value: "cafebabe" },
624
- });
625
- });
626
+ memo: { type: 'MEMO_HASH', value: 'cafebabe' },
627
+ })
628
+ })
626
629
 
627
- it("should leave memo undefined when memo_type is set but memo value is missing", async () => {
630
+ it('should leave memo undefined when memo_type is set but memo value is missing', async () => {
628
631
  const op = makeOp(
629
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
630
- { memo_type: "id", memo: undefined },
631
- );
632
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
633
- expect((out.details as { memo?: unknown }).memo).toBeUndefined();
634
- });
635
- });
636
-
637
- describe("asset and value handling", () => {
638
- it("should set native asset and value=amount*10^7 for native payments", async () => {
639
- const op = makeOp({ type: "payment", from: ADDR, to: OTHER_ADDR, amount: "10" });
640
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
641
- expect(out.asset).toEqual({ type: "native" });
642
- expect(out.value).toBe(100000000n);
632
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
633
+ { memo_type: 'id', memo: undefined }
634
+ )
635
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
636
+ expect((out.details as { memo?: unknown }).memo).toBeUndefined()
637
+ })
638
+ })
639
+
640
+ describe('asset and value handling', () => {
641
+ it('should set native asset and value=amount*10^7 for native payments', async () => {
642
+ const op = makeOp({ type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '10' })
643
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
644
+ expect(out.asset).toEqual({ type: 'native' })
645
+ expect(out.value).toBe(100000000n)
643
646
  expect(out.details).toMatchObject({
644
647
  assetCode: undefined,
645
648
  assetIssuer: undefined,
646
649
  assetAmount: undefined,
647
- });
648
- });
650
+ })
651
+ })
649
652
 
650
- it("should set token asset, NONE type and value=fee_charged when asset_code+asset_issuer are present", async () => {
653
+ it('should set token asset, NONE type and value=fee_charged when asset_code+asset_issuer are present', async () => {
651
654
  const op = makeOp(
652
655
  {
653
- type: "payment",
656
+ type: 'payment',
654
657
  from: ADDR,
655
658
  to: OTHER_ADDR,
656
- amount: "10",
657
- asset_code: "USDC",
658
- asset_issuer: "GISSUER",
659
+ amount: '10',
660
+ asset_code: 'USDC',
661
+ asset_issuer: 'GISSUER',
659
662
  },
660
- { fee_charged: "200" },
661
- );
662
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
663
+ { fee_charged: '200' }
664
+ )
665
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
663
666
  expect(out.asset).toEqual({
664
- type: "token",
665
- assetReference: "USDC",
666
- assetOwner: "GISSUER",
667
- });
668
- expect(out.value).toBe(200n);
669
- expect(out.type).toBe("NONE");
667
+ type: 'token',
668
+ assetReference: 'USDC',
669
+ assetOwner: 'GISSUER',
670
+ })
671
+ expect(out.value).toBe(200n)
672
+ expect(out.type).toBe('NONE')
670
673
  expect(out.details).toMatchObject({
671
- assetCode: "USDC",
672
- assetIssuer: "GISSUER",
673
- assetAmount: "100000000",
674
- });
675
- });
674
+ assetCode: 'USDC',
675
+ assetIssuer: 'GISSUER',
676
+ assetAmount: '100000000',
677
+ })
678
+ })
676
679
 
677
- it("should fall back to native asset when asset_code is set but asset_issuer is missing", async () => {
680
+ it('should fall back to native asset when asset_code is set but asset_issuer is missing', async () => {
678
681
  const op = makeOp({
679
- type: "payment",
682
+ type: 'payment',
680
683
  from: ADDR,
681
684
  to: OTHER_ADDR,
682
- amount: "10",
683
- asset_code: "USDC",
684
- });
685
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
686
- expect(out.asset).toEqual({ type: "native" });
687
- });
688
-
689
- it("should preserve OPT_IN/OPT_OUT type for token change_trust operations", async () => {
685
+ amount: '10',
686
+ asset_code: 'USDC',
687
+ })
688
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
689
+ expect(out.asset).toEqual({ type: 'native' })
690
+ })
691
+
692
+ it('should preserve OPT_IN/OPT_OUT type for token change_trust operations', async () => {
690
693
  const op = makeOp({
691
- type: "change_trust",
694
+ type: 'change_trust',
692
695
  trustor: ADDR,
693
- limit: "1000",
694
- asset_code: "USDC",
695
- asset_issuer: "GISSUER",
696
- });
697
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
698
- expect(out.type).toBe("OPT_IN");
699
- });
700
-
701
- it("should parse create_account starting_balance through the stellar unit (10^7)", async () => {
696
+ limit: '1000',
697
+ asset_code: 'USDC',
698
+ asset_issuer: 'GISSUER',
699
+ })
700
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
701
+ expect(out.type).toBe('OPT_IN')
702
+ })
703
+
704
+ it('should parse create_account starting_balance through the stellar unit (10^7)', async () => {
702
705
  const op = makeOp({
703
- type: "create_account",
706
+ type: 'create_account',
704
707
  funder: ADDR,
705
708
  account: OTHER_ADDR,
706
- starting_balance: "2.5",
707
- });
708
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
709
- expect(out.value).toBe(25000000n);
710
- });
711
- });
712
-
713
- describe("path_payment_strict_send native source side", () => {
714
- it("emits a native OUT row using source_amount when address is the source and source asset is native", async () => {
709
+ starting_balance: '2.5',
710
+ })
711
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
712
+ expect(out.value).toBe(25000000n)
713
+ })
714
+ })
715
+
716
+ describe('path_payment_strict_send native source side', () => {
717
+ it('emits a native OUT row using source_amount when address is the source and source asset is native', async () => {
715
718
  const op = makeOp(
716
719
  {
717
- type: "path_payment_strict_send",
720
+ type: 'path_payment_strict_send',
718
721
  from: ADDR,
719
722
  to: OTHER_ADDR,
720
723
  source_account: ADDR,
721
- source_asset_type: "native",
722
- source_amount: "0.7920000",
723
- asset_type: "credit_alphanum12",
724
- asset_code: "SPDX",
725
- asset_issuer: "GISSUER",
726
- amount: "1234.5678901",
724
+ source_asset_type: 'native',
725
+ source_amount: '0.7920000',
726
+ asset_type: 'credit_alphanum12',
727
+ asset_code: 'SPDX',
728
+ asset_issuer: 'GISSUER',
729
+ amount: '1234.5678901',
727
730
  },
728
- { fee_charged: "100" },
729
- );
730
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
731
+ { fee_charged: '100' }
732
+ )
733
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
731
734
  // No FEES row: native OUT already carries the fee on `tx.fees`.
732
- expect(result.map(o => `${o.type}:${o.asset.type}`)).toEqual(["OUT:native"]);
735
+ expect(result.map((o) => `${o.type}:${o.asset.type}`)).toEqual(['OUT:native'])
733
736
  expect(result[0]).toMatchObject({
734
- type: "OUT",
735
- asset: { type: "native" },
737
+ type: 'OUT',
738
+ asset: { type: 'native' },
736
739
  value: 7920000n,
737
740
  senders: [ADDR],
738
741
  recipients: [OTHER_ADDR],
739
742
  tx: { fees: 100n },
740
- });
741
- });
743
+ })
744
+ })
742
745
 
743
- it("emits a native IN row using `amount` when address is the destination and dest asset is native", async () => {
746
+ it('emits a native IN row using `amount` when address is the destination and dest asset is native', async () => {
744
747
  const op = makeOp(
745
748
  {
746
- type: "path_payment_strict_send",
749
+ type: 'path_payment_strict_send',
747
750
  from: OTHER_ADDR,
748
751
  to: ADDR,
749
752
  source_account: OTHER_ADDR,
750
- source_asset_type: "credit_alphanum4",
751
- source_asset_code: "USDC",
752
- source_asset_issuer: "GISSUER",
753
- source_amount: "10.0000000",
754
- asset_type: "native",
755
- amount: "9.9000000",
753
+ source_asset_type: 'credit_alphanum4',
754
+ source_asset_code: 'USDC',
755
+ source_asset_issuer: 'GISSUER',
756
+ source_amount: '10.0000000',
757
+ asset_type: 'native',
758
+ amount: '9.9000000',
756
759
  },
757
- { fee_charged: "100" },
758
- );
759
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
760
+ { fee_charged: '100' }
761
+ )
762
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
760
763
  expect(result).toEqual([
761
764
  expect.objectContaining({
762
- type: "IN",
763
- asset: { type: "native" },
765
+ type: 'IN',
766
+ asset: { type: 'native' },
764
767
  value: 99000000n,
765
768
  senders: [OTHER_ADDR],
766
769
  recipients: [ADDR],
767
770
  }),
768
- ]);
769
- });
771
+ ])
772
+ })
770
773
 
771
- it("emits a token NONE row when the source asset is a token and address is the source", async () => {
774
+ it('emits a token NONE row when the source asset is a token and address is the source', async () => {
772
775
  const op = makeOp(
773
776
  {
774
- type: "path_payment_strict_send",
777
+ type: 'path_payment_strict_send',
775
778
  from: ADDR,
776
779
  to: OTHER_ADDR,
777
780
  source_account: ADDR,
778
- source_asset_type: "credit_alphanum4",
779
- source_asset_code: "USDC",
780
- source_asset_issuer: "GISSUER",
781
- source_amount: "5.0000000",
782
- asset_type: "credit_alphanum4",
783
- asset_code: "EURC",
784
- asset_issuer: "GISSUER2",
785
- amount: "4.5000000",
781
+ source_asset_type: 'credit_alphanum4',
782
+ source_asset_code: 'USDC',
783
+ source_asset_issuer: 'GISSUER',
784
+ source_amount: '5.0000000',
785
+ asset_type: 'credit_alphanum4',
786
+ asset_code: 'EURC',
787
+ asset_issuer: 'GISSUER2',
788
+ amount: '4.5000000',
786
789
  },
787
- { fee_charged: "300" },
788
- );
789
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
790
- expect(out.type).toBe("NONE");
790
+ { fee_charged: '300' }
791
+ )
792
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
793
+ expect(out.type).toBe('NONE')
791
794
  expect(out.asset).toEqual({
792
- type: "token",
793
- assetReference: "USDC",
794
- assetOwner: "GISSUER",
795
- });
795
+ type: 'token',
796
+ assetReference: 'USDC',
797
+ assetOwner: 'GISSUER',
798
+ })
796
799
  // legacy convention: NONE token rows carry `value = fee_charged` and the
797
800
  // real token amount on `details.assetAmount`.
798
- expect(out.value).toBe(300n);
801
+ expect(out.value).toBe(300n)
799
802
  expect(out.details).toMatchObject({
800
- assetCode: "USDC",
801
- assetIssuer: "GISSUER",
802
- assetAmount: "50000000",
803
- ledgerOpType: "NONE",
804
- });
805
- });
806
-
807
- it("emits both a native OUT (source) and a token NONE (dest) row for self-swaps", async () => {
803
+ assetCode: 'USDC',
804
+ assetIssuer: 'GISSUER',
805
+ assetAmount: '50000000',
806
+ ledgerOpType: 'NONE',
807
+ })
808
+ })
809
+
810
+ it('emits both a native OUT (source) and a token NONE (dest) row for self-swaps', async () => {
808
811
  const op = makeOp(
809
812
  {
810
- type: "path_payment_strict_send",
813
+ type: 'path_payment_strict_send',
811
814
  from: ADDR,
812
815
  to: ADDR,
813
816
  source_account: ADDR,
814
- source_asset_type: "native",
815
- source_amount: "0.7920000",
816
- asset_type: "credit_alphanum12",
817
- asset_code: "SPDX",
818
- asset_issuer: "GISSUER",
819
- amount: "1234.5678901",
820
- id: "op-self-swap",
817
+ source_asset_type: 'native',
818
+ source_amount: '0.7920000',
819
+ asset_type: 'credit_alphanum12',
820
+ asset_code: 'SPDX',
821
+ asset_issuer: 'GISSUER',
822
+ amount: '1234.5678901',
823
+ id: 'op-self-swap',
821
824
  },
822
- { fee_charged: "4580" },
823
- );
824
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
825
- expect(result.map(o => `${o.type}:${o.asset.type}`)).toEqual(["OUT:native", "NONE:token"]);
826
- expect(result.map(o => (o.details as { index: string }).index)).toEqual([
827
- "op-self-swap-OUT-NATIVE",
828
- "op-self-swap-IN-TOKEN-SPDX",
829
- ]);
830
- expect(result[0]).toMatchObject({ value: 7920000n, senders: [ADDR], recipients: [ADDR] });
825
+ { fee_charged: '4580' }
826
+ )
827
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
828
+ expect(result.map((o) => `${o.type}:${o.asset.type}`)).toEqual(['OUT:native', 'NONE:token'])
829
+ expect(result.map((o) => (o.details as { index: string }).index)).toEqual([
830
+ 'op-self-swap-OUT-NATIVE',
831
+ 'op-self-swap-IN-TOKEN-SPDX',
832
+ ])
833
+ expect(result[0]).toMatchObject({ value: 7920000n, senders: [ADDR], recipients: [ADDR] })
831
834
  expect(result[1]).toMatchObject({
832
835
  value: 4580n,
833
- details: { assetAmount: "12345678901" },
834
- });
835
- });
836
- });
836
+ details: { assetAmount: '12345678901' },
837
+ })
838
+ })
839
+ })
837
840
 
838
- describe("liquidity_pool_deposit", () => {
839
- it("emits a native OUT row using reserves_deposited when one of the reserves is native", async () => {
841
+ describe('liquidity_pool_deposit', () => {
842
+ it('emits a native OUT row using reserves_deposited when one of the reserves is native', async () => {
840
843
  const op = makeOp(
841
844
  {
842
- type: "liquidity_pool_deposit",
845
+ type: 'liquidity_pool_deposit',
843
846
  source_account: ADDR,
844
- liquidity_pool_id: "pool-id",
847
+ liquidity_pool_id: 'pool-id',
845
848
  reserves_deposited: [
846
- { asset: "native", amount: "10.0000000" },
847
- { asset: "SPDX:GISSUER", amount: "57173830.2052035" },
849
+ { asset: 'native', amount: '10.0000000' },
850
+ { asset: 'SPDX:GISSUER', amount: '57173830.2052035' },
848
851
  ],
849
- shares_received: "23909.3448196",
850
- id: "op-lp-deposit",
852
+ shares_received: '23909.3448196',
853
+ id: 'op-lp-deposit',
851
854
  },
852
- { fee_charged: "100" },
853
- );
854
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
855
- expect(result.map(o => `${o.type}:${o.asset.type}`)).toEqual(["OUT:native", "NONE:token"]);
855
+ { fee_charged: '100' }
856
+ )
857
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
858
+ expect(result.map((o) => `${o.type}:${o.asset.type}`)).toEqual(['OUT:native', 'NONE:token'])
856
859
  expect(result[0]).toMatchObject({
857
- type: "OUT",
858
- asset: { type: "native" },
860
+ type: 'OUT',
861
+ asset: { type: 'native' },
859
862
  value: 100000000n,
860
863
  tx: { fees: 100n },
861
- });
864
+ })
862
865
  // Token leg: legacy NONE convention with the deposited token amount on
863
866
  // `details.assetAmount`.
864
867
  expect(result[1]).toMatchObject({
865
- type: "NONE",
866
- asset: { type: "token", assetReference: "SPDX", assetOwner: "GISSUER" },
868
+ type: 'NONE',
869
+ asset: { type: 'token', assetReference: 'SPDX', assetOwner: 'GISSUER' },
867
870
  value: 100n,
868
- details: { assetAmount: "571738302052035" },
869
- });
870
- expect(result.map(o => (o.details as { index: string }).index)).toEqual([
871
- "op-lp-deposit-NATIVE",
872
- "op-lp-deposit-TOKEN-SPDX",
873
- ]);
874
- });
875
-
876
- it("does NOT emit a duplicate FEES row when liquidity_pool_deposit is surfaced", async () => {
871
+ details: { assetAmount: '571738302052035' },
872
+ })
873
+ expect(result.map((o) => (o.details as { index: string }).index)).toEqual([
874
+ 'op-lp-deposit-NATIVE',
875
+ 'op-lp-deposit-TOKEN-SPDX',
876
+ ])
877
+ })
878
+
879
+ it('does NOT emit a duplicate FEES row when liquidity_pool_deposit is surfaced', async () => {
877
880
  const op = makeOp(
878
881
  {
879
- type: "liquidity_pool_deposit",
882
+ type: 'liquidity_pool_deposit',
880
883
  source_account: ADDR,
881
- liquidity_pool_id: "pool-id",
884
+ liquidity_pool_id: 'pool-id',
882
885
  reserves_deposited: [
883
- { asset: "native", amount: "10.0000000" },
884
- { asset: "SPDX:GISSUER", amount: "57173830.2052035" },
886
+ { asset: 'native', amount: '10.0000000' },
887
+ { asset: 'SPDX:GISSUER', amount: '57173830.2052035' },
885
888
  ],
886
889
  },
887
- { fee_account: ADDR, fee_charged: "100" },
888
- );
889
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
890
- expect(result.map(o => o.type)).toEqual(["OUT", "NONE"]);
891
- expect(result.find(o => o.type === "FEES")).toBeUndefined();
892
- });
893
- });
894
-
895
- describe("liquidity_pool_withdraw", () => {
896
- it("emits a native IN row using reserves_received when one of the reserves is native", async () => {
890
+ { fee_account: ADDR, fee_charged: '100' }
891
+ )
892
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
893
+ expect(result.map((o) => o.type)).toEqual(['OUT', 'NONE'])
894
+ expect(result.find((o) => o.type === 'FEES')).toBeUndefined()
895
+ })
896
+ })
897
+
898
+ describe('liquidity_pool_withdraw', () => {
899
+ it('emits a native IN row using reserves_received when one of the reserves is native', async () => {
897
900
  const op = makeOp(
898
901
  {
899
- type: "liquidity_pool_withdraw",
902
+ type: 'liquidity_pool_withdraw',
900
903
  source_account: ADDR,
901
- liquidity_pool_id: "pool-id",
904
+ liquidity_pool_id: 'pool-id',
902
905
  reserves_received: [
903
- { asset: "native", amount: "26.6614878" },
904
- { asset: "SPDX:GISSUER", amount: "152433937.6498273" },
906
+ { asset: 'native', amount: '26.6614878' },
907
+ { asset: 'SPDX:GISSUER', amount: '152433937.6498273' },
905
908
  ],
906
- shares: "63745.8705215",
907
- id: "op-lp-withdraw",
909
+ shares: '63745.8705215',
910
+ id: 'op-lp-withdraw',
908
911
  },
909
- { fee_charged: "100" },
910
- );
911
- const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
912
- expect(result.map(o => `${o.type}:${o.asset.type}`)).toEqual(["IN:native", "NONE:token"]);
912
+ { fee_charged: '100' }
913
+ )
914
+ const result = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
915
+ expect(result.map((o) => `${o.type}:${o.asset.type}`)).toEqual(['IN:native', 'NONE:token'])
913
916
  expect(result[0]).toMatchObject({
914
- type: "IN",
915
- asset: { type: "native" },
917
+ type: 'IN',
918
+ asset: { type: 'native' },
916
919
  value: 266614878n,
917
920
  senders: [ADDR],
918
- });
919
- });
920
- });
921
+ })
922
+ })
923
+ })
921
924
 
922
- describe("failed transactions", () => {
923
- it("should set value=0 for IN ops when transaction failed", async () => {
925
+ describe('failed transactions', () => {
926
+ it('should set value=0 for IN ops when transaction failed', async () => {
924
927
  const op = makeOp(
925
928
  {
926
- type: "payment",
929
+ type: 'payment',
927
930
  from: OTHER_ADDR,
928
931
  to: ADDR,
929
- amount: "10",
932
+ amount: '10',
930
933
  source_account: OTHER_ADDR,
931
934
  transaction_successful: false,
932
935
  },
933
- { fee_charged: "150" },
934
- );
935
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
936
- expect(out.value).toBe(0n);
937
- expect(out.tx.failed).toBe(true);
938
- });
939
-
940
- it("should set value=fee_charged for OUT ops when transaction failed", async () => {
936
+ { fee_charged: '150' }
937
+ )
938
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
939
+ expect(out.value).toBe(0n)
940
+ expect(out.tx.failed).toBe(true)
941
+ })
942
+
943
+ it('should set value=fee_charged for OUT ops when transaction failed', async () => {
941
944
  const op = makeOp(
942
945
  {
943
- type: "payment",
946
+ type: 'payment',
944
947
  from: ADDR,
945
948
  to: OTHER_ADDR,
946
- amount: "10",
949
+ amount: '10',
947
950
  transaction_successful: false,
948
951
  },
949
- { fee_charged: "150" },
950
- );
951
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
952
- expect(out.value).toBe(150n);
953
- expect(out.tx.failed).toBe(true);
954
- });
955
- });
956
-
957
- describe("recipients", () => {
958
- it("should use to_muxed for payment when present", async () => {
952
+ { fee_charged: '150' }
953
+ )
954
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
955
+ expect(out.value).toBe(150n)
956
+ expect(out.tx.failed).toBe(true)
957
+ })
958
+ })
959
+
960
+ describe('recipients', () => {
961
+ it('should use to_muxed for payment when present', async () => {
959
962
  const op = makeOp({
960
- type: "payment",
963
+ type: 'payment',
961
964
  from: ADDR,
962
965
  to: OTHER_ADDR,
963
- to_muxed: "MMUXED",
964
- amount: "10",
965
- });
966
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
967
- expect(out.recipients).toEqual(["MMUXED"]);
968
- });
969
-
970
- it("should fall back to `to` for payment when no to_muxed is set", async () => {
971
- const op = makeOp({ type: "payment", from: ADDR, to: OTHER_ADDR, amount: "10" });
972
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
973
- expect(out.recipients).toEqual([OTHER_ADDR]);
974
- });
975
-
976
- it("should use `account` for create_account recipients", async () => {
966
+ to_muxed: 'MMUXED',
967
+ amount: '10',
968
+ })
969
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
970
+ expect(out.recipients).toEqual(['MMUXED'])
971
+ })
972
+
973
+ it('should fall back to `to` for payment when no to_muxed is set', async () => {
974
+ const op = makeOp({ type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '10' })
975
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
976
+ expect(out.recipients).toEqual([OTHER_ADDR])
977
+ })
978
+
979
+ it('should use `account` for create_account recipients', async () => {
977
980
  const op = makeOp({
978
- type: "create_account",
981
+ type: 'create_account',
979
982
  funder: ADDR,
980
983
  account: OTHER_ADDR,
981
- starting_balance: "10",
982
- });
983
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
984
- expect(out.recipients).toEqual([OTHER_ADDR]);
985
- });
984
+ starting_balance: '10',
985
+ })
986
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
987
+ expect(out.recipients).toEqual([OTHER_ADDR])
988
+ })
986
989
 
987
- it("should use `to` for path_payment_strict_send recipients", async () => {
990
+ it('should use `to` for path_payment_strict_send recipients', async () => {
988
991
  const op = makeOp({
989
- type: "path_payment_strict_send",
992
+ type: 'path_payment_strict_send',
990
993
  from: ADDR,
991
994
  to: OTHER_ADDR,
992
- amount: "10",
993
- });
994
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
995
- expect(out.recipients).toEqual([OTHER_ADDR]);
996
- });
995
+ amount: '10',
996
+ })
997
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
998
+ expect(out.recipients).toEqual([OTHER_ADDR])
999
+ })
997
1000
 
998
- it("should return empty recipients for change_trust", async () => {
1001
+ it('should return empty recipients for change_trust', async () => {
999
1002
  const op = makeOp({
1000
- type: "change_trust",
1003
+ type: 'change_trust',
1001
1004
  trustor: ADDR,
1002
- limit: "1000",
1003
- asset_code: "USDC",
1004
- asset_issuer: "GISSUER",
1005
- });
1006
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1007
- expect(out.recipients).toEqual([]);
1008
- });
1009
-
1010
- it("should return empty recipients for path_payment_strict_receive", async () => {
1005
+ limit: '1000',
1006
+ asset_code: 'USDC',
1007
+ asset_issuer: 'GISSUER',
1008
+ })
1009
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1010
+ expect(out.recipients).toEqual([])
1011
+ })
1012
+
1013
+ it('should return empty recipients for path_payment_strict_receive', async () => {
1011
1014
  const op = makeOp({
1012
- type: "path_payment_strict_receive",
1015
+ type: 'path_payment_strict_receive',
1013
1016
  from: OTHER_ADDR,
1014
1017
  to: ADDR,
1015
- amount: "10",
1018
+ amount: '10',
1016
1019
  source_account: OTHER_ADDR,
1017
- });
1018
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1019
- expect(out.recipients).toEqual([ADDR]);
1020
- });
1021
- });
1022
-
1023
- describe("sequence handling", () => {
1024
- it("should expose source_account_sequence as a string when it is a number", async () => {
1020
+ })
1021
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1022
+ expect(out.recipients).toEqual([ADDR])
1023
+ })
1024
+ })
1025
+
1026
+ describe('sequence handling', () => {
1027
+ it('should expose source_account_sequence as a string when it is a number', async () => {
1025
1028
  const op = makeOp(
1026
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
1027
- { source_account_sequence: "123456789" },
1028
- );
1029
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1030
- expect(out.details).toMatchObject({ sequence: "123456789" });
1031
- });
1032
-
1033
- it("should expose sequence as undefined when source_account_sequence is not numeric", async () => {
1029
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
1030
+ { source_account_sequence: '123456789' }
1031
+ )
1032
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1033
+ expect(out.details).toMatchObject({ sequence: '123456789' })
1034
+ })
1035
+
1036
+ it('should expose sequence as undefined when source_account_sequence is not numeric', async () => {
1034
1037
  const op = makeOp(
1035
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
1036
- { source_account_sequence: "not-a-number" },
1037
- );
1038
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1039
- expect((out.details as { sequence?: string }).sequence).toBeUndefined();
1040
- });
1041
- });
1042
-
1043
- describe("transaction metadata", () => {
1044
- it("should expose fee_account as feesPayer when present (fee bump transactions)", async () => {
1038
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
1039
+ { source_account_sequence: 'not-a-number' }
1040
+ )
1041
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1042
+ expect((out.details as { sequence?: string }).sequence).toBeUndefined()
1043
+ })
1044
+ })
1045
+
1046
+ describe('transaction metadata', () => {
1047
+ it('should expose fee_account as feesPayer when present (fee bump transactions)', async () => {
1045
1048
  const op = makeOp(
1046
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
1047
- { fee_account: "GSPONSOR", fee_charged: "500" },
1048
- );
1049
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1050
- expect(out.tx.feesPayer).toBe("GSPONSOR");
1051
- expect(out.tx.fees).toBe(500n);
1052
- });
1053
-
1054
- it("should omit feesPayer when fee_account is not set", async () => {
1055
- const op = makeOp({ type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" });
1056
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1057
- expect("feesPayer" in out.tx).toBe(false);
1058
- });
1059
-
1060
- it("should build the operation id as `${accountId}-${transactionHash}-${type}`", async () => {
1049
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
1050
+ { fee_account: 'GSPONSOR', fee_charged: '500' }
1051
+ )
1052
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1053
+ expect(out.tx.feesPayer).toBe('GSPONSOR')
1054
+ expect(out.tx.fees).toBe(500n)
1055
+ })
1056
+
1057
+ it('should omit feesPayer when fee_account is not set', async () => {
1058
+ const op = makeOp({ type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' })
1059
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1060
+ expect('feesPayer' in out.tx).toBe(false)
1061
+ })
1062
+
1063
+ it('should build the operation id as `${accountId}-${transactionHash}-${type}`', async () => {
1061
1064
  const op = makeOp({
1062
- type: "payment",
1065
+ type: 'payment',
1063
1066
  from: ADDR,
1064
1067
  to: OTHER_ADDR,
1065
- amount: "1",
1066
- transaction_hash: "my-tx-hash",
1067
- });
1068
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1069
- expect(out.id).toBe(`${ACCOUNT_ID}-my-tx-hash-OUT`);
1070
- });
1071
-
1072
- it("should populate block metadata from the ledger record", async () => {
1068
+ amount: '1',
1069
+ transaction_hash: 'my-tx-hash',
1070
+ })
1071
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1072
+ expect(out.id).toBe(`${ACCOUNT_ID}-my-tx-hash-OUT`)
1073
+ })
1074
+
1075
+ it('should populate block metadata from the ledger record', async () => {
1073
1076
  const op = makeOp(
1074
- { type: "payment", from: ADDR, to: OTHER_ADDR, amount: "1" },
1077
+ { type: 'payment', from: ADDR, to: OTHER_ADDR, amount: '1' },
1075
1078
  {
1076
1079
  ledger_attr: 4242,
1077
- ledger_hash: "ledger-hash",
1078
- ledger_closed_at: "2025-07-04T08:30:00Z",
1079
- },
1080
- );
1081
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1080
+ ledger_hash: 'ledger-hash',
1081
+ ledger_closed_at: '2025-07-04T08:30:00Z',
1082
+ }
1083
+ )
1084
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1082
1085
  expect(out.tx.block).toEqual({
1083
- hash: "ledger-hash",
1086
+ hash: 'ledger-hash',
1084
1087
  height: 4242,
1085
- time: new Date("2025-07-04T08:30:00Z"),
1086
- });
1087
- });
1088
+ time: new Date('2025-07-04T08:30:00Z'),
1089
+ })
1090
+ })
1088
1091
 
1089
1092
  it("should set tx.date from the operation's created_at", async () => {
1090
1093
  const op = makeOp({
1091
- type: "payment",
1094
+ type: 'payment',
1092
1095
  from: ADDR,
1093
1096
  to: OTHER_ADDR,
1094
- amount: "1",
1095
- created_at: "2024-02-29T01:02:03Z",
1096
- });
1097
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1098
- expect(out.tx.date).toEqual(new Date("2024-02-29T01:02:03Z"));
1099
- });
1100
-
1101
- it("should include senders from the operation source_account", async () => {
1097
+ amount: '1',
1098
+ created_at: '2024-02-29T01:02:03Z',
1099
+ })
1100
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1101
+ expect(out.tx.date).toEqual(new Date('2024-02-29T01:02:03Z'))
1102
+ })
1103
+
1104
+ it('should include senders from the operation source_account', async () => {
1102
1105
  const op = makeOp({
1103
- type: "payment",
1106
+ type: 'payment',
1104
1107
  from: ADDR,
1105
1108
  to: OTHER_ADDR,
1106
- amount: "1",
1107
- source_account: "GSOURCE",
1108
- });
1109
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1110
- expect(out.senders).toEqual(["GSOURCE"]);
1111
- });
1112
-
1113
- it("should expose pagingToken and index in details", async () => {
1109
+ amount: '1',
1110
+ source_account: 'GSOURCE',
1111
+ })
1112
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1113
+ expect(out.senders).toEqual(['GSOURCE'])
1114
+ })
1115
+
1116
+ it('should expose pagingToken and index in details', async () => {
1114
1117
  const op = makeOp({
1115
- type: "payment",
1118
+ type: 'payment',
1116
1119
  from: ADDR,
1117
1120
  to: OTHER_ADDR,
1118
- amount: "1",
1119
- id: "op-42",
1120
- paging_token: "pt-42",
1121
- });
1122
- const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0);
1123
- expect(out.details).toMatchObject({ pagingToken: "pt-42", index: "op-42" });
1124
- });
1125
- });
1126
-
1127
- describe("batch processing", () => {
1128
- it("should preserve relative order of the operations that pass filters", async () => {
1121
+ amount: '1',
1122
+ id: 'op-42',
1123
+ paging_token: 'pt-42',
1124
+ })
1125
+ const [out] = await rawOperationsToOperations([op], ADDR, ACCOUNT_ID, 0)
1126
+ expect(out.details).toMatchObject({ pagingToken: 'pt-42', index: 'op-42' })
1127
+ })
1128
+ })
1129
+
1130
+ describe('batch processing', () => {
1131
+ it('should preserve relative order of the operations that pass filters', async () => {
1129
1132
  const opA = makeOp({
1130
- type: "payment",
1133
+ type: 'payment',
1131
1134
  from: ADDR,
1132
1135
  to: OTHER_ADDR,
1133
- amount: "1",
1134
- transaction_hash: "tx-a",
1135
- });
1136
+ amount: '1',
1137
+ transaction_hash: 'tx-a',
1138
+ })
1136
1139
  // Unrelated to the listed address: not in any filter field and not the
1137
1140
  // fee payer, so it must be dropped entirely (no fee row).
1138
1141
  const opIgnored = makeOp(
1139
1142
  {
1140
- type: "manage_offer",
1143
+ type: 'manage_offer',
1141
1144
  source_account: OTHER_ADDR,
1142
- transaction_hash: "tx-ignored",
1145
+ transaction_hash: 'tx-ignored',
1143
1146
  },
1144
- { fee_account: OTHER_ADDR },
1145
- );
1147
+ { fee_account: OTHER_ADDR }
1148
+ )
1146
1149
  const opB = makeOp({
1147
- type: "payment",
1150
+ type: 'payment',
1148
1151
  from: OTHER_ADDR,
1149
1152
  to: ADDR,
1150
- amount: "2",
1153
+ amount: '2',
1151
1154
  source_account: OTHER_ADDR,
1152
- transaction_hash: "tx-b",
1153
- });
1155
+ transaction_hash: 'tx-b',
1156
+ })
1154
1157
 
1155
- const result = await rawOperationsToOperations([opA, opIgnored, opB], ADDR, ACCOUNT_ID, 0);
1156
- expect(result.map(o => o.tx.hash)).toEqual(["tx-a", "tx-b"]);
1157
- });
1158
+ const result = await rawOperationsToOperations([opA, opIgnored, opB], ADDR, ACCOUNT_ID, 0)
1159
+ expect(result.map((o) => o.tx.hash)).toEqual(['tx-a', 'tx-b'])
1160
+ })
1158
1161
 
1159
- it("should interleave fee-only ops at the position of their first raw op in the page", async () => {
1162
+ it('should interleave fee-only ops at the position of their first raw op in the page', async () => {
1160
1163
  const opA = makeOp({
1161
- type: "payment",
1164
+ type: 'payment',
1162
1165
  from: ADDR,
1163
1166
  to: OTHER_ADDR,
1164
- amount: "1",
1165
- transaction_hash: "tx-a",
1166
- });
1167
+ amount: '1',
1168
+ transaction_hash: 'tx-a',
1169
+ })
1167
1170
  const opFeeOnly = makeOp(
1168
1171
  {
1169
- type: "set_options",
1172
+ type: 'set_options',
1170
1173
  source_account: ADDR,
1171
- transaction_hash: "tx-fees",
1174
+ transaction_hash: 'tx-fees',
1172
1175
  },
1173
- { fee_account: ADDR, fee_charged: "100" },
1174
- );
1176
+ { fee_account: ADDR, fee_charged: '100' }
1177
+ )
1175
1178
  const opB = makeOp({
1176
- type: "payment",
1179
+ type: 'payment',
1177
1180
  from: OTHER_ADDR,
1178
1181
  to: ADDR,
1179
- amount: "2",
1182
+ amount: '2',
1180
1183
  source_account: OTHER_ADDR,
1181
- transaction_hash: "tx-b",
1182
- });
1183
-
1184
- const result = await rawOperationsToOperations([opA, opFeeOnly, opB], ADDR, ACCOUNT_ID, 0);
1185
- expect(result.map(o => `${o.tx.hash}:${o.type}`)).toEqual([
1186
- "tx-a:OUT",
1187
- "tx-fees:FEES",
1188
- "tx-b:IN",
1189
- ]);
1190
- });
1191
-
1192
- it("should return an empty array when given no operations", async () => {
1193
- expect(await rawOperationsToOperations([], ADDR, ACCOUNT_ID, 0)).toEqual([]);
1194
- });
1195
- });
1196
- });
1184
+ transaction_hash: 'tx-b',
1185
+ })
1186
+
1187
+ const result = await rawOperationsToOperations([opA, opFeeOnly, opB], ADDR, ACCOUNT_ID, 0)
1188
+ expect(result.map((o) => `${o.tx.hash}:${o.type}`)).toEqual([
1189
+ 'tx-a:OUT',
1190
+ 'tx-fees:FEES',
1191
+ 'tx-b:IN',
1192
+ ])
1193
+ })
1194
+
1195
+ it('should return an empty array when given no operations', async () => {
1196
+ expect(await rawOperationsToOperations([], ADDR, ACCOUNT_ID, 0)).toEqual([])
1197
+ })
1198
+ })
1199
+ })