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