diff --git a/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts.go b/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts.go index 4f5ba6cfae..82e8fad135 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts.go @@ -1,22 +1,16 @@ package ccipcommon import ( - "context" "encoding/binary" "encoding/hex" - "fmt" - "sort" "strings" "time" "github.com/avast/retry-go/v4" - "golang.org/x/sync/errgroup" - cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata" ) func GetMessageIDsAsHexString(messages []cciptypes.EVM2EVMMessage) []string { @@ -32,67 +26,38 @@ type BackfillArgs struct { SourceStartBlock, DestStartBlock uint64 } -// GetFilteredSortedLaneTokens returns union of tokens supported on this lane, including fee tokens from the provided price registry -// and the bridgeable tokens from offRamp. Bridgeable tokens are only included if they are configured on the pricegetter -// Fee tokens are not filtered as they must always be priced -func GetFilteredSortedLaneTokens(ctx context.Context, offRamp ccipdata.OffRampReader, priceRegistry cciptypes.PriceRegistryReader, priceGetter cciptypes.PriceGetter) (laneTokens []cciptypes.Address, excludedTokens []cciptypes.Address, err error) { - destFeeTokens, destBridgeableTokens, err := GetDestinationTokens(ctx, offRamp, priceRegistry) - if err != nil { - return nil, nil, fmt.Errorf("get tokens with batch limit: %w", err) - } - - destTokensWithPrice, destTokensWithoutPrice, err := priceGetter.FilterConfiguredTokens(ctx, destBridgeableTokens) - if err != nil { - return nil, nil, fmt.Errorf("filter for priced tokens: %w", err) - } - - return flattenedAndSortedTokens(destFeeTokens, destTokensWithPrice), destTokensWithoutPrice, nil -} - -func flattenedAndSortedTokens(slices ...[]cciptypes.Address) (tokens []cciptypes.Address) { - // fee token can overlap with bridgeable tokens, we need to dedup them to arrive at lane token set - tokens = FlattenUniqueSlice(slices...) - - // return the tokens in deterministic order to aid with testing and debugging - sort.Slice(tokens, func(i, j int) bool { - return tokens[i] < tokens[j] - }) - - return tokens -} - // GetDestinationTokens returns the destination chain fee tokens from the provided price registry // and the bridgeable tokens from the offramp. -func GetDestinationTokens(ctx context.Context, offRamp ccipdata.OffRampReader, priceRegistry cciptypes.PriceRegistryReader) (fee, bridged []cciptypes.Address, err error) { - eg := new(errgroup.Group) - - var destFeeTokens []cciptypes.Address - var destBridgeableTokens []cciptypes.Address - - eg.Go(func() error { - tokens, err := priceRegistry.GetFeeTokens(ctx) - if err != nil { - return fmt.Errorf("get dest fee tokens: %w", err) - } - destFeeTokens = tokens - return nil - }) - - eg.Go(func() error { - tokens, err := offRamp.GetTokens(ctx) - if err != nil { - return fmt.Errorf("get dest bridgeable tokens: %w", err) - } - destBridgeableTokens = tokens.DestinationTokens - return nil - }) - - if err := eg.Wait(); err != nil { - return nil, nil, err - } - - return destFeeTokens, destBridgeableTokens, nil -} +// func GetDestinationTokens(ctx context.Context, offRamp ccipdata.OffRampReader, priceRegistry cciptypes.PriceRegistryReader) (fee, bridged []cciptypes.Address, err error) { +// eg := new(errgroup.Group) + +// var destFeeTokens []cciptypes.Address +// var destBridgeableTokens []cciptypes.Address + +// eg.Go(func() error { +// tokens, err := priceRegistry.GetFeeTokens(ctx) +// if err != nil { +// return fmt.Errorf("get dest fee tokens: %w", err) +// } +// destFeeTokens = tokens +// return nil +// }) + +// eg.Go(func() error { +// tokens, err := offRamp.GetTokens(ctx) +// if err != nil { +// return fmt.Errorf("get dest bridgeable tokens: %w", err) +// } +// destBridgeableTokens = tokens.DestinationTokens +// return nil +// }) + +// if err := eg.Wait(); err != nil { +// return nil, nil, err +// } + +// return destFeeTokens, destBridgeableTokens, nil +// } // FlattenUniqueSlice returns a flattened slice that contains unique elements by preserving their order. func FlattenUniqueSlice[T comparable](slices ...[]T) []T { diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service.go b/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service.go index b2eb8c1137..3cb63ceb2a 100644 --- a/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service.go +++ b/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service.go @@ -18,7 +18,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" cciporm "github.com/smartcontractkit/chainlink/v2/core/services/ccip" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices" @@ -278,16 +277,7 @@ func (p *priceService) observePriceUpdates( if p.gasPriceEstimator == nil || p.destPriceRegistryReader == nil { return nil, nil, fmt.Errorf("gasPriceEstimator and/or destPriceRegistry is not set yet") } - - sortedLaneTokens, filteredLaneTokens, err := ccipcommon.GetFilteredSortedLaneTokens(ctx, p.offRampReader, p.destPriceRegistryReader, p.priceGetter) - - lggr.Debugw("Filtered bridgeable tokens with no configured price getter", "filteredLaneTokens", filteredLaneTokens) - - if err != nil { - return nil, nil, fmt.Errorf("get destination tokens: %w", err) - } - - return p.generatePriceUpdates(ctx, lggr, sortedLaneTokens) + return p.generatePriceUpdates(ctx, lggr) } // All prices are USD ($1=1e18) denominated. All prices must be not nil. @@ -295,37 +285,36 @@ func (p *priceService) observePriceUpdates( func (p *priceService) generatePriceUpdates( ctx context.Context, lggr logger.Logger, - sortedLaneTokens []cciptypes.Address, + // sortedLaneTokens []cciptypes.Address, ) (sourceGasPriceUSD *big.Int, tokenPricesUSD map[cciptypes.Address]*big.Int, err error) { // Include wrapped native in our token query as way to identify the source native USD price. // notice USD is in 1e18 scale, i.e. $1 = 1e18 - queryTokens := ccipcommon.FlattenUniqueSlice([]cciptypes.Address{p.sourceNative}, sortedLaneTokens) - rawTokenPricesUSD, err := p.priceGetter.TokenPricesUSD(ctx, queryTokens) + rawTokenPricesUSD, err := p.priceGetter.TokenPricesUSD(ctx, make([]cciptypes.Address, 0)) + + // Get all the tokens fetched from the PriceGetter + tokensFetched := make([]cciptypes.Address, 0, len(rawTokenPricesUSD)) + for token := range rawTokenPricesUSD { + tokensFetched = append(tokensFetched, token) + } + if err != nil { return nil, nil, err } lggr.Infow("Raw token prices", "rawTokenPrices", rawTokenPricesUSD) - // make sure that we got prices for all the tokens of our query - for _, token := range queryTokens { - if rawTokenPricesUSD[token] == nil { - return nil, nil, fmt.Errorf("missing token price: %+v", token) - } - } - sourceNativePriceUSD, exists := rawTokenPricesUSD[p.sourceNative] if !exists { return nil, nil, fmt.Errorf("missing source native (%s) price", p.sourceNative) } - destTokensDecimals, err := p.destPriceRegistryReader.GetTokensDecimals(ctx, sortedLaneTokens) + destTokensDecimals, err := p.destPriceRegistryReader.GetTokensDecimals(ctx, tokensFetched) if err != nil { return nil, nil, fmt.Errorf("get tokens decimals: %w", err) } tokenPricesUSD = make(map[cciptypes.Address]*big.Int, len(rawTokenPricesUSD)) - for i, token := range sortedLaneTokens { + for i, token := range tokensFetched { tokenPricesUSD[token] = calculateUsdPer1e18TokenAmount(rawTokenPricesUSD[token], destTokensDecimals[i]) } diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline.go index f49e8a1f74..a06b418086 100644 --- a/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline.go +++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline.go @@ -6,7 +6,6 @@ import ( "strings" "time" - mapset "github.com/deckarep/golang-set/v2" "github.com/google/uuid" "github.com/pkg/errors" @@ -60,7 +59,7 @@ func (d *PipelineGetter) FilterConfiguredTokens(ctx context.Context, tokens []cc return configured, unconfigured, nil } -func (d *PipelineGetter) TokenPricesUSD(ctx context.Context, tokens []cciptypes.Address) (map[cciptypes.Address]*big.Int, error) { +func (d *PipelineGetter) TokenPricesUSD(ctx context.Context) (map[cciptypes.Address]*big.Int, error) { _, trrs, err := d.runner.ExecuteRun(ctx, pipeline.Spec{ ID: d.jobID, DotDagSource: d.source, @@ -84,7 +83,6 @@ func (d *PipelineGetter) TokenPricesUSD(ctx context.Context, tokens []cciptypes. return nil, errors.Errorf("expected map output of price pipeline, got %T", finalResult.Values[0]) } - providedTokensSet := mapset.NewSet(tokens...) tokenPrices := make(map[cciptypes.Address]*big.Int) for tokenAddressStr, rawPrice := range prices { tokenAddressStr := ccipcalc.HexToAddress(tokenAddressStr) @@ -93,17 +91,7 @@ func (d *PipelineGetter) TokenPricesUSD(ctx context.Context, tokens []cciptypes. return nil, err } - if providedTokensSet.Contains(tokenAddressStr) { - tokenPrices[tokenAddressStr] = castedPrice - } - } - - // The mapping of token address to source of token price has to live offchain. - // Best we can do is sanity check that the token price spec covers all our desired execution token prices. - for _, token := range tokens { - if _, ok = tokenPrices[token]; !ok { - return nil, errors.Errorf("missing token %s from tokensForFeeCoin spec, got %v", token, prices) - } + tokenPrices[tokenAddressStr] = castedPrice } return tokenPrices, nil