Skip to content

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 timeout
  • requests ([]BroadcastTxn): Sequence of transactions to estimate fees for
  • simulationFlags ([]SimulationFlag): Flags describing transaction execution behavior
  • blockID (BlockID): Block identifier specifying the state to estimate against

Returns

  • []FeeEstimation: Fee estimation for each transaction, including gas consumed and prices
  • error: Error if the request fails

Type Definitions

  1. Input Types (BroadcastTxn, SimulationFlag, BlockID) define what transactions to estimate, how to simulate them, and at which block state.
  2. Result Type (FeeEstimation) returned fee estimate that embeds FeeEstimationCommon and adds the unit (FRI for L2 transactions).
  3. 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 built

    Source: 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.