feat_: change how we compute fees

This commit is contained in:
Anthony 2024-06-19 11:20:41 +02:00 committed by Anthony Laibe
parent 2b7d153826
commit fb261e4a0e
5 changed files with 95 additions and 134 deletions

View File

@ -23,8 +23,8 @@ import (
)
type CommunityTokenFees struct {
GasUnits uint64 `json:"gasUnits"`
SuggestedFees *router.SuggestedFees `json:"suggestedFees"`
GasUnits uint64 `json:"gasUnits"`
SuggestedFees *router.SuggestedFeesGwei `json:"suggestedFees"`
}
func weiToGwei(val *big.Int) *big.Float {
@ -356,7 +356,7 @@ func (s *Service) mintTokensGasUnits(ctx context.Context, chainID uint64, contra
}
func (s *Service) prepareCommunityTokenFees(ctx context.Context, from common.Address, to *common.Address, gasUnits uint64, chainID uint64) (*CommunityTokenFees, error) {
suggestedFees, err := s.feeManager.SuggestedFees(ctx, chainID)
suggestedFees, err := s.feeManager.SuggestedFeesGwei(ctx, chainID)
if err != nil {
return nil, err
}
@ -373,7 +373,7 @@ func (s *Service) prepareCommunityTokenFees(ctx context.Context, from common.Add
}, nil
}
func (s *Service) suggestedFeesToSendTxArgs(from common.Address, to *common.Address, gas uint64, suggestedFees *router.SuggestedFees) transactions.SendTxArgs {
func (s *Service) suggestedFeesToSendTxArgs(from common.Address, to *common.Address, gas uint64, suggestedFees *router.SuggestedFeesGwei) transactions.SendTxArgs {
sendArgs := transactions.SendTxArgs{}
sendArgs.From = types.Address(from)
sendArgs.To = (*types.Address)(to)

View File

@ -416,9 +416,9 @@ func (api *API) FetchTokenDetails(ctx context.Context, symbols []string) (map[st
return api.s.marketManager.FetchTokenDetails(symbols)
}
func (api *API) GetSuggestedFees(ctx context.Context, chainID uint64) (*router.SuggestedFees, error) {
func (api *API) GetSuggestedFees(ctx context.Context, chainID uint64) (*router.SuggestedFeesGwei, error) {
log.Debug("call to GetSuggestedFees")
return api.router.GetFeesManager().SuggestedFees(ctx, chainID)
return api.router.GetFeesManager().SuggestedFeesGwei(ctx, chainID)
}
func (api *API) GetEstimatedLatestBlockNumber(ctx context.Context, chainID uint64) (uint64, error) {
@ -429,7 +429,12 @@ func (api *API) GetEstimatedLatestBlockNumber(ctx context.Context, chainID uint6
// @deprecated
func (api *API) GetTransactionEstimatedTime(ctx context.Context, chainID uint64, maxFeePerGas *big.Float) (router.TransactionEstimation, error) {
log.Debug("call to getTransactionEstimatedTime")
return api.router.GetFeesManager().TransactionEstimatedTime(ctx, chainID, maxFeePerGas), nil
return api.router.GetFeesManager().TransactionEstimatedTime(ctx, chainID, gweiToWei(maxFeePerGas)), nil
}
func gweiToWei(val *big.Float) *big.Int {
res, _ := new(big.Float).Mul(val, big.NewFloat(1000000000)).Int(nil)
return res
}
func (api *API) GetSuggestedRoutes(

View File

@ -24,10 +24,25 @@ const (
GasFeeHigh
)
// //////////////////////////////////////////////////////////////////////////////
// TODO: remove `SuggestedFees` struct once new router is in place
// //////////////////////////////////////////////////////////////////////////////
type MaxFeesLevels struct {
Low *big.Int `json:"low"`
Medium *big.Int `json:"medium"`
High *big.Int `json:"high"`
}
type SuggestedFees struct {
GasPrice *big.Int `json:"gasPrice"`
BaseFee *big.Int `json:"baseFee"`
MaxFeesLevels *MaxFeesLevels `json:"maxFeesLevels"`
MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas"`
L1GasFee *big.Float `json:"l1GasFee,omitempty"`
EIP1559Enabled bool `json:"eip1559Enabled"`
}
// //////////////////////////////////////////////////////////////////////////////
// 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"`
@ -38,13 +53,23 @@ type SuggestedFees struct {
EIP1559Enabled bool `json:"eip1559Enabled"`
}
type PriorityFees struct {
Low *big.Int `json:"low"`
Medium *big.Int `json:"medium"`
High *big.Int `json:"high"`
func (s *SuggestedFees) feeFor(mode GasFeeMode) *big.Int {
if !s.EIP1559Enabled {
return s.GasPrice
}
if mode == GasFeeLow {
return s.MaxFeesLevels.Low
}
if mode == GasFeeHigh {
return s.MaxFeesLevels.High
}
return s.MaxFeesLevels.Medium
}
func (s *SuggestedFees) feeFor(mode GasFeeMode) *big.Float {
func (s *SuggestedFeesGwei) feeFor(mode GasFeeMode) *big.Float {
if !s.EIP1559Enabled {
return s.GasPrice
}
@ -99,12 +124,6 @@ func gweiToWei(val *big.Float) *big.Int {
return res
}
// //////////////////////////////////////////////////////////////////////////////
// TODO: remove `suggestedFees` function once new router is in place
//
// But we should check the client since this function is exposed to API as `GetSuggestedFees` call.
// Maybe we should keep it and remove it later when the client is ready for that change.
// //////////////////////////////////////////////////////////////////////////////
func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64) (*SuggestedFees, error) {
backend, err := f.RPCClient.EthClient(chainID)
if err != nil {
@ -117,13 +136,15 @@ func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64) (*Sugges
maxPriorityFeePerGas, err := backend.SuggestGasTipCap(ctx)
if err != nil {
return &SuggestedFees{
GasPrice: weiToGwei(gasPrice),
BaseFee: big.NewFloat(0),
MaxPriorityFeePerGas: big.NewFloat(0),
MaxFeePerGasLow: big.NewFloat(0),
MaxFeePerGasMedium: big.NewFloat(0),
MaxFeePerGasHigh: big.NewFloat(0),
EIP1559Enabled: false,
GasPrice: gasPrice,
BaseFee: big.NewInt(0),
MaxPriorityFeePerGas: big.NewInt(0),
MaxFeesLevels: &MaxFeesLevels{
Low: big.NewInt(0),
Medium: big.NewInt(0),
High: big.NewInt(0),
},
EIP1559Enabled: false,
}, nil
}
@ -132,47 +153,32 @@ func (f *FeeManager) SuggestedFees(ctx context.Context, chainID uint64) (*Sugges
return nil, err
}
fees, err := f.getFeeHistorySorted(chainID)
if err != nil {
return &SuggestedFees{
GasPrice: weiToGwei(gasPrice),
BaseFee: weiToGwei(baseFee),
MaxPriorityFeePerGas: weiToGwei(maxPriorityFeePerGas),
MaxFeePerGasLow: weiToGwei(maxPriorityFeePerGas),
MaxFeePerGasMedium: weiToGwei(maxPriorityFeePerGas),
MaxFeePerGasHigh: weiToGwei(maxPriorityFeePerGas),
EIP1559Enabled: false,
}, nil
}
perc10 := fees[int64(0.1*float64(len(fees)))-1]
perc20 := fees[int64(0.2*float64(len(fees)))-1]
var maxFeePerGasMedium *big.Int
if baseFee.Cmp(perc20) >= 0 {
maxFeePerGasMedium = baseFee
} else {
maxFeePerGasMedium = perc20
}
if maxPriorityFeePerGas.Cmp(maxFeePerGasMedium) > 0 {
maxFeePerGasMedium = maxPriorityFeePerGas
}
maxFeePerGasHigh := new(big.Int).Mul(maxPriorityFeePerGas, big.NewInt(2))
twoTimesBaseFee := new(big.Int).Mul(baseFee, big.NewInt(2))
if twoTimesBaseFee.Cmp(maxFeePerGasHigh) > 0 {
maxFeePerGasHigh = twoTimesBaseFee
}
return &SuggestedFees{
GasPrice: weiToGwei(gasPrice),
BaseFee: weiToGwei(baseFee),
MaxPriorityFeePerGas: weiToGwei(maxPriorityFeePerGas),
MaxFeePerGasLow: weiToGwei(perc10),
MaxFeePerGasMedium: weiToGwei(maxFeePerGasMedium),
MaxFeePerGasHigh: weiToGwei(maxFeePerGasHigh),
EIP1559Enabled: true,
GasPrice: gasPrice,
BaseFee: baseFee,
MaxPriorityFeePerGas: maxPriorityFeePerGas,
MaxFeesLevels: &MaxFeesLevels{
Low: new(big.Int).Add(baseFee, maxPriorityFeePerGas),
Medium: new(big.Int).Add(new(big.Int).Mul(baseFee, big.NewInt(2)), maxPriorityFeePerGas),
High: new(big.Int).Add(new(big.Int).Mul(baseFee, big.NewInt(3)), maxPriorityFeePerGas),
},
EIP1559Enabled: true,
}, nil
}
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: weiToGwei(fees.GasPrice),
BaseFee: weiToGwei(fees.BaseFee),
MaxPriorityFeePerGas: weiToGwei(fees.MaxPriorityFeePerGas),
MaxFeePerGasLow: weiToGwei(fees.MaxFeesLevels.Low),
MaxFeePerGasMedium: weiToGwei(fees.MaxFeesLevels.Medium),
MaxFeePerGasHigh: weiToGwei(fees.MaxFeesLevels.High),
EIP1559Enabled: fees.EIP1559Enabled,
}, nil
}
@ -200,54 +206,17 @@ func (f *FeeManager) getBaseFee(ctx context.Context, client chain.ClientInterfac
return baseFee, nil
}
func (f *FeeManager) getPriorityFees(ctx context.Context, client chain.ClientInterface, baseFee *big.Int) (PriorityFees, error) {
var priorityFee PriorityFees
fees, err := f.getFeeHistorySorted(client.NetworkID())
if err != nil {
return priorityFee, err
}
suggestedPriorityFee, err := client.SuggestGasTipCap(ctx)
if err != nil {
return priorityFee, err
}
// Calculate Low priority fee
priorityFee.Low = fees[int64(0.1*float64(len(fees)))-1]
// Calculate Medium priority fee
priorityFee.Medium = fees[int64(0.2*float64(len(fees)))-1]
if baseFee.Cmp(priorityFee.Medium) > 0 {
priorityFee.Medium = baseFee
}
if suggestedPriorityFee.Cmp(priorityFee.Medium) > 0 {
priorityFee.Medium = suggestedPriorityFee
}
// Calculate High priority fee
priorityFee.High = new(big.Int).Mul(suggestedPriorityFee, big.NewInt(2))
twoTimesBaseFee := new(big.Int).Mul(baseFee, big.NewInt(2))
if twoTimesBaseFee.Cmp(priorityFee.High) > 0 {
priorityFee.High = twoTimesBaseFee
}
return priorityFee, nil
}
func (f *FeeManager) TransactionEstimatedTime(ctx context.Context, chainID uint64, maxFeePerGas *big.Float) TransactionEstimation {
func (f *FeeManager) TransactionEstimatedTime(ctx context.Context, chainID uint64, maxFeePerGas *big.Int) TransactionEstimation {
fees, err := f.getFeeHistorySorted(chainID)
if err != nil {
return Unknown
}
maxFeePerGasWei := gweiToWei(maxFeePerGas)
// pEvent represents the probability of the transaction being included in a block,
// we assume this one is static over time, in reality it is not.
pEvent := 0.0
for idx, fee := range fees {
if fee.Cmp(maxFeePerGasWei) == 1 || idx == len(fees)-1 {
if fee.Cmp(maxFeePerGas) == 1 || idx == len(fees)-1 {
pEvent = float64(idx) / float64(len(fees))
break
}

View File

@ -51,7 +51,7 @@ type Path struct {
AmountInLocked bool
AmountOut *hexutil.Big
GasAmount uint64
GasFees *SuggestedFees
GasFees *SuggestedFeesGwei
BonderFees *hexutil.Big
TokenFees *big.Float
Cost *big.Float
@ -522,7 +522,7 @@ func (r *Router) SuggestedRoutes(
}
group.Add(func(c context.Context) error {
gasFees, err := r.feesManager.SuggestedFees(ctx, network.ChainID)
gasFees, err := r.feesManager.SuggestedFeesGwei(ctx, network.ChainID)
if err != nil {
return err
}
@ -555,7 +555,7 @@ func (r *Router) SuggestedRoutes(
}
maxFees := gasFees.feeFor(gasFeeMode)
estimatedTime := r.feesManager.TransactionEstimatedTime(ctx, network.ChainID, maxFees)
estimatedTime := r.feesManager.TransactionEstimatedTime(ctx, network.ChainID, gweiToWei(maxFees))
for _, pProcessor := range r.pathProcessors {
// Skip processors that are added because of the Router V2, to not break the current functionality
if pProcessor.Name() == pathprocessor.ProcessorENSRegisterName ||

View File

@ -62,10 +62,10 @@ type PathV2 struct {
AmountInLocked bool // Is the amount locked
AmountOut *hexutil.Big // Amount that will be received on the destination chain
SuggestedPriorityFees *PriorityFees // Suggested priority fees for the transaction
SuggestedLevelsForMaxFeesPerGas *MaxFeesLevels // Suggested max fees for the transaction
TxBaseFee *hexutil.Big // Base fee for the transaction
TxPriorityFee *hexutil.Big // Priority fee for the transaction, by default we're using the Medium priority fee
TxPriorityFee *hexutil.Big // Priority fee for the transaction
TxGasAmount uint64 // Gas used for the transaction
TxBonderFees *hexutil.Big // Bonder fees for the transaction - used for Hop bridge
TxTokenFees *hexutil.Big // Token fees for the transaction - used for bridges (represent the difference between the amount in and the amount out)
@ -432,7 +432,6 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
}
group.Add(func(c context.Context) error {
client, err := r.rpcClient.EthClient(network.ChainID)
if err != nil {
return err
}
@ -529,29 +528,18 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
l1FeeWei, _ = r.feesManager.GetL1Fee(ctx, network.ChainID, txInputData)
}
baseFee, err := r.feesManager.getBaseFee(ctx, client)
fees, err := r.feesManager.SuggestedFees(ctx, network.ChainID)
if err != nil {
continue
}
priorityFees, err := r.feesManager.getPriorityFees(ctx, client, baseFee)
if err != nil {
continue
}
selctedPriorityFee := priorityFees.Medium
if input.GasFeeMode == GasFeeHigh {
selctedPriorityFee = priorityFees.High
} else if input.GasFeeMode == GasFeeLow {
selctedPriorityFee = priorityFees.Low
}
amountOut, err := pProcessor.CalculateAmountOut(processorInputParams)
if err != nil {
continue
}
maxFeesPerGas := new(big.Float)
maxFeesPerGas.Add(new(big.Float).SetInt(baseFee), new(big.Float).SetInt(selctedPriorityFee))
maxFeesPerGas := fees.feeFor(input.GasFeeMode)
estimatedTime := r.feesManager.TransactionEstimatedTime(ctx, network.ChainID, maxFeesPerGas)
if approvalRequired && estimatedTime < MoreThanFiveMinutes {
estimatedTime += 1
@ -567,10 +555,10 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
AmountInLocked: amountLocked,
AmountOut: (*hexutil.Big)(amountOut),
SuggestedPriorityFees: &priorityFees,
SuggestedLevelsForMaxFeesPerGas: fees.MaxFeesLevels,
TxBaseFee: (*hexutil.Big)(baseFee),
TxPriorityFee: (*hexutil.Big)(selctedPriorityFee),
TxBaseFee: (*hexutil.Big)(fees.BaseFee),
TxPriorityFee: (*hexutil.Big)(fees.MaxPriorityFeePerGas),
TxGasAmount: gasLimit,
TxBonderFees: (*hexutil.Big)(bonderFees),
TxTokenFees: (*hexutil.Big)(tokenFees),
@ -579,14 +567,13 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
ApprovalRequired: approvalRequired,
ApprovalAmountRequired: (*hexutil.Big)(approvalAmountRequired),
ApprovalContractAddress: &approvalContractAddress,
ApprovalBaseFee: (*hexutil.Big)(baseFee),
ApprovalPriorityFee: (*hexutil.Big)(selctedPriorityFee),
ApprovalBaseFee: (*hexutil.Big)(fees.BaseFee),
ApprovalPriorityFee: (*hexutil.Big)(fees.MaxPriorityFeePerGas),
ApprovalGasAmount: approvalGasLimit,
ApprovalL1Fee: (*hexutil.Big)(big.NewInt(int64(l1ApprovalFee))),
EstimatedTime: estimatedTime,
},
)
})
mu.Unlock()
}
}