diff --git a/changelog.md b/changelog.md index 3d1298c64a..068070067a 100644 --- a/changelog.md +++ b/changelog.md @@ -20,6 +20,7 @@ * [3374](https://github.com/zeta-chain/node/pull/3374) - remove minimum rent exempt check for SPL token withdrawals * [3348](https://github.com/zeta-chain/node/pull/3348) - add support to perform withdraws in ZetaChain `onRevert` call +* [3416](https://github.com/zeta-chain/node/pull/3416) - add a check for nil gas price in the CheckTxFee function ## v25.0.0 diff --git a/rpc/types/utils.go b/rpc/types/utils.go index acc5eb553a..17ae4854cb 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -17,6 +17,7 @@ package types import ( "context" + "errors" "fmt" "math/big" "strings" @@ -308,6 +309,10 @@ func CheckTxFee(gasPrice *big.Int, gas uint64, feeCap float64) error { if feeCap == 0 { return nil } + // Return an error if gasPrice is nil + if gasPrice == nil { + return errors.New("gasprice is nil") + } totalfee := new(big.Float).SetInt(new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas))) // 1 photon in 10^18 aphoton oneToken := new(big.Float).SetInt(big.NewInt(params.Ether)) diff --git a/rpc/types/utils_test.go b/rpc/types/utils_test.go new file mode 100644 index 0000000000..296e34e6b2 --- /dev/null +++ b/rpc/types/utils_test.go @@ -0,0 +1,85 @@ +package types_test + +import ( + "math/big" + "testing" + + "github.com/zeta-chain/node/rpc/types" +) + +func TestCheckTxFee(t *testing.T) { + tests := []struct { + name string + gasPrice *big.Int + gas uint64 + feeCap float64 + wantErr bool + errMsg string + }{ + { + name: "valid transaction under cap", + gasPrice: big.NewInt(100000000000), // 100 Gwei + gas: 21000, // Standard ETH transfer + feeCap: 1.0, // 1 ETH cap + wantErr: false, + errMsg: "", + }, + { + name: "transaction exceeds cap", + gasPrice: big.NewInt(500000000000), // 500 Gwei + gas: 1000000, // Complex contract interaction + feeCap: 0.1, // 0.1 ETH cap + wantErr: true, + errMsg: "tx fee (0.50 ether) exceeds the configured cap (0.10 ether)", + }, + { + name: "nil gas price", + gasPrice: nil, + gas: 21000, + feeCap: 1.0, + wantErr: true, + errMsg: "gasprice is nil", + }, + { + name: "zero fee cap", + gasPrice: big.NewInt(100000000000), + gas: 21000, + feeCap: 0, + wantErr: false, + errMsg: "", + }, + { + name: "very low gas price", + gasPrice: big.NewInt(1), + gas: 21000, + feeCap: 1.0, + wantErr: false, + errMsg: "", + }, + { + name: "very high gas price", + gasPrice: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(100)), // 100 ETH per gas unit + gas: 21000, + feeCap: 1000.0, + wantErr: true, + errMsg: "tx fee (2100000.00 ether) exceeds the configured cap (1000.00 ether)", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := types.CheckTxFee(tt.gasPrice, tt.gas, tt.feeCap) + + // Check if we expected an error + if (err != nil) != tt.wantErr { + t.Errorf("CheckTxFee() error = %v, wantErr %v", err, tt.wantErr) + return + } + + // If we expected an error, verify the error message + if tt.wantErr && err.Error() != tt.errMsg { + t.Errorf("CheckTxFee() error message = %v, want %v", err.Error(), tt.errMsg) + } + }) + } +}