diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index 83d0db05b921be376df5ebcb8d11c66d6cceed67..cfbe2914d51e7d8e33ec47b6287c2b4e317157ee 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -39,6 +39,7 @@ import (
 	"github.com/ethereum/go-ethereum/eth/filters"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rpc"
 )
@@ -401,6 +402,27 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
 	} else {
 		hi = b.pendingBlock.GasLimit()
 	}
+	// Recap the highest gas allowance with account's balance.
+	if call.GasPrice != nil && call.GasPrice.Uint64() != 0 {
+		balance := b.pendingState.GetBalance(call.From) // from can't be nil
+		available := new(big.Int).Set(balance)
+		if call.Value != nil {
+			if call.Value.Cmp(available) >= 0 {
+				return 0, errors.New("insufficient funds for transfer")
+			}
+			available.Sub(available, call.Value)
+		}
+		allowance := new(big.Int).Div(available, call.GasPrice)
+		if hi > allowance.Uint64() {
+			transfer := call.Value
+			if transfer == nil {
+				transfer = new(big.Int)
+			}
+			log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
+				"sent", transfer, "gasprice", call.GasPrice, "fundable", allowance)
+			hi = allowance.Uint64()
+		}
+	}
 	cap = hi
 
 	// Create a helper to check if a gas allowance results in an executable transaction
diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go
index a28f99aeaac5838f49b55389c74bd3c2a0f9d1c1..a55b4460aa8ad1138f8ba84dc377f748945817ef 100644
--- a/accounts/abi/bind/backends/simulated_test.go
+++ b/accounts/abi/bind/backends/simulated_test.go
@@ -466,6 +466,73 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
 	}
 }
 
+func TestSimulatedBackend_EstimateGasWithPrice(t *testing.T) {
+	key, _ := crypto.GenerateKey()
+	addr := crypto.PubkeyToAddress(key.PublicKey)
+
+	sim := NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether*2 + 2e17)}}, 10000000)
+	defer sim.Close()
+
+	receipant := common.HexToAddress("deadbeef")
+	var cases = []struct {
+		name        string
+		message     ethereum.CallMsg
+		expect      uint64
+		expectError error
+	}{
+		{"EstimateWithoutPrice", ethereum.CallMsg{
+			From:     addr,
+			To:       &receipant,
+			Gas:      0,
+			GasPrice: big.NewInt(0),
+			Value:    big.NewInt(1000),
+			Data:     nil,
+		}, 21000, nil},
+
+		{"EstimateWithPrice", ethereum.CallMsg{
+			From:     addr,
+			To:       &receipant,
+			Gas:      0,
+			GasPrice: big.NewInt(1000),
+			Value:    big.NewInt(1000),
+			Data:     nil,
+		}, 21000, nil},
+
+		{"EstimateWithVeryHighPrice", ethereum.CallMsg{
+			From:     addr,
+			To:       &receipant,
+			Gas:      0,
+			GasPrice: big.NewInt(1e14), // gascost = 2.1ether
+			Value:    big.NewInt(1e17), // the remaining balance for fee is 2.1ether
+			Data:     nil,
+		}, 21000, nil},
+
+		{"EstimateWithSuperhighPrice", ethereum.CallMsg{
+			From:     addr,
+			To:       &receipant,
+			Gas:      0,
+			GasPrice: big.NewInt(2e14), // gascost = 4.2ether
+			Value:    big.NewInt(1000),
+			Data:     nil,
+		}, 21000, errors.New("gas required exceeds allowance (10999)")}, // 10999=(2.2ether-1000wei)/(2e14)
+	}
+	for _, c := range cases {
+		got, err := sim.EstimateGas(context.Background(), c.message)
+		if c.expectError != nil {
+			if err == nil {
+				t.Fatalf("Expect error, got nil")
+			}
+			if c.expectError.Error() != err.Error() {
+				t.Fatalf("Expect error, want %v, got %v", c.expectError, err)
+			}
+			continue
+		}
+		if got != c.expect {
+			t.Fatalf("Gas estimation mismatch, want %d, got %d", c.expect, got)
+		}
+	}
+}
+
 func TestSimulatedBackend_HeaderByHash(t *testing.T) {
 	testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
 
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index febfcb22425ddba400874b98ef3f42563283b55c..45240aa2cfb710c1deff43a76632d0299da937b3 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -906,6 +906,11 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
 		hi  uint64
 		cap uint64
 	)
+	// Use zero address if sender unspecified.
+	if args.From == nil {
+		args.From = new(common.Address)
+	}
+	// Determine the highest gas limit can be used during the estimation.
 	if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
 		hi = uint64(*args.Gas)
 	} else {
@@ -916,16 +921,38 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
 		}
 		hi = block.GasLimit()
 	}
+	// Recap the highest gas limit with account's available balance.
+	if args.GasPrice != nil && args.GasPrice.ToInt().Uint64() != 0 {
+		state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
+		if err != nil {
+			return 0, err
+		}
+		balance := state.GetBalance(*args.From) // from can't be nil
+		available := new(big.Int).Set(balance)
+		if args.Value != nil {
+			if args.Value.ToInt().Cmp(available) >= 0 {
+				return 0, errors.New("insufficient funds for transfer")
+			}
+			available.Sub(available, args.Value.ToInt())
+		}
+		allowance := new(big.Int).Div(available, args.GasPrice.ToInt())
+		if hi > allowance.Uint64() {
+			transfer := args.Value
+			if transfer == nil {
+				transfer = new(hexutil.Big)
+			}
+			log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
+				"sent", transfer.ToInt(), "gasprice", args.GasPrice.ToInt(), "fundable", allowance)
+			hi = allowance.Uint64()
+		}
+	}
+	// Recap the highest gas allowance with specified gascap.
 	if gasCap != nil && hi > gasCap.Uint64() {
 		log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
 		hi = gasCap.Uint64()
 	}
 	cap = hi
 
-	// Use zero address if sender unspecified.
-	if args.From == nil {
-		args.From = new(common.Address)
-	}
 	// Create a helper to check if a gas allowance results in an executable transaction
 	executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
 		args.Gas = (*hexutil.Uint64)(&gas)