Estimate fees
By default, all non-free Starknet commands (declare, deploy, invoke) work without any cost limits.
You might want to inform the DAPP user of the cost of the incoming paid command before proceeding and requesting its validation.
Starknet.js proposes several functions to estimate the fees:
estimateInvokeFee
To estimate the cost to invoke a contract in the network:
const { suggestedMaxFee, unit } = await account0.estimateInvokeFee({
contractAddress: testAddress,
entrypoint: 'increase_balance',
calldata: ['10', '30'],
});
The result is in suggestedMaxFee
, of type BigInt. The corresponding unit for this number is in unit
. It's WEI for "legacy" transactions, and FRI for V3 transactions.
More details about the complex subject of Starknet fees in Starknet docs
The complete answer for a V3 transaction:
{
overall_fee: 4188627200000000000n,
unit: 'FRI',
l1_gas_consumed: 0n,
l1_gas_price: 100000000000n,
l2_gas_consumed: 41886080n,
l2_gas_price: 100000000000n,
l1_data_gas_consumed: 192n,
l1_data_gas_price: 100000000000n,
suggestedMaxFee: 6282940800000000000n,
resourceBounds: {
l2_gas: { max_amount: '0x3beb240', max_price_per_unit: '0x22ecb25c00' },
l1_gas: { max_amount: '0x0', max_price_per_unit: '0x22ecb25c00' },
l1_data_gas: { max_amount: '0x120', max_price_per_unit: '0x22ecb25c00' }
}
}
estimateDeclareFee
To estimate the cost to declare a contract in the network:
const { suggestedMaxFee } = await account0.estimateDeclareFee({
contract: compiledTest,
classHash: testClassHash,
});
The result is in suggestedMaxFee
, of type BigInt. The units and full response format are the same as invoke
.
estimateDeployFee
To estimate the cost to deploy a contract in the network:
const { suggestedMaxFee } = await account0.estimateDeployFee({
classHash: testClassHash,
// `constructorCalldata` is not necessary if the contract to deploy has no constructor
constructorCalldata: callData,
});
The result is in suggestedMaxFee
, of type BigInt. The units and full response format are the same as invoke
.
estimateAccountDeployFee
To estimate the cost to deploy an account in the network:
const { suggestedMaxFee } = await account0.estimateAccountDeployFee({
classHash: OZaccountClassHash,
constructorCalldata: OZaccountConstructorCallData,
contractAddress: OZcontractAddress,
});
The result is in suggestedMaxFee
, of type BigInt. Units and full response format are the same than invoke
.
Fee limitation
In some cases, a transaction can fail due to the fees being underestimated. You can increase these limits by setting a global config setting (default values are 50):
config.set('resourceBoundsOverhead', {
l1_gas: {
max_amount: 75,
max_price_per_unit: 60,
},
l2_gas: {
max_amount: 100,
max_price_per_unit: 60,
},
l1_data_gas: {
max_amount: 80,
max_price_per_unit: 70,
},
});
- Values are additional percentage: 75 means 75% additional fees.
- To get back to normal values: set all values to 50.
- In v8,
feeMarginPercentage
has been replaced withresourceBoundsOverhead
.
Example for declaring, with 80% additional fees:
config.set('resourceBoundsOverhead', {
l1_gas: {
max_amount: 80,
max_price_per_unit: 80,
},
l2_gas: {
max_amount: 80,
max_price_per_unit: 80,
},
l1_data_gas: {
max_amount: 80,
max_price_per_unit: 80,
},
});
const declareResponse = await account0.declareIfNot({ contract: testSierra, casm: testCasm });
Real fees paid
After a transaction has been processed, you can read the fees that have actually been paid:
const txR = await myProvider.waitForTransaction(declareResponse.transaction_hash);
txR.match({
success: (txR: SuccessfulTransactionReceiptResponse) => {
console.log('Fees paid =', txR.actual_fee);
},
_: () => {},
});
For STRK fees, the result is:
{ "unit": "FRI", "amount": "0x3a4f43814e180000" }
For ETH fees:
{ "unit": "WEI", "amount": "0x70c6fff3c000" }