synapsecns/sanguine

View on GitHub
ethergo/chain/gas/gas_price.go

Summary

Maintainability
A
0 mins
Test Coverage
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{}