135 lines
4.7 KiB
Go

package fees
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/errors"
"github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/services/wallet/common"
)
type GasFeeMode int
const (
GasFeeLow GasFeeMode = iota
GasFeeMedium
GasFeeHigh
GasFeeCustom
)
var (
ErrCustomFeeModeNotAvailableInSuggestedFees = &errors.ErrorResponse{Code: errors.ErrorCode("WRF-001"), Details: "custom fee mode is not available in suggested fees"}
ErrEIP1559IncompaibleChain = &errors.ErrorResponse{Code: errors.ErrorCode("WRF-002"), Details: "EIP-1559 is not supported on this chain"}
ErrInvalidRewardData = &errors.ErrorResponse{Code: errors.ErrorCode("WRF-003"), Details: "invalid reward data"}
)
type MaxFeesLevels struct {
Low *hexutil.Big `json:"low"`
Medium *hexutil.Big `json:"medium"`
High *hexutil.Big `json:"high"`
}
type MaxPriorityFeesSuggestedBounds struct {
Lower *big.Int
Upper *big.Int
}
type SuggestedFees struct {
GasPrice *big.Int
BaseFee *big.Int
CurrentBaseFee *big.Int // Current network base fee (in ETH WEI)
MaxFeesLevels *MaxFeesLevels
MaxPriorityFeePerGas *big.Int
MaxPriorityFeeSuggestedBounds *MaxPriorityFeesSuggestedBounds
L1GasFee *big.Float
EIP1559Enabled bool
}
// //////////////////////////////////////////////////////////////////////////////
// TODO: remove `SuggestedFeesGwei` struct once new router is in place
// //////////////////////////////////////////////////////////////////////////////
type SuggestedFeesGwei struct {
GasPrice *big.Float `json:"gasPrice"`
BaseFee *big.Float `json:"baseFee"`
MaxPriorityFeePerGas *big.Float `json:"maxPriorityFeePerGas"`
MaxFeePerGasLow *big.Float `json:"maxFeePerGasLow"`
MaxFeePerGasMedium *big.Float `json:"maxFeePerGasMedium"`
MaxFeePerGasHigh *big.Float `json:"maxFeePerGasHigh"`
MaxFeePerGasCustom *big.Float `json:"maxFeePerGasCustom"`
L1GasFee *big.Float `json:"l1GasFee,omitempty"`
EIP1559Enabled bool `json:"eip1559Enabled"`
}
func (m *MaxFeesLevels) FeeFor(mode GasFeeMode) (*big.Int, error) {
if mode == GasFeeCustom {
return nil, ErrCustomFeeModeNotAvailableInSuggestedFees
}
if mode == GasFeeLow {
return m.Low.ToInt(), nil
}
if mode == GasFeeHigh {
return m.High.ToInt(), nil
}
return m.Medium.ToInt(), nil
}
func (s *SuggestedFees) FeeFor(mode GasFeeMode) (*big.Int, error) {
return s.MaxFeesLevels.FeeFor(mode)
}
type FeeManager struct {
RPCClient rpc.ClientInterface
}
func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64) (*SuggestedFees, error) {
feeHistory, err := f.getFeeHistory(ctx, chainID, 300, "latest", []int{25, 50, 75})
if err != nil {
return f.getNonEIP1559SuggestedFees(ctx, chainID)
}
maxPriorityFeePerGasLowerBound, maxPriorityFeePerGas, maxPriorityFeePerGasUpperBound, baseFee, err := getEIP1559SuggestedFees(feeHistory)
if err != nil {
return f.getNonEIP1559SuggestedFees(ctx, chainID)
}
return &SuggestedFees{
BaseFee: baseFee,
CurrentBaseFee: baseFee,
MaxPriorityFeePerGas: maxPriorityFeePerGas,
MaxPriorityFeeSuggestedBounds: &MaxPriorityFeesSuggestedBounds{
Lower: maxPriorityFeePerGasLowerBound,
Upper: maxPriorityFeePerGasUpperBound,
},
MaxFeesLevels: &MaxFeesLevels{
Low: (*hexutil.Big)(new(big.Int).Add(baseFee, maxPriorityFeePerGas)),
Medium: (*hexutil.Big)(new(big.Int).Add(new(big.Int).Mul(baseFee, big.NewInt(2)), maxPriorityFeePerGas)),
High: (*hexutil.Big)(new(big.Int).Add(new(big.Int).Mul(baseFee, big.NewInt(3)), maxPriorityFeePerGas)),
},
EIP1559Enabled: true,
}, nil
}
// //////////////////////////////////////////////////////////////////////////////
// TODO: remove `SuggestedFeesGwei` once mobile app fully switched to router, this function should not be exposed via api
// //////////////////////////////////////////////////////////////////////////////
func (f *FeeManager) SuggestedFeesGwei(ctx context.Context, chainID uint64) (*SuggestedFeesGwei, error) {
fees, err := f.SuggestedFees(ctx, chainID)
if err != nil {
return nil, err
}
return &SuggestedFeesGwei{
GasPrice: common.WeiToGwei(fees.GasPrice),
BaseFee: common.WeiToGwei(fees.BaseFee),
MaxPriorityFeePerGas: common.WeiToGwei(fees.MaxPriorityFeePerGas),
MaxFeePerGasLow: common.WeiToGwei(fees.MaxFeesLevels.Low.ToInt()),
MaxFeePerGasMedium: common.WeiToGwei(fees.MaxFeesLevels.Medium.ToInt()),
MaxFeePerGasHigh: common.WeiToGwei(fees.MaxFeesLevels.High.ToInt()),
EIP1559Enabled: fees.EIP1559Enabled,
}, nil
}