@ledgerhq/coin-tezos 10.2.4 → 10.2.6
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 +25 -0
- package/lib/api/index.js +45 -17
- package/lib/api/index.js.map +1 -1
- package/lib/logic/craftRawOperations.js +2 -3
- package/lib/logic/craftRawOperations.js.map +1 -1
- package/lib/logic/craftTransaction.d.ts +6 -0
- package/lib/logic/craftTransaction.d.ts.map +1 -1
- package/lib/logic/craftTransaction.js +1 -1
- package/lib/logic/craftTransaction.js.map +1 -1
- package/lib/logic/estimateFees.d.ts +7 -1
- package/lib/logic/estimateFees.d.ts.map +1 -1
- package/lib/logic/estimateFees.js +30 -0
- package/lib/logic/estimateFees.js.map +1 -1
- package/lib-es/api/index.js +45 -17
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/logic/craftRawOperations.js +2 -3
- package/lib-es/logic/craftRawOperations.js.map +1 -1
- package/lib-es/logic/craftTransaction.d.ts +6 -0
- package/lib-es/logic/craftTransaction.d.ts.map +1 -1
- package/lib-es/logic/craftTransaction.js +1 -1
- package/lib-es/logic/craftTransaction.js.map +1 -1
- package/lib-es/logic/estimateFees.d.ts +7 -1
- package/lib-es/logic/estimateFees.d.ts.map +1 -1
- package/lib-es/logic/estimateFees.js +30 -1
- package/lib-es/logic/estimateFees.js.map +1 -1
- package/package.json +1 -1
- package/src/api/index.test.ts +176 -0
- package/src/api/index.ts +50 -15
- package/src/logic/craftRawOperations.ts +2 -3
- package/src/logic/craftTransaction.test.ts +30 -0
- package/src/logic/craftTransaction.ts +7 -1
- package/src/logic/estimateFees.test.ts +100 -0
- package/src/logic/estimateFees.ts +33 -1
package/src/api/index.ts
CHANGED
|
@@ -20,7 +20,6 @@ import type {
|
|
|
20
20
|
import { rejectBalanceOptions } from '@ledgerhq/coin-module-framework/api/getBalance/rejectBalanceOptions'
|
|
21
21
|
import { IncorrectTypeError } from '@ledgerhq/coin-module-framework/api/index'
|
|
22
22
|
import { craftTransactionData } from '@ledgerhq/coin-module-framework/logic/craftTransactionData'
|
|
23
|
-
import { getRevealFee } from '@taquito/taquito'
|
|
24
23
|
import { getPkhfromPk, validatePublicKey, ValidationResult } from '@taquito/utils'
|
|
25
24
|
import {
|
|
26
25
|
broadcast,
|
|
@@ -37,6 +36,7 @@ import {
|
|
|
37
36
|
rawEncode,
|
|
38
37
|
validateIntent,
|
|
39
38
|
} from '../logic'
|
|
39
|
+
import { getRevealFeeForEstimation } from '../logic/estimateFees'
|
|
40
40
|
import { getTezosToolkit } from '../logic/tezosToolkit'
|
|
41
41
|
import { validateAddress } from '../logic/validateAddress'
|
|
42
42
|
import { hasManagerKey } from '../network/types'
|
|
@@ -107,6 +107,27 @@ function isTezosTransactionType(
|
|
|
107
107
|
): type is 'send' | 'delegate' | 'undelegate' | 'stake' | 'unstake' | 'finalize_unstake' {
|
|
108
108
|
return ['send', 'delegate', 'undelegate', 'stake', 'unstake', 'finalize_unstake'].includes(type)
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Whether a failed estimation is the `contract.manager.inconsistent_hash` case that the
|
|
112
|
+
* keyless retry exists for. Taquito surfaces it as an HTTP error whose body carries the
|
|
113
|
+
* protocol error id.
|
|
114
|
+
*/
|
|
115
|
+
function isInconsistentHashError(error: unknown): boolean {
|
|
116
|
+
if (typeof error !== 'object' || error === null) {
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
119
|
+
const parts: unknown[] = []
|
|
120
|
+
if ('message' in error) {
|
|
121
|
+
parts.push(error.message)
|
|
122
|
+
}
|
|
123
|
+
if ('body' in error) {
|
|
124
|
+
parts.push(error.body)
|
|
125
|
+
}
|
|
126
|
+
return parts.some(
|
|
127
|
+
(part) => typeof part === 'string' && part.includes('contract.manager.inconsistent_hash')
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
110
131
|
async function craft(
|
|
111
132
|
context: TezosContext,
|
|
112
133
|
transactionIntent: TransactionIntent,
|
|
@@ -160,25 +181,24 @@ async function craft(
|
|
|
160
181
|
const needsReveal = hasManagerKey(senderApiAcc) && !senderApiAcc.revealed
|
|
161
182
|
const totalFee = Number(fee.fees || '0')
|
|
162
183
|
|
|
163
|
-
const feesConfig = config.fees
|
|
164
184
|
const revealFeeForSplit = needsReveal
|
|
165
|
-
?
|
|
185
|
+
? getRevealFeeForEstimation(config, transactionIntent.sender)
|
|
166
186
|
: 0
|
|
167
187
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
188
|
+
// The device compares the sum of the batch fees against the single total it was handed, so the
|
|
189
|
+
// split has to close exactly.
|
|
190
|
+
const desiredTxFee =
|
|
191
|
+
!customFees && estimation.parameters?.txFee !== undefined
|
|
192
|
+
? Number(estimation.parameters.txFee)
|
|
193
|
+
: totalFee - revealFeeForSplit
|
|
194
|
+
const txFee = Math.min(Math.max(desiredTxFee, 0), totalFee)
|
|
195
|
+
const revealFee = totalFee - txFee
|
|
176
196
|
|
|
177
197
|
const txForCraft = {
|
|
178
198
|
type: mappedType,
|
|
179
199
|
recipient: transactionIntent.recipient,
|
|
180
200
|
amount: amountToUse,
|
|
181
|
-
fee: { ...fee, fees: txFee.toString() },
|
|
201
|
+
fee: { ...fee, fees: txFee.toString(), revealFees: revealFee.toString() },
|
|
182
202
|
...(tokenCraftInfo && {
|
|
183
203
|
contractAddress: tokenCraftInfo.contractAddress,
|
|
184
204
|
tokenId: tokenCraftInfo.tokenId,
|
|
@@ -304,6 +324,13 @@ async function estimate(
|
|
|
304
324
|
// it's not clear why this happens, it couldn't be further investigated
|
|
305
325
|
// so we fallback to make an estimation without the public key
|
|
306
326
|
// there is a test that covers this, see "fallback to an estimation without the public key" index-mainnet.integ.test.ts
|
|
327
|
+
//
|
|
328
|
+
// A token estimate retries only for that error. Otherwise the keyless retry throws
|
|
329
|
+
// PublicKeyNotFoundError, and the native-transfer fallback answering it under-provisions
|
|
330
|
+
// the FA2 transfer. Other modes still depend on reaching that fallback.
|
|
331
|
+
if (tezosModeForEstimate === 'send_token' && !isInconsistentHashError(error)) {
|
|
332
|
+
throw error
|
|
333
|
+
}
|
|
307
334
|
context.logger('estimate-error', 'error estimating fees, trying without pubkey', { error })
|
|
308
335
|
estimation = await logicEstimate()
|
|
309
336
|
}
|
|
@@ -325,6 +352,14 @@ async function estimate(
|
|
|
325
352
|
} catch (error: unknown) {
|
|
326
353
|
// Handle PublicKeyNotFoundError
|
|
327
354
|
if (error instanceof Error && error.message.includes('Public key not found')) {
|
|
355
|
+
// Everything below describes a native tez transfer. An FA2 transfer costs several times
|
|
356
|
+
// more gas and the amounts vary per contract, so these values silently under-provision
|
|
357
|
+
// it: the operation is crafted correctly and the chain rejects it with gas_exhausted,
|
|
358
|
+
// charging the fee.
|
|
359
|
+
if (tezosModeForEstimate === 'send_token') {
|
|
360
|
+
throw error
|
|
361
|
+
}
|
|
362
|
+
|
|
328
363
|
const apiAccount = await api.getAccountByAddress(transactionIntent.recipient)
|
|
329
364
|
const storageLimit =
|
|
330
365
|
!hasEmptyBalance(apiAccount) || transactionIntent.type === 'stake' ? 0n : 277n
|
|
@@ -350,11 +385,11 @@ async function estimate(
|
|
|
350
385
|
} catch {
|
|
351
386
|
// When estimation fails because the sender is unrevealed (PublicKeyNotFoundError),
|
|
352
387
|
// fallback to a conservative gas value suitable for typical new-account XTZ transfers.
|
|
353
|
-
//
|
|
388
|
+
// A standard transfer consumes about 2169 gas, so 2500 leaves a small margin.
|
|
354
389
|
// The fee is computed according to Taquito's calculation so it will satisfy the Tezos prefilter rule:
|
|
355
390
|
// total_fees >= ceil(100 + 0.1*total_gas + op_size)
|
|
356
391
|
// We use a base of 120 instead of 100 to mimic Taquito and minimize rejected low-fee ops.
|
|
357
|
-
const SAFE_FALLBACK_GAS = 2500
|
|
392
|
+
const SAFE_FALLBACK_GAS = 2500
|
|
358
393
|
const FALLBACK_OP_SIZE_BYTES = 154 // typical forged size for a simple XTZ transfer
|
|
359
394
|
txGasLimit = BigInt(SAFE_FALLBACK_GAS)
|
|
360
395
|
baseTxFee = BigInt(
|
|
@@ -366,7 +401,7 @@ async function estimate(
|
|
|
366
401
|
}
|
|
367
402
|
|
|
368
403
|
const revealFee = needsReveal
|
|
369
|
-
? BigInt(
|
|
404
|
+
? BigInt(getRevealFeeForEstimation(config, transactionIntent.sender))
|
|
370
405
|
: 0n
|
|
371
406
|
const totalFee = baseTxFee + revealFee
|
|
372
407
|
|
|
@@ -232,9 +232,8 @@ async function estimateOperations(
|
|
|
232
232
|
`craftRawOperations: expected ${expected} estimate(s) for ${operations.length} operation(s), got ${estimates.length}`
|
|
233
233
|
)
|
|
234
234
|
}
|
|
235
|
-
// Keep the trailing N estimates, dropping a prepended reveal estimate if present. The
|
|
236
|
-
//
|
|
237
|
-
// craftTransaction) rather than this batch-prepended value, which is discarded.
|
|
235
|
+
// Keep the trailing N estimates, dropping a prepended reveal estimate if present. The REVEAL
|
|
236
|
+
// op itself uses the config-clamped estimateRevealLimits value, not this one.
|
|
238
237
|
return estimates.slice(estimates.length - operations.length)
|
|
239
238
|
}
|
|
240
239
|
|
|
@@ -177,6 +177,36 @@ describe('craftTransaction', () => {
|
|
|
177
177
|
])
|
|
178
178
|
})
|
|
179
179
|
|
|
180
|
+
it('stamps the reveal fee the caller supplies, not the node estimate', async () => {
|
|
181
|
+
// The device asserts that the batch fees sum to the single total the caller reported, which a
|
|
182
|
+
// reveal priced from the node would break.
|
|
183
|
+
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
184
|
+
mockTezosToolkit.estimate.reveal.mockResolvedValue({
|
|
185
|
+
gasLimit: 271,
|
|
186
|
+
storageLimit: 0,
|
|
187
|
+
suggestedFeeMutez: 310,
|
|
188
|
+
})
|
|
189
|
+
currentConfig = {
|
|
190
|
+
...mockConfig,
|
|
191
|
+
fees: { ...mockConfig.fees, minFees: 0, minRevealGasLimit: 0 },
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const account = { address: 'tz1...' }
|
|
195
|
+
const transaction: TransactionInput = {
|
|
196
|
+
type: 'send',
|
|
197
|
+
recipient: 'tz2...',
|
|
198
|
+
amount: BigInt(1000),
|
|
199
|
+
fee: { fees: '100', gasLimit: '200', storageLimit: '300', revealFees: '334' },
|
|
200
|
+
}
|
|
201
|
+
const publicKey = { publicKey: 'publicKey', publicKeyHash: 'publicKeyHash' }
|
|
202
|
+
|
|
203
|
+
const result = await craftTransaction(context, account, transaction, publicKey)
|
|
204
|
+
|
|
205
|
+
expect(result.contents[0]).toEqual(
|
|
206
|
+
expect.objectContaining({ kind: OpKind.REVEAL, fee: '334', gas_limit: '271' })
|
|
207
|
+
)
|
|
208
|
+
})
|
|
209
|
+
|
|
180
210
|
describe('when suggested fee is above or below minFees floor', () => {
|
|
181
211
|
it('craft transaction when default estimation is greater than minFees', async () => {
|
|
182
212
|
mockTezosToolkit.rpc.getContract.mockResolvedValue({ counter: '1' })
|
|
@@ -13,6 +13,12 @@ export type TransactionFee = {
|
|
|
13
13
|
fees?: string
|
|
14
14
|
gasLimit?: string
|
|
15
15
|
storageLimit?: string
|
|
16
|
+
/**
|
|
17
|
+
* Fee to stamp on the leading reveal operation. The caller sets it so the batch fees sum to the
|
|
18
|
+
* total it already reported. Without it the reveal keeps its own node estimate, which that
|
|
19
|
+
* total never accounted for.
|
|
20
|
+
*/
|
|
21
|
+
revealFees?: string
|
|
16
22
|
}
|
|
17
23
|
export type TransactionType =
|
|
18
24
|
| 'OUT'
|
|
@@ -76,7 +82,7 @@ export async function craftTransaction(
|
|
|
76
82
|
|
|
77
83
|
contents.push({
|
|
78
84
|
kind: OpKind.REVEAL,
|
|
79
|
-
fee: reveal.fee.toString(),
|
|
85
|
+
fee: transaction.fee.revealFees ?? reveal.fee.toString(),
|
|
80
86
|
gas_limit: reveal.gasLimit.toString(),
|
|
81
87
|
storage_limit: reveal.storageLimit.toString(),
|
|
82
88
|
source: publicKey.publicKeyHash,
|
|
@@ -54,9 +54,19 @@ describe('estimateFees', () => {
|
|
|
54
54
|
contract: {
|
|
55
55
|
at: jest.fn(),
|
|
56
56
|
},
|
|
57
|
+
rpc: {
|
|
58
|
+
getConstants: jest.fn(),
|
|
59
|
+
},
|
|
57
60
|
setProvider: jest.fn(),
|
|
58
61
|
}
|
|
59
62
|
|
|
63
|
+
// Mainnet values; the two are equal, which is what makes a reveal + operation batch
|
|
64
|
+
// overflow the block limit unless the operation's gas is capped.
|
|
65
|
+
const MAINNET_GAS_CONSTANTS = {
|
|
66
|
+
hard_gas_limit_per_operation: 1040000,
|
|
67
|
+
hard_gas_limit_per_block: 1040000,
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
let currentConfig: TezosCoinConfig
|
|
61
71
|
const context: TezosContext = {
|
|
62
72
|
config: async () => currentConfig,
|
|
@@ -72,6 +82,7 @@ describe('estimateFees', () => {
|
|
|
72
82
|
jest
|
|
73
83
|
.mocked<DeepPartialReturn<typeof getTezosToolkit>>(getTezosToolkit)
|
|
74
84
|
.mockReturnValue(mockTezosToolkit)
|
|
85
|
+
mockTezosToolkit.rpc.getConstants.mockResolvedValue(MAINNET_GAS_CONSTANTS)
|
|
75
86
|
currentConfig = mkConfig(defaultFeesConfig)
|
|
76
87
|
})
|
|
77
88
|
|
|
@@ -779,6 +790,95 @@ describe('estimateFees', () => {
|
|
|
779
790
|
expect(result.amount).toBe(100n)
|
|
780
791
|
})
|
|
781
792
|
|
|
793
|
+
it('send_token unrevealed caps gas so the reveal batch fits the block limit', async () => {
|
|
794
|
+
const { transfer } = setupFa2ContractMock()
|
|
795
|
+
mockTezosToolkit.contract.at.mockResolvedValue({ methods: { transfer } })
|
|
796
|
+
mockTezosToolkit.estimate.transfer.mockResolvedValue({
|
|
797
|
+
suggestedFeeMutez: 600,
|
|
798
|
+
gasLimit: 4000,
|
|
799
|
+
storageLimit: 0,
|
|
800
|
+
burnFeeMutez: 0,
|
|
801
|
+
opSize: 250,
|
|
802
|
+
})
|
|
803
|
+
|
|
804
|
+
await estimateFees(context, {
|
|
805
|
+
account: unrevealedAccount,
|
|
806
|
+
transaction: {
|
|
807
|
+
mode: 'send_token',
|
|
808
|
+
recipient: 'tz1VSUr8wwNhLAzempoch5d6nLRSNtxK8LBr',
|
|
809
|
+
amount: BigInt(100),
|
|
810
|
+
contractAddress: 'KT1CpeSQKdkhWi4pinYcseCFKmDhs5M74BkU',
|
|
811
|
+
tokenId: 0,
|
|
812
|
+
},
|
|
813
|
+
})
|
|
814
|
+
|
|
815
|
+
// min(1040000, 1040000 / 3): leaves room for the reveal Taquito prepends, so the
|
|
816
|
+
// simulation does not overflow hard_gas_limit_per_block.
|
|
817
|
+
expect(mockTezosToolkit.estimate.transfer).toHaveBeenCalledWith(
|
|
818
|
+
expect.objectContaining({ gasLimit: 346666 })
|
|
819
|
+
)
|
|
820
|
+
})
|
|
821
|
+
|
|
822
|
+
it('send_token derives the gas cap from protocol constants', async () => {
|
|
823
|
+
mockTezosToolkit.rpc.getConstants.mockResolvedValue({
|
|
824
|
+
hard_gas_limit_per_operation: 900000,
|
|
825
|
+
hard_gas_limit_per_block: 2400000,
|
|
826
|
+
})
|
|
827
|
+
const { transfer } = setupFa2ContractMock()
|
|
828
|
+
mockTezosToolkit.contract.at.mockResolvedValue({ methods: { transfer } })
|
|
829
|
+
mockTezosToolkit.estimate.transfer.mockResolvedValue({
|
|
830
|
+
suggestedFeeMutez: 600,
|
|
831
|
+
gasLimit: 4000,
|
|
832
|
+
storageLimit: 0,
|
|
833
|
+
burnFeeMutez: 0,
|
|
834
|
+
opSize: 250,
|
|
835
|
+
})
|
|
836
|
+
|
|
837
|
+
await estimateFees(context, {
|
|
838
|
+
account: unrevealedAccount,
|
|
839
|
+
transaction: {
|
|
840
|
+
mode: 'send_token',
|
|
841
|
+
recipient: 'tz1VSUr8wwNhLAzempoch5d6nLRSNtxK8LBr',
|
|
842
|
+
amount: BigInt(100),
|
|
843
|
+
contractAddress: 'KT1CpeSQKdkhWi4pinYcseCFKmDhs5M74BkU',
|
|
844
|
+
tokenId: 0,
|
|
845
|
+
},
|
|
846
|
+
})
|
|
847
|
+
|
|
848
|
+
// min(900000, 2400000 / 3): the block-derived bound is the tighter one here.
|
|
849
|
+
expect(mockTezosToolkit.estimate.transfer).toHaveBeenCalledWith(
|
|
850
|
+
expect.objectContaining({ gasLimit: 800000 })
|
|
851
|
+
)
|
|
852
|
+
})
|
|
853
|
+
|
|
854
|
+
it('send_token revealed passes no gas cap', async () => {
|
|
855
|
+
const { transfer } = setupFa2ContractMock()
|
|
856
|
+
mockTezosToolkit.contract.at.mockResolvedValue({ methods: { transfer } })
|
|
857
|
+
mockTezosToolkit.estimate.transfer.mockResolvedValue({
|
|
858
|
+
suggestedFeeMutez: 600,
|
|
859
|
+
gasLimit: 4000,
|
|
860
|
+
storageLimit: 0,
|
|
861
|
+
burnFeeMutez: 0,
|
|
862
|
+
opSize: 250,
|
|
863
|
+
})
|
|
864
|
+
|
|
865
|
+
await estimateFees(context, {
|
|
866
|
+
account: revealedAccount,
|
|
867
|
+
transaction: {
|
|
868
|
+
mode: 'send_token',
|
|
869
|
+
recipient: 'tz1VSUr8wwNhLAzempoch5d6nLRSNtxK8LBr',
|
|
870
|
+
amount: BigInt(100),
|
|
871
|
+
contractAddress: 'KT1CpeSQKdkhWi4pinYcseCFKmDhs5M74BkU',
|
|
872
|
+
tokenId: 0,
|
|
873
|
+
},
|
|
874
|
+
})
|
|
875
|
+
|
|
876
|
+
// No reveal is prepended, so the batch cannot overflow and Taquito keeps its own default.
|
|
877
|
+
const params = mockTezosToolkit.estimate.transfer.mock.calls.at(-1)?.[0]
|
|
878
|
+
expect(params).not.toHaveProperty('gasLimit')
|
|
879
|
+
expect(mockTezosToolkit.rpc.getConstants).not.toHaveBeenCalled()
|
|
880
|
+
})
|
|
881
|
+
|
|
782
882
|
it('send_token unrevealed adds reveal fee to estimatedFees', async () => {
|
|
783
883
|
const { transfer } = setupFa2ContractMock()
|
|
784
884
|
mockTezosToolkit.contract.at.mockResolvedValue({ methods: { transfer } })
|
|
@@ -190,9 +190,13 @@ export async function estimateFees(
|
|
|
190
190
|
},
|
|
191
191
|
])
|
|
192
192
|
.toTransferParams({ mutez: true })
|
|
193
|
+
const revealBatchGasLimit = account.revealed
|
|
194
|
+
? undefined
|
|
195
|
+
: await gasLimitForRevealBatch(tezosToolkit)
|
|
193
196
|
estimate = await tezosToolkit.estimate.transfer({
|
|
194
197
|
...transferParams,
|
|
195
198
|
source: account.address,
|
|
199
|
+
...(revealBatchGasLimit !== undefined && { gasLimit: revealBatchGasLimit }),
|
|
196
200
|
})
|
|
197
201
|
break
|
|
198
202
|
}
|
|
@@ -405,7 +409,35 @@ function protocolErrorIds(text: string): string[] {
|
|
|
405
409
|
}
|
|
406
410
|
}
|
|
407
411
|
|
|
408
|
-
|
|
412
|
+
/**
|
|
413
|
+
* Gas limit to hand Taquito when the source account is unrevealed.
|
|
414
|
+
*
|
|
415
|
+
* Taquito prepends a reveal to any operation from an unrevealed account, then gives the
|
|
416
|
+
* operation itself `hard_gas_limit_per_operation` for the simulation. Mainnet sets
|
|
417
|
+
* `hard_gas_limit_per_block` to that same value, so the reveal's own gas tips the batch past
|
|
418
|
+
* the block limit and the node answers HTTP 500 `gas_exhausted.block`. Without a cap the
|
|
419
|
+
* estimation fails and the caller falls back to native-transfer constants, which are far too
|
|
420
|
+
* small for an FA2 transfer.
|
|
421
|
+
*
|
|
422
|
+
* Mirrors Taquito's own batch adjustment, `min(perOperation, perBlock / (opCount + 1))`, so
|
|
423
|
+
* the value tracks the protocol rather than a hardcoded figure.
|
|
424
|
+
*/
|
|
425
|
+
async function gasLimitForRevealBatch(
|
|
426
|
+
tezosToolkit: ReturnType<typeof getTezosToolkit>
|
|
427
|
+
): Promise<number> {
|
|
428
|
+
const constants = await tezosToolkit.rpc.getConstants()
|
|
429
|
+
const perOperation = Number(constants.hard_gas_limit_per_operation)
|
|
430
|
+
const perBlock = Number(constants.hard_gas_limit_per_block)
|
|
431
|
+
const REVEAL_PLUS_OPERATION = 2
|
|
432
|
+
return Math.floor(Math.min(perOperation, perBlock / (REVEAL_PLUS_OPERATION + 1)))
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Reveal fee the estimation reports as part of the total, derived from Taquito's static per-curve
|
|
437
|
+
* table rather than a node estimate. The account is unrevealed and the public key is often absent
|
|
438
|
+
* at estimation time, so `estimate.reveal()` is not reliably available here.
|
|
439
|
+
*/
|
|
440
|
+
export function getRevealFeeForEstimation(config: TezosCoinConfig, address: string): number {
|
|
409
441
|
const minFees = config.fees.minFees ?? 0
|
|
410
442
|
return Math.max(minFees, getRevealFee(address))
|
|
411
443
|
}
|