Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EvmFeeEstimator return Optimistic Rollup's L1BaseFee #10557

Merged
merged 15 commits into from
Sep 16, 2023

Conversation

matYang
Copy link
Contributor

@matYang matYang commented Sep 8, 2023

In CCIP, when user sends a message from Chain A -> Chain B, the OnRamp contract on Chain A needs to calculate the tx cost on Chain B in order to charge user such cost.

This requires OnRamp on Chain A to know Chain B's tx price components. When Chain B is an optimistic rollup, Chain A needs to know Chain B's l1GasPrice, in addition to regular gasPrice. This PR proposes to extend EvmFeeEstimator to return l1GasPrice, by adding a L1Oracle service into WrappedEvmEstimator

Inside CCIP, we can consume it as

if l1Oracle := r.config.sourceFeeEstimator.L1Oracle(); l1Oracle != nil {
   l1gasPrice = l1Oracle.L1GasPrice()
}

@github-actions
Copy link
Contributor

github-actions bot commented Sep 8, 2023

I see that you haven't updated any README files. Would it make sense to do so?

@github-actions
Copy link
Contributor

github-actions bot commented Sep 8, 2023

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@matYang matYang changed the title Evm estimator return gas price EvmFeeEstimator return gas price components Sep 10, 2023
@matYang matYang changed the title EvmFeeEstimator return gas price components EvmFeeEstimator return Optimistic Rollup's L1BaseFee Sep 10, 2023
@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@matYang matYang marked this pull request as ready for review September 10, 2023 04:37
@dimriou dimriou requested a review from aalu1418 September 13, 2023 11:04
case config.ChainArbitrum:
address = ArbGasInfoAddress
selector = ArbGasInfo_getL1BaseFeeEstimate
case config.ChainOptimismBedrock:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Base also uses OptimismBedorck chaintype, can we confirm the address and the hex code are the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matYang matYang requested a review from dimriou September 14, 2023 06:08
@@ -4,6 +4,7 @@ import (
"context"

"github.com/pkg/errors"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: revert this change, and keep this file untouched

}
}

func (e WrappedEvmEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit uint32, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (fee EvmFee, chainSpecificFeeLimit uint32, err error) {
func NewWrappedEvmEstimatorWithL1Oracle(e EvmEstimator, eip1559Enabled bool, o chainoracles.L1Oracle) EvmFeeEstimator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to create this new function.
Just add the L1Oracle param to the existing NewWrappedEvmEstimator().
For chains that don't support the L1Oracle, just pass nil there.

address = OPGasOracleAddress
selector = OPGasOracle_l1BaseFee
default:
return nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are calling this NewL1GasPriceOracle() only for chains that support it, the default case here should just call panic().
This will help surface up a misconfig or error faster.

defer close(o.chDone)

t := o.refresh()
close(o.chInitialised)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of from here, close this from within refresh(), once we successfully are able to set l1GasPrice there.
This way, this component is in started mode only after it fetches a valid l1GasPrice.

Copy link
Contributor Author

@matYang matYang Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Start() call is blocked on the chInitialised channel, so we need to close it regardless of fetching prices (refresh()) was successful or not right, closing it once here makes sense to me. This pattern is same in L2Suggested and Arbitrum estimators.

}

if len(b) != 32 { // returns uint256;
o.logger.Warnf("return data length (%d) different than expected (%d)", len(b), 32)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a critical error. It indicates the response format has changed.

Data: common.Hex2Bytes(o.selector),
}, big.NewInt(-1))
if err != nil {
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an error log here too

errOracle = e.l1Oracle.Ready()
}

if errEVM != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block of code can happen before even calling l1Oracle.Ready()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'd only execute either when e.l1Oracle is nil, or e.l1Oracle.Ready() has been called. The drawback is if EvmEstimator and l1Oracle both error, only errEVM will be surfaced. I think that's fine since it doesn't alter the outcome and EvmEstimator is the more critical component.

b, err := o.client.CallContract(ctx, ethereum.CallMsg{
To: &precompile,
Data: common.Hex2Bytes(o.selector),
}, big.NewInt(-1))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be nil instead. Not sure why on Arbitrum Estimator is also -1

pollPeriod: PollPeriod,
logger: lggr.Named(fmt.Sprintf("L1GasPriceOracle(%s)", chainType)),
address: address,
selector: selector,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about call instead, since this is a hex-encoded call? Selector doesn't provide much context.

@@ -0,0 +1,176 @@
package chainoracles
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Just wondering, if this name is appropriate.
This seems to be a package for Rollups.
Could rollups be a better name?


var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock}

func IsL1OracleChain(chainType config.ChainType) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name can confuse someone into thinking if this chain itself is an L1 chain.
Is this a better name: IsRollupWithL1Support.

// For example, on Optimistic Rollups, this oracle can return rollup-specific l1BaseFee
//
//go:generate mockery --quiet --name L1Oracle --output ./mocks/ --case=underscore
type L1Oracle interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about renaming to UnderlyingL1.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer L1Oracle since it is not actually calling the underlying L1, it is fetching from the L1 oracle contract provided by the L2

type L1Oracle interface {
services.ServiceCtx

L1GasPrice(ctx context.Context) (*assets.Wei, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the interface itself is named L1..., this function doesn't need to repeat it. Just say GasPrice()

Copy link
Contributor

@prashantkumar1982 prashantkumar1982 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. Just asked a few question on the right namings.

dimriou
dimriou previously approved these changes Sep 15, 2023
Copy link
Collaborator

@dimriou dimriou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Prashant on the names. Other than that LGTM

@cl-sonarqube-production
Copy link

Copy link
Contributor

@prashantkumar1982 prashantkumar1982 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot!

@matYang matYang added this pull request to the merge queue Sep 16, 2023
Merged via the queue into develop with commit f6256c3 Sep 16, 2023
@matYang matYang deleted the evm-estimator-return-gas-price branch September 16, 2023 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants