EstimateFee
Estimates the resources required by transactions when applied on a given state. This method simulates transaction execution without actually submitting transactions to the network, returning gas consumption and fee estimates for each transaction in the request.
Method Signature
func (provider *Provider) EstimateFee(
ctx context.Context,
requests []BroadcastTxn,
simulationFlags []SimulationFlag,
blockID BlockID,
) ([]FeeEstimation, error)Source: contract.go
Parameters
ctx(context.Context): Context for request cancellation and timeoutrequests([]BroadcastTxn): Sequence of transactions to estimate fees forsimulationFlags([]SimulationFlag): Flags describing transaction execution behaviorblockID(BlockID): Block identifier specifying the state to estimate against
Returns
[]FeeEstimation: Fee estimation for each transaction, including gas consumed and priceserror: Error if the request fails
Type Definitions
- Input Types (
BroadcastTxn,SimulationFlag,BlockID) define what transactions to estimate, how to simulate them, and at which block state. - Result Type (
FeeEstimation) returned fee estimate that embedsFeeEstimationCommonand adds the unit (FRI for L2 transactions). - Common Fee Fields (
FeeEstimationCommon) shared structure containing all gas consumption and pricing details (L1 gas, L2 gas, data gas, and overall fee)
The method accepts an array of BroadcastTxn (any v3 transaction type) with optional SimulationFlag values, and returns an array of FeeEstimation - one per input transaction. Each FeeEstimation contains detailed gas breakdowns through its embedded FeeEstimationCommon fields.
BroadcastTxn
type BroadcastTxn interface{}
var (
_ BroadcastTxn = (*BroadcastInvokeTxnV3)(nil)
_ BroadcastTxn = (*BroadcastDeclareTxnV3)(nil)
_ BroadcastTxn = (*BroadcastDeployAccountTxnV3)(nil)
)Source: types_broadcast_transaction.go
SimulationFlag
type SimulationFlag string
const (
SkipFeeCharge SimulationFlag = "SKIP_FEE_CHARGE"
SkipValidate SimulationFlag = "SKIP_VALIDATE"
)Flags that indicate how to simulate a given transaction. By default, the sequencer behaviour is replicated locally. Source: types_trace.go
FeeEstimation
type FeeEstimation struct {
FeeEstimationCommon
// Units in which the fee is given, can only be FRI
Unit PriceUnitFri `json:"unit"`
}Source: types.go
FeeEstimationCommon
type FeeEstimationCommon struct {
// The Ethereum gas consumption of the transaction, charged for L1->L2
// messages and, depending on the block's DA_MODE, state diffs
L1GasConsumed *felt.Felt `json:"l1_gas_consumed"`
// The gas price (in wei or fri, depending on the tx version) that was
// used in the cost estimation.
L1GasPrice *felt.Felt `json:"l1_gas_price"`
// The L2 gas consumption of the transaction
L2GasConsumed *felt.Felt `json:"l2_gas_consumed"`
// The L2 gas price (in wei or fri, depending on the tx version) that
// was used in the cost estimation.
L2GasPrice *felt.Felt `json:"l2_gas_price"`
// The Ethereum data gas consumption of the transaction.
L1DataGasConsumed *felt.Felt `json:"l1_data_gas_consumed"`
// The data gas price (in wei or fri, depending on the tx version) that
// was used in the cost estimation.
L1DataGasPrice *felt.Felt `json:"l1_data_gas_price"`
// The estimated fee for the transaction (in wei or fri, depending on the
// tx version), equals to gas_consumed*gas_price + data_gas_consumed*data_gas_price.
OverallFee *felt.Felt `json:"overall_fee"`
}Source: types.go
BlockID
The blockID parameter specifies which block state to query. You can identify a block in three ways:
type BlockID struct {
Number *uint64 `json:"block_number,omitempty"`
Hash *felt.Felt `json:"block_hash,omitempty"`
Tag BlockTag `json:"tag,omitempty"`
}Source: types_block.go
There are helper functions for creating BlockID. So Instead of manually creating the BlockID struct, use these convenience functions.
-
By Block Number - Get a specific block by its height
blockID := rpc.WithBlockNumber(123456)Source: block.go
-
By Block Hash - Get a specific block by its hash
hash, _ := new(felt.Felt).SetString("0x1234...") blockID := rpc.WithBlockHash(hash)Source: block.go
-
By Block Tag - Get a dynamic block reference
blockID := rpc.WithBlockTag("latest") // Latest accepted block blockID := rpc.WithBlockTag("pending") // Block currently being builtSource: block.go
Usage Example
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"github.com/NethermindEth/starknet.go/rpc"
"github.com/NethermindEth/starknet.go/utils"
"github.com/joho/godotenv"
)
func main() {
// Load environment variables from .env file
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
// Get RPC URL from environment variable
rpcURL := os.Getenv("STARKNET_RPC_URL")
if rpcURL == "" {
log.Fatal("STARKNET_RPC_URL not found in .env file")
}
// Initialize provider
provider, err := rpc.NewProvider(context.Background(), rpcURL)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Account address
senderAddress, err := utils.HexToFelt("0x36d67ab362562a97f9fba8a1051cf8e37ff1a1449530fb9f1f0e32ac2da7d06")
if err != nil {
log.Fatal(err)
}
// Get current nonce
nonce, err := provider.Nonce(ctx, rpc.WithBlockTag("latest"), senderAddress)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Current nonce: %s\n", nonce)
// Build transaction JSON with current nonce
txData := fmt.Sprintf(`{
"type": "INVOKE",
"version": "0x3",
"nonce": "%s",
"sender_address": "0x36d67ab362562a97f9fba8a1051cf8e37ff1a1449530fb9f1f0e32ac2da7d06",
"signature": [
"0x33a831e9428920f71c1df9248d4dbf9101fb5ee2bd100c0ad0d10c94c28dfe3",
"0x3fa865114ae29b2a49469401e11eb0db953a7d854916512c2ed400320405c8a"
],
"calldata": [
"0x1",
"0x669e24364ce0ae7ec2864fb03eedbe60cfbc9d1c74438d10fa4b86552907d54",
"0x2f0b3c5710379609eb5495f1ecd348cb28167711b73609fe565a72734550354",
"0x2",
"0xffffffff",
"0x0"
],
"resource_bounds": {
"l1_data_gas": {
"max_amount": "0x1e0",
"max_price_per_unit": "0x922"
},
"l1_gas": {
"max_amount": "0x0",
"max_price_per_unit": "0xfbfdefe2186"
},
"l2_gas": {
"max_amount": "0x16eea0",
"max_price_per_unit": "0x1830e58f7"
}
},
"tip": "0x0",
"paymaster_data": [],
"account_deployment_data": [],
"nonce_data_availability_mode": "L1",
"fee_data_availability_mode": "L1"
}`, nonce)
var invokeTx rpc.BroadcastInvokeTxnV3
if err := json.Unmarshal([]byte(txData), &invokeTx); err != nil {
log.Fatal(err)
}
// Estimate fee with SKIP_VALIDATE flag
result, err := provider.EstimateFee(
ctx,
[]rpc.BroadcastTxn{invokeTx},
[]rpc.SimulationFlag{rpc.SkipValidate},
rpc.WithBlockTag("latest"),
)
if err != nil {
log.Fatal(err)
}
resultJSON, _ := json.MarshalIndent(result, "", " ")
fmt.Printf("Fee estimate:\n%s\n", resultJSON)
}Error Handling
result, err := provider.EstimateFee(ctx, []rpc.BroadcastTxn{invokeTx}, []rpc.SimulationFlag{rpc.SkipValidate}, rpc.WithBlockTag("latest"))
if err != nil {
if errors.Is(err, rpc.ErrTxnExec) {
log.Printf("Transaction execution failed during estimation")
return
}
if errors.Is(err, rpc.ErrBlockNotFound) {
log.Printf("Block not found")
return
}
log.Printf("Error estimating fee: %v", err)
return
}
fmt.Printf("Overall fee: %s FRI\n", result[0].OverallFee)Common Use Cases
- Estimating transaction fees before sending to determine if the account has sufficient balance.
- Comparing fee estimates across different blocks to optimize transaction timing.
- Using simulation flags to skip validation when estimating fees for unsigned transactions.

