Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ee50242
Add GetFQAddressDynamic functionality
sowgandhi11 Mar 24, 2026
b6c4fa1
Fix build error
sowgandhi11 Mar 24, 2026
8cd6c9b
ChainFamilyAdapter implement DynamicFeeQuoter interface
sowgandhi11 Mar 24, 2026
683b2f1
Add default case for get fq address non dynamically
sowgandhi11 Mar 25, 2026
f4f63bf
Merge branch 'main' into sowgandhi11/CCIP-9957
sowgandhi11 Mar 25, 2026
c1ff026
Fix build errors
sowgandhi11 Mar 25, 2026
02fd0b4
use the non-v2 bind package for *bind.CallOpts
sowgandhi11 Mar 25, 2026
7ad3901
Use ptr for Environment param in populateAddresses
sowgandhi11 Mar 25, 2026
540f514
Merge branch 'main' into sowgandhi11/CCIP-9957
sowgandhi11 Mar 25, 2026
41a4657
Add tests & fix GetFQVersion to use dynamic address
sowgandhi11 Mar 25, 2026
2f40094
Fix build errors
sowgandhi11 Mar 26, 2026
aafd986
Merge branch 'main' into sowgandhi11/CCIP-9957
sowgandhi11 Mar 26, 2026
05c0085
Fix tests
sowgandhi11 Mar 26, 2026
e7ff734
Debugging
sowgandhi11 Mar 26, 2026
7ec7ed3
Debugging
sowgandhi11 Mar 26, 2026
a0c0f30
Fix debugging case
sowgandhi11 Mar 26, 2026
15b8020
Fix debug
sowgandhi11 Mar 26, 2026
d83a887
Revert any changes to TestConnectChains_EVM2EVM_UpgradeFeeQuoter_Then…
sowgandhi11 Mar 26, 2026
cf32bc7
cleanup
sowgandhi11 Mar 26, 2026
5b9705d
Merge branch 'main' into sowgandhi11/CCIP-9957
sowgandhi11 Mar 26, 2026
6c1fe3b
Adding check to ensure new interface method references 1.6.3 FQ
sowgandhi11 Mar 26, 2026
51d9553
Fix chain family mismatch
sowgandhi11 Mar 26, 2026
d33dfcf
Merge branch 'main' into sowgandhi11/CCIP-9957
sowgandhi11 Mar 27, 2026
ff4048a
Switch fatal messages to require statements in TestDowngradeLane_Conn…
sowgandhi11 Mar 27, 2026
e2f35dc
Switch fatal messages to require statements in TestDowngradeLane_Conn…
sowgandhi11 Mar 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions ccv/chains/evm/deployment/v1_7_0/adapters/chain_family.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package adapters

import (
"encoding/binary"
"fmt"
"math/big"

"github.com/smartcontractkit/chainlink-deployments-framework/chain"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"

cldf_chain "github.com/smartcontractkit/chainlink-deployments-framework/chain"
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
"github.com/smartcontractkit/chainlink-deployments-framework/operations"

Expand All @@ -24,12 +28,12 @@ import (
type ChainFamilyAdapter struct{}

// ConfigureLaneLegAsSource returns the sequence for configuring a chain of the EVM family as a source chain for CCIP lanes.
func (c *ChainFamilyAdapter) ConfigureLaneLegAsSource() *operations.Sequence[lanes.UpdateLanesInput, seq_core.OnChainOutput, chain.BlockChains] {
func (c *ChainFamilyAdapter) ConfigureLaneLegAsSource() *operations.Sequence[lanes.UpdateLanesInput, seq_core.OnChainOutput, cldf_chain.BlockChains] {
return sequences.ConfigureLaneLegAsSource
}

// ConfigureLaneLegAsDest returns the sequence for configuring a chain of the EVM family as a destination chain for CCIP lanes.
func (c *ChainFamilyAdapter) ConfigureLaneLegAsDest() *operations.Sequence[lanes.UpdateLanesInput, seq_core.OnChainOutput, chain.BlockChains] {
func (c *ChainFamilyAdapter) ConfigureLaneLegAsDest() *operations.Sequence[lanes.UpdateLanesInput, seq_core.OnChainOutput, cldf_chain.BlockChains] {
return sequences.ConfigureLaneLegAsDest
}

Expand Down Expand Up @@ -69,7 +73,36 @@ func (a *ChainFamilyAdapter) GetFQAddress(ds datastore.DataStore, chainSelector
return addr, nil
}

func (c *ChainFamilyAdapter) DisableRemoteChain() *operations.Sequence[lanes.DisableRemoteChainInput, seq_core.OnChainOutput, chain.BlockChains] {
func (a *ChainFamilyAdapter) GetFQAddressDynamic(ds datastore.DataStore, chainSelector uint64, chains cldf_chain.BlockChains) ([]byte, error) {
onRampAddr, err := datastore_utils.FindAndFormatRef(ds, datastore.AddressRef{
ChainSelector: chainSelector,
Type: datastore.ContractType(onramp.ContractType),
Version: onramp.Version,
}, chainSelector, evm_datastore_utils.ToEVMAddressBytes)
if err != nil {
return nil, fmt.Errorf("failed to find onramp address for chain selector %d: %w", chainSelector, err)
}

chain := chains.EVMChains()[chainSelector]

onrampContract, err := onramp.NewOnRampContract(common.BytesToAddress(onRampAddr), chain.Client)
if err != nil {
return nil, fmt.Errorf("failed to create onramp contract instance for chain selector %d: %w", chainSelector, err)
}

dynamicConfig, err := onrampContract.GetDynamicConfig(&bind.CallOpts{})
if err != nil {
return nil, fmt.Errorf("failed to call GetDynamicConfig on onramp contract for chain selector %d: %w", chainSelector, err)
}

fqAddress := dynamicConfig.FeeQuoter
if fqAddress == (common.Address{}) {
return nil, fmt.Errorf("fee quoter address is zero in onramp dynamic config for chain selector %d", chainSelector)
}
return common.Address(fqAddress).Bytes(), nil
}

func (c *ChainFamilyAdapter) DisableRemoteChain() *operations.Sequence[lanes.DisableRemoteChainInput, seq_core.OnChainOutput, cldf_chain.BlockChains] {
return evm_sequences.DisableRemoteChainSequence
}

Expand Down
2 changes: 1 addition & 1 deletion chains/evm/deployment/v1_6_0/adapters/fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func NewFeesAdapter(evmAdapter *evmseq.EVMAdapter) *FeesAdapter {

func (a *FeesAdapter) GetFeeContractRef(e cldf.Environment, src uint64, dst uint64) (datastore.AddressRef, error) {
ds := e.DataStore
fqAddr, err := a.evm.GetFQAddress(ds, src)
fqAddr, err := a.evm.GetFQAddressDynamic(ds, src, e.BlockChains)
if err != nil {
return datastore.AddressRef{}, fmt.Errorf("failed to get FeeQuoter address for chain selector %d: %w", src, err)
}
Expand Down
55 changes: 46 additions & 9 deletions chains/evm/deployment/v1_6_0/sequences/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"math/big"

"github.com/Masterminds/semver/v3"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"

chain_selectors "github.com/smartcontractkit/chain-selectors"
Expand Down Expand Up @@ -87,6 +88,34 @@ func (a *EVMAdapter) GetFQAddress(ds datastore.DataStore, chainSelector uint64)
return evm_datastore_utils.ToEVMAddressBytes(ref)
}

func (a *EVMAdapter) GetFQAddressDynamic(ds datastore.DataStore, chainSelector uint64, chains cldf_chain.BlockChains) ([]byte, error) {
onRampAddr, err := datastore_utils.FindAndFormatRef(ds, datastore.AddressRef{
ChainSelector: chainSelector,
Type: datastore.ContractType(onramp.ContractType),
Version: onramp.Version,
}, chainSelector, evm_datastore_utils.ToEVMAddressBytes)
if err != nil {
return nil, fmt.Errorf("failed to find onramp address for chain selector %d: %w", chainSelector, err)
}

chain := chains.EVMChains()[chainSelector]

onrampContract, err := onramp.NewOnRampContract(common.BytesToAddress(onRampAddr), chain.Client)
if err != nil {
return nil, fmt.Errorf("failed to create onramp contract instance for chain selector %d: %w", chainSelector, err)
}
dynamicConfig, err := onrampContract.GetDynamicConfig(&bind.CallOpts{})
if err != nil {
return nil, fmt.Errorf("failed to call GetDynamicConfig on onramp contract for chain selector %d: %w", chainSelector, err)
Comment on lines +107 to +109
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

This file imports github.com/ethereum/go-ethereum/accounts/abi/bind/v2, but the generated onramp contract wrapper (chains/evm/deployment/v1_6_0/operations/onramp) uses github.com/ethereum/go-ethereum/accounts/abi/bind and expects *bind.CallOpts. As written, &bind.CallOpts{} will be the wrong type and won’t compile; use the non-v2 bind package or simply pass nil call opts to GetDynamicConfig.

Copilot uses AI. Check for mistakes.
}

fqAddress := dynamicConfig.FeeQuoter
if fqAddress == (common.Address{}) {
return nil, fmt.Errorf("fee quoter address is zero in onramp dynamic config for chain selector %d", chainSelector)
}
return common.Address(fqAddress).Bytes(), nil
}

func (a *EVMAdapter) GetRouterAddress(ds datastore.DataStore, chainSelector uint64) ([]byte, error) {
addr, err := datastore_utils.FindAndFormatRef(ds, datastore.AddressRef{
ChainSelector: chainSelector,
Expand Down Expand Up @@ -243,18 +272,26 @@ func (a *EVMAdapter) GetChainFamilySelector() [4]byte {

// GetFQVersion implements the optional FeeQuoterVersionProvider interface so that
// update_lanes can choose 1.6 vs 2.0 FeeQuoter operations based on the deployed contract version.
func (a *EVMAdapter) GetFQVersion(ds datastore.DataStore, address []byte, chainSelector uint64) (*semver.Version, error) {
refs := ds.Addresses().Filter(
datastore.AddressRefByType(datastore.ContractType(fee_quoter.ContractType)),
datastore.AddressRefByChainSelector(chainSelector),
)
ref, err := GetFeeQuoterAddress(refs, chainSelector, nil)
func (a *EVMAdapter) GetFQVersion(ds datastore.DataStore, address []byte, chainSelector uint64, chains cldf_chain.BlockChains) (*semver.Version, error) {
addressOnChain, err := a.GetFQAddressDynamic(ds, chainSelector, chains)
if err != nil {
return nil, err
}
// Sanity check that the AddressRef we found matches the one we expect.
if ref.Address != common.BytesToAddress(address).Hex() {
return nil, fmt.Errorf("fee quoter address mismatch for chain selector %d: expected %s, got %s", chainSelector, common.BytesToAddress(address).Hex(), ref.Address)
if common.BytesToAddress(addressOnChain).Hex() != common.BytesToAddress(address).Hex() {
return nil, fmt.Errorf("fee quoter address mismatch for chain selector %d: expected %s, got %s", chainSelector, common.BytesToAddress(address).Hex(), common.BytesToAddress(addressOnChain).Hex())
}

ref := ds.Addresses().Filter(
datastore.AddressRefByType(datastore.ContractType(fee_quoter.ContractType)),
datastore.AddressRefByChainSelector(chainSelector),
datastore.AddressRefByAddress(common.BytesToAddress(address).Hex()),
)
if len(ref) == 0 {
return nil, fmt.Errorf("no fee quoter address found for chain selector %d at address %s", chainSelector, common.BytesToAddress(address).Hex())
}
if len(ref) > 1 {
return nil, fmt.Errorf("multiple fee quoter addresses found for chain selector %d at address %s", chainSelector, common.BytesToAddress(address).Hex())
}
return ref.Version, nil
return ref[0].Version, nil
}
2 changes: 1 addition & 1 deletion chains/evm/deployment/v2_0_0/adapters/fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func NewFeesAdapter(evmAdapter *evmseq16.EVMAdapter) *FeesAdapter {

func (a *FeesAdapter) GetFeeContractRef(e cldf.Environment, src uint64, dst uint64) (datastore.AddressRef, error) {
ds := e.DataStore
fqAddr, err := a.evm.GetFQAddress(ds, src)
fqAddr, err := a.evm.GetFQAddressDynamic(ds, src, e.BlockChains)
if err != nil {
return datastore.AddressRef{}, fmt.Errorf("failed to get FeeQuoter address for chain selector %d: %w", src, err)
}
Expand Down
22 changes: 15 additions & 7 deletions deployment/lanes/connect_chains.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,11 @@ func makeApply(laneRegistry *LaneAdapterRegistry, mcmsRegistry *changesets.MCMSR
if !exists {
return cldf.ChangesetOutput{}, fmt.Errorf("no ChainAdapter registered for chain family '%s'", chainBFamily)
}
err = populateAddresses(e.DataStore, chainA, chainAAdapter, lane.Version, lane.TestRouter)
err = populateAddresses(&e, chainA, chainAAdapter, lane.Version, lane.TestRouter)
if err != nil {
return cldf.ChangesetOutput{}, fmt.Errorf("error fetching address for src chain %d: %w", chainA.Selector, err)
}
err = populateAddresses(e.DataStore, chainB, chainBAdapter, lane.Version, lane.TestRouter)
err = populateAddresses(&e, chainB, chainBAdapter, lane.Version, lane.TestRouter)
if err != nil {
return cldf.ChangesetOutput{}, fmt.Errorf("error fetching address for dest chain %d: %w", chainB.Selector, err)
}
Expand Down Expand Up @@ -257,7 +257,8 @@ func populateCommitteeInputsIfNeeded(e cldf.Environment, lane *LaneConfig, popul
return nil
}

func populateAddresses(ds datastore.DataStore, chainDef *ChainDefinition, adapter LaneAdapter, version *semver.Version, isTestRouter bool) error {
func populateAddresses(e *cldf.Environment, chainDef *ChainDefinition, adapter LaneAdapter, version *semver.Version, isTestRouter bool) error {
ds := e.DataStore
var err error
chainDef.OnRamp, err = adapter.GetOnRampAddress(ds, chainDef.Selector)
if err != nil {
Expand All @@ -267,12 +268,19 @@ func populateAddresses(ds datastore.DataStore, chainDef *ChainDefinition, adapte
if err != nil {
return fmt.Errorf("error fetching offramp address for chain %d: %w", chainDef.Selector, err)
}
chainDef.FeeQuoter, err = adapter.GetFQAddress(ds, chainDef.Selector)
if err != nil {
return fmt.Errorf("error fetching fee quoter address for chain %d: %w", chainDef.Selector, err)
if dfq, ok := adapter.(DynamicFeeQuoter); ok {
chainDef.FeeQuoter, err = dfq.GetFQAddressDynamic(ds, chainDef.Selector, e.BlockChains)
if err != nil {
return fmt.Errorf("error fetching fee quoter address for chain %d: %w", chainDef.Selector, err)
}
} else {
chainDef.FeeQuoter, err = adapter.GetFQAddress(ds, chainDef.Selector)
if err != nil {
return fmt.Errorf("error fetching fee quoter address for chain %d: %w", chainDef.Selector, err)
}
}
if vp, ok := adapter.(FeeQuoterVersionProvider); ok {
chainDef.FeeQuoterVersion, err = vp.GetFQVersion(ds, chainDef.FeeQuoter, chainDef.Selector)
chainDef.FeeQuoterVersion, err = vp.GetFQVersion(ds, chainDef.FeeQuoter, chainDef.Selector, e.BlockChains)
if err != nil {
return fmt.Errorf("error fetching fee quoter version for chain %d: %w", chainDef.Selector, err)
}
Expand Down
4 changes: 2 additions & 2 deletions deployment/lanes/disable_lane.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ func makeDisableApply(
chainADef := &ChainDefinition{Selector: lane.ChainA}
chainBDef := &ChainDefinition{Selector: lane.ChainB}

err = populateAddresses(e.DataStore, chainADef, chainAAdapter, lane.Version, false)
err = populateAddresses(&e, chainADef, chainAAdapter, lane.Version, false)
if err != nil {
return cldf.ChangesetOutput{}, fmt.Errorf("error fetching addresses for chain %d: %w", lane.ChainA, err)
}
err = populateAddresses(e.DataStore, chainBDef, chainBAdapter, lane.Version, false)
err = populateAddresses(&e, chainBDef, chainBAdapter, lane.Version, false)
if err != nil {
return cldf.ChangesetOutput{}, fmt.Errorf("error fetching addresses for chain %d: %w", lane.ChainB, err)
}
Expand Down
7 changes: 6 additions & 1 deletion deployment/lanes/product.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ type LaneAdapter interface {
// to report the FeeQuoter contract version for a chain (e.g. 1.6.x vs 2.0.x).
// When set, it is used to choose the correct FeeQuoter operations in update_lanes.
type FeeQuoterVersionProvider interface {
GetFQVersion(ds datastore.DataStore, address []byte, chainSelector uint64) (*semver.Version, error)
GetFQVersion(ds datastore.DataStore, address []byte, chainSelector uint64, chains cldf_chain.BlockChains) (*semver.Version, error)
}

// DynamicFeeQuoter is an optional interface that LaneAdapters can implement to dynamically retrieve the FeeQuoter.
type DynamicFeeQuoter interface {
GetFQAddressDynamic(ds datastore.DataStore, chainSelector uint64, chains cldf_chain.BlockChains) ([]byte, error)
}

// TokenPriceProvider is an optional interface that LaneAdapters can implement
Expand Down
Loading
Loading