-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add changeset to add bidirectional lanes #17015
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
a8eb00b
4e1de94
318cfe3
9b9f0a9
2c7392e
110da4a
5059146
a053047
ff7bdd7
917da16
f63a767
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,235 @@ | ||
| package v1_6 | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "math/big" | ||
|
|
||
| "github.com/smartcontractkit/mcms" | ||
|
|
||
| "github.com/smartcontractkit/chainlink/deployment" | ||
| "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" | ||
| "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" | ||
| "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_6_0/fee_quoter" | ||
| ) | ||
|
|
||
| // AddBidirectionalLanesChangeset adds multiple bidirectional lanes to CCIP. | ||
| // It batches all lane additions into a single MCMS proposal. | ||
| var AddBidirectionalLanesChangeset = deployment.CreateChangeSet(addBidirectionalLanesLogic, addBidirectionalLanesPrecondition) | ||
|
|
||
| // BidirectionalLaneDefinition indicates two chains that we want to connect. | ||
| type BidirectionalLaneDefinition [2]ChainDefinition | ||
|
|
||
| // laneDefinition defines a lane between source and destination. | ||
| type laneDefinition struct { | ||
| // Source defines the source chain. | ||
| Source ChainDefinition | ||
| // Dest defines the destination chain. | ||
| Dest ChainDefinition | ||
| } | ||
|
|
||
| // AddBidirectionalLanesConfig is a configuration struct for AddBidirectionalLanesChangeset. | ||
| type AddBidirectionalLanesConfig struct { | ||
| // MCMSConfig defines the MCMS configuration for the changeset. | ||
| MCMSConfig *proposalutils.TimelockConfig | ||
| // Lanes describes the lanes that we want to create. | ||
| Lanes []BidirectionalLaneDefinition | ||
| // TestRouter indicates if we want to enable these lanes on the test router. | ||
| TestRouter bool | ||
| } | ||
|
|
||
| type addBidirectionalLanesChangesetConfigs struct { | ||
| UpdateFeeQuoterDestsConfig UpdateFeeQuoterDestsConfig | ||
| UpdateFeeQuoterPricesConfig UpdateFeeQuoterPricesConfig | ||
| UpdateOnRampDestsConfig UpdateOnRampDestsConfig | ||
| UpdateOffRampSourcesConfig UpdateOffRampSourcesConfig | ||
| UpdateRouterRampsConfig UpdateRouterRampsConfig | ||
| } | ||
|
|
||
| func (c AddBidirectionalLanesConfig) buildConfigs() addBidirectionalLanesChangesetConfigs { | ||
| onRampUpdatesByChain := make(map[uint64]map[uint64]OnRampDestinationUpdate) | ||
| offRampUpdatesByChain := make(map[uint64]map[uint64]OffRampSourceUpdate) | ||
| routerUpdatesByChain := make(map[uint64]RouterUpdates) | ||
| feeQuoterDestUpdatesByChain := make(map[uint64]map[uint64]fee_quoter.FeeQuoterDestChainConfig) | ||
| feeQuoterPriceUpdatesByChain := make(map[uint64]FeeQuoterPriceUpdatePerSource) | ||
|
|
||
| for _, lane := range c.Lanes { | ||
| chainA := lane[0] | ||
| chainB := lane[1] | ||
|
|
||
| laneAToB := laneDefinition{ | ||
| Source: chainA, | ||
| Dest: chainB, | ||
| } | ||
| laneBToA := laneDefinition{ | ||
| Source: chainB, | ||
| Dest: chainA, | ||
| } | ||
|
|
||
| for _, laneDef := range []laneDefinition{laneAToB, laneBToA} { | ||
| // Setting the destination on the on ramp | ||
| if onRampUpdatesByChain[laneDef.Source.Selector] == nil { | ||
| onRampUpdatesByChain[laneDef.Source.Selector] = make(map[uint64]OnRampDestinationUpdate) | ||
| } | ||
| onRampUpdatesByChain[laneDef.Source.Selector][laneDef.Dest.Selector] = OnRampDestinationUpdate{ | ||
| IsEnabled: true, | ||
|
||
| TestRouter: c.TestRouter, | ||
| AllowListEnabled: laneDef.Dest.AllowListEnabled, | ||
| } | ||
|
|
||
| // Setting the source on the off ramp | ||
| if offRampUpdatesByChain[laneDef.Dest.Selector] == nil { | ||
| offRampUpdatesByChain[laneDef.Dest.Selector] = make(map[uint64]OffRampSourceUpdate) | ||
| } | ||
| offRampUpdatesByChain[laneDef.Dest.Selector][laneDef.Source.Selector] = OffRampSourceUpdate{ | ||
| IsEnabled: true, | ||
| TestRouter: c.TestRouter, | ||
| IsRMNVerificationDisabled: laneDef.Source.RMNVerificationDisabled, | ||
| } | ||
|
|
||
| // Setting the on ramp on the source router | ||
| routerUpdatesOnSource := routerUpdatesByChain[laneDef.Source.Selector] | ||
| if routerUpdatesByChain[laneDef.Source.Selector].OnRampUpdates == nil { | ||
| routerUpdatesOnSource.OnRampUpdates = make(map[uint64]bool) | ||
| } | ||
| routerUpdatesOnSource.OnRampUpdates[laneDef.Dest.Selector] = true | ||
| routerUpdatesByChain[laneDef.Source.Selector] = routerUpdatesOnSource | ||
|
|
||
| // Setting the off ramp on the dest router | ||
| routerUpdatesOnDest := routerUpdatesByChain[laneDef.Dest.Selector] | ||
| if routerUpdatesByChain[laneDef.Dest.Selector].OffRampUpdates == nil { | ||
| routerUpdatesOnDest.OffRampUpdates = make(map[uint64]bool) | ||
| } | ||
| routerUpdatesOnDest.OffRampUpdates[laneDef.Source.Selector] = true | ||
| routerUpdatesByChain[laneDef.Dest.Selector] = routerUpdatesOnDest | ||
|
|
||
| // Setting the fee quoter destination on the source chain | ||
| if feeQuoterDestUpdatesByChain[laneDef.Source.Selector] == nil { | ||
| feeQuoterDestUpdatesByChain[laneDef.Source.Selector] = make(map[uint64]fee_quoter.FeeQuoterDestChainConfig) | ||
| } | ||
| feeQuoterDestUpdatesByChain[laneDef.Source.Selector][laneDef.Dest.Selector] = laneDef.Dest.FeeQuoterDestChainConfig | ||
|
|
||
| // Setting the destination gas prices on the source chain | ||
| feeQuoterPriceUpdatesOnSource := feeQuoterPriceUpdatesByChain[laneDef.Source.Selector] | ||
| if feeQuoterPriceUpdatesOnSource.GasPrices == nil { | ||
| feeQuoterPriceUpdatesOnSource.GasPrices = make(map[uint64]*big.Int) | ||
| } | ||
| feeQuoterPriceUpdatesOnSource.GasPrices[laneDef.Dest.Selector] = laneDef.Dest.GasPrice | ||
| feeQuoterPriceUpdatesByChain[laneDef.Source.Selector] = feeQuoterPriceUpdatesOnSource | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are you missing the token prices here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Token prices are not tied to a dest chain selector. They are tied to token addresses on the source chain. That is to say that when you add a lane, you shouldn't be adding a new token price. These should already exist. If you need to add a new token price to a chain, that is a separate process and should not go through "add lane". |
||
|
|
||
| routerMCMSConfig := c.MCMSConfig | ||
| if c.TestRouter { | ||
| routerMCMSConfig = nil // Test router is never owned by MCMS | ||
| } | ||
|
|
||
| return addBidirectionalLanesChangesetConfigs{ | ||
| UpdateFeeQuoterDestsConfig: UpdateFeeQuoterDestsConfig{ | ||
| MCMS: c.MCMSConfig, | ||
| UpdatesByChain: feeQuoterDestUpdatesByChain, | ||
| }, | ||
| UpdateFeeQuoterPricesConfig: UpdateFeeQuoterPricesConfig{ | ||
| MCMS: c.MCMSConfig, | ||
| PricesByChain: feeQuoterPriceUpdatesByChain, | ||
| }, | ||
| UpdateOnRampDestsConfig: UpdateOnRampDestsConfig{ | ||
| MCMS: c.MCMSConfig, | ||
| UpdatesByChain: onRampUpdatesByChain, | ||
| }, | ||
| UpdateOffRampSourcesConfig: UpdateOffRampSourcesConfig{ | ||
| MCMS: c.MCMSConfig, | ||
| UpdatesByChain: offRampUpdatesByChain, | ||
| }, | ||
| UpdateRouterRampsConfig: UpdateRouterRampsConfig{ | ||
| TestRouter: c.TestRouter, | ||
| MCMS: routerMCMSConfig, | ||
| UpdatesByChain: routerUpdatesByChain, | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| func addBidirectionalLanesPrecondition(e deployment.Environment, c AddBidirectionalLanesConfig) error { | ||
| configs := c.buildConfigs() | ||
| state, err := changeset.LoadOnchainState(e) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to load onchain state: %w", err) | ||
| } | ||
|
|
||
| err = configs.UpdateFeeQuoterDestsConfig.Validate(e) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to validate UpdateFeeQuoterDestsConfig: %w", err) | ||
| } | ||
|
|
||
| err = configs.UpdateFeeQuoterPricesConfig.Validate(e) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to validate UpdateFeeQuoterPricesConfig: %w", err) | ||
| } | ||
|
|
||
| err = configs.UpdateOnRampDestsConfig.Validate(e) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to validate UpdateOnRampDestsConfig: %w", err) | ||
| } | ||
|
|
||
| err = configs.UpdateOffRampSourcesConfig.Validate(e, state) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to validate UpdateOffRampSourcesConfig: %w", err) | ||
| } | ||
|
|
||
| err = configs.UpdateRouterRampsConfig.Validate(e, state) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to validate UpdateRouterRampsConfig: %w", err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func addBidirectionalLanesLogic(e deployment.Environment, c AddBidirectionalLanesConfig) (deployment.ChangesetOutput, error) { | ||
|
||
| proposals := make([]mcms.TimelockProposal, 0) | ||
| configs := c.buildConfigs() | ||
|
|
||
| out, err := UpdateFeeQuoterDestsChangeset(e, configs.UpdateFeeQuoterDestsConfig) | ||
| if err != nil { | ||
| return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateFeeQuoterDestsChangeset: %w", err) | ||
| } | ||
| proposals = append(proposals, out.MCMSTimelockProposals...) | ||
|
|
||
| out, err = UpdateFeeQuoterPricesChangeset(e, configs.UpdateFeeQuoterPricesConfig) | ||
| if err != nil { | ||
| return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateFeeQuoterPricesChangeset: %w", err) | ||
| } | ||
| proposals = append(proposals, out.MCMSTimelockProposals...) | ||
|
|
||
| out, err = UpdateOnRampsDestsChangeset(e, configs.UpdateOnRampDestsConfig) | ||
| if err != nil { | ||
| return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateOnRampDestsChangeset: %w", err) | ||
| } | ||
| proposals = append(proposals, out.MCMSTimelockProposals...) | ||
|
|
||
| out, err = UpdateOffRampSourcesChangeset(e, configs.UpdateOffRampSourcesConfig) | ||
| if err != nil { | ||
| return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateOffRampSourcesChangeset: %w", err) | ||
| } | ||
| proposals = append(proposals, out.MCMSTimelockProposals...) | ||
|
|
||
| out, err = UpdateRouterRampsChangeset(e, configs.UpdateRouterRampsConfig) | ||
| if err != nil { | ||
| return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateRouterRampsChangeset: %w", err) | ||
| } | ||
| proposals = append(proposals, out.MCMSTimelockProposals...) | ||
|
|
||
| state, err := changeset.LoadOnchainState(e) | ||
| if err != nil { | ||
| return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err) | ||
| } | ||
| proposal, err := aggregateProposals(e, state, proposals, nil, "Add multiple bidirectional lanes", c.MCMSConfig) | ||
| if err != nil { | ||
| return deployment.ChangesetOutput{}, fmt.Errorf("failed to aggregate proposals: %w", err) | ||
| } | ||
| if proposal == nil { | ||
| return deployment.ChangesetOutput{}, nil | ||
| } | ||
|
|
||
| return deployment.ChangesetOutput{ | ||
| MCMSTimelockProposals: []mcms.TimelockProposal{*proposal}, | ||
| }, nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's add an unit test for this func
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5059146