diff --git a/jsonrpc/backend/backend.go b/jsonrpc/backend/backend.go
index 505f895..4f39d85 100644
--- a/jsonrpc/backend/backend.go
+++ b/jsonrpc/backend/backend.go
@@ -2,6 +2,7 @@ package backend
 
 import (
 	"context"
+	"fmt"
 	"sync"
 	"time"
 
@@ -39,6 +40,11 @@ type JSONRPCBackend struct {
 	txLookupCache *lru.Cache[common.Hash, *rpctypes.RPCTransaction]
 	receiptCache  *lru.Cache[common.Hash, *coretypes.Receipt]
 
+	// fee cache
+	feeDenom    string
+	feeDecimals uint8
+	feeMutex    sync.RWMutex
+
 	mut     sync.Mutex // mutex for accMuts
 	accMuts map[string]*AccMut
 
@@ -65,6 +71,7 @@ const (
 
 // NewJSONRPCBackend creates a new JSONRPCBackend instance
 func NewJSONRPCBackend(
+	ctx context.Context,
 	app *app.MinitiaApp,
 	logger log.Logger,
 	svrCtx *server.Context,
@@ -86,8 +93,7 @@ func NewJSONRPCBackend(
 		return nil, err
 	}
 
-	ctx := context.Background()
-	return &JSONRPCBackend{
+	b := &JSONRPCBackend{
 		app:    app,
 		logger: logger,
 
@@ -113,7 +119,70 @@ func NewJSONRPCBackend(
 		svrCtx:    svrCtx,
 		clientCtx: clientCtx,
 		cfg:       cfg,
-	}, nil
+	}
+
+	// start fee fetcher
+	go b.feeFetcher()
+
+	return b, nil
+}
+
+func (b *JSONRPCBackend) feeInfo() (string, uint8, error) {
+	b.feeMutex.RLock()
+	defer b.feeMutex.RUnlock()
+
+	if b.feeDenom == "" {
+		return "", 0, NewInternalError("jsonrpc is not ready")
+	}
+
+	return b.feeDenom, b.feeDecimals, nil
+}
+
+func (b *JSONRPCBackend) feeFetcher() {
+	fetcher := func() (err error) {
+		defer func() {
+			if r := recover(); r != nil {
+				err = fmt.Errorf("feeFetcher panic: %v", r)
+			}
+		}()
+
+		queryCtx, err := b.getQueryCtx()
+		if err != nil {
+			return err
+		}
+
+		params, err := b.app.EVMKeeper.Params.Get(queryCtx)
+		if err != nil {
+			return err
+		}
+
+		feeDenom := params.FeeDenom
+		decimals, err := b.app.EVMKeeper.ERC20Keeper().GetDecimals(queryCtx, feeDenom)
+		if err != nil {
+			return err
+		}
+
+		b.feeMutex.Lock()
+		b.feeDenom = feeDenom
+		b.feeDecimals = decimals
+		b.feeMutex.Unlock()
+
+		return nil
+	}
+
+	ticker := time.NewTicker(3 * time.Second)
+	defer ticker.Stop()
+
+	for {
+		select {
+		case <-ticker.C:
+			if err := fetcher(); err != nil {
+				b.logger.Error("failed to fetch fee", "err", err)
+			}
+		case <-b.ctx.Done():
+			return
+		}
+	}
 }
 
 type AccMut struct {
diff --git a/jsonrpc/backend/eth.go b/jsonrpc/backend/eth.go
index ac76657..1376f42 100644
--- a/jsonrpc/backend/eth.go
+++ b/jsonrpc/backend/eth.go
@@ -25,7 +25,7 @@ func (b *JSONRPCBackend) GetBalance(address common.Address, blockNrOrHash rpc.Bl
 		return nil, err
 	}
 
-	feeDenom, decimals, err := b.feeDenomWithDecimals()
+	feeDenom, feeDecimals, err := b.feeInfo()
 	if err != nil {
 		return nil, err
 	}
@@ -35,7 +35,7 @@ func (b *JSONRPCBackend) GetBalance(address common.Address, blockNrOrHash rpc.Bl
 		return nil, err
 	}
 
-	return (*hexutil.Big)(types.ToEthersUint(decimals, balance.BigInt())), nil
+	return (*hexutil.Big)(types.ToEthersUint(feeDecimals, balance.BigInt())), nil
 }
 
 func (b *JSONRPCBackend) Call(args rpctypes.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *rpctypes.StateOverride, blockOverrides *rpctypes.BlockOverrides) (hexutil.Bytes, error) {
diff --git a/jsonrpc/backend/gas.go b/jsonrpc/backend/gas.go
index 38d0fad..5158609 100644
--- a/jsonrpc/backend/gas.go
+++ b/jsonrpc/backend/gas.go
@@ -39,7 +39,7 @@ func (b *JSONRPCBackend) EstimateGas(args rpctypes.TransactionArgs, blockNrOrHas
 		return hexutil.Uint64(0), err
 	}
 
-	_, decimals, err := b.feeDenomWithDecimals()
+	_, feeDecimals, err := b.feeInfo()
 	if err != nil {
 		return hexutil.Uint64(0), err
 	}
@@ -49,14 +49,14 @@ func (b *JSONRPCBackend) EstimateGas(args rpctypes.TransactionArgs, blockNrOrHas
 		sdkMsgs = append(sdkMsgs, &types.MsgCreate{
 			Sender: sender,
 			Code:   hexutil.Encode(args.GetData()),
-			Value:  math.NewIntFromBigInt(types.FromEthersUnit(decimals, args.Value.ToInt())),
+			Value:  math.NewIntFromBigInt(types.FromEthersUnit(feeDecimals, args.Value.ToInt())),
 		})
 	} else {
 		sdkMsgs = append(sdkMsgs, &types.MsgCall{
 			Sender:       sender,
 			ContractAddr: args.To.Hex(),
 			Input:        hexutil.Encode(args.GetData()),
-			Value:        math.NewIntFromBigInt(types.FromEthersUnit(decimals, args.Value.ToInt())),
+			Value:        math.NewIntFromBigInt(types.FromEthersUnit(feeDecimals, args.Value.ToInt())),
 		})
 	}
 
@@ -90,39 +90,6 @@ func (b *JSONRPCBackend) EstimateGas(args rpctypes.TransactionArgs, blockNrOrHas
 	return hexutil.Uint64(gasInfo.GasUsed), nil
 }
 
-func (b *JSONRPCBackend) feeDenom() (string, error) {
-	queryCtx, err := b.getQueryCtx()
-	if err != nil {
-		return "", err
-	}
-
-	params, err := b.app.EVMKeeper.Params.Get(queryCtx)
-	if err != nil {
-		return "", err
-	}
-
-	return params.FeeDenom, nil
-}
-
-func (b *JSONRPCBackend) feeDenomWithDecimals() (string, uint8, error) {
-	feeDenom, err := b.feeDenom()
-	if err != nil {
-		return "", 0, err
-	}
-
-	queryCtx, err := b.getQueryCtx()
-	if err != nil {
-		return "", 0, err
-	}
-
-	decimals, err := b.app.EVMKeeper.ERC20Keeper().GetDecimals(queryCtx, feeDenom)
-	if err != nil {
-		return "", 0, err
-	}
-
-	return feeDenom, decimals, nil
-}
-
 func (b *JSONRPCBackend) GasPrice() (*hexutil.Big, error) {
 	queryCtx, err := b.getQueryCtx()
 	if err != nil {
@@ -134,17 +101,26 @@ func (b *JSONRPCBackend) GasPrice() (*hexutil.Big, error) {
 		return nil, err
 	}
 
-	feeDenom, decimals, err := b.feeDenomWithDecimals()
+	feeDenom, feeDecimals, err := b.feeInfo()
 	if err != nil {
 		return nil, err
 	}
 
+	// Multiply by 1e9 to maintain precision during conversion
+	// This adds 9 decimal places to prevent truncation errors
+	const precisionMultiplier = 1e9
+
 	// multiply by 1e9 to prevent decimal drops
 	gasPrice := params.MinGasPrices.AmountOf(feeDenom).
-		MulTruncate(math.LegacyNewDec(1e9)).
+		MulTruncate(math.LegacyNewDec(precisionMultiplier)).
 		TruncateInt().BigInt()
 
-	return (*hexutil.Big)(types.ToEthersUint(decimals+9, gasPrice)), nil
+	// Verify the result is within safe bounds
+	if gasPrice.BitLen() > 256 {
+		return nil, NewInternalError("gas price overflow")
+	}
+
+	return (*hexutil.Big)(types.ToEthersUint(feeDecimals+9, gasPrice)), nil
 }
 
 func (b *JSONRPCBackend) MaxPriorityFeePerGas() (*hexutil.Big, error) {
diff --git a/jsonrpc/jsonrpc.go b/jsonrpc/jsonrpc.go
index 88a7e9b..b33d036 100644
--- a/jsonrpc/jsonrpc.go
+++ b/jsonrpc/jsonrpc.go
@@ -64,7 +64,7 @@ func StartJSONRPC(
 	rpcServer := rpc.NewServer()
 	rpcServer.SetBatchLimits(jsonRPCConfig.BatchRequestLimit, jsonRPCConfig.BatchResponseMaxSize)
 
-	bkd, err := backend.NewJSONRPCBackend(app, logger, svrCtx, clientCtx, jsonRPCConfig)
+	bkd, err := backend.NewJSONRPCBackend(ctx, app, logger, svrCtx, clientCtx, jsonRPCConfig)
 	if err != nil {
 		return err
 	}
@@ -73,37 +73,37 @@ func StartJSONRPC(
 		{
 			Namespace: EthNamespace,
 			Version:   apiVersion,
-			Service:   ethns.NewEthAPI(logger, bkd),
+			Service:   ethns.NewEthAPI(ctx, logger, bkd),
 			Public:    true,
 		},
 		{
 			Namespace: EthNamespace,
 			Version:   apiVersion,
-			Service:   filters.NewFilterAPI(app, bkd, logger),
+			Service:   filters.NewFilterAPI(ctx, app, bkd, logger),
 			Public:    true,
 		},
 		{
 			Namespace: NetNamespace,
 			Version:   apiVersion,
-			Service:   netns.NewNetAPI(logger, bkd),
+			Service:   netns.NewNetAPI(ctx, logger, bkd),
 			Public:    true,
 		},
 		{
 			Namespace: Web3Namespace,
 			Version:   apiVersion,
-			Service:   web3ns.NewWeb3API(logger, bkd),
+			Service:   web3ns.NewWeb3API(ctx, logger, bkd),
 			Public:    true,
 		},
 		{
 			Namespace: TxPoolNamespace,
 			Version:   apiVersion,
-			Service:   txpoolns.NewTxPoolAPI(logger, bkd),
+			Service:   txpoolns.NewTxPoolAPI(ctx, logger, bkd),
 			Public:    true,
 		},
 		{
 			Namespace: CosmosNamespace,
 			Version:   apiVersion,
-			Service:   cosmosns.NewCosmosAPI(logger, bkd),
+			Service:   cosmosns.NewCosmosAPI(ctx, logger, bkd),
 			Public:    true,
 		},
 	}
diff --git a/jsonrpc/namespaces/cosmos/api.go b/jsonrpc/namespaces/cosmos/api.go
index 5689814..ccc7abf 100644
--- a/jsonrpc/namespaces/cosmos/api.go
+++ b/jsonrpc/namespaces/cosmos/api.go
@@ -17,9 +17,9 @@ type CosmosAPI struct {
 }
 
 // NewCosmosAPI creates an instance of the public ETH Web3 API.
-func NewCosmosAPI(logger log.Logger, backend *backend.JSONRPCBackend) *CosmosAPI {
+func NewCosmosAPI(ctx context.Context, logger log.Logger, backend *backend.JSONRPCBackend) *CosmosAPI {
 	api := &CosmosAPI{
-		ctx:     context.TODO(),
+		ctx:     ctx,
 		logger:  logger.With("client", "json-rpc"),
 		backend: backend,
 	}
diff --git a/jsonrpc/namespaces/eth/api.go b/jsonrpc/namespaces/eth/api.go
index b5d3abc..549bdd5 100644
--- a/jsonrpc/namespaces/eth/api.go
+++ b/jsonrpc/namespaces/eth/api.go
@@ -107,9 +107,9 @@ type EthAPI struct {
 }
 
 // NewEthAPI creates an instance of the public ETH Web3 API.
-func NewEthAPI(logger log.Logger, backend *backend.JSONRPCBackend) *EthAPI {
+func NewEthAPI(ctx context.Context, logger log.Logger, backend *backend.JSONRPCBackend) *EthAPI {
 	api := &EthAPI{
-		ctx:     context.TODO(),
+		ctx:     ctx,
 		logger:  logger.With("client", "json-rpc"),
 		backend: backend,
 	}
diff --git a/jsonrpc/namespaces/eth/filters/api.go b/jsonrpc/namespaces/eth/filters/api.go
index 092c837..9332a06 100644
--- a/jsonrpc/namespaces/eth/filters/api.go
+++ b/jsonrpc/namespaces/eth/filters/api.go
@@ -42,6 +42,8 @@ type filter struct {
 
 // FilterAPI is the eth_ filter namespace API
 type FilterAPI struct {
+	ctx context.Context
+
 	app     *app.MinitiaApp
 	backend *backend.JSONRPCBackend
 
@@ -63,9 +65,11 @@ type FilterAPI struct {
 }
 
 // NewFiltersAPI returns a new instance
-func NewFilterAPI(app *app.MinitiaApp, backend *backend.JSONRPCBackend, logger log.Logger) *FilterAPI {
+func NewFilterAPI(ctx context.Context, app *app.MinitiaApp, backend *backend.JSONRPCBackend, logger log.Logger) *FilterAPI {
 	logger = logger.With("api", "filter")
 	api := &FilterAPI{
+		ctx: ctx,
+
 		app:     app,
 		backend: backend,
 
@@ -98,23 +102,27 @@ func (api *FilterAPI) clearUnusedFilters() {
 
 	var toUninstall []*subscription
 	for {
-		<-ticker.C
-		api.filtersMut.Lock()
-		for id, f := range api.filters {
-			if time.Since(f.lastUsed) > timeout {
-				toUninstall = append(toUninstall, f.s)
-				delete(api.filters, id)
+		select {
+		case <-ticker.C:
+			api.filtersMut.Lock()
+			for id, f := range api.filters {
+				if time.Since(f.lastUsed) > timeout {
+					toUninstall = append(toUninstall, f.s)
+					delete(api.filters, id)
+				}
 			}
-		}
-		api.filtersMut.Unlock()
+			api.filtersMut.Unlock()
 
-		// Unsubscribes are processed outside the lock to avoid the following scenario:
-		// event loop attempts broadcasting events to still active filters while
-		// Unsubscribe is waiting for it to process the uninstall request.
-		for _, s := range toUninstall {
-			api.uninstallSubscription(s)
+			// Unsubscribes are processed outside the lock to avoid the following scenario:
+			// event loop attempts broadcasting events to still active filters while
+			// Unsubscribe is waiting for it to process the uninstall request.
+			for _, s := range toUninstall {
+				api.uninstallSubscription(s)
+			}
+			toUninstall = nil
+		case <-api.ctx.Done():
+			return
 		}
-		toUninstall = nil
 	}
 }
 
@@ -155,6 +163,8 @@ func (api *FilterAPI) eventLoop() {
 		case s := <-api.uninstall:
 			delete(api.subscriptions, s.id)
 			close(s.err)
+		case <-api.ctx.Done():
+			return
 		}
 	}
 }
diff --git a/jsonrpc/namespaces/net/api.go b/jsonrpc/namespaces/net/api.go
index 23c8732..fc3b8ff 100644
--- a/jsonrpc/namespaces/net/api.go
+++ b/jsonrpc/namespaces/net/api.go
@@ -24,9 +24,9 @@ type NetAPI struct {
 }
 
 // NewNetAPI creates a new net API instance
-func NewNetAPI(logger log.Logger, backend *backend.JSONRPCBackend) *NetAPI {
+func NewNetAPI(ctx context.Context, logger log.Logger, backend *backend.JSONRPCBackend) *NetAPI {
 	return &NetAPI{
-		ctx:     context.TODO(),
+		ctx:     ctx,
 		logger:  logger,
 		backend: backend,
 	}
diff --git a/jsonrpc/namespaces/txpool/api.go b/jsonrpc/namespaces/txpool/api.go
index b64bb69..5cc78f8 100644
--- a/jsonrpc/namespaces/txpool/api.go
+++ b/jsonrpc/namespaces/txpool/api.go
@@ -32,9 +32,9 @@ type TxPoolAPI struct {
 }
 
 // NewTxPoolAPI creates a new txpool API instance.
-func NewTxPoolAPI(logger log.Logger, backend *backend.JSONRPCBackend) *TxPoolAPI {
+func NewTxPoolAPI(ctx context.Context, logger log.Logger, backend *backend.JSONRPCBackend) *TxPoolAPI {
 	return &TxPoolAPI{
-		ctx:     context.TODO(),
+		ctx:     ctx,
 		logger:  logger,
 		backend: backend,
 	}
diff --git a/jsonrpc/namespaces/web3/api.go b/jsonrpc/namespaces/web3/api.go
index 115e26a..cfb7f95 100644
--- a/jsonrpc/namespaces/web3/api.go
+++ b/jsonrpc/namespaces/web3/api.go
@@ -25,9 +25,9 @@ type Web3API struct {
 }
 
 // NewWeb3API creates a new net API instance
-func NewWeb3API(logger log.Logger, backend *backend.JSONRPCBackend) *Web3API {
+func NewWeb3API(ctx context.Context, logger log.Logger, backend *backend.JSONRPCBackend) *Web3API {
 	return &Web3API{
-		ctx:     context.TODO(),
+		ctx:     ctx,
 		logger:  logger,
 		backend: backend,
 	}