From 00b3f89459cbe4b7ded1a1783d82f9101f0b6ab7 Mon Sep 17 00:00:00 2001 From: "valerii.kabisov" Date: Fri, 28 Jun 2024 15:02:05 +0400 Subject: [PATCH] daPriceEstimator rework --- .../plugins/ccip/ccipcommit/initializers.go | 13 +++- .../plugins/ccip/ccipexec/initializers.go | 69 +++++++++++++++++-- .../ccip/internal/ccipdata/factory/offramp.go | 12 +++- .../ccip/internal/ccipdata/offramp_reader.go | 2 + .../ccip/internal/ccipdata/v1_0_0/offramp.go | 15 ++-- .../internal/ccipdata/v1_2_0/commit_store.go | 5 ++ .../ccip/internal/ccipdata/v1_2_0/offramp.go | 24 +++++-- .../ccip/internal/ccipdata/v1_5_0/offramp.go | 18 +++-- .../plugins/ccip/prices/da_price_estimator.go | 56 ++++++++++----- 9 files changed, 179 insertions(+), 35 deletions(-) diff --git a/core/services/ocr2/plugins/ccip/ccipcommit/initializers.go b/core/services/ocr2/plugins/ccip/ccipcommit/initializers.go index 97730ce85ba..43fa80f44d9 100644 --- a/core/services/ocr2/plugins/ccip/ccipcommit/initializers.go +++ b/core/services/ocr2/plugins/ccip/ccipcommit/initializers.go @@ -206,7 +206,17 @@ func jobSpecToCommitPluginConfig(ctx context.Context, orm cciporm.ORM, lggr logg if err != nil { return nil, nil, nil, nil, errors.Wrap(err, "failed onramp reader") } - offRampReader, err := factory.NewOffRampReader(commitLggr, versionFinder, params.pluginConfig.OffRamp, params.destChain.Client(), params.destChain.LogPoller(), params.destChain.GasEstimator(), params.destChain.Config().EVM().GasEstimator().PriceMax().ToInt(), true) + + offRampReader, err := factory.NewOffRampReader( + commitLggr, + versionFinder, + params.pluginConfig.OffRamp, + params.destChain.Client(), + params.destChain.LogPoller(), + params.destChain.GasEstimator(), + params.destChain.Config().EVM().GasEstimator().PriceMax().ToInt(), + true, + ) if err != nil { return nil, nil, nil, nil, errors.Wrap(err, "failed offramp reader") } @@ -297,6 +307,7 @@ type jobSpecParams struct { pluginConfig ccipconfig.CommitPluginJobSpecConfig commitStoreAddress cciptypes.Address commitStoreStaticCfg commit_store.CommitStoreStaticConfig + daGasPriceEstimator cciptypes.GasPriceEstimator sourceChain legacyevm.Chain destChain legacyevm.Chain } diff --git a/core/services/ocr2/plugins/ccip/ccipexec/initializers.go b/core/services/ocr2/plugins/ccip/ccipexec/initializers.go index 9631a596760..b16d135e007 100644 --- a/core/services/ocr2/plugins/ccip/ccipexec/initializers.go +++ b/core/services/ocr2/plugins/ccip/ccipexec/initializers.go @@ -4,9 +4,15 @@ import ( "context" "encoding/json" "fmt" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices" "math/big" "net/url" "strconv" + "strings" "time" "github.com/Masterminds/semver/v3" @@ -45,6 +51,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/promwrapper" ) +const ( + ConfigSetEventName = "ConfigSet" +) + var ( // tokenDataWorkerTimeout defines 1) The timeout while waiting for a bg call to the token data 3P provider. // 2) When a client requests token data and does not specify a timeout this value is used as a default. @@ -100,7 +110,7 @@ func NewExecutionServices(ctx context.Context, lggr logger.Logger, jb job.Job, c // See comment in UnregisterCommitPluginLpFilters // It MUST mirror the filters registered in NewExecutionServices. func UnregisterExecPluginLpFilters(ctx context.Context, lggr logger.Logger, jb job.Job, chainSet legacyevm.LegacyChainContainer) error { - params, err := extractJobSpecParams(lggr, jb, chainSet, false) + params, err := extractJobSpecParams(ctx, lggr, jb, chainSet, false) if err != nil { return err } @@ -180,7 +190,7 @@ func initTokenDataProviders(lggr logger.Logger, jobID string, pluginConfig ccipc } func jobSpecToExecPluginConfig(ctx context.Context, lggr logger.Logger, jb job.Job, chainSet legacyevm.LegacyChainContainer) (*ExecutionPluginStaticConfig, *ccipcommon.BackfillArgs, *cache.ObservedChainHealthcheck, *tokendata.BackgroundWorker, error) { - params, err := extractJobSpecParams(lggr, jb, chainSet, true) + params, err := extractJobSpecParams(ctx, lggr, jb, chainSet, true) if err != nil { return nil, nil, nil, nil, err } @@ -307,6 +317,48 @@ func jobSpecToExecPluginConfig(ctx context.Context, lggr logger.Logger, jb job.J tokenDataWorkerTimeout, 2*tokenDataWorkerTimeout, ) + + // TODO: evm_2_evm_onramp_1_2_0 version specific, need fetch updates in the version agnostic way + onRampABI, err := abi.JSON(strings.NewReader(evm_2_evm_onramp_1_2_0.EVM2EVMOnRampABI)) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("get onRampABI: %w", err) + } + + onRampAddress, err := ccipcalc.GenericAddrToEvm(params.offRampConfig.OnRamp) + onRampConfigCache := cache.NewLogpollerEventsBased[cciptypes.OnRampDynamicConfig]( + params.sourceChain.LogPoller(), + []common.Hash{ + abihelpers.MustGetEventID(ConfigSetEventName, onRampABI), + }, + onRampAddress, + ) + + dynamicConfigFetcher := func(_ context.Context) (cciptypes.OnRampDynamicConfig, error) { + if onRampReader == nil { + return cciptypes.OnRampDynamicConfig{}, fmt.Errorf("onramp not initialized") + } + dynamicConfig, err := onRampReader.GetDynamicConfig(ctx) + if err != nil { + return cciptypes.OnRampDynamicConfig{}, fmt.Errorf("get dynamic config v1.2: %w", err) + } + return cciptypes.OnRampDynamicConfig{ + DestDataAvailabilityOverheadGas: dynamicConfig.DestDataAvailabilityOverheadGas, + DestGasPerDataAvailabilityByte: dynamicConfig.DestGasPerDataAvailabilityByte, + DestDataAvailabilityMultiplierBps: dynamicConfig.DestDataAvailabilityMultiplierBps, + }, nil + } + + gasPriceEstimator := prices.NewDAGasPriceEstimator( + params.destChain.GasEstimator(), + params.destChain.Config().EVM().GasEstimator().PriceMax().ToInt(), + 0, + 0, + dynamicConfigFetcher, + onRampConfigCache, + ) + + offRampReader.SetDAGasEstimator(ctx, gasPriceEstimator) + return &ExecutionPluginStaticConfig{ lggr: execLggr, onRampReader: onRampReader, @@ -340,7 +392,7 @@ type jobSpecParams struct { destChain legacyevm.Chain } -func extractJobSpecParams(lggr logger.Logger, jb job.Job, chainSet legacyevm.LegacyChainContainer, registerFilters bool) (*jobSpecParams, error) { +func extractJobSpecParams(ctx context.Context, lggr logger.Logger, jb job.Job, chainSet legacyevm.LegacyChainContainer, registerFilters bool) (*jobSpecParams, error) { if jb.OCR2OracleSpec == nil { return nil, errors.New("spec is nil") } @@ -358,7 +410,16 @@ func extractJobSpecParams(lggr logger.Logger, jb job.Job, chainSet legacyevm.Leg versionFinder := factory.NewEvmVersionFinder() offRampAddress := ccipcalc.HexToAddress(spec.ContractID) - offRampReader, err := factory.NewOffRampReader(lggr, versionFinder, offRampAddress, destChain.Client(), destChain.LogPoller(), destChain.GasEstimator(), destChain.Config().EVM().GasEstimator().PriceMax().ToInt(), registerFilters) + offRampReader, err := factory.NewOffRampReader( + lggr, + versionFinder, + offRampAddress, + destChain.Client(), + destChain.LogPoller(), + destChain.GasEstimator(), + destChain.Config().EVM().GasEstimator().PriceMax().ToInt(), + registerFilters, + ) if err != nil { return nil, errors.Wrap(err, "create offRampReader") } diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp.go index c6fa63ee820..eabcdab554e 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp.go @@ -35,7 +35,17 @@ func CloseOffRampReader(lggr logger.Logger, versionFinder VersionFinder, addr cc return err } -func initOrCloseOffRampReader(lggr logger.Logger, versionFinder VersionFinder, addr cciptypes.Address, destClient client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int, closeReader bool, registerFilters bool) (ccipdata.OffRampReader, error) { +func initOrCloseOffRampReader( + lggr logger.Logger, + versionFinder VersionFinder, + addr cciptypes.Address, + destClient client.Client, + lp logpoller.LogPoller, + estimator gas.EvmFeeEstimator, + destMaxGasPrice *big.Int, + closeReader bool, + registerFilters bool, +) (ccipdata.OffRampReader, error) { contractType, version, err := versionFinder.TypeAndVersion(addr, destClient) if err != nil { return nil, errors.Wrapf(err, "unable to read type and version") diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader.go index 2f39f1cd919..cbe6ca6c94e 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader.go @@ -1,6 +1,7 @@ package ccipdata import ( + "context" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip" ) @@ -11,4 +12,5 @@ const ( //go:generate mockery --quiet --name OffRampReader --filename offramp_reader_mock.go --case=underscore type OffRampReader interface { cciptypes.OffRampReader + SetDAGasEstimator(context.Context, cciptypes.GasPriceEstimator) } diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp.go index 6495fe21741..63f12a60b5b 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp.go @@ -156,10 +156,11 @@ type OffRamp struct { // Dynamic config // configMu guards all the dynamic config fields. - configMu sync.RWMutex - gasPriceEstimator prices.GasPriceEstimatorExec - offchainConfig cciptypes.ExecOffchainConfig - onchainConfig cciptypes.ExecOnchainConfig + configMu sync.RWMutex + gasPriceEstimator prices.GasPriceEstimatorExec + offchainConfig cciptypes.ExecOffchainConfig + onchainConfig cciptypes.ExecOnchainConfig + daGasPriceEstimator cciptypes.GasPriceEstimator // TODO: specify minimum interface } func (o *OffRamp) GetStaticConfig(ctx context.Context) (cciptypes.OffRampStaticConfig, error) { @@ -180,6 +181,12 @@ func (o *OffRamp) GetStaticConfig(ctx context.Context) (cciptypes.OffRampStaticC }, nil } +func (o *OffRamp) SetDAGasEstimator(_ context.Context, gpe cciptypes.GasPriceEstimator) { + o.configMu.RLock() + defer o.configMu.RUnlock() + o.daGasPriceEstimator = gpe +} + func (o *OffRamp) GetExecutionState(ctx context.Context, sequenceNumber uint64) (uint8, error) { return o.offRampV100.GetExecutionState(&bind.CallOpts{Context: ctx}, sequenceNumber) } diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store.go index 34ce05c2d2c..54eb68a378d 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store.go @@ -249,11 +249,16 @@ func (c *CommitStore) ChangeConfig(_ context.Context, onchainConfig []byte, offc return "", fmt.Errorf("this CommitStore sourceMaxGasPrice is nil. SetSourceMaxGasPrice should be called before ChangeConfig") } + // TODO: move out to the initializer c.gasPriceEstimator = prices.NewDAGasPriceEstimator( *c.estimator, c.sourceMaxGasPrice, int64(offchainConfigParsed.ExecGasPriceDeviationPPB), int64(offchainConfigParsed.DAGasPriceDeviationPPB), + func(ctx context.Context) (cciptypes.OnRampDynamicConfig, error) { + return cciptypes.OnRampDynamicConfig{}, nil + }, + nil, ) c.offchainConfig = ccipdata.NewCommitOffchainConfig( offchainConfigParsed.ExecGasPriceDeviationPPB, diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp.go index 94c9a45e265..20d38ec1b76 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp.go @@ -26,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices" ) var ( @@ -121,7 +120,8 @@ func (c JSONExecOffchainConfig) Validate() error { // OffRamp In 1.2 we have a different estimator impl type OffRamp struct { *v1_0_0.OffRamp - offRampV120 evm_2_evm_offramp_1_2_0.EVM2EVMOffRampInterface + offRampV120 evm_2_evm_offramp_1_2_0.EVM2EVMOffRampInterface + daGasPriceEstimator cciptypes.GasPriceEstimator // TODO: specify minimum interface } func (o *OffRamp) CurrentRateLimiterState(ctx context.Context) (cciptypes.TokenBucketRateLimit, error) { @@ -146,6 +146,10 @@ func (o *OffRamp) GetRouter(ctx context.Context) (cciptypes.Address, error) { return ccipcalc.EvmAddrToGeneric(dynamicConfig.Router), nil } +func (o *OffRamp) SetDAGasEstimator(ctx context.Context, gpe cciptypes.GasPriceEstimator) { + o.daGasPriceEstimator = gpe +} + func (o *OffRamp) ChangeConfig(ctx context.Context, onchainConfigBytes []byte, offchainConfigBytes []byte) (cciptypes.Address, cciptypes.Address, error) { // Same as the v1.0.0 method, except for the ExecOnchainConfig type. onchainConfigParsed, err := abihelpers.DecodeAbiStruct[ExecOnchainConfig](onchainConfigBytes) @@ -177,9 +181,12 @@ func (o *OffRamp) ChangeConfig(ctx context.Context, onchainConfigBytes []byte, o PermissionLessExecutionThresholdSeconds: time.Second * time.Duration(onchainConfigParsed.PermissionLessExecutionThresholdSeconds), Router: cciptypes.Address(onchainConfigParsed.Router.String()), } - priceEstimator := prices.NewDAGasPriceEstimator(o.Estimator, o.DestMaxGasPrice, 0, 0) - o.UpdateDynamicConfig(onchainConfig, offchainConfig, priceEstimator) + //TODO: for reference, remove it + //priceEstimator := prices.NewDAGasPriceEstimator(o.Estimator, o.DestMaxGasPrice, 0, 0) + //_ = priceEstimator + + o.UpdateDynamicConfig(onchainConfig, offchainConfig, o.daGasPriceEstimator) o.Logger.Infow("Starting exec plugin", "offchainConfig", onchainConfigParsed, @@ -317,7 +324,14 @@ func (o *OffRamp) DecodeExecutionReport(ctx context.Context, report []byte) (cci return DecodeExecReport(ctx, o.ExecutionReportArgs, report) } -func NewOffRamp(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int) (*OffRamp, error) { +func NewOffRamp( + lggr logger.Logger, + addr common.Address, + ec client.Client, + lp logpoller.LogPoller, + estimator gas.EvmFeeEstimator, + destMaxGasPrice *big.Int, +) (*OffRamp, error) { v100, err := v1_0_0.NewOffRamp(lggr, addr, ec, lp, estimator, destMaxGasPrice) if err != nil { return nil, err diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp.go index 89d3047381f..f61cd5b707d 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp.go @@ -22,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices" ) var ( @@ -78,6 +77,7 @@ type OffRamp struct { *v1_2_0.OffRamp offRampV150 evm_2_evm_offramp.EVM2EVMOffRampInterface cachedRateLimitTokens cache.AutoSync[cciptypes.OffRampTokens] + daGasPriceEstimator cciptypes.GasPriceEstimator // TODO: specify minimum interface } // GetTokens Returns no data as the offRamps no longer have this information. @@ -92,6 +92,10 @@ func (o *OffRamp) GetTokens(ctx context.Context) (cciptypes.OffRampTokens, error }, nil } +func (o *OffRamp) SetDAGasEstimator(ctx context.Context, gpe cciptypes.GasPriceEstimator) { + o.daGasPriceEstimator = gpe +} + func (o *OffRamp) GetSourceAndDestRateLimitTokens(ctx context.Context) (sourceTokens []cciptypes.Address, destTokens []cciptypes.Address, err error) { cachedTokens, err := o.cachedRateLimitTokens.Get(ctx, func(ctx context.Context) (cciptypes.OffRampTokens, error) { tokens, err2 := o.offRampV150.GetAllRateLimitTokens(&bind.CallOpts{Context: ctx}) @@ -162,9 +166,8 @@ func (o *OffRamp) ChangeConfig(ctx context.Context, onchainConfigBytes []byte, o PermissionLessExecutionThresholdSeconds: time.Second * time.Duration(onchainConfigParsed.PermissionLessExecutionThresholdSeconds), Router: cciptypes.Address(onchainConfigParsed.Router.String()), } - priceEstimator := prices.NewDAGasPriceEstimator(o.Estimator, o.DestMaxGasPrice, 0, 0) - o.UpdateDynamicConfig(onchainConfig, offchainConfig, priceEstimator) + o.UpdateDynamicConfig(onchainConfig, offchainConfig, o.daGasPriceEstimator) o.Logger.Infow("Starting exec plugin", "offchainConfig", onchainConfigParsed, @@ -173,7 +176,14 @@ func (o *OffRamp) ChangeConfig(ctx context.Context, onchainConfigBytes []byte, o cciptypes.Address(destWrappedNative.String()), nil } -func NewOffRamp(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int) (*OffRamp, error) { +func NewOffRamp( + lggr logger.Logger, + addr common.Address, + ec client.Client, + lp logpoller.LogPoller, + estimator gas.EvmFeeEstimator, + destMaxGasPrice *big.Int, +) (*OffRamp, error) { v120, err := v1_2_0.NewOffRamp(lggr, addr, ec, lp, estimator, destMaxGasPrice) if err != nil { return nil, err diff --git a/core/services/ocr2/plugins/ccip/prices/da_price_estimator.go b/core/services/ocr2/plugins/ccip/prices/da_price_estimator.go index 83869dc0ef2..62fc5adbb67 100644 --- a/core/services/ocr2/plugins/ccip/prices/da_price_estimator.go +++ b/core/services/ocr2/plugins/ccip/prices/da_price_estimator.go @@ -3,6 +3,7 @@ package prices import ( "context" "fmt" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache" "math/big" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip" @@ -12,13 +13,15 @@ import ( ) type DAGasPriceEstimator struct { - execEstimator GasPriceEstimator - l1Oracle rollups.L1Oracle - priceEncodingLength uint - daDeviationPPB int64 - daOverheadGas int64 - gasPerDAByte int64 - daMultiplier int64 + execEstimator GasPriceEstimator + l1Oracle rollups.L1Oracle + priceEncodingLength uint + daDeviationPPB int64 + daOverheadGas int64 + gasPerDAByte int64 + daMultiplier int64 + dynamicConfigFetcher func(ctx context.Context) (cciptypes.OnRampDynamicConfig, error) + cachedOnRampConfig cache.AutoSync[cciptypes.OnRampDynamicConfig] } func NewDAGasPriceEstimator( @@ -26,12 +29,16 @@ func NewDAGasPriceEstimator( maxGasPrice *big.Int, deviationPPB int64, daDeviationPPB int64, + dynamicConfigFetcher func(ctx context.Context) (cciptypes.OnRampDynamicConfig, error), + cachedOnRampConfig cache.AutoSync[cciptypes.OnRampDynamicConfig], ) DAGasPriceEstimator { return DAGasPriceEstimator{ - execEstimator: NewExecGasPriceEstimator(estimator, maxGasPrice, deviationPPB), - l1Oracle: estimator.L1Oracle(), - priceEncodingLength: daGasPriceEncodingLength, - daDeviationPPB: daDeviationPPB, + execEstimator: NewExecGasPriceEstimator(estimator, maxGasPrice, deviationPPB), + l1Oracle: estimator.L1Oracle(), + priceEncodingLength: daGasPriceEncodingLength, + daDeviationPPB: daDeviationPPB, + dynamicConfigFetcher: dynamicConfigFetcher, + cachedOnRampConfig: cachedOnRampConfig, } } @@ -141,7 +148,11 @@ func (g DAGasPriceEstimator) EstimateMsgCostUSD(p *big.Int, wrappedNativePrice * // If there is data availability price component, then include data availability cost in fee estimation if daGasPrice.Cmp(big.NewInt(0)) > 0 { - daGasCostUSD := g.estimateDACostUSD(daGasPrice, wrappedNativePrice, msg) + daGasCostUSD, err := g.estimateDACostUSD(daGasPrice, wrappedNativePrice, msg) + if err != nil { + return nil, err + } + execCostUSD = new(big.Int).Add(daGasCostUSD, execCostUSD) } return execCostUSD, nil @@ -160,17 +171,30 @@ func (g DAGasPriceEstimator) parseEncodedGasPrice(p *big.Int) (*big.Int, *big.In return daGasPrice, execGasPrice, nil } -func (g DAGasPriceEstimator) estimateDACostUSD(daGasPrice *big.Int, wrappedNativePrice *big.Int, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) *big.Int { +func (g DAGasPriceEstimator) estimateDACostUSD( + daGasPrice *big.Int, + wrappedNativePrice *big.Int, + msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, +) (*big.Int, error) { var sourceTokenDataLen int for _, tokenData := range msg.SourceTokenData { sourceTokenDataLen += len(tokenData) } + onRampDynamicConfig, err := g.cachedOnRampConfig.Get(context.Background(), g.dynamicConfigFetcher) + if err != nil { + return nil, err + } + + gasPerDAByte := int64(onRampDynamicConfig.DestGasPerDataAvailabilityByte) + daOverheadGas := int64(onRampDynamicConfig.DestGasOverhead) + daMultiplier := int64(onRampDynamicConfig.DestDataAvailabilityMultiplierBps) + dataLen := evmMessageFixedBytes + len(msg.Data) + len(msg.TokenAmounts)*evmMessageBytesPerToken + sourceTokenDataLen - dataGas := big.NewInt(int64(dataLen)*g.gasPerDAByte + g.daOverheadGas) + dataGas := big.NewInt(int64(dataLen)*gasPerDAByte + daOverheadGas) dataGasEstimate := new(big.Int).Mul(dataGas, daGasPrice) - dataGasEstimate = new(big.Int).Div(new(big.Int).Mul(dataGasEstimate, big.NewInt(g.daMultiplier)), big.NewInt(daMultiplierBase)) + dataGasEstimate = new(big.Int).Div(new(big.Int).Mul(dataGasEstimate, big.NewInt(daMultiplier)), big.NewInt(daMultiplierBase)) - return ccipcalc.CalculateUsdPerUnitGas(dataGasEstimate, wrappedNativePrice) + return ccipcalc.CalculateUsdPerUnitGas(dataGasEstimate, wrappedNativePrice), nil }