@ledgerhq/coin-tezos 10.1.1 → 10.2.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/CHANGELOG.md +20 -0
- package/lib/api/index.d.ts +35 -2
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +12 -15
- package/lib/api/index.js.map +1 -1
- package/lib/logic/craftRawOperations.js +26 -17
- package/lib/logic/craftRawOperations.js.map +1 -1
- package/lib/logic/estimateFees.js +4 -4
- package/lib/logic/estimateFees.js.map +1 -1
- package/lib/logic/listOperations.d.ts.map +1 -1
- package/lib/logic/listOperations.js +9 -7
- package/lib/logic/listOperations.js.map +1 -1
- package/lib/logic/validateIntent.js +1 -1
- package/lib/logic/validateIntent.js.map +1 -1
- package/lib/network/tzkt.js +1 -1
- package/lib/network/tzkt.js.map +1 -1
- package/lib/test/config.d.ts +2 -22
- package/lib/test/config.d.ts.map +1 -1
- package/lib/test/config.js.map +1 -1
- package/lib/utils.d.ts +0 -3
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +17 -3
- package/lib/utils.js.map +1 -1
- package/lib-es/api/index.d.ts +35 -2
- package/lib-es/api/index.d.ts.map +1 -1
- package/lib-es/api/index.js +13 -16
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/logic/craftRawOperations.js +26 -17
- package/lib-es/logic/craftRawOperations.js.map +1 -1
- package/lib-es/logic/estimateFees.js +4 -4
- package/lib-es/logic/estimateFees.js.map +1 -1
- package/lib-es/logic/listOperations.d.ts.map +1 -1
- package/lib-es/logic/listOperations.js +9 -7
- package/lib-es/logic/listOperations.js.map +1 -1
- package/lib-es/logic/validateIntent.js +1 -1
- package/lib-es/logic/validateIntent.js.map +1 -1
- package/lib-es/network/tzkt.js +1 -1
- package/lib-es/network/tzkt.js.map +1 -1
- package/lib-es/test/config.d.ts +2 -22
- package/lib-es/test/config.d.ts.map +1 -1
- package/lib-es/test/config.js.map +1 -1
- package/lib-es/utils.d.ts +0 -3
- package/lib-es/utils.d.ts.map +1 -1
- package/lib-es/utils.js +17 -3
- package/lib-es/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/api/index-mainnet.integ.test.ts +40 -50
- package/src/api/index.integ.test.ts +60 -45
- package/src/api/index.test.ts +229 -180
- package/src/api/index.ts +22 -30
- package/src/logic/broadcast.integ.test.ts +2 -7
- package/src/logic/craftRawOperations.test.ts +11 -10
- package/src/logic/craftRawOperations.ts +35 -19
- package/src/logic/craftTransaction.integ.test.ts +2 -2
- package/src/logic/craftTransaction.test.ts +63 -95
- package/src/logic/estimateFees.integ.test.ts +19 -20
- package/src/logic/estimateFees.test.ts +30 -63
- package/src/logic/estimateFees.ts +4 -4
- package/src/logic/getBalance.test.ts +6 -6
- package/src/logic/getBlock.integ.test.ts +20 -21
- package/src/logic/getBlock.test.ts +44 -51
- package/src/logic/getBlockInfo.integ.test.ts +13 -14
- package/src/logic/getBlockInfo.test.ts +8 -7
- package/src/logic/getStakes.test.ts +17 -17
- package/src/logic/listOperations.integ.test.ts +40 -37
- package/src/logic/listOperations.test.ts +34 -31
- package/src/logic/listOperations.ts +19 -19
- package/src/logic/validateIntent.test.ts +17 -19
- package/src/logic/validateIntent.ts +1 -1
- package/src/network/bakers.integ.test.ts +1 -1
- package/src/network/bakers.test.ts +7 -15
- package/src/network/tzkt.integ.test.ts +13 -14
- package/src/network/tzkt.test.ts +194 -259
- package/src/network/tzkt.ts +1 -1
- package/src/test/config.ts +3 -1
- package/src/utils.ts +18 -3
- package/.oxlintrc.json +0 -20
package/src/api/index.ts
CHANGED
|
@@ -6,25 +6,19 @@ import type { CoreAccountInfo, CoreTransactionInfo, EstimatedFees } from '../log
|
|
|
6
6
|
import type { TezosOperationMode } from '../types/model'
|
|
7
7
|
import type { TezosAccountInfo, TezosFeeEstimation } from './types'
|
|
8
8
|
import type {
|
|
9
|
+
CoinModuleImpl,
|
|
9
10
|
CraftedTransaction,
|
|
10
|
-
Cursor,
|
|
11
11
|
ListOperationsOptions,
|
|
12
12
|
Page,
|
|
13
|
-
Reward,
|
|
14
|
-
Validator,
|
|
15
13
|
} from '@ledgerhq/coin-module-framework/api/index'
|
|
14
|
+
import type { Operation } from '@ledgerhq/coin-module-framework/api/index'
|
|
16
15
|
import type {
|
|
17
16
|
BalanceOptions,
|
|
18
|
-
CoinModuleApi,
|
|
19
17
|
FeeEstimation,
|
|
20
18
|
TransactionIntent,
|
|
21
19
|
} from '@ledgerhq/coin-module-framework/api/types'
|
|
22
20
|
import { rejectBalanceOptions } from '@ledgerhq/coin-module-framework/api/getBalance/rejectBalanceOptions'
|
|
23
|
-
import {
|
|
24
|
-
IncorrectTypeError,
|
|
25
|
-
notSupported,
|
|
26
|
-
type Operation,
|
|
27
|
-
} from '@ledgerhq/coin-module-framework/api/index'
|
|
21
|
+
import { IncorrectTypeError } from '@ledgerhq/coin-module-framework/api/index'
|
|
28
22
|
import { craftTransactionData } from '@ledgerhq/coin-module-framework/logic/craftTransactionData'
|
|
29
23
|
import { log } from '@ledgerhq/logs'
|
|
30
24
|
import { getRevealFee } from '@taquito/taquito'
|
|
@@ -57,14 +51,18 @@ import {
|
|
|
57
51
|
} from '../utils'
|
|
58
52
|
|
|
59
53
|
// The caller builds the {@link TezosContext} (config + logger) and passes it to each method (ADR-019).
|
|
60
|
-
|
|
54
|
+
// Checked against CoinModuleImpl with `satisfies` rather than annotated as it, so the precise shape
|
|
55
|
+
// survives and a caller sees exactly which methods exist.
|
|
56
|
+
//
|
|
57
|
+
// Omitted rather than stubbed: `call`, `register`, `getRewards` and `getValidators`. Staking is
|
|
58
|
+
// partial rather than absent — `getStakes` is implemented, while Tezos exposes no reward-event
|
|
59
|
+
// series and no enumerable validator set here. The consumer resolver applies `withDefaults`, which
|
|
60
|
+
// answers "not supported" for each.
|
|
61
|
+
export function createApi() {
|
|
61
62
|
return {
|
|
62
|
-
broadcast: (context, tx) => broadcast(context, tx),
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
},
|
|
66
|
-
combine: (_context, tx, signature) => combine(tx, signature),
|
|
67
|
-
craftTransaction: (context, transactionIntent, options) =>
|
|
63
|
+
broadcast: (context, tx, _options?) => broadcast(context, tx),
|
|
64
|
+
combine: (_context, tx, signature, _options?) => combine(tx, signature),
|
|
65
|
+
craftTransaction: (context, transactionIntent, options?) =>
|
|
68
66
|
craft(context, transactionIntent, options?.customFees),
|
|
69
67
|
craftRawTransaction: async (
|
|
70
68
|
context,
|
|
@@ -76,13 +74,14 @@ export function createApi(): CoinModuleApi<TezosCoinConfig> {
|
|
|
76
74
|
const tx = await craftRawOperations(context, transaction, sender, publicKey, sequence)
|
|
77
75
|
return { transaction: tx }
|
|
78
76
|
},
|
|
79
|
-
estimateFees: (context, transactionIntent) => estimate(context, transactionIntent),
|
|
77
|
+
estimateFees: (context, transactionIntent, _options?) => estimate(context, transactionIntent),
|
|
80
78
|
getBalance: (context, address: string, options?: BalanceOptions) =>
|
|
81
79
|
rejectBalanceOptions(() => getBalance(context, address), options),
|
|
82
80
|
lastBlock: (context) => lastBlock(context),
|
|
83
81
|
listOperations: (context, address, options) => operations(context, address, options),
|
|
84
|
-
getStakes: (context, address, options) => getStakes(context, address, options?.cursor),
|
|
85
|
-
validateIntent: (context, transactionIntent
|
|
82
|
+
getStakes: (context, address, options?) => getStakes(context, address, options?.cursor),
|
|
83
|
+
validateIntent: (context, transactionIntent, _balances, _options?) =>
|
|
84
|
+
validateIntent(context, transactionIntent),
|
|
86
85
|
getNextSequence: async (context, address: string) => {
|
|
87
86
|
const config = await context.config()
|
|
88
87
|
const accountInfo = await createTzktApi(config).getAccountByAddress(address)
|
|
@@ -98,16 +97,9 @@ export function createApi(): CoinModuleApi<TezosCoinConfig> {
|
|
|
98
97
|
},
|
|
99
98
|
getBlock: (context, height) => getBlock(context, height),
|
|
100
99
|
getBlockInfo: (context, height) => getBlockInfo(context, height),
|
|
101
|
-
getRewards(_context, _address: string, _options?: { cursor?: Cursor }): Promise<Page<Reward>> {
|
|
102
|
-
throw new Error('getRewards is not supported')
|
|
103
|
-
},
|
|
104
|
-
register: notSupported('register'),
|
|
105
|
-
getValidators(_context, _options?: { cursor?: Cursor }): Promise<Page<Validator>> {
|
|
106
|
-
throw new Error('getValidators is not supported')
|
|
107
|
-
},
|
|
108
100
|
validateAddress: (_context, address, parameters) => validateAddress(address, parameters),
|
|
109
101
|
craftTransactionData: (_context, intent) => craftTransactionData(intent),
|
|
110
|
-
}
|
|
102
|
+
} satisfies CoinModuleImpl<TezosCoinConfig>
|
|
111
103
|
}
|
|
112
104
|
|
|
113
105
|
function isTezosTransactionType(
|
|
@@ -137,7 +129,7 @@ async function craft(
|
|
|
137
129
|
|
|
138
130
|
const tezosMode = resolveTezosOperationMode(transactionIntent.type, transactionIntent.asset)
|
|
139
131
|
const mappedType: TezosOperationMode =
|
|
140
|
-
tezosMode === 'send_token' ? 'send_token' :
|
|
132
|
+
tezosMode === 'send_token' ? 'send_token' : transactionIntent.type
|
|
141
133
|
const tokenCraftInfo =
|
|
142
134
|
tezosMode === 'send_token' ? parseTezosTokenAsset(transactionIntent.asset)! : undefined
|
|
143
135
|
|
|
@@ -338,9 +330,9 @@ async function estimate(
|
|
|
338
330
|
txFee: estimation.fees,
|
|
339
331
|
},
|
|
340
332
|
}
|
|
341
|
-
} catch (error:
|
|
333
|
+
} catch (error: unknown) {
|
|
342
334
|
// Handle PublicKeyNotFoundError
|
|
343
|
-
if (error
|
|
335
|
+
if (error instanceof Error && error.message.includes('Public key not found')) {
|
|
344
336
|
const apiAccount = await api.getAccountByAddress(transactionIntent.recipient)
|
|
345
337
|
const storageLimit =
|
|
346
338
|
!hasEmptyBalance(apiAccount) || transactionIntent.type === 'stake' ? 0n : 277n
|
|
@@ -4,17 +4,12 @@
|
|
|
4
4
|
import type { TezosContext } from '../config'
|
|
5
5
|
import { InMemorySigner } from '@taquito/signer'
|
|
6
6
|
import { OpKind, TezosToolkit } from '@taquito/taquito'
|
|
7
|
+
import { mockConfig } from '../test/config'
|
|
7
8
|
import { broadcast } from './broadcast'
|
|
8
9
|
|
|
9
10
|
describe('Broadcast', () => {
|
|
10
11
|
const context: TezosContext = {
|
|
11
|
-
config: async () =>
|
|
12
|
-
({
|
|
13
|
-
status: { type: 'active' },
|
|
14
|
-
node: {
|
|
15
|
-
url: 'https://xtz-node.api.live.ledger.com',
|
|
16
|
-
},
|
|
17
|
-
}) as any,
|
|
12
|
+
config: async () => mockConfig,
|
|
18
13
|
logger: () => undefined,
|
|
19
14
|
}
|
|
20
15
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { TezosContext } from '../config'
|
|
5
|
+
import type { DeepPartialReturn } from '@ledgerhq/coin-module-framework/test/utils'
|
|
5
6
|
import { OpKind } from '@taquito/rpc'
|
|
6
7
|
import { getPkhfromPk } from '@taquito/utils'
|
|
8
|
+
import { mockConfig } from '../test/config'
|
|
7
9
|
import { UnsupportedOperationKind } from '../types/errors'
|
|
8
10
|
import { craftRawOperations } from './craftRawOperations'
|
|
9
11
|
import { getTezosToolkit } from './tezosToolkit'
|
|
@@ -45,16 +47,15 @@ describe('craftRawOperations', () => {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
const context: TezosContext = {
|
|
48
|
-
config: async () =>
|
|
49
|
-
({
|
|
50
|
-
fees: { minFees: 100, minRevealGasLimit: 0, minStorageLimit: 0 },
|
|
51
|
-
}) as unknown as TezosCoinConfig,
|
|
50
|
+
config: async () => ({ ...mockConfig, fees: { ...mockConfig.fees, minFees: 100 } }),
|
|
52
51
|
logger: () => undefined,
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
beforeEach(() => {
|
|
56
55
|
jest.clearAllMocks()
|
|
57
|
-
|
|
56
|
+
jest
|
|
57
|
+
.mocked<DeepPartialReturn<typeof getTezosToolkit>>(getTezosToolkit)
|
|
58
|
+
.mockReturnValue(mockTezosToolkit)
|
|
58
59
|
mockTezosToolkit.rpc.getBlock.mockResolvedValue({ hash: 'BLockHash' })
|
|
59
60
|
mockTezosToolkit.rpc.forgeOperations.mockResolvedValue('deadbeef')
|
|
60
61
|
// Default: account already revealed (no leading reveal op).
|
|
@@ -162,7 +163,7 @@ describe('craftRawOperations', () => {
|
|
|
162
163
|
|
|
163
164
|
it('uses the trailing op estimate when a reveal estimate is prepended for an unrevealed source', async () => {
|
|
164
165
|
mockTezosToolkit.rpc.getManagerKey.mockResolvedValue(null)
|
|
165
|
-
|
|
166
|
+
jest.mocked(getPkhfromPk).mockReturnValue(SENDER)
|
|
166
167
|
mockTezosToolkit.estimate.reveal.mockResolvedValue({
|
|
167
168
|
suggestedFeeMutez: 374,
|
|
168
169
|
gasLimit: 1000,
|
|
@@ -224,7 +225,7 @@ describe('craftRawOperations', () => {
|
|
|
224
225
|
|
|
225
226
|
it('prepends a reveal when the sender is not revealed', async () => {
|
|
226
227
|
mockTezosToolkit.rpc.getManagerKey.mockResolvedValue(null)
|
|
227
|
-
|
|
228
|
+
jest.mocked(getPkhfromPk).mockReturnValue(SENDER)
|
|
228
229
|
mockTezosToolkit.estimate.reveal.mockResolvedValue({
|
|
229
230
|
suggestedFeeMutez: 374,
|
|
230
231
|
gasLimit: 1000,
|
|
@@ -248,7 +249,7 @@ describe('craftRawOperations', () => {
|
|
|
248
249
|
|
|
249
250
|
it('falls back to SDK reveal helpers when estimate.reveal throws', async () => {
|
|
250
251
|
mockTezosToolkit.rpc.getManagerKey.mockResolvedValue(null)
|
|
251
|
-
|
|
252
|
+
jest.mocked(getPkhfromPk).mockReturnValue(SENDER)
|
|
252
253
|
mockTezosToolkit.estimate.reveal.mockRejectedValue(new Error('inconsistent_hash'))
|
|
253
254
|
|
|
254
255
|
const ops = [{ kind: 'transaction', destination: RECIPIENT, amount: '1000' }]
|
|
@@ -264,7 +265,7 @@ describe('craftRawOperations', () => {
|
|
|
264
265
|
|
|
265
266
|
it('rejects a reveal whose public key does not match the sender', async () => {
|
|
266
267
|
mockTezosToolkit.rpc.getManagerKey.mockResolvedValue(null)
|
|
267
|
-
|
|
268
|
+
jest.mocked(getPkhfromPk).mockReturnValue('tz1someoneElse')
|
|
268
269
|
|
|
269
270
|
const ops = [{ kind: 'transaction', destination: RECIPIENT, amount: '1000' }]
|
|
270
271
|
|
|
@@ -133,31 +133,46 @@ function parseOperations(rawTransaction: string): PartialTezosOperation[] {
|
|
|
133
133
|
return parsed.map(validateOperation)
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
function isRecord(v: unknown): v is Record<string, unknown> {
|
|
137
|
+
return !!v && typeof v === 'object' && !Array.isArray(v)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function assertTransaction(
|
|
141
|
+
op: Record<string, unknown>
|
|
142
|
+
): asserts op is PartialTezosTransactionOperation {
|
|
143
|
+
if (!isValidAddress(op.destination)) {
|
|
144
|
+
throw new Error('craftRawOperations: a transaction requires a valid `destination` address')
|
|
145
|
+
}
|
|
146
|
+
assertMutezAmount(op.amount)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function assertDelegation(
|
|
150
|
+
op: Record<string, unknown>
|
|
151
|
+
): asserts op is PartialTezosDelegationOperation {
|
|
152
|
+
// A delegation with no `delegate` is an undelegation; when present it must be a valid
|
|
153
|
+
// implicit account (an empty/invalid string must not be silently treated as absent).
|
|
154
|
+
if (op.delegate !== undefined && !isImplicitAddress(op.delegate)) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
'craftRawOperations: `delegate` must be a valid implicit account address when present'
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
136
161
|
function validateOperation(op: unknown): PartialTezosOperation {
|
|
137
|
-
if (!op
|
|
162
|
+
if (!isRecord(op)) {
|
|
138
163
|
throw new Error('craftRawOperations: invalid operation')
|
|
139
164
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
switch (candidate.kind) {
|
|
165
|
+
assertOptionalLimits(op)
|
|
166
|
+
switch (op.kind) {
|
|
143
167
|
case 'transaction':
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
assertMutezAmount(candidate.amount)
|
|
148
|
-
return candidate as PartialTezosTransactionOperation
|
|
168
|
+
assertTransaction(op)
|
|
169
|
+
return op
|
|
149
170
|
case 'delegation':
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (candidate.delegate !== undefined && !isImplicitAddress(candidate.delegate)) {
|
|
153
|
-
throw new Error(
|
|
154
|
-
'craftRawOperations: `delegate` must be a valid implicit account address when present'
|
|
155
|
-
)
|
|
156
|
-
}
|
|
157
|
-
return candidate as unknown as PartialTezosDelegationOperation
|
|
171
|
+
assertDelegation(op)
|
|
172
|
+
return op
|
|
158
173
|
default:
|
|
159
174
|
throw new UnsupportedOperationKind('unsupported operation kind', {
|
|
160
|
-
kind: String(
|
|
175
|
+
kind: String(op.kind),
|
|
161
176
|
})
|
|
162
177
|
}
|
|
163
178
|
}
|
|
@@ -284,8 +299,9 @@ function buildOperationContent(
|
|
|
284
299
|
// Compile-time exhaustiveness guard: a new PartialTezosOperation kind becomes a type error
|
|
285
300
|
// here. validateOperation already rejects unknown kinds at runtime before crafting.
|
|
286
301
|
function assertNever(op: never): never {
|
|
302
|
+
const r: Record<string, unknown> = op
|
|
287
303
|
throw new UnsupportedOperationKind('unsupported operation kind', {
|
|
288
|
-
kind: String(
|
|
304
|
+
kind: String(r.kind),
|
|
289
305
|
})
|
|
290
306
|
}
|
|
291
307
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { TezosContext } from '../config'
|
|
5
5
|
import { OpKind } from '@taquito/rpc'
|
|
6
6
|
import { mockConfig } from '../test/config'
|
|
7
7
|
import { craftTransaction } from '.'
|
|
@@ -16,7 +16,7 @@ import { craftTransaction } from '.'
|
|
|
16
16
|
describe('Tezos Api', () => {
|
|
17
17
|
const address = 'tz1heMGVHQnx7ALDcDKqez8fan64Eyicw4DJ'
|
|
18
18
|
const context: TezosContext = {
|
|
19
|
-
config: async () => mockConfig
|
|
19
|
+
config: async () => mockConfig,
|
|
20
20
|
logger: () => undefined,
|
|
21
21
|
}
|
|
22
22
|
it('should craft a send transaction', async () => {
|
|
@@ -2,19 +2,14 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import type { TezosCoinConfig, TezosContext } from '../config'
|
|
5
|
+
import type { DeepPartialReturn } from '@ledgerhq/coin-module-framework/test/utils'
|
|
5
6
|
import { OpKind } from '@taquito/rpc'
|
|
6
7
|
import { getRevealFee } from '@taquito/taquito'
|
|
8
|
+
import { mockConfig } from '../test/config'
|
|
7
9
|
import { craftTransaction, rawEncode } from './craftTransaction'
|
|
8
10
|
import { getTezosToolkit } from './tezosToolkit'
|
|
9
11
|
|
|
10
|
-
type
|
|
11
|
-
| 'send'
|
|
12
|
-
| 'delegate'
|
|
13
|
-
| 'undelegate'
|
|
14
|
-
| 'send_token'
|
|
15
|
-
| 'stake'
|
|
16
|
-
| 'unstake'
|
|
17
|
-
| 'finalize_unstake'
|
|
12
|
+
type TransactionInput = Parameters<typeof craftTransaction>[2]
|
|
18
13
|
|
|
19
14
|
jest.mock('./tezosToolkit')
|
|
20
15
|
|
|
@@ -52,16 +47,18 @@ describe('craftTransaction', () => {
|
|
|
52
47
|
|
|
53
48
|
beforeEach(() => {
|
|
54
49
|
jest.clearAllMocks()
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
jest
|
|
51
|
+
.mocked<DeepPartialReturn<typeof getTezosToolkit>>(getTezosToolkit)
|
|
52
|
+
.mockReturnValue(mockTezosToolkit)
|
|
53
|
+
currentConfig = mockConfig
|
|
57
54
|
})
|
|
58
55
|
|
|
59
56
|
it('should craft a send transaction', async () => {
|
|
60
57
|
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
61
58
|
|
|
62
59
|
const account = { address: 'tz1...' }
|
|
63
|
-
const transaction = {
|
|
64
|
-
type: 'send'
|
|
60
|
+
const transaction: TransactionInput = {
|
|
61
|
+
type: 'send',
|
|
65
62
|
recipient: 'tz2...',
|
|
66
63
|
amount: BigInt(1000),
|
|
67
64
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -88,8 +85,8 @@ describe('craftTransaction', () => {
|
|
|
88
85
|
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
89
86
|
|
|
90
87
|
const account = { address: 'tz1...' }
|
|
91
|
-
const transaction = {
|
|
92
|
-
type: 'delegate'
|
|
88
|
+
const transaction: TransactionInput = {
|
|
89
|
+
type: 'delegate',
|
|
93
90
|
recipient: 'tz2...',
|
|
94
91
|
amount: BigInt(0),
|
|
95
92
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -115,8 +112,8 @@ describe('craftTransaction', () => {
|
|
|
115
112
|
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
116
113
|
|
|
117
114
|
const account = { address: 'tz1...' }
|
|
118
|
-
const transaction = {
|
|
119
|
-
type: 'undelegate'
|
|
115
|
+
const transaction: TransactionInput = {
|
|
116
|
+
type: 'undelegate',
|
|
120
117
|
recipient: '',
|
|
121
118
|
amount: BigInt(0),
|
|
122
119
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -144,17 +141,11 @@ describe('craftTransaction', () => {
|
|
|
144
141
|
storageLimit: 0,
|
|
145
142
|
suggestedFeeMutez: getRevealFee('tz1...'),
|
|
146
143
|
})
|
|
147
|
-
currentConfig = {
|
|
148
|
-
fees: {
|
|
149
|
-
minRevealGasLimit: 100,
|
|
150
|
-
minFees: 0,
|
|
151
|
-
minStorageLimit: 0,
|
|
152
|
-
},
|
|
153
|
-
} as unknown as TezosCoinConfig
|
|
144
|
+
currentConfig = { ...mockConfig, fees: { ...mockConfig.fees, minRevealGasLimit: 100 } }
|
|
154
145
|
|
|
155
146
|
const account = { address: 'tz1...' }
|
|
156
|
-
const transaction = {
|
|
157
|
-
type: 'send'
|
|
147
|
+
const transaction: TransactionInput = {
|
|
148
|
+
type: 'send',
|
|
158
149
|
recipient: 'tz2...',
|
|
159
150
|
amount: BigInt(1000),
|
|
160
151
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -197,17 +188,14 @@ describe('craftTransaction', () => {
|
|
|
197
188
|
})
|
|
198
189
|
const minFees = 500
|
|
199
190
|
currentConfig = {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
minStorageLimit: 0,
|
|
204
|
-
},
|
|
205
|
-
} as unknown as TezosCoinConfig
|
|
191
|
+
...mockConfig,
|
|
192
|
+
fees: { ...mockConfig.fees, minRevealGasLimit: 300, minFees },
|
|
193
|
+
}
|
|
206
194
|
|
|
207
195
|
const account = { address: 'tz2...' }
|
|
208
196
|
const mainOpFee = 600
|
|
209
|
-
const transaction = {
|
|
210
|
-
type: 'delegate'
|
|
197
|
+
const transaction: TransactionInput = {
|
|
198
|
+
type: 'delegate',
|
|
211
199
|
recipient: 'tz3...',
|
|
212
200
|
amount: BigInt(0),
|
|
213
201
|
fee: { fees: String(mainOpFee), gasLimit: '10000', storageLimit: '0' },
|
|
@@ -216,11 +204,11 @@ describe('craftTransaction', () => {
|
|
|
216
204
|
|
|
217
205
|
const result = await craftTransaction(context, account, transaction, publicKey)
|
|
218
206
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
expect(
|
|
207
|
+
expect(result.contents[0]).toMatchObject({
|
|
208
|
+
kind: OpKind.REVEAL,
|
|
209
|
+
fee: String(suggestedRevealFee),
|
|
210
|
+
})
|
|
211
|
+
expect(result.contents[1]).toMatchObject({ fee: String(mainOpFee) })
|
|
224
212
|
})
|
|
225
213
|
|
|
226
214
|
it('craft transaction when default estimation is lesser than minFees', async () => {
|
|
@@ -232,16 +220,13 @@ describe('craftTransaction', () => {
|
|
|
232
220
|
})
|
|
233
221
|
const minFees = 500
|
|
234
222
|
currentConfig = {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
minStorageLimit: 25,
|
|
239
|
-
},
|
|
240
|
-
} as unknown as TezosCoinConfig
|
|
223
|
+
...mockConfig,
|
|
224
|
+
fees: { ...mockConfig.fees, minRevealGasLimit: 300, minStorageLimit: 25, minFees },
|
|
225
|
+
}
|
|
241
226
|
|
|
242
227
|
const account = { address: 'tz2...' }
|
|
243
|
-
const transaction = {
|
|
244
|
-
type: 'delegate'
|
|
228
|
+
const transaction: TransactionInput = {
|
|
229
|
+
type: 'delegate',
|
|
245
230
|
recipient: 'tz3...',
|
|
246
231
|
amount: BigInt(0),
|
|
247
232
|
fee: { fees: '200', gasLimit: '1000', storageLimit: '0' },
|
|
@@ -250,11 +235,12 @@ describe('craftTransaction', () => {
|
|
|
250
235
|
|
|
251
236
|
const result = await craftTransaction(context, account, transaction, publicKey)
|
|
252
237
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
238
|
+
expect(result.contents[0]).toMatchObject({
|
|
239
|
+
kind: OpKind.REVEAL,
|
|
240
|
+
fee: String(minFees),
|
|
241
|
+
gas_limit: '300',
|
|
242
|
+
storage_limit: '25',
|
|
243
|
+
})
|
|
258
244
|
})
|
|
259
245
|
|
|
260
246
|
it('craft transaction with customFee splits total so reveal and main op respect minFees', async () => {
|
|
@@ -266,17 +252,14 @@ describe('craftTransaction', () => {
|
|
|
266
252
|
})
|
|
267
253
|
const minFees = 1000
|
|
268
254
|
currentConfig = {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
minStorageLimit: 0,
|
|
273
|
-
},
|
|
274
|
-
} as unknown as TezosCoinConfig
|
|
255
|
+
...mockConfig,
|
|
256
|
+
fees: { ...mockConfig.fees, minRevealGasLimit: 300, minFees },
|
|
257
|
+
}
|
|
275
258
|
|
|
276
259
|
const account = { address: 'tz2TaTpo31sAiX2HBJUTLLdUnqVJR4QjLy1V' }
|
|
277
260
|
const mainOpFee = 1000
|
|
278
|
-
const transaction = {
|
|
279
|
-
type: 'delegate'
|
|
261
|
+
const transaction: TransactionInput = {
|
|
262
|
+
type: 'delegate',
|
|
280
263
|
recipient: 'tz3Vq38qYD3GEbWcXHMLt5PaASZrkDtEiA8D',
|
|
281
264
|
amount: BigInt(0),
|
|
282
265
|
fee: { fees: String(mainOpFee), gasLimit: '10000', storageLimit: '0' },
|
|
@@ -286,25 +269,21 @@ describe('craftTransaction', () => {
|
|
|
286
269
|
const result = await craftTransaction(context, account, transaction, publicKey)
|
|
287
270
|
|
|
288
271
|
expect(result.contents).toHaveLength(2)
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const total = revealFee + delegationFee
|
|
292
|
-
expect(revealFee).toBe(minFees)
|
|
293
|
-
expect(delegationFee).toBe(mainOpFee)
|
|
294
|
-
expect(total).toBe(minFees + mainOpFee)
|
|
272
|
+
expect(result.contents[0]).toMatchObject({ fee: String(minFees) })
|
|
273
|
+
expect(result.contents[1]).toMatchObject({ fee: String(mainOpFee) })
|
|
295
274
|
})
|
|
296
275
|
})
|
|
297
276
|
|
|
298
277
|
it('should craft an FA2 send_token transaction', async () => {
|
|
299
|
-
const fa2Param = { entrypoint: 'transfer', value: { prim: 'Pair'
|
|
278
|
+
const fa2Param = { entrypoint: 'transfer', value: { prim: 'Pair' } }
|
|
300
279
|
const { transfer } = setupFa2ContractMock(fa2Param)
|
|
301
280
|
mockTezosToolkit.contract.at.mockResolvedValue({ methods: { transfer } })
|
|
302
281
|
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
303
282
|
|
|
304
283
|
const contractAddress = 'KT1CpeSQKdkhWi4pinYcseCFKmDhs5M74BkU'
|
|
305
284
|
const account = { address: 'tz1VSUr8wwNhLAzempoch5d6nLRSNtxK8LBr' }
|
|
306
|
-
const transaction = {
|
|
307
|
-
type: 'send_token'
|
|
285
|
+
const transaction: TransactionInput = {
|
|
286
|
+
type: 'send_token',
|
|
308
287
|
recipient: 'tz1VSUr8wwNhLAzempoch5d6nLRSNtxK8LBr',
|
|
309
288
|
amount: BigInt(5),
|
|
310
289
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -347,18 +326,12 @@ describe('craftTransaction', () => {
|
|
|
347
326
|
storageLimit: 0,
|
|
348
327
|
suggestedFeeMutez: getRevealFee('tz1...'),
|
|
349
328
|
})
|
|
350
|
-
currentConfig = {
|
|
351
|
-
fees: {
|
|
352
|
-
minRevealGasLimit: 100,
|
|
353
|
-
minFees: 0,
|
|
354
|
-
minStorageLimit: 0,
|
|
355
|
-
},
|
|
356
|
-
} as unknown as TezosCoinConfig
|
|
329
|
+
currentConfig = { ...mockConfig, fees: { ...mockConfig.fees, minRevealGasLimit: 100 } }
|
|
357
330
|
|
|
358
331
|
const contractAddress = 'KT1CpeSQKdkhWi4pinYcseCFKmDhs5M74BkU'
|
|
359
332
|
const account = { address: 'tz1...' }
|
|
360
|
-
const transaction = {
|
|
361
|
-
type: 'send_token'
|
|
333
|
+
const transaction: TransactionInput = {
|
|
334
|
+
type: 'send_token',
|
|
362
335
|
recipient: 'tz2...',
|
|
363
336
|
amount: BigInt(1),
|
|
364
337
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -388,7 +361,7 @@ describe('craftTransaction', () => {
|
|
|
388
361
|
context,
|
|
389
362
|
{ address: 'tz1...' },
|
|
390
363
|
{
|
|
391
|
-
type: 'send_token'
|
|
364
|
+
type: 'send_token',
|
|
392
365
|
recipient: 'tz2...',
|
|
393
366
|
amount: 1n,
|
|
394
367
|
fee: {},
|
|
@@ -401,7 +374,7 @@ describe('craftTransaction', () => {
|
|
|
401
374
|
context,
|
|
402
375
|
{ address: 'tz1...' },
|
|
403
376
|
{
|
|
404
|
-
type: 'send_token'
|
|
377
|
+
type: 'send_token',
|
|
405
378
|
recipient: 'tz2...',
|
|
406
379
|
amount: 1n,
|
|
407
380
|
fee: {},
|
|
@@ -415,8 +388,8 @@ describe('craftTransaction', () => {
|
|
|
415
388
|
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
416
389
|
|
|
417
390
|
const account = { address: 'tz1...' }
|
|
418
|
-
const transaction = {
|
|
419
|
-
type: 'stake'
|
|
391
|
+
const transaction: TransactionInput = {
|
|
392
|
+
type: 'stake',
|
|
420
393
|
recipient: '',
|
|
421
394
|
amount: BigInt(1234),
|
|
422
395
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -444,8 +417,8 @@ describe('craftTransaction', () => {
|
|
|
444
417
|
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
445
418
|
|
|
446
419
|
const account = { address: 'tz1...' }
|
|
447
|
-
const transaction = {
|
|
448
|
-
type: 'unstake'
|
|
420
|
+
const transaction: TransactionInput = {
|
|
421
|
+
type: 'unstake',
|
|
449
422
|
recipient: '',
|
|
450
423
|
amount: BigInt(4321),
|
|
451
424
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -473,8 +446,8 @@ describe('craftTransaction', () => {
|
|
|
473
446
|
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
474
447
|
|
|
475
448
|
const account = { address: 'tz1...' }
|
|
476
|
-
const transaction = {
|
|
477
|
-
type: 'finalize_unstake'
|
|
449
|
+
const transaction: TransactionInput = {
|
|
450
|
+
type: 'finalize_unstake',
|
|
478
451
|
recipient: '',
|
|
479
452
|
// even with a non-zero amount the operation must serialize amount: "0"
|
|
480
453
|
amount: BigInt(999),
|
|
@@ -506,17 +479,11 @@ describe('craftTransaction', () => {
|
|
|
506
479
|
storageLimit: 0,
|
|
507
480
|
suggestedFeeMutez: getRevealFee('tz1...'),
|
|
508
481
|
})
|
|
509
|
-
currentConfig = {
|
|
510
|
-
fees: {
|
|
511
|
-
minRevealGasLimit: 100,
|
|
512
|
-
minFees: 0,
|
|
513
|
-
minStorageLimit: 0,
|
|
514
|
-
},
|
|
515
|
-
} as unknown as TezosCoinConfig
|
|
482
|
+
currentConfig = { ...mockConfig, fees: { ...mockConfig.fees, minRevealGasLimit: 100 } }
|
|
516
483
|
|
|
517
484
|
const account = { address: 'tz1...' }
|
|
518
|
-
const transaction = {
|
|
519
|
-
type: 'stake'
|
|
485
|
+
const transaction: TransactionInput = {
|
|
486
|
+
type: 'stake',
|
|
520
487
|
recipient: '',
|
|
521
488
|
amount: BigInt(500),
|
|
522
489
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
@@ -553,12 +520,13 @@ describe('craftTransaction', () => {
|
|
|
553
520
|
it('should throw an error for unsupported transaction type', async () => {
|
|
554
521
|
const account = { address: 'tz1...' }
|
|
555
522
|
const transaction = {
|
|
556
|
-
type: 'invalid'
|
|
523
|
+
type: 'invalid',
|
|
557
524
|
recipient: 'tz2...',
|
|
558
525
|
amount: BigInt(1000),
|
|
559
526
|
fee: { fees: '100', gasLimit: '200', storageLimit: '300' },
|
|
560
527
|
}
|
|
561
528
|
|
|
529
|
+
// @ts-expect-error -- intentionally invalid type to test the unsupported-type error path
|
|
562
530
|
await expect(craftTransaction(context, account, transaction)).rejects.toThrow(
|
|
563
531
|
'unsupported mode'
|
|
564
532
|
)
|