Skip to content

Commit f159b1c

Browse files
authored
token expansion v2 (#998)
* wip * gomod * gomod * fix * tidy * refactor token combos * lint * comments * Revert "comments" This reverts commit 8d78711. * comments * Revert "comments" This reverts commit eb6bad7. * bump * split * gomod * gomod
1 parent 2841adc commit f159b1c

12 files changed

Lines changed: 818 additions & 492 deletions

File tree

build/devenv/cciptestinterfaces/interface.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import (
1111
"github.com/prometheus/client_golang/prometheus"
1212

1313
"github.com/smartcontractkit/chainlink-ccip/deployment/lanes"
14+
tokensapi "github.com/smartcontractkit/chainlink-ccip/deployment/tokens"
1415
"github.com/smartcontractkit/chainlink-ccip/deployment/v1_7_0/adapters"
1516
"github.com/smartcontractkit/chainlink-ccip/deployment/v1_7_0/offchain"
17+
devenvcommon "github.com/smartcontractkit/chainlink-ccv/build/devenv/common"
1618
"github.com/smartcontractkit/chainlink-ccv/protocol"
1719
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
1820
"github.com/smartcontractkit/chainlink-deployments-framework/deployment"
@@ -218,6 +220,46 @@ type ChainLaneProfile struct {
218220
GasForVerification uint32
219221
}
220222

223+
// TokenConfigProvider abstracts the chain-specific decisions that feed into
224+
// TokenExpansion (token type, decimals, admin addresses, pre-mint amounts)
225+
// and any post-deployment work (e.g. funding lock-release pools on EVM).
226+
//
227+
// It is separate from OnChainConfigurable so chain families can deploy CCIP
228+
// core contracts and lanes without implementing token pools (e.g. messaging-only
229+
// or AltVM before token support exists). Devenv uses type assertions; when absent,
230+
// token deployment and ConfigureTokensForTransfers are skipped.
231+
type TokenConfigProvider interface {
232+
// GetSupportedPools returns pool types and versions this chain can deploy.
233+
GetSupportedPools() []devenvcommon.PoolCapability
234+
235+
// GetTokenExpansionConfigs returns one TokenExpansionInputPerChain per
236+
// token/pool that should be deployed on the given chain, driven by the
237+
// pre-computed token combinations. Return nil, nil if token transfers
238+
// are not supported.
239+
GetTokenExpansionConfigs(
240+
env *deployment.Environment,
241+
selector uint64,
242+
combos []devenvcommon.TokenCombination,
243+
) ([]tokensapi.TokenExpansionInputPerChain, error)
244+
245+
// PostTokenDeploy runs chain-specific work after all tokens and pools have
246+
// been deployed via TokenExpansion (e.g. funding lock-release pools on EVM).
247+
PostTokenDeploy(
248+
env *deployment.Environment,
249+
selector uint64,
250+
deployedRefs []datastore.AddressRef,
251+
) error
252+
253+
// GetTokenTransferConfigs builds TokenTransferConfig entries for all pools
254+
// deployed on this chain, using chain-specific registry and CCV refs.
255+
GetTokenTransferConfigs(
256+
env *deployment.Environment,
257+
selector uint64,
258+
remoteSelectors []uint64,
259+
topology *offchain.EnvironmentTopology,
260+
) ([]tokensapi.TokenTransferConfig, error)
261+
}
262+
221263
// OnChainConfigurable defines methods that allows devenv to
222264
// deploy, configure Chainlink product and connect on-chain part with other chains.
223265
type OnChainConfigurable interface {

build/devenv/common/common.go

Lines changed: 274 additions & 99 deletions
Large diffs are not rendered by default.

build/devenv/environment.go

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import (
2222

2323
chainsel "github.com/smartcontractkit/chain-selectors"
2424

25-
tokenscore "github.com/smartcontractkit/chainlink-ccip/deployment/tokens"
26-
changesetscore "github.com/smartcontractkit/chainlink-ccip/deployment/utils/changesets"
2725
ccipAdapters "github.com/smartcontractkit/chainlink-ccip/deployment/v1_7_0/adapters"
2826
ccipChangesets "github.com/smartcontractkit/chainlink-ccip/deployment/v1_7_0/changesets"
2927
ccipOffchain "github.com/smartcontractkit/chainlink-ccip/deployment/v1_7_0/offchain"
@@ -36,7 +34,6 @@ import (
3634
"github.com/smartcontractkit/chainlink-ccv/build/devenv/services/chainconfig"
3735
"github.com/smartcontractkit/chainlink-ccv/build/devenv/services/committeeverifier"
3836
executorsvc "github.com/smartcontractkit/chainlink-ccv/build/devenv/services/executor"
39-
"github.com/smartcontractkit/chainlink-ccv/build/devenv/tokenconfig"
4037
"github.com/smartcontractkit/chainlink-ccv/build/devenv/util"
4138
"github.com/smartcontractkit/chainlink-ccv/executor"
4239
"github.com/smartcontractkit/chainlink-ccv/indexer/pkg/config"
@@ -1025,6 +1022,21 @@ func NewEnvironment() (in *Cfg, err error) {
10251022
}
10261023

10271024
timeTrack.Record("[infra] deploying blockchains")
1025+
// Collect pool capabilities from all impls and compute valid cross-chain combinations.
1026+
capsBySelector := make(map[uint64][]devenvcommon.PoolCapability, len(impls))
1027+
for i, impl := range impls {
1028+
networkInfo, lookupErr := chainsel.GetChainDetailsByChainIDAndFamily(in.Blockchains[i].ChainID, impl.ChainFamily())
1029+
if lookupErr != nil {
1030+
return nil, lookupErr
1031+
}
1032+
if tcp, ok := impl.(cciptestinterfaces.TokenConfigProvider); ok {
1033+
capsBySelector[networkInfo.ChainSelector] = tcp.GetSupportedPools()
1034+
} else {
1035+
capsBySelector[networkInfo.ChainSelector] = nil
1036+
}
1037+
}
1038+
combos := devenvcommon.ComputeTokenCombinations(capsBySelector, topology)
1039+
10281040
ds := datastore.NewMemoryDataStore()
10291041
for i, impl := range impls {
10301042
var networkInfo chainsel.ChainDetails
@@ -1041,13 +1053,41 @@ func NewEnvironment() (in *Cfg, err error) {
10411053
return nil, fmt.Errorf("failed to bump deployer nonce for chain %d: %w", networkInfo.ChainSelector, err)
10421054
}
10431055
}
1056+
// Per-chain accumulator so we can report all addresses deployed in
1057+
// this iteration (core contracts + tokens) to in.CLDF.
1058+
chainDS := datastore.NewMemoryDataStore()
1059+
10441060
var dsi datastore.DataStore
10451061
dsi, err = impl.DeployContractsForSelector(ctx, e, networkInfo.ChainSelector, topology)
10461062
if err != nil {
10471063
return nil, err
10481064
}
1065+
if err = ds.Merge(dsi); err != nil {
1066+
return nil, err
1067+
}
1068+
if err = chainDS.Merge(dsi); err != nil {
1069+
return nil, err
1070+
}
1071+
e.DataStore = ds.Seal()
1072+
1073+
// Deploy generic tokens and pools via the chain-agnostic path.
1074+
// USDC and Lombard stay inside DeployContractsForSelector.
1075+
tokenDS := datastore.NewMemoryDataStore()
1076+
if tcp, ok := impl.(cciptestinterfaces.TokenConfigProvider); ok {
1077+
if err = DeployTokensAndPools(tcp, e, networkInfo.ChainSelector, combos, tokenDS); err != nil {
1078+
return nil, fmt.Errorf("deploy tokens and pools for selector %d: %w", networkInfo.ChainSelector, err)
1079+
}
1080+
}
1081+
if err = ds.Merge(tokenDS.Seal()); err != nil {
1082+
return nil, err
1083+
}
1084+
if err = chainDS.Merge(tokenDS.Seal()); err != nil {
1085+
return nil, err
1086+
}
1087+
e.DataStore = ds.Seal()
1088+
10491089
var addresses []datastore.AddressRef
1050-
addresses, err = dsi.Addresses().Fetch()
1090+
addresses, err = chainDS.Seal().Addresses().Fetch()
10511091
if err != nil {
10521092
return nil, err
10531093
}
@@ -1057,9 +1097,6 @@ func NewEnvironment() (in *Cfg, err error) {
10571097
return nil, err
10581098
}
10591099
in.CLDF.AddAddresses(string(a))
1060-
if err = ds.Merge(dsi); err != nil {
1061-
return nil, err
1062-
}
10631100
}
10641101
e.DataStore = ds.Seal()
10651102
///////////////////////////
@@ -1070,33 +1107,10 @@ func NewEnvironment() (in *Cfg, err error) {
10701107
// START: Connect chains to each other //
10711108
/////////////////////////////////////////
10721109

1073-
// ConfigureTokensForTransfers must run first so token pools (including those used by CCTP/Lombard)
1074-
// have remote chain allowlists set. Otherwise sends can revert with custom error 0xa9902c7e (chain
1075-
// not allowed), where the error argument is the destination chain selector.
1076-
// Call it once per pool-identity group (e.g. all chains' configs for "BurnMintTokenPool 2.0.0 default"):
1077-
// an internal mapping is keyed such that the last config in the list gets the index for a given chain
1078-
// selector, so we invoke once per setup with all counterpart configs (same pool type on every chain)
1079-
// so remote tokens and mapping slots are correct.
1080-
// Token adapter registration is already registry-based (EVM adapters registered in evm/impl.go init()).
1081-
// A future improvement: add a GetTokenTransferConfigs() method to CCIP17Configuration so each
1082-
// chain impl provides its own token configs, rather than using a centralized BuildTokenTransferConfigs.
1083-
allTokenConfigs := tokenconfig.BuildTokenTransferConfigs(topology, selectors, e.DataStore)
1084-
if len(allTokenConfigs) > 0 {
1085-
byPoolIdentity := make(map[string][]tokenscore.TokenTransferConfig)
1086-
for i := range allTokenConfigs {
1087-
key := tokenconfig.PoolIdentityKey(&allTokenConfigs[i])
1088-
byPoolIdentity[key] = append(byPoolIdentity[key], allTokenConfigs[i])
1089-
}
1090-
tokenAdapterRegistry := tokenscore.GetTokenAdapterRegistry()
1091-
mcmsReaderRegistry := changesetscore.GetRegistry()
1092-
for _, group := range byPoolIdentity {
1093-
_, err = tokenscore.ConfigureTokensForTransfers(tokenAdapterRegistry, mcmsReaderRegistry).Apply(*e, tokenscore.ConfigureTokensForTransfersConfig{
1094-
Tokens: group,
1095-
})
1096-
if err != nil {
1097-
return nil, fmt.Errorf("configure tokens for transfers: %w", err)
1098-
}
1099-
}
1110+
// Configure cross-chain token transfers: each chain impl builds its own
1111+
// TokenTransferConfigs using chain-specific registry and CCV refs.
1112+
if err = ConfigureAllTokenTransfers(impls, selectors, e, topology); err != nil {
1113+
return nil, fmt.Errorf("configure all token transfers: %w", err)
11001114
}
11011115

11021116
var connectErr error

0 commit comments

Comments
 (0)