ethergo/chain/gas/gas_price.go
package gas
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/params"
"github.com/ipfs/go-log"
"github.com/synapsecns/sanguine/ethergo/chain/gas/backend"
"github.com/synapsecns/sanguine/ethergo/chain/gas/londinium"
"github.com/teivah/onecontext"
"math/big"
)
var logger = log.Logger("synapse-gas")
// DefaultGasPriceEstimate estimates the default gas price.
// This is exposed as a variable so it can be modified by tests, but will be removed in a future version.
var DefaultGasPriceEstimate = big.NewInt(int64(params.GWei))
// PriceEstimator handles estimating gas prices for type 0 txes on evm based chains. The logic is entirely derived from eth's
// SuggestPrice() logic (see: https://git.io/JZFlE), but designed to be deterministic from a given block height
// (with older block gas price estimations garbage collected).
// This is needed because, unlike in cases with a single signer gas prices need to be estimated deterministically.
// This is done by deriving the price at a given height (taken from the event log in cases where an event is being handles)
// and then following eth's estimation logic on the last n blocks. All clients arrive at the same price every time.
// The client is responsible for determining the height they wish to get the gas price at and coordinating this if
// the event log is cross chain.
type PriceEstimator interface {
// EstimateGasPrice estimates a gas price deterministically at a given height
EstimateGasPrice(ctx context.Context, height uint64, config gasprice.Config) (*big.Int, error)
}
type gasFeeEstimatorImpl struct {
//nolint: containedctx
ctx context.Context
oracleBackend londinium.OracleBackend
}
// NewGasPriceEstimator creates a gas estimator for v0 transactions.
func NewGasPriceEstimator(ctx context.Context, oracle backend.OracleBackendChain) (g PriceEstimator) {
g = &gasFeeEstimatorImpl{ctx: ctx, oracleBackend: londinium.NewOracleBackendFromChain(oracle)}
return g
}
// EstimateGasPrice deterministically determines the gas price at a given height.
func (g *gasFeeEstimatorImpl) EstimateGasPrice(ctx context.Context, height uint64, config gasprice.Config) (gasPrice *big.Int, err error) {
// copy this to avoid mutating the default value
defaultEstimate, _ := big.NewInt(0).SetString(DefaultGasPriceEstimate.String(), 10)
if height < uint64(config.Blocks) {
return defaultEstimate, nil
}
ctx, cancel := onecontext.Merge(g.ctx, ctx)
defer cancel()
oracleBackend := londinium.NewOracleBackendFromHeight(height, g.oracleBackend)
gasOracle := londinium.NewOracle(oracleBackend, londinium.ToLondiniumConfig(config))
price, err := gasOracle.SuggestPrice(ctx)
if err != nil {
logger.Warn(fmt.Errorf("could not estimate gas price: %w", err))
return defaultEstimate, nil
}
return price, nil
}
var _ PriceEstimator = &gasFeeEstimatorImpl{}