@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
|
@@ -1,42 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { estimateFees } from "./estimateFees";
|
|
4
|
-
import { lastBlock } from "./lastBlock";
|
|
1
|
+
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
5
3
|
|
|
6
|
-
|
|
4
|
+
import { fetchBaseFee, broadcastTransaction, getLastBlock } from '../network'
|
|
5
|
+
import { broadcast } from './broadcast'
|
|
6
|
+
import { estimateFees } from './estimateFees'
|
|
7
|
+
import { lastBlock } from './lastBlock'
|
|
8
|
+
|
|
9
|
+
jest.mock('../network', () => ({
|
|
7
10
|
fetchBaseFee: jest.fn(),
|
|
8
11
|
broadcastTransaction: jest.fn(),
|
|
9
12
|
getLastBlock: jest.fn(),
|
|
10
|
-
}))
|
|
13
|
+
}))
|
|
11
14
|
|
|
12
|
-
describe(
|
|
15
|
+
describe('network wrapper helpers', () => {
|
|
13
16
|
beforeEach(() => {
|
|
14
|
-
jest.clearAllMocks()
|
|
15
|
-
})
|
|
17
|
+
jest.clearAllMocks()
|
|
18
|
+
})
|
|
16
19
|
|
|
17
|
-
it(
|
|
18
|
-
(broadcastTransaction as jest.Mock).mockResolvedValue(
|
|
20
|
+
it('broadcast delegates to broadcastTransaction', async () => {
|
|
21
|
+
;(broadcastTransaction as jest.Mock).mockResolvedValue('tx-hash')
|
|
19
22
|
|
|
20
|
-
await expect(broadcast(
|
|
21
|
-
expect(broadcastTransaction).toHaveBeenCalledWith(
|
|
22
|
-
})
|
|
23
|
+
await expect(broadcast('signed-xdr')).resolves.toBe('tx-hash')
|
|
24
|
+
expect(broadcastTransaction).toHaveBeenCalledWith('signed-xdr')
|
|
25
|
+
})
|
|
23
26
|
|
|
24
|
-
it(
|
|
25
|
-
(fetchBaseFee as jest.Mock).mockResolvedValue({ recommendedFee: 100, baseFee: 100 })
|
|
27
|
+
it('estimateFees converts recommended fee to bigint', async () => {
|
|
28
|
+
;(fetchBaseFee as jest.Mock).mockResolvedValue({ recommendedFee: 100, baseFee: 100 })
|
|
26
29
|
|
|
27
|
-
await expect(estimateFees()).resolves.toBe(100n)
|
|
28
|
-
expect(fetchBaseFee).toHaveBeenCalledTimes(1)
|
|
29
|
-
})
|
|
30
|
+
await expect(estimateFees()).resolves.toBe(100n)
|
|
31
|
+
expect(fetchBaseFee).toHaveBeenCalledTimes(1)
|
|
32
|
+
})
|
|
30
33
|
|
|
31
|
-
it(
|
|
34
|
+
it('lastBlock delegates to getLastBlock', async () => {
|
|
32
35
|
const block = {
|
|
33
36
|
height: 123,
|
|
34
|
-
hash:
|
|
35
|
-
time: new Date(
|
|
36
|
-
}
|
|
37
|
-
(getLastBlock as jest.Mock).mockResolvedValue(block)
|
|
38
|
-
|
|
39
|
-
await expect(lastBlock()).resolves.toEqual(block)
|
|
40
|
-
expect(getLastBlock).toHaveBeenCalledTimes(1)
|
|
41
|
-
})
|
|
42
|
-
})
|
|
37
|
+
hash: 'block-hash',
|
|
38
|
+
time: new Date('2026-01-01T00:00:00.000Z'),
|
|
39
|
+
}
|
|
40
|
+
;(getLastBlock as jest.Mock).mockResolvedValue(block)
|
|
41
|
+
|
|
42
|
+
await expect(lastBlock()).resolves.toEqual(block)
|
|
43
|
+
expect(getLastBlock).toHaveBeenCalledTimes(1)
|
|
44
|
+
})
|
|
45
|
+
})
|
package/src/logic/sdkWrapper.ts
CHANGED
|
@@ -1,32 +1,35 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
1
4
|
import {
|
|
2
5
|
Account as StellarSdkAccount,
|
|
3
6
|
Operation as StellarSdkOperation,
|
|
4
7
|
TransactionBuilder,
|
|
5
8
|
Networks,
|
|
6
9
|
Asset,
|
|
7
|
-
} from
|
|
8
|
-
import { stellarUnit } from
|
|
10
|
+
} from '@stellar/stellar-sdk'
|
|
11
|
+
import { stellarUnit } from './common'
|
|
9
12
|
|
|
10
13
|
export function buildTransactionBuilder(source: StellarSdkAccount, fee: bigint) {
|
|
11
|
-
const formattedFee = fee.toString()
|
|
14
|
+
const formattedFee = fee.toString()
|
|
12
15
|
return new TransactionBuilder(source, {
|
|
13
16
|
fee: formattedFee,
|
|
14
17
|
networkPassphrase: Networks.PUBLIC,
|
|
15
|
-
})
|
|
18
|
+
})
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export function buildChangeTrustOperation(assetCode: string, assetIssuer: string) {
|
|
19
22
|
return StellarSdkOperation.changeTrust({
|
|
20
23
|
asset: new Asset(assetCode, assetIssuer),
|
|
21
|
-
})
|
|
24
|
+
})
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export function buildCreateAccountOperation(destination: string, amount: bigint) {
|
|
25
|
-
const formattedAmount = getFormattedAmount(amount)
|
|
28
|
+
const formattedAmount = getFormattedAmount(amount)
|
|
26
29
|
return StellarSdkOperation.createAccount({
|
|
27
30
|
destination: destination,
|
|
28
31
|
startingBalance: formattedAmount,
|
|
29
|
-
})
|
|
32
|
+
})
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
export function buildPaymentOperation({
|
|
@@ -35,24 +38,24 @@ export function buildPaymentOperation({
|
|
|
35
38
|
assetCode,
|
|
36
39
|
assetIssuer,
|
|
37
40
|
}: {
|
|
38
|
-
destination: string
|
|
39
|
-
amount: bigint
|
|
40
|
-
assetCode: string | undefined
|
|
41
|
-
assetIssuer: string | undefined
|
|
41
|
+
destination: string
|
|
42
|
+
amount: bigint
|
|
43
|
+
assetCode: string | undefined
|
|
44
|
+
assetIssuer: string | undefined
|
|
42
45
|
}) {
|
|
43
|
-
const formattedAmount = getFormattedAmount(amount)
|
|
46
|
+
const formattedAmount = getFormattedAmount(amount)
|
|
44
47
|
// Non-native assets should always have asset code and asset issuer. If an
|
|
45
48
|
// asset doesn't have both, we assume it is native asset.
|
|
46
|
-
const asset = assetCode && assetIssuer ? new Asset(assetCode, assetIssuer) : Asset.native()
|
|
49
|
+
const asset = assetCode && assetIssuer ? new Asset(assetCode, assetIssuer) : Asset.native()
|
|
47
50
|
return StellarSdkOperation.payment({
|
|
48
51
|
destination: destination,
|
|
49
52
|
amount: formattedAmount,
|
|
50
53
|
asset,
|
|
51
|
-
})
|
|
54
|
+
})
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
function getFormattedAmount(amount: bigint) {
|
|
55
|
-
const div = 10 ** stellarUnit.magnitude
|
|
58
|
+
const div = 10 ** stellarUnit.magnitude
|
|
56
59
|
// BigInt division is always an integer, never a float. We need to convert first to a Number.
|
|
57
|
-
return (Number(amount) / div).toString()
|
|
60
|
+
return (Number(amount) / div).toString()
|
|
58
61
|
}
|
package/src/logic/utils.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import { StrKey } from '@stellar/stellar-sdk'
|
|
5
|
+
import { fetchSigners } from '../network'
|
|
6
|
+
|
|
7
|
+
export const STELLAR_BURN_ADDRESS = 'GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF'
|
|
5
8
|
|
|
6
9
|
export async function isAccountMultiSign(account: string): Promise<boolean> {
|
|
7
|
-
const signers = await fetchSigners(account)
|
|
8
|
-
return signers.length > 1
|
|
10
|
+
const signers = await fetchSigners(account)
|
|
11
|
+
return signers.length > 1
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
/**
|
|
@@ -14,19 +17,19 @@ export async function isAccountMultiSign(account: string): Promise<boolean> {
|
|
|
14
17
|
* @param {*} address
|
|
15
18
|
*/
|
|
16
19
|
export function isAddressValid(address: string): boolean {
|
|
17
|
-
if (!address) return false
|
|
20
|
+
if (!address) return false
|
|
18
21
|
|
|
19
22
|
// FIXME Workaround for burn address, see https://ledgerhq.atlassian.net/browse/LIVE-4014
|
|
20
|
-
if (address === STELLAR_BURN_ADDRESS) return false
|
|
23
|
+
if (address === STELLAR_BURN_ADDRESS) return false
|
|
21
24
|
|
|
22
25
|
try {
|
|
23
|
-
return StrKey.isValidEd25519PublicKey(address) || StrKey.isValidMed25519PublicKey(address)
|
|
26
|
+
return StrKey.isValidEd25519PublicKey(address) || StrKey.isValidMed25519PublicKey(address)
|
|
24
27
|
} catch {
|
|
25
|
-
return false
|
|
28
|
+
return false
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
/** Compile-time exhaustiveness helper: call when a value should be `never`. */
|
|
30
33
|
export function assertUnreachable(_: never): never {
|
|
31
|
-
throw new Error(
|
|
34
|
+
throw new Error('unreachable assertion failed')
|
|
32
35
|
}
|
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import { isAddressValid } from './utils'
|
|
5
|
+
import { validateAddress } from './validateAddress'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
jest.mock('./utils')
|
|
8
|
+
|
|
9
|
+
describe('validateAddress', () => {
|
|
10
|
+
const mockedIsAddressValid = jest.mocked(isAddressValid)
|
|
8
11
|
|
|
9
12
|
beforeEach(() => {
|
|
10
|
-
mockedIsAddressValid.mockClear()
|
|
11
|
-
})
|
|
13
|
+
mockedIsAddressValid.mockClear()
|
|
14
|
+
})
|
|
12
15
|
|
|
13
16
|
it.each([true, false])(
|
|
14
|
-
|
|
17
|
+
'should call isAddressValid and return expected value (%s)',
|
|
15
18
|
async (expectedValue: boolean) => {
|
|
16
|
-
mockedIsAddressValid.mockReturnValueOnce(expectedValue)
|
|
19
|
+
mockedIsAddressValid.mockReturnValueOnce(expectedValue)
|
|
17
20
|
|
|
18
|
-
const address =
|
|
19
|
-
const parameters = {}
|
|
20
|
-
const result = await validateAddress(address, parameters)
|
|
21
|
-
expect(result).toEqual(expectedValue)
|
|
21
|
+
const address = 'some random address'
|
|
22
|
+
const parameters = {}
|
|
23
|
+
const result = await validateAddress(address, parameters)
|
|
24
|
+
expect(result).toEqual(expectedValue)
|
|
22
25
|
|
|
23
|
-
expect(mockedIsAddressValid).toHaveBeenCalledTimes(1)
|
|
24
|
-
expect(mockedIsAddressValid).toHaveBeenCalledWith(address)
|
|
25
|
-
}
|
|
26
|
-
)
|
|
27
|
-
})
|
|
26
|
+
expect(mockedIsAddressValid).toHaveBeenCalledTimes(1)
|
|
27
|
+
expect(mockedIsAddressValid).toHaveBeenCalledWith(address)
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
})
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import type { AddressValidationCurrencyParameters } from '@ledgerhq/coin-module-framework/api/types'
|
|
5
|
+
import { isAddressValid } from './utils'
|
|
3
6
|
|
|
4
7
|
export async function validateAddress(
|
|
5
8
|
address: string,
|
|
6
|
-
_parameters: Partial<AddressValidationCurrencyParameters
|
|
9
|
+
_parameters: Partial<AddressValidationCurrencyParameters>
|
|
7
10
|
): Promise<boolean> {
|
|
8
|
-
return isAddressValid(address)
|
|
11
|
+
return isAddressValid(address)
|
|
9
12
|
}
|
|
@@ -1,86 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import * as network from "../network";
|
|
4
|
-
import * as horizon from "../network/horizon";
|
|
5
|
-
import { NetworkInfo, StellarMemo, StellarMemoKind, StellarWrongMemoFormat } from "../types";
|
|
6
|
-
import * as utils from "./utils";
|
|
7
|
-
import { validateIntent } from "./validateIntent";
|
|
8
|
-
import * as logicValidateMemo from "./validateMemo";
|
|
1
|
+
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
9
3
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
import { FeeEstimation, TransactionIntent } from '@ledgerhq/coin-module-framework/api/types'
|
|
5
|
+
import BigNumber from 'bignumber.js'
|
|
6
|
+
import * as network from '../network'
|
|
7
|
+
import * as horizon from '../network/horizon'
|
|
8
|
+
import { NetworkInfo, StellarMemo, StellarMemoKind, StellarWrongMemoFormat } from '../types'
|
|
9
|
+
import * as utils from './utils'
|
|
10
|
+
import { validateIntent } from './validateIntent'
|
|
11
|
+
import * as logicValidateMemo from './validateMemo'
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
jest.mock('../network/horizon')
|
|
14
|
+
jest.mock('./validateMemo')
|
|
15
|
+
jest.mock('./utils')
|
|
16
|
+
|
|
17
|
+
describe('validateIntent', () => {
|
|
18
|
+
const spiedValidateMemo = logicValidateMemo.validateMemo as jest.Mock
|
|
19
|
+
const spiedFetchAccount = jest.spyOn(horizon, 'fetchAccount')
|
|
20
|
+
const spiedFetchAccountNetworkInfo = jest.spyOn(network, 'fetchAccountNetworkInfo')
|
|
21
|
+
const spiedIsAccountMultiSign = jest.spyOn(utils, 'isAccountMultiSign')
|
|
19
22
|
|
|
20
23
|
beforeEach(() => {
|
|
21
|
-
spiedValidateMemo.mockClear()
|
|
22
|
-
spiedFetchAccount.mockClear()
|
|
23
|
-
spiedFetchAccountNetworkInfo.mockClear()
|
|
24
|
-
spiedIsAccountMultiSign.mockClear()
|
|
24
|
+
spiedValidateMemo.mockClear()
|
|
25
|
+
spiedFetchAccount.mockClear()
|
|
26
|
+
spiedFetchAccountNetworkInfo.mockClear()
|
|
27
|
+
spiedIsAccountMultiSign.mockClear()
|
|
25
28
|
|
|
26
29
|
spiedFetchAccount.mockResolvedValue({
|
|
27
30
|
spendableBalance: BigNumber(0),
|
|
28
31
|
balance: BigNumber(0),
|
|
29
32
|
blockHeight: 0,
|
|
30
33
|
assets: [],
|
|
31
|
-
})
|
|
34
|
+
})
|
|
32
35
|
spiedFetchAccountNetworkInfo.mockResolvedValue({
|
|
33
36
|
baseFee: BigNumber(0),
|
|
34
37
|
fees: BigNumber(0),
|
|
35
|
-
} as NetworkInfo)
|
|
36
|
-
spiedIsAccountMultiSign.mockResolvedValue(false)
|
|
37
|
-
})
|
|
38
|
+
} as NetworkInfo)
|
|
39
|
+
spiedIsAccountMultiSign.mockResolvedValue(false)
|
|
40
|
+
})
|
|
38
41
|
|
|
39
|
-
it.each([
|
|
40
|
-
|
|
42
|
+
it.each(['MEMO_TEXT', 'MEMO_ID', 'MEMO_HASH', 'MEMO_RETURN'])(
|
|
43
|
+
'should not set error on transaction when memo is validated for type %s',
|
|
41
44
|
async (type: string) => {
|
|
42
|
-
spiedValidateMemo.mockReturnValue(true)
|
|
45
|
+
spiedValidateMemo.mockReturnValue(true)
|
|
43
46
|
|
|
44
47
|
const intent = {
|
|
45
|
-
asset: { type:
|
|
46
|
-
memo: { type, value:
|
|
47
|
-
} as TransactionIntent<{ type: Exclude<StellarMemoKind,
|
|
48
|
-
const fees = {} as FeeEstimation
|
|
49
|
-
const status = await validateIntent(intent, [], fees)
|
|
50
|
-
expect(status.errors.transaction).not.toBeDefined()
|
|
48
|
+
asset: { type: 'native' },
|
|
49
|
+
memo: { type, value: 'random memo for unit test' },
|
|
50
|
+
} as TransactionIntent<{ type: Exclude<StellarMemoKind, 'NO_MEMO'>; value: string }>
|
|
51
|
+
const fees = {} as FeeEstimation
|
|
52
|
+
const status = await validateIntent(intent, [], fees)
|
|
53
|
+
expect(status.errors.transaction).not.toBeDefined()
|
|
51
54
|
|
|
52
|
-
expect(spiedValidateMemo).toHaveBeenCalledWith(intent.memo.value, intent.memo.type)
|
|
53
|
-
}
|
|
54
|
-
)
|
|
55
|
+
expect(spiedValidateMemo).toHaveBeenCalledWith(intent.memo.value, intent.memo.type)
|
|
56
|
+
}
|
|
57
|
+
)
|
|
55
58
|
|
|
56
|
-
it.each([
|
|
57
|
-
|
|
59
|
+
it.each(['MEMO_TEXT', 'MEMO_ID', 'MEMO_HASH', 'MEMO_RETURN'])(
|
|
60
|
+
'should set error on transaction when memo is invalidated for type %s',
|
|
58
61
|
async (type: string) => {
|
|
59
|
-
spiedValidateMemo.mockReturnValue(false)
|
|
62
|
+
spiedValidateMemo.mockReturnValue(false)
|
|
60
63
|
|
|
61
64
|
const intent = {
|
|
62
|
-
asset: { type:
|
|
63
|
-
memo: { type, value:
|
|
64
|
-
} as TransactionIntent<{ type: Exclude<StellarMemoKind,
|
|
65
|
-
const fees = {} as FeeEstimation
|
|
66
|
-
const status = await validateIntent(intent, [], fees)
|
|
67
|
-
expect(status.errors.transaction).toBeInstanceOf(StellarWrongMemoFormat)
|
|
65
|
+
asset: { type: 'native' },
|
|
66
|
+
memo: { type, value: 'random memo for unit test' },
|
|
67
|
+
} as TransactionIntent<{ type: Exclude<StellarMemoKind, 'NO_MEMO'>; value: string }>
|
|
68
|
+
const fees = {} as FeeEstimation
|
|
69
|
+
const status = await validateIntent(intent, [], fees)
|
|
70
|
+
expect(status.errors.transaction).toBeInstanceOf(StellarWrongMemoFormat)
|
|
68
71
|
|
|
69
|
-
expect(spiedValidateMemo).toHaveBeenCalledWith(intent.memo.value, intent.memo.type)
|
|
70
|
-
}
|
|
71
|
-
)
|
|
72
|
+
expect(spiedValidateMemo).toHaveBeenCalledWith(intent.memo.value, intent.memo.type)
|
|
73
|
+
}
|
|
74
|
+
)
|
|
72
75
|
|
|
73
|
-
it(
|
|
74
|
-
spiedValidateMemo.mockReturnValue(true)
|
|
76
|
+
it('should not validate memo when type is NO_MEMO', async () => {
|
|
77
|
+
spiedValidateMemo.mockReturnValue(true)
|
|
75
78
|
|
|
76
79
|
const intent = {
|
|
77
|
-
asset: { type:
|
|
78
|
-
memo: { type:
|
|
79
|
-
} as TransactionIntent<StellarMemo
|
|
80
|
-
const fees = {} as FeeEstimation
|
|
81
|
-
const status = await validateIntent(intent, [], fees)
|
|
82
|
-
expect(status.errors.transaction).not.toBeDefined()
|
|
80
|
+
asset: { type: 'native' },
|
|
81
|
+
memo: { type: 'NO_MEMO' },
|
|
82
|
+
} as TransactionIntent<StellarMemo>
|
|
83
|
+
const fees = {} as FeeEstimation
|
|
84
|
+
const status = await validateIntent(intent, [], fees)
|
|
85
|
+
expect(status.errors.transaction).not.toBeDefined()
|
|
83
86
|
|
|
84
|
-
expect(spiedValidateMemo).not.toHaveBeenCalled()
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
+
expect(spiedValidateMemo).not.toHaveBeenCalled()
|
|
88
|
+
})
|
|
89
|
+
})
|