From 674605ea505f4cc98ddd35791583b73b32382ec6 Mon Sep 17 00:00:00 2001 From: Anindita Ghosh <88458927+AnieeG@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:57:42 -0700 Subject: [PATCH] Ccip-3398 populate state initial PR (#14391) * initial draft * individual snapshot * change interface name * changes * add all destchainselectors * rmn details * more changes * omitempty * add onRamp reader * changes * format errors * add Feequoter * change approach direct go-binding reference * fix import cycle * moduler * fix panic * add interface for snapshot * more changes * rename * fix lint * more review comments * fix rmnremote version * one more fix --------- Co-authored-by: Oliver Townsend --- integration-tests/deployment/ccip/deploy.go | 2 +- .../deployment/ccip/deploy_test.go | 2 +- integration-tests/deployment/ccip/state.go | 172 ++++++++---------- .../deployment/ccip/view/chain.go | 27 +++ .../deployment/ccip/view/state.go | 11 ++ .../ccip/view/types/contract_state.go | 33 ++++ .../deployment/ccip/view/v1_2/router.go | 56 ++++++ .../ccip/view/v1_5/tokenadminregistry.go | 30 +++ .../deployment/ccip/view/v1_6/feequoter.go | 153 ++++++++++++++++ .../deployment/ccip/view/v1_6/noncemanager.go | 31 ++++ .../deployment/ccip/view/v1_6/onramp.go | 106 +++++++++++ .../deployment/ccip/view/v1_6/rmnremote.go | 54 ++++++ 12 files changed, 579 insertions(+), 98 deletions(-) create mode 100644 integration-tests/deployment/ccip/view/chain.go create mode 100644 integration-tests/deployment/ccip/view/state.go create mode 100644 integration-tests/deployment/ccip/view/types/contract_state.go create mode 100644 integration-tests/deployment/ccip/view/v1_2/router.go create mode 100644 integration-tests/deployment/ccip/view/v1_5/tokenadminregistry.go create mode 100644 integration-tests/deployment/ccip/view/v1_6/feequoter.go create mode 100644 integration-tests/deployment/ccip/view/v1_6/noncemanager.go create mode 100644 integration-tests/deployment/ccip/view/v1_6/onramp.go create mode 100644 integration-tests/deployment/ccip/view/v1_6/rmnremote.go diff --git a/integration-tests/deployment/ccip/deploy.go b/integration-tests/deployment/ccip/deploy.go index f0641b65165..358a72bad11 100644 --- a/integration-tests/deployment/ccip/deploy.go +++ b/integration-tests/deployment/ccip/deploy.go @@ -248,7 +248,7 @@ func DeployChainContracts( chain.Selector, ) return ContractDeploy[*rmn_remote.RMNRemote]{ - rmnRemoteAddr, rmnRemote, tx, deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_0_0), err2, + rmnRemoteAddr, rmnRemote, tx, deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_6_0_dev), err2, } }) if err != nil { diff --git a/integration-tests/deployment/ccip/deploy_test.go b/integration-tests/deployment/ccip/deploy_test.go index db739f64134..a278f29842e 100644 --- a/integration-tests/deployment/ccip/deploy_test.go +++ b/integration-tests/deployment/ccip/deploy_test.go @@ -51,7 +51,7 @@ func TestDeployCCIPContracts(t *testing.T) { require.NoError(t, err) state, err := LoadOnchainState(e, ab) require.NoError(t, err) - snap, err := state.Snapshot(e.AllChainSelectors()) + snap, err := state.View(e.AllChainSelectors()) require.NoError(t, err) // Assert expect every deployed address to be in the address book. diff --git a/integration-tests/deployment/ccip/state.go b/integration-tests/deployment/ccip/state.go index d32c51ae65f..d6bd8894396 100644 --- a/integration-tests/deployment/ccip/state.go +++ b/integration-tests/deployment/ccip/state.go @@ -11,11 +11,19 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/deployment" - owner_wrappers "github.com/smartcontractkit/ccip-owner-contracts/tools/gethwrappers" + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view" + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/v1_2" + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/v1_5" + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/v1_6" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" + + owner_wrappers "github.com/smartcontractkit/ccip-owner-contracts/tools/gethwrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/nonce_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" @@ -25,8 +33,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" ) type CCIPChainState struct { @@ -61,6 +67,58 @@ type CCIPChainState struct { TestRouter *router.Router } +func (c CCIPChainState) GenerateView() (view.ChainView, error) { + chainView := view.NewChain() + if c.Router != nil { + routerView, err := v1_2.GenerateRouterView(c.Router) + if err != nil { + return chainView, err + } + chainView.Router[c.Router.Address().Hex()] = routerView + } + if c.TokenAdminRegistry != nil { + taView, err := v1_5.GenerateTokenAdminRegistryView(c.TokenAdminRegistry) + if err != nil { + return chainView, err + } + chainView.TokenAdminRegistry[c.TokenAdminRegistry.Address().Hex()] = taView + } + if c.NonceManager != nil { + nmView, err := v1_6.GenerateNonceManagerView(c.NonceManager) + if err != nil { + return chainView, err + } + chainView.NonceManager[c.NonceManager.Address().Hex()] = nmView + } + if c.RMNRemote != nil { + rmnView, err := v1_6.GenerateRMNRemoteView(c.RMNRemote) + if err != nil { + return chainView, err + } + chainView.RMN[c.RMNRemote.Address().Hex()] = rmnView + } + if c.FeeQuoter != nil && c.Router != nil && c.TokenAdminRegistry != nil { + fqView, err := v1_6.GenerateFeeQuoterView(c.FeeQuoter, c.Router, c.TokenAdminRegistry) + if err != nil { + return chainView, err + } + chainView.FeeQuoter[c.FeeQuoter.Address().Hex()] = fqView + } + + if c.OnRamp != nil && c.Router != nil && c.TokenAdminRegistry != nil { + onRampView, err := v1_6.GenerateOnRampView( + c.OnRamp, + c.Router, + c.TokenAdminRegistry, + ) + if err != nil { + return chainView, err + } + chainView.OnRamp[c.OnRamp.Address().Hex()] = onRampView + } + return chainView, nil +} + // Onchain state always derivable from an address book. // Offchain state always derivable from a list of nodeIds. // Note can translate this into Go struct needed for MCMS/Docs/UI. @@ -71,115 +129,37 @@ type CCIPOnChainState struct { Chains map[uint64]CCIPChainState } -type CCIPSnapShot struct { - Chains map[string]Chain `json:"chains"` -} - -type Contract struct { - TypeAndVersion string `json:"typeAndVersion"` - Address common.Address `json:"address"` -} - -type TokenAdminRegistryView struct { - Contract - Tokens []common.Address `json:"tokens"` -} - -type NonceManagerView struct { - Contract - AuthorizedCallers []common.Address `json:"authorizedCallers"` -} - -type Chain struct { - // TODO: this will have to be versioned for getting state during upgrades. - TokenAdminRegistry TokenAdminRegistryView `json:"tokenAdminRegistry"` - NonceManager NonceManagerView `json:"nonceManager"` -} - -func (s CCIPOnChainState) Snapshot(chains []uint64) (CCIPSnapShot, error) { - snapshot := CCIPSnapShot{ - Chains: make(map[string]Chain), - } +func (s CCIPOnChainState) View(chains []uint64) (view.CCIPView, error) { + ccipView := view.NewCCIPView() for _, chainSelector := range chains { // TODO: Need a utility for this chainid, err := chainsel.ChainIdFromSelector(chainSelector) if err != nil { - return snapshot, err + return ccipView, err } chainName, err := chainsel.NameFromChainId(chainid) if err != nil { - return snapshot, err + return ccipView, err } if _, ok := s.Chains[chainSelector]; !ok { - return snapshot, fmt.Errorf("chain not supported %d", chainSelector) + return ccipView, fmt.Errorf("chain not supported %d", chainSelector) } - var c Chain - ta := s.Chains[chainSelector].TokenAdminRegistry - if ta != nil { - tokens, err := ta.GetAllConfiguredTokens(nil, 0, 10) - if err != nil { - return snapshot, err - } - tv, err := ta.TypeAndVersion(nil) - if err != nil { - return snapshot, err - } - c.TokenAdminRegistry = TokenAdminRegistryView{ - Contract: Contract{ - TypeAndVersion: tv, - Address: ta.Address(), - }, - Tokens: tokens, - } - } - nm := s.Chains[chainSelector].NonceManager - if nm != nil { - authorizedCallers, err := nm.GetAllAuthorizedCallers(nil) - if err != nil { - return snapshot, err - } - tv, err := nm.TypeAndVersion(nil) - if err != nil { - return snapshot, err - } - c.NonceManager = NonceManagerView{ - Contract: Contract{ - TypeAndVersion: tv, - Address: nm.Address(), - }, - // TODO: these can be resolved using an address book - AuthorizedCallers: authorizedCallers, - } - } - if nm != nil { - authorizedCallers, err := nm.GetAllAuthorizedCallers(nil) - if err != nil { - return snapshot, err - } - tv, err := nm.TypeAndVersion(nil) - if err != nil { - return snapshot, err - } - c.NonceManager = NonceManagerView{ - Contract: Contract{ - TypeAndVersion: tv, - Address: nm.Address(), - }, - // TODO: these can be resolved using an address book - AuthorizedCallers: authorizedCallers, - } + chainState := s.Chains[chainSelector] + chainView, err := chainState.GenerateView() + if err != nil { + return ccipView, err } - snapshot.Chains[chainName] = c + ccipView.Chains[chainName] = chainView } - return snapshot, nil + return ccipView, nil } -func SnapshotState(e deployment.Environment, ab deployment.AddressBook) (CCIPSnapShot, error) { +func StateView(e deployment.Environment, ab deployment.AddressBook) (view.CCIPView, error) { state, err := LoadOnchainState(e, ab) if err != nil { - return CCIPSnapShot{}, err + return view.CCIPView{}, err } - return state.Snapshot(e.AllChainSelectors()) + return state.View(e.AllChainSelectors()) } func LoadOnchainState(e deployment.Environment, ab deployment.AddressBook) (CCIPOnChainState, error) { @@ -242,7 +222,7 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type return state, err } state.ArmProxy = armProxy - case deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_0_0).String(): + case deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_6_0_dev).String(): rmnRemote, err := rmn_remote.NewRMNRemote(common.HexToAddress(address), chain.Client) if err != nil { return state, err diff --git a/integration-tests/deployment/ccip/view/chain.go b/integration-tests/deployment/ccip/view/chain.go new file mode 100644 index 00000000000..468e5e7d487 --- /dev/null +++ b/integration-tests/deployment/ccip/view/chain.go @@ -0,0 +1,27 @@ +package view + +import ( + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/v1_2" + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/v1_5" + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/v1_6" +) + +type ChainView struct { + TokenAdminRegistry map[string]v1_5.TokenAdminRegistryView `json:"tokenAdminRegistry,omitempty"` + FeeQuoter map[string]v1_6.FeeQuoterView `json:"feeQuoter,omitempty"` + NonceManager map[string]v1_6.NonceManagerView `json:"nonceManager,omitempty"` + Router map[string]v1_2.RouterView `json:"router,omitempty"` + RMN map[string]v1_6.RMNRemoteView `json:"rmn,omitempty"` + OnRamp map[string]v1_6.OnRampView `json:"onRamp,omitempty"` +} + +func NewChain() ChainView { + return ChainView{ + TokenAdminRegistry: make(map[string]v1_5.TokenAdminRegistryView), + NonceManager: make(map[string]v1_6.NonceManagerView), + Router: make(map[string]v1_2.RouterView), + RMN: make(map[string]v1_6.RMNRemoteView), + OnRamp: make(map[string]v1_6.OnRampView), + FeeQuoter: make(map[string]v1_6.FeeQuoterView), + } +} diff --git a/integration-tests/deployment/ccip/view/state.go b/integration-tests/deployment/ccip/view/state.go new file mode 100644 index 00000000000..5c86f8e27a5 --- /dev/null +++ b/integration-tests/deployment/ccip/view/state.go @@ -0,0 +1,11 @@ +package view + +type CCIPView struct { + Chains map[string]ChainView `json:"chains,omitempty"` +} + +func NewCCIPView() CCIPView { + return CCIPView{ + Chains: make(map[string]ChainView), + } +} diff --git a/integration-tests/deployment/ccip/view/types/contract_state.go b/integration-tests/deployment/ccip/view/types/contract_state.go new file mode 100644 index 00000000000..f65c510af53 --- /dev/null +++ b/integration-tests/deployment/ccip/view/types/contract_state.go @@ -0,0 +1,33 @@ +package types + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" +) + +type ContractMetaData struct { + TypeAndVersion string `json:"typeAndVersion,omitempty"` + Address common.Address `json:"address,omitempty"` + Owner common.Address `json:"owner,omitempty"` +} + +func NewContractMetaData(tv Meta, addr common.Address) (ContractMetaData, error) { + tvStr, err := tv.TypeAndVersion(nil) + if err != nil { + return ContractMetaData{}, err + } + owner, err := tv.Owner(nil) + if err != nil { + return ContractMetaData{}, err + } + return ContractMetaData{ + TypeAndVersion: tvStr, + Address: addr, + Owner: owner, + }, nil +} + +type Meta interface { + TypeAndVersion(opts *bind.CallOpts) (string, error) + Owner(opts *bind.CallOpts) (common.Address, error) +} diff --git a/integration-tests/deployment/ccip/view/v1_2/router.go b/integration-tests/deployment/ccip/view/v1_2/router.go new file mode 100644 index 00000000000..9d3711d0c28 --- /dev/null +++ b/integration-tests/deployment/ccip/view/v1_2/router.go @@ -0,0 +1,56 @@ +package v1_2 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" +) + +type RouterView struct { + types.ContractMetaData + WrappedNative common.Address `json:"wrappedNative,omitempty"` + ARMProxy common.Address `json:"armProxy,omitempty"` + OnRamps map[uint64]common.Address `json:"onRamps,omitempty"` // Map of DestinationChainSelectors to OnRamp Addresses + OffRamps map[uint64]common.Address `json:"offRamps,omitempty"` // Map of SourceChainSelectors to a list of OffRamp Addresses +} + +func GenerateRouterView(r *router.Router) (RouterView, error) { + meta, err := types.NewContractMetaData(r, r.Address()) + if err != nil { + return RouterView{}, fmt.Errorf("view error to get router metadata: %w", err) + } + wrappedNative, err := r.GetWrappedNative(nil) + if err != nil { + return RouterView{}, fmt.Errorf("view error to get router wrapped native: %w", err) + } + armProxy, err := r.GetArmProxy(nil) + if err != nil { + return RouterView{}, fmt.Errorf("view error to get router arm proxy: %w", err) + } + onRamps := make(map[uint64]common.Address) + offRamps := make(map[uint64]common.Address) + offRampList, err := r.GetOffRamps(nil) + if err != nil { + return RouterView{}, fmt.Errorf("view error to get router offRamps: %w", err) + } + for _, offRamp := range offRampList { + offRamps[offRamp.SourceChainSelector] = offRamp.OffRamp + } + for selector := range offRamps { + onRamp, err := r.GetOnRamp(nil, selector) + if err != nil { + return RouterView{}, fmt.Errorf("view error to get router onRamp: %w", err) + } + onRamps[selector] = onRamp + } + return RouterView{ + ContractMetaData: meta, + WrappedNative: wrappedNative, + ARMProxy: armProxy, + OnRamps: onRamps, + OffRamps: offRamps, + }, nil +} diff --git a/integration-tests/deployment/ccip/view/v1_5/tokenadminregistry.go b/integration-tests/deployment/ccip/view/v1_5/tokenadminregistry.go new file mode 100644 index 00000000000..1e704efae72 --- /dev/null +++ b/integration-tests/deployment/ccip/view/v1_5/tokenadminregistry.go @@ -0,0 +1,30 @@ +package v1_5 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry" +) + +type TokenAdminRegistryView struct { + types.ContractMetaData + Tokens []common.Address `json:"tokens"` +} + +func GenerateTokenAdminRegistryView(taContract *token_admin_registry.TokenAdminRegistry) (TokenAdminRegistryView, error) { + tokens, err := taContract.GetAllConfiguredTokens(nil, 0, 10) + if err != nil { + return TokenAdminRegistryView{}, fmt.Errorf("view error for token admin registry: %w", err) + } + tvMeta, err := types.NewContractMetaData(taContract, taContract.Address()) + if err != nil { + return TokenAdminRegistryView{}, fmt.Errorf("metadata error for token admin registry: %w", err) + } + return TokenAdminRegistryView{ + ContractMetaData: tvMeta, + Tokens: tokens, + }, nil +} diff --git a/integration-tests/deployment/ccip/view/v1_6/feequoter.go b/integration-tests/deployment/ccip/view/v1_6/feequoter.go new file mode 100644 index 00000000000..10e0b984f3f --- /dev/null +++ b/integration-tests/deployment/ccip/view/v1_6/feequoter.go @@ -0,0 +1,153 @@ +package v1_6 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" + router1_2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry" +) + +type FeeQuoterView struct { + types.ContractMetaData + AuthorizedCallers []string `json:"authorizedCallers,omitempty"` + FeeTokens []string `json:"feeTokens,omitempty"` + StaticConfig FeeQuoterStaticConfig `json:"staticConfig,omitempty"` + DestinationChainConfig map[uint64]FeeQuoterDestChainConfig `json:"destinationChainConfig,omitempty"` + TokenPriceFeedConfig map[string]FeeQuoterTokenPriceFeedConfig `json:"tokenPriceFeedConfig,omitempty"` +} + +type FeeQuoterStaticConfig struct { + MaxFeeJuelsPerMsg string `json:"maxFeeJuelsPerMsg,omitempty"` + LinkToken string `json:"linkToken,omitempty"` + StalenessThreshold uint32 `json:"stalenessThreshold,omitempty"` +} + +type FeeQuoterDestChainConfig struct { + IsEnabled bool `json:"isEnabled,omitempty"` + MaxNumberOfTokensPerMsg uint16 `json:"maxNumberOfTokensPerMsg,omitempty"` + MaxDataBytes uint32 `json:"maxDataBytes,omitempty"` + MaxPerMsgGasLimit uint32 `json:"maxPerMsgGasLimit,omitempty"` + DestGasOverhead uint32 `json:"destGasOverhead,omitempty"` + DestGasPerPayloadByte uint16 `json:"destGasPerPayloadByte,omitempty"` + DestDataAvailabilityOverheadGas uint32 `json:"destDataAvailabilityOverheadGas,omitempty"` + DestGasPerDataAvailabilityByte uint16 `json:"destGasPerDataAvailabilityByte,omitempty"` + DestDataAvailabilityMultiplierBps uint16 `json:"destDataAvailabilityMultiplierBps,omitempty"` + DefaultTokenFeeUSDCents uint16 `json:"defaultTokenFeeUSDCents,omitempty"` + DefaultTokenDestGasOverhead uint32 `json:"defaultTokenDestGasOverhead,omitempty"` + DefaultTxGasLimit uint32 `json:"defaultTxGasLimit,omitempty"` + GasMultiplierWeiPerEth uint64 `json:"gasMultiplierWeiPerEth,omitempty"` + NetworkFeeUSDCents uint32 `json:"networkFeeUSDCents,omitempty"` + EnforceOutOfOrder bool `json:"enforceOutOfOrder,omitempty"` + ChainFamilySelector string `json:"chainFamilySelector,omitempty"` +} + +type FeeQuoterTokenPriceFeedConfig struct { + DataFeedAddress string `json:"dataFeedAddress,omitempty"` + TokenDecimals uint8 `json:"tokenDecimals,omitempty"` +} + +func GenerateFeeQuoterView(fqContract *fee_quoter.FeeQuoter, router *router1_2.Router, ta *token_admin_registry.TokenAdminRegistry) (FeeQuoterView, error) { + fq := FeeQuoterView{} + authorizedCallers, err := fqContract.GetAllAuthorizedCallers(nil) + if err != nil { + return FeeQuoterView{}, err + } + fq.AuthorizedCallers = make([]string, 0, len(authorizedCallers)) + for _, ac := range authorizedCallers { + fq.AuthorizedCallers = append(fq.AuthorizedCallers, ac.Hex()) + } + fq.ContractMetaData, err = types.NewContractMetaData(fqContract, fqContract.Address()) + if err != nil { + return FeeQuoterView{}, fmt.Errorf("metadata error for FeeQuoter: %w", err) + } + feeTokens, err := fqContract.GetFeeTokens(nil) + if err != nil { + return FeeQuoterView{}, err + } + fq.FeeTokens = make([]string, 0, len(feeTokens)) + for _, ft := range feeTokens { + fq.FeeTokens = append(fq.FeeTokens, ft.Hex()) + } + staticConfig, err := fqContract.GetStaticConfig(nil) + if err != nil { + return FeeQuoterView{}, err + } + fq.StaticConfig = FeeQuoterStaticConfig{ + MaxFeeJuelsPerMsg: staticConfig.MaxFeeJuelsPerMsg.String(), + LinkToken: staticConfig.LinkToken.Hex(), + StalenessThreshold: staticConfig.StalenessThreshold, + } + // find router contract in dependencies + fq.DestinationChainConfig = make(map[uint64]FeeQuoterDestChainConfig) + destSelectors, err := GetDestinationSelectors(router) + if err != nil { + return FeeQuoterView{}, fmt.Errorf("view error for FeeQuoter: %w", err) + } + for _, destChainSelector := range destSelectors { + destChainConfig, err := fqContract.GetDestChainConfig(nil, destChainSelector) + if err != nil { + return FeeQuoterView{}, err + } + fq.DestinationChainConfig[destChainSelector] = FeeQuoterDestChainConfig{ + IsEnabled: destChainConfig.IsEnabled, + MaxNumberOfTokensPerMsg: destChainConfig.MaxNumberOfTokensPerMsg, + MaxDataBytes: destChainConfig.MaxDataBytes, + MaxPerMsgGasLimit: destChainConfig.MaxPerMsgGasLimit, + DestGasOverhead: destChainConfig.DestGasOverhead, + DestGasPerPayloadByte: destChainConfig.DestGasPerPayloadByte, + DestDataAvailabilityOverheadGas: destChainConfig.DestDataAvailabilityOverheadGas, + DestGasPerDataAvailabilityByte: destChainConfig.DestGasPerDataAvailabilityByte, + DestDataAvailabilityMultiplierBps: destChainConfig.DestDataAvailabilityMultiplierBps, + DefaultTokenFeeUSDCents: destChainConfig.DefaultTokenFeeUSDCents, + DefaultTokenDestGasOverhead: destChainConfig.DefaultTokenDestGasOverhead, + DefaultTxGasLimit: destChainConfig.DefaultTxGasLimit, + GasMultiplierWeiPerEth: destChainConfig.GasMultiplierWeiPerEth, + NetworkFeeUSDCents: destChainConfig.NetworkFeeUSDCents, + EnforceOutOfOrder: destChainConfig.EnforceOutOfOrder, + ChainFamilySelector: fmt.Sprintf("%x", destChainConfig.ChainFamilySelector), + } + } + fq.TokenPriceFeedConfig = make(map[string]FeeQuoterTokenPriceFeedConfig) + tokens, err := GetSupportedTokens(ta) + if err != nil { + return FeeQuoterView{}, fmt.Errorf("view error for FeeQuoter: %w", err) + } + for _, token := range tokens { + t, err := fqContract.GetTokenPriceFeedConfig(nil, token) + if err != nil { + return FeeQuoterView{}, err + } + fq.TokenPriceFeedConfig[token.String()] = FeeQuoterTokenPriceFeedConfig{ + DataFeedAddress: t.DataFeedAddress.Hex(), + TokenDecimals: t.TokenDecimals, + } + } + return fq, nil +} + +func GetSupportedTokens(taContract *token_admin_registry.TokenAdminRegistry) ([]common.Address, error) { + // TODO : include pagination CCIP-3416 + tokens, err := taContract.GetAllConfiguredTokens(nil, 0, 10) + if err != nil { + return nil, fmt.Errorf("failed to get tokens from token_admin_registry: %w", err) + } + return tokens, nil +} + +func GetDestinationSelectors(routerContract *router1_2.Router) ([]uint64, error) { + destSelectors := make([]uint64, 0) + offRamps, err := routerContract.GetOffRamps(nil) + if err != nil { + return nil, fmt.Errorf("failed to get offRamps from router: %w", err) + } + // lanes are bidirectional, so we get the list of source chains to know which chains are supported as destinations as well + for _, offRamp := range offRamps { + destSelectors = append(destSelectors, offRamp.SourceChainSelector) + } + + return destSelectors, nil +} diff --git a/integration-tests/deployment/ccip/view/v1_6/noncemanager.go b/integration-tests/deployment/ccip/view/v1_6/noncemanager.go new file mode 100644 index 00000000000..23df56c3d24 --- /dev/null +++ b/integration-tests/deployment/ccip/view/v1_6/noncemanager.go @@ -0,0 +1,31 @@ +package v1_6 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/nonce_manager" +) + +type NonceManagerView struct { + types.ContractMetaData + AuthorizedCallers []common.Address `json:"authorizedCallers,omitempty"` +} + +func GenerateNonceManagerView(nm *nonce_manager.NonceManager) (NonceManagerView, error) { + authorizedCallers, err := nm.GetAllAuthorizedCallers(nil) + if err != nil { + return NonceManagerView{}, fmt.Errorf("view error for nonce manager: %w", err) + } + nmMeta, err := types.NewContractMetaData(nm, nm.Address()) + if err != nil { + return NonceManagerView{}, fmt.Errorf("metadata error for nonce manager: %w", err) + } + return NonceManagerView{ + ContractMetaData: nmMeta, + // TODO: these can be resolved using an address book + AuthorizedCallers: authorizedCallers, + }, nil +} diff --git a/integration-tests/deployment/ccip/view/v1_6/onramp.go b/integration-tests/deployment/ccip/view/v1_6/onramp.go new file mode 100644 index 00000000000..a5fe13bfb5c --- /dev/null +++ b/integration-tests/deployment/ccip/view/v1_6/onramp.go @@ -0,0 +1,106 @@ +package v1_6 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" + router1_2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry" +) + +type OnRampView struct { + types.ContractMetaData + DynamicConfig onramp.OnRampDynamicConfig `json:"dynamicConfig"` + StaticConfig onramp.OnRampStaticConfig `json:"staticConfig"` + Owner common.Address `json:"owner"` + SourceTokenToPool map[common.Address]common.Address `json:"sourceTokenToPool"` + DestChainSpecificData map[uint64]DestChainSpecificData `json:"destChainSpecificData"` +} + +type DestChainSpecificData struct { + AllowedSendersList []common.Address `json:"allowedSendersList"` + DestChainConfig onramp.GetDestChainConfig `json:"destChainConfig"` + ExpectedNextSeqNum uint64 `json:"expectedNextSeqNum"` + Router common.Address `json:"router"` +} + +func GenerateOnRampView( + onRampContract *onramp.OnRamp, + routerContract *router1_2.Router, + taContract *token_admin_registry.TokenAdminRegistry, +) (OnRampView, error) { + tv, err := types.NewContractMetaData(onRampContract, onRampContract.Address()) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get contract metadata: %w", err) + } + dynamicConfig, err := onRampContract.GetDynamicConfig(nil) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get dynamic config: %w", err) + } + + staticConfig, err := onRampContract.GetStaticConfig(nil) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get static config: %w", err) + } + + owner, err := onRampContract.Owner(nil) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get owner: %w", err) + } + // populate destChainSelectors from router + destChainSelectors, err := GetDestinationSelectors(routerContract) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get destination selectors: %w", err) + } + // populate sourceTokens from token admin registry contract + sourceTokens, err := taContract.GetAllConfiguredTokens(nil, 0, 10) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get all configured tokens: %w", err) + } + sourceTokenToPool := make(map[common.Address]common.Address) + for _, sourceToken := range sourceTokens { + pool, err := onRampContract.GetPoolBySourceToken(nil, 0, sourceToken) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get pool by source token: %w", err) + } + sourceTokenToPool[sourceToken] = pool + } + + destChainSpecificData := make(map[uint64]DestChainSpecificData) + for _, destChainSelector := range destChainSelectors { + allowedSendersList, err := onRampContract.GetAllowedSendersList(nil, destChainSelector) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get allowed senders list: %w", err) + } + destChainConfig, err := onRampContract.GetDestChainConfig(nil, destChainSelector) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get dest chain config: %w", err) + } + expectedNextSeqNum, err := onRampContract.GetExpectedNextSequenceNumber(nil, destChainSelector) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get expected next sequence number: %w", err) + } + router, err := onRampContract.GetRouter(nil, destChainSelector) + if err != nil { + return OnRampView{}, fmt.Errorf("failed to get router: %w", err) + } + destChainSpecificData[destChainSelector] = DestChainSpecificData{ + AllowedSendersList: allowedSendersList, + DestChainConfig: destChainConfig, + ExpectedNextSeqNum: expectedNextSeqNum, + Router: router, + } + } + + return OnRampView{ + ContractMetaData: tv, + DynamicConfig: dynamicConfig, + StaticConfig: staticConfig, + Owner: owner, + SourceTokenToPool: sourceTokenToPool, + DestChainSpecificData: destChainSpecificData, + }, nil +} diff --git a/integration-tests/deployment/ccip/view/v1_6/rmnremote.go b/integration-tests/deployment/ccip/view/v1_6/rmnremote.go new file mode 100644 index 00000000000..bf0fefaa2eb --- /dev/null +++ b/integration-tests/deployment/ccip/view/v1_6/rmnremote.go @@ -0,0 +1,54 @@ +package v1_6 + +import ( + "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_remote" +) + +type RMNRemoteView struct { + types.ContractMetaData + IsCursed bool `json:"isCursed"` + Config RMNRemoteVersionedConfig `json:"config,omitempty"` +} + +type RMNRemoteVersionedConfig struct { + Version uint32 `json:"version"` + Signers []RMNRemoteSigner `json:"signers"` + MinSigners uint64 `json:"minSigners"` +} + +type RMNRemoteSigner struct { + OnchainPublicKey string `json:"onchain_public_key"` + NodeIndex uint64 `json:"node_index"` +} + +func GenerateRMNRemoteView(rmnReader *rmn_remote.RMNRemote) (RMNRemoteView, error) { + tv, err := types.NewContractMetaData(rmnReader, rmnReader.Address()) + if err != nil { + return RMNRemoteView{}, err + } + config, err := rmnReader.GetVersionedConfig(nil) + if err != nil { + return RMNRemoteView{}, err + } + rmnConfig := RMNRemoteVersionedConfig{ + Version: config.Version, + Signers: make([]RMNRemoteSigner, 0, len(config.Config.Signers)), + MinSigners: config.Config.MinSigners, + } + for _, signer := range config.Config.Signers { + rmnConfig.Signers = append(rmnConfig.Signers, RMNRemoteSigner{ + OnchainPublicKey: signer.OnchainPublicKey.Hex(), + NodeIndex: signer.NodeIndex, + }) + } + isCursed, err := rmnReader.IsCursed0(nil) + if err != nil { + return RMNRemoteView{}, err + } + return RMNRemoteView{ + ContractMetaData: tv, + IsCursed: isCursed, + Config: rmnConfig, + }, nil +}