@ledgerhq/coin-tezos 7.12.0 → 9.0.0
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/CHANGELOG.md +39 -0
- package/lib/api/index.d.ts +1 -2
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +45 -44
- package/lib/api/index.js.map +1 -1
- package/lib/api/types.d.ts +3 -2
- package/lib/api/types.d.ts.map +1 -1
- package/lib/config.d.ts +3 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib/logic/broadcast.d.ts +2 -1
- package/lib/logic/broadcast.d.ts.map +1 -1
- package/lib/logic/broadcast.js +3 -2
- 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 +4 -1
- package/lib/logic/combine.js.map +1 -1
- package/lib/logic/craftRawOperations.d.ts +2 -1
- package/lib/logic/craftRawOperations.d.ts.map +1 -1
- package/lib/logic/craftRawOperations.js +5 -8
- package/lib/logic/craftRawOperations.js.map +1 -1
- package/lib/logic/craftTransaction.d.ts +3 -2
- package/lib/logic/craftTransaction.d.ts.map +1 -1
- package/lib/logic/craftTransaction.js +6 -9
- package/lib/logic/craftTransaction.js.map +1 -1
- package/lib/logic/estimateFees.d.ts +2 -1
- package/lib/logic/estimateFees.d.ts.map +1 -1
- package/lib/logic/estimateFees.js +24 -19
- package/lib/logic/estimateFees.js.map +1 -1
- package/lib/logic/getBalance.d.ts +2 -1
- package/lib/logic/getBalance.d.ts.map +1 -1
- package/lib/logic/getBalance.js +7 -8
- package/lib/logic/getBalance.js.map +1 -1
- package/lib/logic/getBlock.d.ts +2 -1
- package/lib/logic/getBlock.d.ts.map +1 -1
- package/lib/logic/getBlock.js +12 -10
- package/lib/logic/getBlock.js.map +1 -1
- package/lib/logic/getBlockInfo.d.ts +2 -1
- package/lib/logic/getBlockInfo.d.ts.map +1 -1
- package/lib/logic/getBlockInfo.js +5 -3
- package/lib/logic/getBlockInfo.js.map +1 -1
- package/lib/logic/getStakes.d.ts +3 -2
- package/lib/logic/getStakes.d.ts.map +1 -1
- package/lib/logic/getStakes.js +9 -9
- package/lib/logic/getStakes.js.map +1 -1
- package/lib/logic/lastBlock.d.ts +2 -1
- package/lib/logic/lastBlock.d.ts.map +1 -1
- package/lib/logic/lastBlock.js +4 -6
- package/lib/logic/lastBlock.js.map +1 -1
- package/lib/logic/listOperations.d.ts +2 -1
- package/lib/logic/listOperations.d.ts.map +1 -1
- package/lib/logic/listOperations.js +8 -6
- package/lib/logic/listOperations.js.map +1 -1
- package/lib/logic/tezosToolkit.d.ts +2 -1
- package/lib/logic/tezosToolkit.d.ts.map +1 -1
- package/lib/logic/tezosToolkit.js +2 -6
- package/lib/logic/tezosToolkit.js.map +1 -1
- package/lib/logic/validateIntent.d.ts +2 -1
- package/lib/logic/validateIntent.d.ts.map +1 -1
- package/lib/logic/validateIntent.js +12 -13
- package/lib/logic/validateIntent.js.map +1 -1
- package/lib/network/bakers.d.ts +5 -4
- package/lib/network/bakers.d.ts.map +1 -1
- package/lib/network/bakers.js +9 -10
- package/lib/network/bakers.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 -5
- package/lib/network/index.js.map +1 -1
- package/lib/network/tzkt.d.ts +16 -9
- package/lib/network/tzkt.d.ts.map +1 -1
- package/lib/network/tzkt.js +341 -333
- package/lib/network/tzkt.js.map +1 -1
- package/lib/utils.d.ts +2 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +1 -6
- package/lib/utils.js.map +1 -1
- package/lib-es/api/index.d.ts +1 -2
- package/lib-es/api/index.d.ts.map +1 -1
- package/lib-es/api/index.js +40 -36
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/api/types.d.ts +3 -2
- package/lib-es/api/types.d.ts.map +1 -1
- package/lib-es/config.d.ts +3 -1
- package/lib-es/config.d.ts.map +1 -1
- package/lib-es/config.js.map +1 -1
- package/lib-es/logic/broadcast.d.ts +2 -1
- package/lib-es/logic/broadcast.d.ts.map +1 -1
- package/lib-es/logic/broadcast.js +3 -2
- 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 +4 -1
- package/lib-es/logic/combine.js.map +1 -1
- package/lib-es/logic/craftRawOperations.d.ts +2 -1
- package/lib-es/logic/craftRawOperations.d.ts.map +1 -1
- package/lib-es/logic/craftRawOperations.js +5 -5
- package/lib-es/logic/craftRawOperations.js.map +1 -1
- package/lib-es/logic/craftTransaction.d.ts +3 -2
- package/lib-es/logic/craftTransaction.d.ts.map +1 -1
- package/lib-es/logic/craftTransaction.js +6 -6
- package/lib-es/logic/craftTransaction.js.map +1 -1
- package/lib-es/logic/estimateFees.d.ts +2 -1
- package/lib-es/logic/estimateFees.d.ts.map +1 -1
- package/lib-es/logic/estimateFees.js +24 -16
- package/lib-es/logic/estimateFees.js.map +1 -1
- package/lib-es/logic/getBalance.d.ts +2 -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 +2 -1
- package/lib-es/logic/getBlock.d.ts.map +1 -1
- package/lib-es/logic/getBlock.js +10 -8
- package/lib-es/logic/getBlock.js.map +1 -1
- package/lib-es/logic/getBlockInfo.d.ts +2 -1
- package/lib-es/logic/getBlockInfo.d.ts.map +1 -1
- package/lib-es/logic/getBlockInfo.js +4 -2
- package/lib-es/logic/getBlockInfo.js.map +1 -1
- package/lib-es/logic/getStakes.d.ts +3 -2
- package/lib-es/logic/getStakes.d.ts.map +1 -1
- package/lib-es/logic/getStakes.js +9 -6
- package/lib-es/logic/getStakes.js.map +1 -1
- package/lib-es/logic/lastBlock.d.ts +2 -1
- package/lib-es/logic/lastBlock.d.ts.map +1 -1
- package/lib-es/logic/lastBlock.js +4 -3
- package/lib-es/logic/lastBlock.js.map +1 -1
- package/lib-es/logic/listOperations.d.ts +2 -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/tezosToolkit.d.ts +2 -1
- package/lib-es/logic/tezosToolkit.d.ts.map +1 -1
- package/lib-es/logic/tezosToolkit.js +2 -3
- package/lib-es/logic/tezosToolkit.js.map +1 -1
- package/lib-es/logic/validateIntent.d.ts +2 -1
- package/lib-es/logic/validateIntent.d.ts.map +1 -1
- package/lib-es/logic/validateIntent.js +10 -8
- package/lib-es/logic/validateIntent.js.map +1 -1
- package/lib-es/network/bakers.d.ts +5 -4
- package/lib-es/network/bakers.d.ts.map +1 -1
- package/lib-es/network/bakers.js +9 -10
- package/lib-es/network/bakers.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 +1 -1
- package/lib-es/network/index.js.map +1 -1
- package/lib-es/network/tzkt.d.ts +16 -9
- package/lib-es/network/tzkt.d.ts.map +1 -1
- package/lib-es/network/tzkt.js +340 -333
- package/lib-es/network/tzkt.js.map +1 -1
- package/lib-es/utils.d.ts +2 -1
- package/lib-es/utils.d.ts.map +1 -1
- package/lib-es/utils.js +1 -3
- package/lib-es/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/api/index-mainnet.integ.test.ts +34 -30
- package/src/api/index.integ.test.ts +69 -53
- package/src/api/index.test.ts +99 -60
- package/src/api/index.ts +52 -36
- package/src/api/types.ts +3 -2
- package/src/config.ts +4 -1
- package/src/logic/broadcast.integ.test.ts +12 -13
- package/src/logic/broadcast.ts +4 -2
- package/src/logic/combine.test.ts +17 -0
- package/src/logic/combine.ts +5 -2
- package/src/logic/craftRawOperations.test.ts +47 -33
- package/src/logic/craftRawOperations.ts +6 -4
- package/src/logic/craftTransaction.integ.test.ts +12 -5
- package/src/logic/craftTransaction.test.ts +39 -31
- package/src/logic/craftTransaction.ts +10 -5
- package/src/logic/estimateFees.integ.test.ts +7 -7
- package/src/logic/estimateFees.test.ts +52 -49
- package/src/logic/estimateFees.ts +34 -22
- package/src/logic/getBalance.test.ts +19 -17
- package/src/logic/getBalance.ts +6 -3
- package/src/logic/getBlock.integ.test.ts +8 -30
- package/src/logic/getBlock.test.ts +91 -81
- package/src/logic/getBlock.ts +11 -8
- package/src/logic/getBlockInfo.integ.test.ts +9 -18
- package/src/logic/getBlockInfo.test.ts +19 -9
- package/src/logic/getBlockInfo.ts +5 -2
- package/src/logic/getStakes.test.ts +46 -49
- package/src/logic/getStakes.ts +14 -5
- package/src/logic/lastBlock.ts +5 -3
- package/src/logic/listOperations.integ.test.ts +40 -67
- package/src/logic/listOperations.test.ts +65 -59
- package/src/logic/listOperations.ts +8 -3
- package/src/logic/tezosToolkit.ts +3 -3
- package/src/logic/validateIntent.test.ts +78 -74
- package/src/logic/validateIntent.ts +17 -7
- package/src/network/bakers.integ.test.ts +2 -5
- package/src/network/bakers.test.ts +5 -6
- package/src/network/bakers.ts +13 -10
- package/src/network/index.ts +2 -1
- package/src/network/tzkt.integ.test.ts +3 -14
- package/src/network/tzkt.test.ts +128 -96
- package/src/network/tzkt.ts +426 -393
- package/src/utils.ts +2 -3
package/src/logic/getBlock.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import type { TezosContext } from '../config'
|
|
4
5
|
import type {
|
|
5
6
|
APIBlock,
|
|
6
7
|
APIDelegationType,
|
|
@@ -19,13 +20,13 @@ import type {
|
|
|
19
20
|
} from '@ledgerhq/coin-module-framework/api/index'
|
|
20
21
|
import { STAKING_ACTION_TO_OP_TYPE } from '../constants'
|
|
21
22
|
import {
|
|
23
|
+
createTzktApi,
|
|
22
24
|
fetchBlockDelegations,
|
|
23
25
|
fetchBlockOriginations,
|
|
24
26
|
fetchBlockReveals,
|
|
25
27
|
fetchBlockStaking,
|
|
26
28
|
fetchBlockTokenTransfers,
|
|
27
29
|
fetchBlockTransactions,
|
|
28
|
-
tzkt,
|
|
29
30
|
} from '../network'
|
|
30
31
|
|
|
31
32
|
const NATIVE_ASSET: AssetInfo = { type: 'native', name: 'XTZ' }
|
|
@@ -514,11 +515,13 @@ function groupAndMapTransactions(
|
|
|
514
515
|
* - Appends FA token transfer operations to the owning BlockTransaction when a
|
|
515
516
|
* matching `transactionId` can be resolved; otherwise creates a standalone entry.
|
|
516
517
|
*/
|
|
517
|
-
export async function getBlock(height: number): Promise<Block> {
|
|
518
|
+
export async function getBlock(context: TezosContext, height: number): Promise<Block> {
|
|
518
519
|
if (!Number.isSafeInteger(height) || height <= 0) {
|
|
519
520
|
throw new Error(`getBlock: height must be a positive integer, got ${height}`)
|
|
520
521
|
}
|
|
521
522
|
|
|
523
|
+
const config = await context.config()
|
|
524
|
+
const tzkt = createTzktApi(config)
|
|
522
525
|
const [
|
|
523
526
|
block,
|
|
524
527
|
parentBlock,
|
|
@@ -531,12 +534,12 @@ export async function getBlock(height: number): Promise<Block> {
|
|
|
531
534
|
] = await Promise.all([
|
|
532
535
|
tzkt.getBlockByLevel(height),
|
|
533
536
|
tzkt.getBlockByLevel(height - 1),
|
|
534
|
-
fetchBlockTransactions(height),
|
|
535
|
-
fetchBlockTokenTransfers(height),
|
|
536
|
-
fetchBlockDelegations(height),
|
|
537
|
-
fetchBlockStaking(height),
|
|
538
|
-
fetchBlockOriginations(height),
|
|
539
|
-
fetchBlockReveals(height),
|
|
537
|
+
fetchBlockTransactions(config, height),
|
|
538
|
+
fetchBlockTokenTransfers(config, height),
|
|
539
|
+
fetchBlockDelegations(config, height),
|
|
540
|
+
fetchBlockStaking(config, height),
|
|
541
|
+
fetchBlockOriginations(config, height),
|
|
542
|
+
fetchBlockReveals(config, height),
|
|
540
543
|
])
|
|
541
544
|
|
|
542
545
|
// Token transfers triggered by originations from other blocks carry an
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import type { TezosCoinConfig } from '../config'
|
|
5
|
-
import coinConfig from '../config'
|
|
4
|
+
import type { TezosCoinConfig, TezosContext } from '../config'
|
|
6
5
|
import { getBlock } from './getBlock'
|
|
7
6
|
import { getBlockInfo } from './getBlockInfo'
|
|
8
7
|
|
|
@@ -15,8 +14,6 @@ import { getBlockInfo } from './getBlockInfo'
|
|
|
15
14
|
* consistent, independently verifiable data.
|
|
16
15
|
*/
|
|
17
16
|
|
|
18
|
-
let originalGetCoinConfig: () => TezosCoinConfig
|
|
19
|
-
|
|
20
17
|
const shadownetConfig = (): TezosCoinConfig =>
|
|
21
18
|
({
|
|
22
19
|
status: { type: 'active' },
|
|
@@ -32,20 +29,14 @@ const shadownetConfig = (): TezosCoinConfig =>
|
|
|
32
29
|
},
|
|
33
30
|
}) as TezosCoinConfig
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
afterAll(() => {
|
|
42
|
-
if (originalGetCoinConfig) {
|
|
43
|
-
coinConfig.setCoinConfig(originalGetCoinConfig)
|
|
44
|
-
}
|
|
45
|
-
})
|
|
32
|
+
const context: TezosContext = {
|
|
33
|
+
config: async () => shadownetConfig(),
|
|
34
|
+
logger: () => undefined,
|
|
35
|
+
}
|
|
46
36
|
|
|
37
|
+
describe('getBlockInfo', () => {
|
|
47
38
|
it('should fetch and parse block info for block 3113219 correctly', async () => {
|
|
48
|
-
const blockInfo = await getBlockInfo(3113219)
|
|
39
|
+
const blockInfo = await getBlockInfo(context, 3113219)
|
|
49
40
|
|
|
50
41
|
expect(blockInfo).toMatchObject({
|
|
51
42
|
height: 3113219,
|
|
@@ -59,8 +50,8 @@ describe('getBlockInfo', () => {
|
|
|
59
50
|
})
|
|
60
51
|
|
|
61
52
|
it('should return consistent data with getBlock for the same block', async () => {
|
|
62
|
-
const blockInfo = await getBlockInfo(3113219)
|
|
63
|
-
const block = await getBlock(3113219)
|
|
53
|
+
const blockInfo = await getBlockInfo(context, 3113219)
|
|
54
|
+
const block = await getBlock(context, 3113219)
|
|
64
55
|
|
|
65
56
|
expect(blockInfo).toMatchObject({
|
|
66
57
|
height: block.info.height,
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import type { TezosCoinConfig, TezosContext } from '../config'
|
|
5
5
|
import { getBlockInfo } from './getBlockInfo'
|
|
6
6
|
|
|
7
|
-
const mockGetBlockByLevel = jest.
|
|
7
|
+
const mockGetBlockByLevel = jest.fn()
|
|
8
|
+
jest.mock('../network', () => ({
|
|
9
|
+
createTzktApi: () => ({
|
|
10
|
+
getBlockByLevel: (...args: unknown[]) => mockGetBlockByLevel(...args),
|
|
11
|
+
}),
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
const context: TezosContext = {
|
|
15
|
+
config: async () => ({}) as unknown as TezosCoinConfig,
|
|
16
|
+
logger: () => undefined,
|
|
17
|
+
}
|
|
8
18
|
|
|
9
19
|
describe('getBlockInfo', () => {
|
|
10
20
|
beforeEach(() => {
|
|
@@ -26,7 +36,7 @@ describe('getBlockInfo', () => {
|
|
|
26
36
|
} as any)
|
|
27
37
|
|
|
28
38
|
// When
|
|
29
|
-
const result = await getBlockInfo(level)
|
|
39
|
+
const result = await getBlockInfo(context, level)
|
|
30
40
|
|
|
31
41
|
// Then
|
|
32
42
|
expect(mockGetBlockByLevel).toHaveBeenCalledTimes(2)
|
|
@@ -50,7 +60,7 @@ describe('getBlockInfo', () => {
|
|
|
50
60
|
} as any)
|
|
51
61
|
|
|
52
62
|
// When
|
|
53
|
-
const result = await getBlockInfo(8_000_000)
|
|
63
|
+
const result = await getBlockInfo(context, 8_000_000)
|
|
54
64
|
|
|
55
65
|
// Then
|
|
56
66
|
expect(result.time).toBeInstanceOf(Date)
|
|
@@ -59,7 +69,7 @@ describe('getBlockInfo', () => {
|
|
|
59
69
|
|
|
60
70
|
it('throws for height = 0 without calling the API', async () => {
|
|
61
71
|
// When / Then
|
|
62
|
-
await expect(getBlockInfo(0)).rejects.toThrow(
|
|
72
|
+
await expect(getBlockInfo(context, 0)).rejects.toThrow(
|
|
63
73
|
'getBlockInfo: height must be a positive integer, got 0'
|
|
64
74
|
)
|
|
65
75
|
expect(mockGetBlockByLevel).not.toHaveBeenCalled()
|
|
@@ -67,7 +77,7 @@ describe('getBlockInfo', () => {
|
|
|
67
77
|
|
|
68
78
|
it('throws for negative height without calling the API', async () => {
|
|
69
79
|
// When / Then
|
|
70
|
-
await expect(getBlockInfo(-5)).rejects.toThrow(
|
|
80
|
+
await expect(getBlockInfo(context, -5)).rejects.toThrow(
|
|
71
81
|
'getBlockInfo: height must be a positive integer, got -5'
|
|
72
82
|
)
|
|
73
83
|
expect(mockGetBlockByLevel).not.toHaveBeenCalled()
|
|
@@ -76,7 +86,7 @@ describe('getBlockInfo', () => {
|
|
|
76
86
|
it.each([NaN, 1.5, Infinity, -Infinity])(
|
|
77
87
|
'throws for non-safe-integer height (%s) without calling the API',
|
|
78
88
|
async (height) => {
|
|
79
|
-
await expect(getBlockInfo(height)).rejects.toThrow(
|
|
89
|
+
await expect(getBlockInfo(context, height)).rejects.toThrow(
|
|
80
90
|
'getBlockInfo: height must be a positive integer'
|
|
81
91
|
)
|
|
82
92
|
expect(mockGetBlockByLevel).not.toHaveBeenCalled()
|
|
@@ -97,7 +107,7 @@ describe('getBlockInfo', () => {
|
|
|
97
107
|
} as any)
|
|
98
108
|
|
|
99
109
|
// When
|
|
100
|
-
const result = await getBlockInfo(1)
|
|
110
|
+
const result = await getBlockInfo(context, 1)
|
|
101
111
|
|
|
102
112
|
// Then
|
|
103
113
|
expect(result.parent).toEqual({ height: 0, hash: 'BLGenesis' })
|
|
@@ -108,6 +118,6 @@ describe('getBlockInfo', () => {
|
|
|
108
118
|
mockGetBlockByLevel.mockRejectedValue(new Error('TzKT unreachable'))
|
|
109
119
|
|
|
110
120
|
// When / Then
|
|
111
|
-
await expect(getBlockInfo(999_999)).rejects.toThrow('TzKT unreachable')
|
|
121
|
+
await expect(getBlockInfo(context, 999_999)).rejects.toThrow('TzKT unreachable')
|
|
112
122
|
})
|
|
113
123
|
})
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import type { TezosContext } from '../config'
|
|
4
5
|
import type { BlockInfo } from '@ledgerhq/coin-module-framework/api/index'
|
|
5
|
-
import {
|
|
6
|
+
import { createTzktApi } from '../network'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Returns lightweight metadata for a Tezos block at the given level.
|
|
@@ -10,11 +11,13 @@ import { tzkt } from '../network'
|
|
|
10
11
|
* Fetches the block and its predecessor in parallel so that `BlockInfo.parent`
|
|
11
12
|
* is always populated without adding serial latency.
|
|
12
13
|
*/
|
|
13
|
-
export async function getBlockInfo(height: number): Promise<BlockInfo> {
|
|
14
|
+
export async function getBlockInfo(context: TezosContext, height: number): Promise<BlockInfo> {
|
|
14
15
|
if (!Number.isSafeInteger(height) || height <= 0) {
|
|
15
16
|
throw new Error(`getBlockInfo: height must be a positive integer, got ${height}`)
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
const config = await context.config()
|
|
20
|
+
const tzkt = createTzktApi(config)
|
|
18
21
|
const [block, parentBlock] = await Promise.all([
|
|
19
22
|
tzkt.getBlockByLevel(height),
|
|
20
23
|
tzkt.getBlockByLevel(height - 1),
|
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
|
|
4
|
+
import type { TezosCoinConfig, TezosContext } from '../config'
|
|
5
|
+
import { getStakes } from './getStakes'
|
|
6
|
+
|
|
7
|
+
const mockGetAccountByAddress = jest.fn()
|
|
8
|
+
const mockGetUnstakeRequests = jest.fn()
|
|
9
|
+
jest.mock('../network/tzkt', () => ({
|
|
10
|
+
__esModule: true,
|
|
11
|
+
createTzktApi: () => ({
|
|
12
|
+
getAccountByAddress: (...args: unknown[]) => mockGetAccountByAddress(...args),
|
|
13
|
+
getUnstakeRequests: (...args: unknown[]) => mockGetUnstakeRequests(...args),
|
|
14
|
+
}),
|
|
15
|
+
}))
|
|
7
16
|
|
|
8
17
|
describe('getStakes', () => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
const context: TezosContext = {
|
|
19
|
+
config: async () =>
|
|
20
|
+
({
|
|
21
|
+
status: { type: 'active' },
|
|
22
|
+
baker: { url: 'http://baker.example.com' },
|
|
23
|
+
explorer: { url: 'http://tezos.explorer.com', maxTxQuery: 100 },
|
|
24
|
+
node: { url: 'http://tezos.node.com' },
|
|
25
|
+
fees: {
|
|
26
|
+
minGasLimit: 600,
|
|
27
|
+
minRevealGasLimit: 300,
|
|
28
|
+
minStorageLimit: 0,
|
|
29
|
+
minFees: 500,
|
|
30
|
+
minEstimatedFees: 500,
|
|
31
|
+
},
|
|
32
|
+
}) as unknown as TezosCoinConfig,
|
|
33
|
+
logger: () => undefined,
|
|
34
|
+
}
|
|
24
35
|
|
|
25
36
|
const makeRequest = (
|
|
26
37
|
overrides: Partial<{
|
|
@@ -45,20 +56,6 @@ describe('getStakes', () => {
|
|
|
45
56
|
beforeEach(() => {
|
|
46
57
|
jest.clearAllMocks()
|
|
47
58
|
mockGetUnstakeRequests.mockResolvedValue([])
|
|
48
|
-
|
|
49
|
-
coinConfig.setCoinConfig(() => ({
|
|
50
|
-
status: { type: 'active' },
|
|
51
|
-
baker: { url: 'http://baker.example.com' },
|
|
52
|
-
explorer: { url: 'http://tezos.explorer.com', maxTxQuery: 100 },
|
|
53
|
-
node: { url: 'http://tezos.node.com' },
|
|
54
|
-
fees: {
|
|
55
|
-
minGasLimit: 600,
|
|
56
|
-
minRevealGasLimit: 300,
|
|
57
|
-
minStorageLimit: 0,
|
|
58
|
-
minFees: 500,
|
|
59
|
-
minEstimatedFees: 500,
|
|
60
|
-
},
|
|
61
|
-
}))
|
|
62
59
|
})
|
|
63
60
|
|
|
64
61
|
describe('account types', () => {
|
|
@@ -76,7 +73,7 @@ describe('getStakes', () => {
|
|
|
76
73
|
firstActivityTime: '2021-01-01T00:00:00Z',
|
|
77
74
|
})
|
|
78
75
|
|
|
79
|
-
const result = await
|
|
76
|
+
const result = await getStakes(context, 'tz1WvvbEGpBXGeTVbLiR6DYBe1izmgiYuZbq')
|
|
80
77
|
|
|
81
78
|
expect(result.items).toEqual([])
|
|
82
79
|
})
|
|
@@ -88,7 +85,7 @@ describe('getStakes', () => {
|
|
|
88
85
|
counter: 0,
|
|
89
86
|
})
|
|
90
87
|
|
|
91
|
-
const result = await
|
|
88
|
+
const result = await getStakes(context, 'tz1EmptyAccount')
|
|
92
89
|
|
|
93
90
|
expect(result.items).toEqual([])
|
|
94
91
|
})
|
|
@@ -109,7 +106,7 @@ describe('getStakes', () => {
|
|
|
109
106
|
firstActivityTime: '2021-01-01T00:00:00Z',
|
|
110
107
|
})
|
|
111
108
|
|
|
112
|
-
const result = await
|
|
109
|
+
const result = await getStakes(context, address)
|
|
113
110
|
|
|
114
111
|
expect(result.items).toEqual([
|
|
115
112
|
{
|
|
@@ -143,7 +140,7 @@ describe('getStakes', () => {
|
|
|
143
140
|
makeRequest({ id: 42, bakerAddress, actualAmount: 10, firstTime: '2026-05-01T00:00:00Z' }),
|
|
144
141
|
])
|
|
145
142
|
|
|
146
|
-
const result = await
|
|
143
|
+
const result = await getStakes(context, address)
|
|
147
144
|
|
|
148
145
|
expect(result.items).toEqual([
|
|
149
146
|
{
|
|
@@ -184,7 +181,7 @@ describe('getStakes', () => {
|
|
|
184
181
|
it('should return delegation stake for delegated account with no staking', async () => {
|
|
185
182
|
mockGetAccountByAddress.mockResolvedValue(makeAccount())
|
|
186
183
|
|
|
187
|
-
const result = await
|
|
184
|
+
const result = await getStakes(context, address)
|
|
188
185
|
|
|
189
186
|
expect(result.items).toEqual([
|
|
190
187
|
{
|
|
@@ -202,7 +199,7 @@ describe('getStakes', () => {
|
|
|
202
199
|
it('should handle account with zero balance but delegation', async () => {
|
|
203
200
|
mockGetAccountByAddress.mockResolvedValue(makeAccount({ balance: 0 }))
|
|
204
201
|
|
|
205
|
-
const result = await
|
|
202
|
+
const result = await getStakes(context, address)
|
|
206
203
|
|
|
207
204
|
expect(result.items).toEqual([
|
|
208
205
|
{
|
|
@@ -220,7 +217,7 @@ describe('getStakes', () => {
|
|
|
220
217
|
it('should return delegation + stake when stakedBalance > 0', async () => {
|
|
221
218
|
mockGetAccountByAddress.mockResolvedValue(makeAccount({ balance: 100, stakedBalance: 30 }))
|
|
222
219
|
|
|
223
|
-
const result = await
|
|
220
|
+
const result = await getStakes(context, address)
|
|
224
221
|
|
|
225
222
|
expect(result.items).toEqual([
|
|
226
223
|
{
|
|
@@ -255,7 +252,7 @@ describe('getStakes', () => {
|
|
|
255
252
|
}),
|
|
256
253
|
])
|
|
257
254
|
|
|
258
|
-
const result = await
|
|
255
|
+
const result = await getStakes(context, address)
|
|
259
256
|
|
|
260
257
|
expect(result.items).toEqual([
|
|
261
258
|
{
|
|
@@ -293,7 +290,7 @@ describe('getStakes', () => {
|
|
|
293
290
|
}),
|
|
294
291
|
])
|
|
295
292
|
|
|
296
|
-
const result = await
|
|
293
|
+
const result = await getStakes(context, address)
|
|
297
294
|
|
|
298
295
|
expect(result.items).toEqual([
|
|
299
296
|
{
|
|
@@ -376,7 +373,7 @@ describe('getStakes', () => {
|
|
|
376
373
|
}),
|
|
377
374
|
])
|
|
378
375
|
|
|
379
|
-
const result = await
|
|
376
|
+
const result = await getStakes(context, address)
|
|
380
377
|
|
|
381
378
|
expect(result.items).toEqual([
|
|
382
379
|
{
|
|
@@ -423,7 +420,7 @@ describe('getStakes', () => {
|
|
|
423
420
|
}),
|
|
424
421
|
])
|
|
425
422
|
|
|
426
|
-
const result = await
|
|
423
|
+
const result = await getStakes(context, address)
|
|
427
424
|
|
|
428
425
|
const unstaking = result.items.find((i) => i.uid === 'unstaking-99')
|
|
429
426
|
expect(unstaking?.delegate).toBe(previousBaker)
|
|
@@ -436,7 +433,7 @@ describe('getStakes', () => {
|
|
|
436
433
|
makeRequest({ id: 4, actualAmount: 10, firstTime: '2026-05-04T00:00:00Z' }),
|
|
437
434
|
])
|
|
438
435
|
|
|
439
|
-
const result = await
|
|
436
|
+
const result = await getStakes(context, address)
|
|
440
437
|
|
|
441
438
|
expect(result.items.filter((i) => i.uid.startsWith('unstaking-'))).toHaveLength(1)
|
|
442
439
|
expect(result.items.find((i) => i.uid === 'unstaking-4')?.amount).toBe(10n)
|
|
@@ -445,7 +442,7 @@ describe('getStakes', () => {
|
|
|
445
442
|
it('skips the unstake-requests endpoint entirely when unstakedBalance is 0', async () => {
|
|
446
443
|
mockGetAccountByAddress.mockResolvedValue(makeAccount({ balance: 1000, unstakedBalance: 0 }))
|
|
447
444
|
|
|
448
|
-
const result = await
|
|
445
|
+
const result = await getStakes(context, address)
|
|
449
446
|
|
|
450
447
|
expect(result.items).toEqual([])
|
|
451
448
|
expect(mockGetUnstakeRequests).not.toHaveBeenCalled()
|
|
@@ -458,7 +455,7 @@ describe('getStakes', () => {
|
|
|
458
455
|
makeRequest({ id: 2, actualAmount: 20, firstTime: '2026-05-04T00:00:00Z' }),
|
|
459
456
|
])
|
|
460
457
|
|
|
461
|
-
const result = await
|
|
458
|
+
const result = await getStakes(context, address)
|
|
462
459
|
|
|
463
460
|
expect(result.items.map((i) => i.uid)).toEqual(['unstaking-2'])
|
|
464
461
|
})
|
|
@@ -470,7 +467,7 @@ describe('getStakes', () => {
|
|
|
470
467
|
makeRequest({ id: 2, actualAmount: 30, firstTime: '2026-05-04T00:00:00Z' }),
|
|
471
468
|
])
|
|
472
469
|
|
|
473
|
-
const result = await
|
|
470
|
+
const result = await getStakes(context, address)
|
|
474
471
|
|
|
475
472
|
expect(result.items.map((i) => i.uid)).toEqual(['unstaking-2'])
|
|
476
473
|
expect(result.items.find((i) => i.uid === 'unstaking-2')?.amount).toBe(30n)
|
|
@@ -480,7 +477,7 @@ describe('getStakes', () => {
|
|
|
480
477
|
mockGetAccountByAddress.mockResolvedValue(makeAccount({ balance: 100, unstakedBalance: 10 }))
|
|
481
478
|
mockGetUnstakeRequests.mockRejectedValueOnce(new Error('tzkt 500'))
|
|
482
479
|
|
|
483
|
-
await expect(
|
|
480
|
+
await expect(getStakes(context, address)).rejects.toThrow('tzkt 500')
|
|
484
481
|
})
|
|
485
482
|
})
|
|
486
483
|
|
|
@@ -504,7 +501,7 @@ describe('getStakes', () => {
|
|
|
504
501
|
firstActivityTime: '2026-01-01T00:00:00Z',
|
|
505
502
|
})
|
|
506
503
|
|
|
507
|
-
const result = await
|
|
504
|
+
const result = await getStakes(context, address)
|
|
508
505
|
|
|
509
506
|
const delegation = result.items.find((i) => i.uid === `delegation-${address}`)
|
|
510
507
|
expect(delegation?.amount).toBe(0n)
|
package/src/logic/getStakes.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import type { TezosCoinConfig, TezosContext } from '../config'
|
|
4
5
|
import type { APIAccount, APIManagerAccount, APIUnstakeRequest } from '../network/types'
|
|
5
6
|
import type { Cursor, Page, Stake } from '@ledgerhq/coin-module-framework/api/types'
|
|
6
7
|
import { log } from '@ledgerhq/logs'
|
|
7
8
|
import { hasManagerKey } from '../network/types'
|
|
8
|
-
import
|
|
9
|
+
import { createTzktApi } from '../network/tzkt'
|
|
9
10
|
import { partitionNativeBalance } from '../utils'
|
|
10
11
|
import { STAKING_UID_PREFIX } from './positionUid'
|
|
11
12
|
|
|
@@ -17,11 +18,14 @@ export {
|
|
|
17
18
|
} from './positionUid'
|
|
18
19
|
|
|
19
20
|
export function fetchUnstakeRequests(
|
|
21
|
+
config: TezosCoinConfig,
|
|
20
22
|
address: string,
|
|
21
23
|
account: APIAccount
|
|
22
24
|
): Promise<APIUnstakeRequest[]> {
|
|
23
25
|
if (!hasManagerKey(account)) return Promise.resolve([])
|
|
24
|
-
return (account.unstakedBalance ?? 0) > 0
|
|
26
|
+
return (account.unstakedBalance ?? 0) > 0
|
|
27
|
+
? createTzktApi(config).getUnstakeRequests(address)
|
|
28
|
+
: Promise.resolve([])
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
function unstakeRequestToStake(address: string, req: APIUnstakeRequest): Stake | null {
|
|
@@ -124,9 +128,14 @@ export function buildStakesForAccount(
|
|
|
124
128
|
return stakes
|
|
125
129
|
}
|
|
126
130
|
|
|
127
|
-
export async function getStakes(
|
|
128
|
-
|
|
131
|
+
export async function getStakes(
|
|
132
|
+
context: TezosContext,
|
|
133
|
+
address: string,
|
|
134
|
+
_cursor?: Cursor
|
|
135
|
+
): Promise<Page<Stake>> {
|
|
136
|
+
const config = await context.config()
|
|
137
|
+
const accountInfo = await createTzktApi(config).getAccountByAddress(address)
|
|
129
138
|
if (!hasManagerKey(accountInfo)) return { items: [] }
|
|
130
|
-
const unstakeRequests = await fetchUnstakeRequests(address, accountInfo)
|
|
139
|
+
const unstakeRequests = await fetchUnstakeRequests(config, address, accountInfo)
|
|
131
140
|
return { items: buildStakesForAccount(address, accountInfo, unstakeRequests) }
|
|
132
141
|
}
|
package/src/logic/lastBlock.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import type { TezosContext } from '../config'
|
|
4
5
|
import type { BlockInfo } from '@ledgerhq/coin-module-framework/api/index'
|
|
5
|
-
import
|
|
6
|
+
import { createTzktApi } from '../network/tzkt'
|
|
6
7
|
|
|
7
|
-
export async function lastBlock(): Promise<BlockInfo> {
|
|
8
|
-
const
|
|
8
|
+
export async function lastBlock(context: TezosContext): Promise<BlockInfo> {
|
|
9
|
+
const config = await context.config()
|
|
10
|
+
const result = await createTzktApi(config).getLastBlock()
|
|
9
11
|
|
|
10
12
|
return {
|
|
11
13
|
height: result.level,
|