Skip to content

Commit 0033a68

Browse files
committed
Merge remote-tracking branch 'origin/main' into tt/fqd
2 parents b94ed78 + c243148 commit 0033a68

File tree

34 files changed

+1434
-303
lines changed

34 files changed

+1434
-303
lines changed

chains/evm/deployment/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ require (
2121
github.com/smartcontractkit/chain-selectors v1.0.97
2222
github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260121163256-85accaf3d28d
2323
github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-00010101000000-000000000000
24-
github.com/smartcontractkit/chainlink-common v0.10.0
24+
github.com/smartcontractkit/chainlink-common v0.10.1-0.20260310151336-c98a9c147ac0
2525
github.com/smartcontractkit/chainlink-deployments-framework v0.75.2-0.20260120092221-c83e6ba1e827
2626
github.com/smartcontractkit/chainlink-evm v0.3.3
2727
github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd
@@ -217,7 +217,7 @@ require (
217217
github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250908144012-8184001834b5 // indirect
218218
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect
219219
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250717121125-2350c82883e2 // indirect
220-
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260210221717-2546aed27ebe // indirect
220+
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 // indirect
221221
github.com/smartcontractkit/chainlink-protos/job-distributor v0.17.0 // indirect
222222
github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect
223223
github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b // indirect

chains/evm/deployment/go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260121163256-8
681681
github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260121163256-85accaf3d28d/go.mod h1:bgmqE7x9xwmIVr8PqLbC0M5iPm4AV2DBl596lO6S5Sw=
682682
github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250908144012-8184001834b5 h1:QhcYGEhRLInr1/qh/3RJiVdvJ0nxBHKhPe65WLbSBnU=
683683
github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250908144012-8184001834b5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg=
684-
github.com/smartcontractkit/chainlink-common v0.10.0 h1:d90b9UPJecrIryzhl43F1oQwkJQoug3TaANlJ1xLHyI=
685-
github.com/smartcontractkit/chainlink-common v0.10.0/go.mod h1:13YN2kb3Vqpw2S7d4IwhX/578WPGC0JHN5JrOnAEsOc=
684+
github.com/smartcontractkit/chainlink-common v0.10.1-0.20260310151336-c98a9c147ac0 h1:eui+u6ge2RYW01F/DeXWrc5UOqc+8+lyPoi9TIAmMgo=
685+
github.com/smartcontractkit/chainlink-common v0.10.1-0.20260310151336-c98a9c147ac0/go.mod h1:0ghbAr7tRO0tT5ZqBXhOyzgUO37tNNe33Yn0hskauVM=
686686
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg=
687687
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY=
688688
github.com/smartcontractkit/chainlink-deployments-framework v0.75.2-0.20260120092221-c83e6ba1e827 h1:8R5BstwQlzucsa/wfHXsIG5lOD6B1fYPHHC/yFYossw=
@@ -693,8 +693,8 @@ github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c
693693
github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd/go.mod h1:7Jlt72+V9891y3LnGwHzmQwt9tfEGYryRKiGlQHo/o8=
694694
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250717121125-2350c82883e2 h1:JU1JUrkzdAUHsOYdS9DENPkJfmrxweFRPRSztad6oPM=
695695
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250717121125-2350c82883e2/go.mod h1:+pRGfDej1r7cHMs1dYmuyPuOZzYB9Q+PKu0FvZOYlmw=
696-
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260210221717-2546aed27ebe h1:Vc4zoSc/j6/FdCQ7vcyHTTB7kzHI2f+lHCHqFuiCcJQ=
697-
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260210221717-2546aed27ebe/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8=
696+
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 h1:03tbcwjyIEjvHba1IWOj1sfThwebm2XNzyFHSuZtlWc=
697+
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8=
698698
github.com/smartcontractkit/chainlink-protos/job-distributor v0.17.0 h1:xHPmFDhff7QpeFxKsZfk+24j4AlnQiFjjRh5O87Peu4=
699699
github.com/smartcontractkit/chainlink-protos/job-distributor v0.17.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE=
700700
github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM=

chains/evm/deployment/v1_2_0/adapters/laneversionresolver.go

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package adapters
22

33
import (
4+
"context"
45
"fmt"
56

67
"github.com/Masterminds/semver/v3"
78
"github.com/ethereum/go-ethereum/accounts/abi/bind"
89
"github.com/ethereum/go-ethereum/common"
9-
"github.com/smartcontractkit/chainlink-ccip/chains/evm/gobindings/generated/v1_2_0/router"
10+
"github.com/smartcontractkit/chainlink-deployments-framework/chain/evm"
1011
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
1112
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
1213

14+
"github.com/smartcontractkit/chainlink-ccip/chains/evm/gobindings/generated/v1_2_0/router"
15+
1316
"github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment/utils"
1417
evm_datastore_utils "github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment/utils/datastore"
1518
routerops "github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment/v1_2_0/operations/router"
@@ -57,19 +60,13 @@ func (r *LaneVersionResolver) DeriveLaneVersionsForChain(e cldf.Environment, cha
5760
laneVersionForRemoteChain := make(map[uint64]*semver.Version)
5861
// for all remote chains, find the onRamp and check its version , if unique add it to the list of versions to import
5962
for remoteChain := range remoteChains {
60-
onRamp, err := routerC.GetOnRamp(&bind.CallOpts{
61-
Context: e.GetContext(),
62-
}, remoteChain)
63+
version, err := GetLaneVersionForRemoteChain(e.GetContext(), chain, remoteChain, routerAddr)
6364
if err != nil {
64-
return nil, nil, fmt.Errorf("failed to get onramp for remote chain %d from router at address %s for chain %d: %w", remoteChain, routerAddr.Hex(), chainSel, err)
65+
return nil, nil, fmt.Errorf("failed to get version for remoteChain %d on chain %d: %w", remoteChain, chainSel, err)
6566
}
66-
if onRamp == (common.Address{}) {
67+
if version == nil {
6768
continue
6869
}
69-
_, version, err := utils.TypeAndVersion(onRamp, chain.Client)
70-
if err != nil {
71-
return nil, nil, fmt.Errorf("failed to get version for onramp at address %s on chain %d: %w", onRamp.Hex(), chainSel, err)
72-
}
7370
if _, exists := versions[version.String()]; !exists {
7471
versions[version.String()] = version
7572
}
@@ -84,3 +81,26 @@ func (r *LaneVersionResolver) DeriveLaneVersionsForChain(e cldf.Environment, cha
8481
}
8582
return laneVersionForRemoteChain, versionList, nil
8683
}
84+
85+
func GetLaneVersionForRemoteChain(ctx context.Context, chain evm.Chain, remoteChain uint64, routerAddr common.Address) (*semver.Version, error) {
86+
routerC, err := router.NewRouter(routerAddr, chain.Client)
87+
if err != nil {
88+
return nil, fmt.Errorf("failed to bind router contract at address %s: %w", routerAddr.Hex(), err)
89+
}
90+
// get the onRamp for the remote chain and check its version
91+
onRamp, err := routerC.GetOnRamp(&bind.CallOpts{
92+
Context: ctx,
93+
}, remoteChain)
94+
if err != nil {
95+
return nil, fmt.Errorf("failed to get onramp for remote chain %d from router at address %s: %w", remoteChain, routerAddr.Hex(), err)
96+
}
97+
// if there is no onramp for this remote chain, return nil
98+
if onRamp == (common.Address{}) {
99+
return nil, nil
100+
}
101+
_, version, err := utils.TypeAndVersion(onRamp, chain.Client)
102+
if err != nil {
103+
return nil, fmt.Errorf("failed to get type and version for onramp at address %s: %w", onRamp.Hex(), err)
104+
}
105+
return version, nil
106+
}

chains/evm/deployment/v1_5_0/adapters/configimport.go

Lines changed: 126 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
package adapters
22

33
import (
4+
"context"
45
"fmt"
6+
"sync"
57

68
"github.com/Masterminds/semver/v3"
9+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
710
"github.com/ethereum/go-ethereum/common"
8-
"github.com/smartcontractkit/chainlink-ccip/chains/evm/gobindings/generated/v1_2_0/router"
11+
"github.com/smartcontractkit/chainlink-common/pkg/logger"
912
cldf_chain "github.com/smartcontractkit/chainlink-deployments-framework/chain"
1013
"github.com/smartcontractkit/chainlink-deployments-framework/chain/evm"
1114
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
1215
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
1316
cldf_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations"
17+
"golang.org/x/sync/errgroup"
1418

19+
adapters1_2 "github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment/v1_2_0/adapters"
1520
"github.com/smartcontractkit/chainlink-ccip/chains/evm/gobindings/generated/v1_5_0/evm_2_evm_offramp"
1621
"github.com/smartcontractkit/chainlink-ccip/chains/evm/gobindings/generated/v1_5_0/evm_2_evm_onramp"
1722
"github.com/smartcontractkit/chainlink-ccip/chains/evm/gobindings/generated/v1_5_0/token_admin_registry"
@@ -29,14 +34,25 @@ import (
2934
"github.com/smartcontractkit/chainlink-ccip/deployment/utils/sequences"
3035
)
3136

32-
var GetTokensPaginationSize = uint64(20)
37+
var (
38+
getTokensPaginationSize = uint64(20)
39+
// getSupportedTokensPoolConcurrency caps concurrent RPC calls when fetching supported tokens per pool.
40+
// Limits in-flight requests to avoid overwhelming the node/provider (rate limits, timeouts) and memory.
41+
getSupportedTokensPoolConcurrency = 10
42+
)
3343

3444
type ConfigImportAdapter struct {
3545
OnRamp map[uint64]common.Address
3646
OffRamp map[uint64]common.Address
3747
TokenAdminReg common.Address
3848
PriceRegistry common.Address
3949
Router common.Address
50+
51+
// connectedChainsCache memoizes the result of ConnectedChains per chain selector
52+
// to avoid duplicate (potentially expensive) RPC work when the method is called
53+
// multiple times for the same chain within the same adapter instance.
54+
connectedChainsCache map[uint64][]uint64
55+
connectedChainsMu sync.Mutex
4056
}
4157

4258
func (ci *ConfigImportAdapter) InitializeAdapter(e cldf.Environment, sel uint64) error {
@@ -110,28 +126,42 @@ func (ci *ConfigImportAdapter) InitializeAdapter(e cldf.Environment, sel uint64)
110126
}
111127

112128
func (ci *ConfigImportAdapter) ConnectedChains(e cldf.Environment, chainsel uint64) ([]uint64, error) {
113-
var connected []uint64
114-
// to ensure deduplication in case there are multiple onramps addresses in datastore for the same remote chain selector
115-
var mapConnectedChains = make(map[uint64]bool)
116-
chain, ok := e.BlockChains.EVMChains()[chainsel]
117-
if !ok {
118-
return nil, fmt.Errorf("chain with selector %d not found in environment", chainsel)
129+
// Fast path: return cached result if available to avoid duplicate RPC work.
130+
ci.connectedChainsMu.Lock()
131+
if ci.connectedChainsCache == nil {
132+
ci.connectedChainsCache = make(map[uint64][]uint64)
133+
}
134+
if cached, ok := ci.connectedChainsCache[chainsel]; ok {
135+
// Return a copy to prevent callers from mutating the cached slice.
136+
result := make([]uint64, len(cached))
137+
copy(result, cached)
138+
ci.connectedChainsMu.Unlock()
139+
return result, nil
119140
}
120-
routerC, err := router.NewRouter(ci.Router, chain.Client)
141+
ci.connectedChainsMu.Unlock()
142+
143+
var connected []uint64
144+
laneResolver := adapters1_2.LaneVersionResolver{}
145+
remoteChainToVersionMap, _, err := laneResolver.DeriveLaneVersionsForChain(e, chainsel)
121146
if err != nil {
122-
return nil, fmt.Errorf("failed to instantiate router contract at %s on chain %d: %w", ci.Router.String(), chain.Selector, err)
147+
return nil, fmt.Errorf("failed to derive lane versions for chain %d: %w", chainsel, err)
123148
}
124-
for destSel, onrampForDest := range ci.OnRamp {
125-
onRamp, err := routerC.GetOnRamp(nil, destSel)
126-
if err != nil {
127-
return nil, fmt.Errorf("failed to get onramp for dest chain %d from router at %s on chain %d: %w", destSel, ci.Router.String(), chain.Selector, err)
128-
}
129-
// if the onramp address from the router doesn't match the onramp address we have, then this chain is not actually connected with 1.5
130-
if onRamp == onrampForDest && !mapConnectedChains[destSel] {
149+
for destSel, version := range remoteChainToVersionMap {
150+
if version.Equal(semver.MustParse("1.5.0")) {
131151
connected = append(connected, destSel)
132-
mapConnectedChains[destSel] = true
133152
}
134153
}
154+
155+
// Cache the computed result for subsequent calls.
156+
ci.connectedChainsMu.Lock()
157+
if ci.connectedChainsCache == nil {
158+
ci.connectedChainsCache = make(map[uint64][]uint64)
159+
}
160+
cached := make([]uint64, len(connected))
161+
copy(cached, connected)
162+
ci.connectedChainsCache[chainsel] = cached
163+
ci.connectedChainsMu.Unlock()
164+
135165
return connected, nil
136166
}
137167

@@ -140,8 +170,12 @@ func (ci *ConfigImportAdapter) SupportedTokensPerRemoteChain(e cldf.Environment,
140170
if !ok {
141171
return nil, fmt.Errorf("chain with selector %d not found in environment", chainsel)
142172
}
173+
remoteChains, err := ci.ConnectedChains(e, chainsel)
174+
if err != nil {
175+
return nil, fmt.Errorf("failed to get connected chains for chain %d: %w", chainsel, err)
176+
}
143177
// get all supported tokens from token admin registry
144-
return GetSupportedTokensPerRemoteChain(ci.TokenAdminReg, chain)
178+
return GetSupportedTokensPerRemoteChain(e.GetContext(), e.Logger, ci.TokenAdminReg, chain, remoteChains)
145179
}
146180

147181
func (ci *ConfigImportAdapter) SequenceImportConfig() *cldf_ops.Sequence[api.ImportConfigPerChainInput, sequences.OnChainOutput, cldf_chain.BlockChains] {
@@ -181,7 +215,7 @@ func (ci *ConfigImportAdapter) SequenceImportConfig() *cldf_ops.Sequence[api.Imp
181215
})
182216
}
183217

184-
func GetSupportedTokensPerRemoteChain(tokenAdminRegAddr common.Address, chain evm.Chain) (map[uint64][]common.Address, error) {
218+
func GetSupportedTokensPerRemoteChain(ctx context.Context, l logger.Logger, tokenAdminRegAddr common.Address, chain evm.Chain, remoteChains []uint64) (map[uint64][]common.Address, error) {
185219
// get all supported tokens from token admin registry
186220
tokenAdminRegC, err := token_admin_registry.NewTokenAdminRegistry(tokenAdminRegAddr, chain.Client)
187221
if err != nil {
@@ -190,13 +224,13 @@ func GetSupportedTokensPerRemoteChain(tokenAdminRegAddr common.Address, chain ev
190224
startIndex := uint64(0)
191225
allTokens := make([]common.Address, 0)
192226
for {
193-
fetchedTokens, err := tokenAdminRegC.GetAllConfiguredTokens(nil, startIndex, GetTokensPaginationSize)
227+
fetchedTokens, err := tokenAdminRegC.GetAllConfiguredTokens(nil, startIndex, getTokensPaginationSize)
194228
if err != nil {
195229
return nil, err
196230
}
197231
allTokens = append(allTokens, fetchedTokens...)
198-
startIndex += GetTokensPaginationSize
199-
if uint64(len(fetchedTokens)) < GetTokensPaginationSize {
232+
startIndex += getTokensPaginationSize
233+
if uint64(len(fetchedTokens)) < getTokensPaginationSize {
200234
break
201235
}
202236
}
@@ -205,26 +239,80 @@ func GetSupportedTokensPerRemoteChain(tokenAdminRegAddr common.Address, chain ev
205239
return nil, fmt.Errorf("failed to get pools for tokens from token admin registry at %s on chain %d: %w", tokenAdminRegAddr.String(), chain.Selector, err)
206240
}
207241
tokensPerRemoteChain := make(map[uint64][]common.Address)
242+
var mu sync.Mutex
243+
grp, grpCtx := errgroup.WithContext(ctx)
244+
grp.SetLimit(getSupportedTokensPoolConcurrency)
208245
for _, poolAddr := range pools {
209246
// there is no supported pool for this token
210247
if poolAddr == (common.Address{}) {
211248
continue
212249
}
213-
tokenPoolC, err := token_pool.NewTokenPool(poolAddr, chain.Client)
214-
if err != nil {
215-
return nil, fmt.Errorf("failed to instantiate token pool contract at %s on chain %d: %w", poolAddr.String(), chain.Selector, err)
216-
}
217-
chains, err := tokenPoolC.GetSupportedChains(nil)
218-
if err != nil {
219-
return nil, fmt.Errorf("failed to get supported chains from token pool at %s on chain %d: %w", poolAddr.String(), chain.Selector, err)
220-
}
221-
tokenAddr, err := tokenPoolC.GetToken(nil)
222-
if err != nil {
223-
return nil, fmt.Errorf("failed to get token address from token pool at %s on chain %d: %w", poolAddr.String(), chain.Selector, err)
224-
}
225-
for _, remoteChain := range chains {
226-
tokensPerRemoteChain[remoteChain] = append(tokensPerRemoteChain[remoteChain], tokenAddr)
227-
}
250+
poolAddr := poolAddr
251+
grp.Go(func() error {
252+
tokenPoolC, err := token_pool.NewTokenPool(poolAddr, chain.Client)
253+
if err != nil {
254+
return fmt.Errorf("failed to instantiate token pool contract at %s on chain %d: %w", poolAddr.String(), chain.Selector, err)
255+
}
256+
257+
// Cache the token address per pool so we only fetch it once, and
258+
// track when certain pool methods appear to be unsupported so we
259+
// can avoid repeated failed calls and warning spam.
260+
var (
261+
tokenAddr common.Address
262+
tokenFetched bool
263+
isSupportedChainUnsupported bool
264+
getTokenUnsupported bool
265+
)
266+
267+
for _, remoteChain := range remoteChains {
268+
// If we've already determined that IsSupportedChain or GetToken
269+
// are unsupported for this pool, stop checking further chains.
270+
if isSupportedChainUnsupported || getTokenUnsupported {
271+
break
272+
}
273+
274+
supported, err := tokenPoolC.IsSupportedChain(&bind.CallOpts{
275+
Context: grpCtx,
276+
}, remoteChain)
277+
if err != nil {
278+
// If we fail to check if the pool supports a remote chain,
279+
// assume this method isn't supported by this pool, log once,
280+
// and short-circuit to avoid failing the entire import and
281+
// spamming warnings for every remote chain.
282+
l.Warnf("failed to check if token pool at %s on chain %d supports remote chain %d: %v", poolAddr.String(), chain.Selector, remoteChain, err)
283+
isSupportedChainUnsupported = true
284+
break
285+
}
286+
if !supported {
287+
continue
288+
}
289+
290+
// Fetch the token address at most once per pool.
291+
if !tokenFetched {
292+
tokenAddr, err = tokenPoolC.GetToken(&bind.CallOpts{
293+
Context: grpCtx,
294+
})
295+
if err != nil {
296+
// If we fail to get the token address for a pool, assume
297+
// this method isn't supported or is consistently failing
298+
// for this pool. Log once and short-circuit further
299+
// attempts for this pool to avoid warning spam.
300+
l.Warnf("failed to get token address for token pool at %s on chain %d: %v", poolAddr.String(), chain.Selector, err)
301+
getTokenUnsupported = true
302+
break
303+
}
304+
tokenFetched = true
305+
}
306+
307+
mu.Lock()
308+
tokensPerRemoteChain[remoteChain] = append(tokensPerRemoteChain[remoteChain], tokenAddr)
309+
mu.Unlock()
310+
}
311+
return nil
312+
})
313+
}
314+
if err := grp.Wait(); err != nil {
315+
return nil, err
228316
}
229317
return tokensPerRemoteChain, nil
230318
}

0 commit comments

Comments
 (0)