Skip to content

Commit ebbb205

Browse files
authored
Create changesets for new token pools (#18787)
* Create changesets for new token pools * fix linter * remove panics
1 parent ab37c24 commit ebbb205

2 files changed

Lines changed: 142 additions & 18 deletions

File tree

deployment/ccip/changeset/solana_v0_1_1/cs_deploy_chain_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/smartcontractkit/chainlink/deployment/common/proposalutils"
2222
"github.com/smartcontractkit/chainlink/deployment/common/types"
2323

24+
solTestTokenPool "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/test_token_pool"
2425
"github.com/smartcontractkit/chainlink/deployment"
2526
ccipChangesetSolana "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/solana_v0_1_1"
2627
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers"
@@ -364,6 +365,29 @@ func TestUpgrade(t *testing.T) {
364365
// solana verification
365366
err = testhelpers.ValidateSolanaState(e, solChainSelectors)
366367
require.NoError(t, err)
368+
369+
burnMintTokenPoolType := solTestTokenPool.BurnAndMint_PoolType
370+
lockReleaseTokenPoolType := solTestTokenPool.LockAndRelease_PoolType
371+
372+
e, _, err = commonchangeset.ApplyChangesets(t, e, []commonchangeset.ConfiguredChangeSet{
373+
commonchangeset.Configure(
374+
cldf.CreateLegacyChangeSet(ccipChangesetSolana.InitGlobalConfigTokenPoolProgram),
375+
ccipChangesetSolana.TokenPoolConfigWithMCM{
376+
ChainSelector: solChainSelectors[0],
377+
PoolType: &burnMintTokenPoolType,
378+
Metadata: shared.CLLMetadata,
379+
},
380+
),
381+
commonchangeset.Configure(
382+
cldf.CreateLegacyChangeSet(ccipChangesetSolana.InitGlobalConfigTokenPoolProgram),
383+
ccipChangesetSolana.TokenPoolConfigWithMCM{
384+
ChainSelector: solChainSelectors[0],
385+
PoolType: &lockReleaseTokenPoolType,
386+
Metadata: shared.CLLMetadata,
387+
},
388+
),
389+
})
390+
require.NoError(t, err)
367391
}
368392

369393
func TestIDL(t *testing.T) {

deployment/ccip/changeset/solana_v0_1_1/cs_token_pool.go

Lines changed: 118 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ type TokenPoolConfigWithMCM struct {
113113
TokenPubKey solana.PublicKey
114114
Metadata string
115115
MCMS *proposalutils.TimelockConfig
116+
UpgradeConfig UpgradeConfig
116117
}
117118

118119
func (cfg TokenPoolConfigWithMCM) Validate(e cldf.Environment, chainState solanastateview.CCIPChainState) error {
@@ -126,6 +127,20 @@ func (cfg TokenPoolConfigWithMCM) Validate(e cldf.Environment, chainState solana
126127
return chainState.ValidatePoolDeployment(&e, *cfg.PoolType, cfg.ChainSelector, cfg.TokenPubKey, false, cfg.Metadata)
127128
}
128129

130+
func (cfg TokenPoolConfigWithMCM) ValidateForGlobalInit() error {
131+
if cfg.ChainSelector == 0 {
132+
return errors.New("chain selector must be defined")
133+
}
134+
if cfg.PoolType == nil {
135+
return errors.New("pool type must be defined")
136+
}
137+
if cfg.Metadata == "" {
138+
return errors.New("metadata must be defined")
139+
}
140+
141+
return nil
142+
}
143+
129144
type NewMintTokenPoolConfig struct {
130145
ChainSelector uint64
131146
PoolType *solTestTokenPool.PoolType
@@ -197,7 +212,7 @@ func AddTokenPoolAndLookupTable(e cldf.Environment, cfg AddTokenPoolAndLookupTab
197212

198213
var configPDA solana.PublicKey
199214
// Global Configuration
200-
configPDA, err = tokenPoolGlobalConfigPDA(tokenPool)
215+
configPDA, err = TokenPoolGlobalConfigPDA(tokenPool)
201216
if err != nil {
202217
return cldf.ChangesetOutput{}, fmt.Errorf("failed to get solana token pool global config PDA: %w", err)
203218
}
@@ -438,19 +453,18 @@ func InitGlobalConfigTokenPoolProgram(e cldf.Environment, cfg TokenPoolConfigWit
438453
return cldf.ChangesetOutput{}, err
439454
}
440455
solChainState := state.SolChains[cfg.ChainSelector]
441-
if err := cfg.Validate(e, solChainState); err != nil {
456+
if err := cfg.ValidateForGlobalInit(); err != nil {
442457
return cldf.ChangesetOutput{}, err
443458
}
444459
chain := e.BlockChains.SolanaChains()[cfg.ChainSelector]
445-
tokenPubKey := cfg.TokenPubKey
446460
tokenPool, contractType := solChainState.GetActiveTokenPool(*cfg.PoolType, cfg.Metadata)
447461
chainState := state.SolChains[cfg.ChainSelector]
448462
routerProgramAddress, _, _ := chainState.GetRouterInfo()
449463
rmnRemoteAddress := chainState.RMNRemote
450464

451465
var configPDA solana.PublicKey
452466
// Global Configuration
453-
configPDA, err = tokenPoolGlobalConfigPDA(tokenPool)
467+
configPDA, err = TokenPoolGlobalConfigPDA(tokenPool)
454468
if err != nil {
455469
return cldf.ChangesetOutput{}, fmt.Errorf("failed to get solana token pool global config PDA: %w", err)
456470
}
@@ -475,26 +489,112 @@ func InitGlobalConfigTokenPoolProgram(e cldf.Environment, cfg TokenPoolConfigWit
475489
solLockReleaseTokenPool.SetProgramID(tokenPool)
476490
initGlobalConfigIx, err = solLockReleaseTokenPool.NewInitGlobalConfigInstruction(routerProgramAddress, rmnRemoteAddress, configPDA, chain.DeployerKey.PublicKey(), solana.SystemProgramID, tokenPool, programData.Address).ValidateAndBuild()
477491
default:
478-
panic("unhandled default case")
492+
return cldf.ChangesetOutput{}, fmt.Errorf("invalid token pool type: %w", err)
479493
}
480494
if err != nil {
481495
return cldf.ChangesetOutput{}, fmt.Errorf("failed to build ix to init global config: %w", err)
482496
}
483497

484498
var txns []mcmsTypes.Transaction
485499

486-
useMcms := solanastateview.IsSolanaProgramOwnedByTimelock(
487-
&e,
488-
chain,
489-
solChainState,
490-
contractType,
491-
tokenPubKey,
492-
cfg.Metadata,
493-
)
500+
instructions := []solana.Instruction{initGlobalConfigIx}
501+
502+
timelockSignerPDA, err := FetchTimelockSigner(e, cfg.ChainSelector)
503+
if err != nil {
504+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to fetch timelock signer: %w", err)
505+
}
506+
if cfg.UpgradeConfig.UpgradeAuthority == timelockSignerPDA {
507+
err := appendTxs(instructions, tokenPool, contractType, &txns)
508+
if err != nil {
509+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to generate mcms txn: %w", err)
510+
}
511+
} else {
512+
if err := chain.Confirm(instructions); err != nil {
513+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err)
514+
}
515+
}
516+
517+
if len(txns) > 0 {
518+
proposal, err := BuildProposalsForTxns(
519+
e, cfg.ChainSelector, "proposal to init global config in Solana Token Pool", cfg.MCMS.MinDelay, txns)
520+
if err != nil {
521+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to build proposal: %w", err)
522+
}
523+
return cldf.ChangesetOutput{
524+
MCMSTimelockProposals: []mcms.TimelockProposal{*proposal},
525+
}, nil
526+
}
527+
528+
return cldf.ChangesetOutput{}, nil
529+
}
530+
531+
func EnableSelfServedInTokenPoolProgram(e cldf.Environment, cfg TokenPoolConfigWithMCM) (cldf.ChangesetOutput, error) {
532+
e.Logger.Infow("Enable self served token pool", "cfg", cfg)
533+
534+
return modifySelfServedConfig(e, cfg, true)
535+
}
536+
537+
func DisableSelfServedInTokenPoolProgram(e cldf.Environment, cfg TokenPoolConfigWithMCM) (cldf.ChangesetOutput, error) {
538+
e.Logger.Infow("Disable self served token pool", "cfg", cfg)
539+
540+
return modifySelfServedConfig(e, cfg, false)
541+
}
542+
543+
func modifySelfServedConfig(e cldf.Environment, cfg TokenPoolConfigWithMCM, enabled bool) (cldf.ChangesetOutput, error) {
544+
state, err := stateview.LoadOnchainState(e)
545+
if err != nil {
546+
return cldf.ChangesetOutput{}, err
547+
}
548+
solChainState := state.SolChains[cfg.ChainSelector]
549+
if err := cfg.ValidateForGlobalInit(); err != nil {
550+
return cldf.ChangesetOutput{}, err
551+
}
552+
chain := e.BlockChains.SolanaChains()[cfg.ChainSelector]
553+
tokenPool, contractType := solChainState.GetActiveTokenPool(*cfg.PoolType, cfg.Metadata)
554+
555+
var configPDA solana.PublicKey
556+
// Global Configuration
557+
configPDA, err = TokenPoolGlobalConfigPDA(tokenPool)
558+
if err != nil {
559+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to get solana token pool global config PDA: %w", err)
560+
}
561+
562+
// Checking that configPDA exists, so the update method will not fail
563+
_, err = chain.Client.GetAccountInfo(context.Background(), configPDA)
564+
if err != nil {
565+
e.Logger.Infow("Global config not initialized", "configPDA", configPDA.String())
566+
return cldf.ChangesetOutput{}, nil
567+
}
568+
569+
programData, err := getSolProgramData(e, chain, tokenPool)
570+
if err != nil {
571+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to get solana token pool program data: %w", err)
572+
}
573+
574+
var initGlobalConfigIx solana.Instruction
575+
switch *cfg.PoolType {
576+
case solTestTokenPool.BurnAndMint_PoolType:
577+
solBurnMintTokenPool.SetProgramID(tokenPool)
578+
initGlobalConfigIx, err = solBurnMintTokenPool.NewUpdateSelfServedAllowedInstruction(enabled, configPDA, chain.DeployerKey.PublicKey(), tokenPool, programData.Address).ValidateAndBuild()
579+
case solTestTokenPool.LockAndRelease_PoolType:
580+
solLockReleaseTokenPool.SetProgramID(tokenPool)
581+
initGlobalConfigIx, err = solLockReleaseTokenPool.NewUpdateSelfServedAllowedInstruction(enabled, configPDA, chain.DeployerKey.PublicKey(), tokenPool, programData.Address).ValidateAndBuild()
582+
default:
583+
return cldf.ChangesetOutput{}, fmt.Errorf("invalid token pool type: %w", err)
584+
}
585+
if err != nil {
586+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to build ix to init global config: %w", err)
587+
}
494588

495589
instructions := []solana.Instruction{initGlobalConfigIx}
496590

497-
if useMcms {
591+
var txns []mcmsTypes.Transaction
592+
593+
timelockSignerPDA, err := FetchTimelockSigner(e, cfg.ChainSelector)
594+
if err != nil {
595+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to fetch timelock signer: %w", err)
596+
}
597+
if cfg.UpgradeConfig.UpgradeAuthority == timelockSignerPDA {
498598
err := appendTxs(instructions, tokenPool, contractType, &txns)
499599
if err != nil {
500600
return cldf.ChangesetOutput{}, fmt.Errorf("failed to generate mcms txn: %w", err)
@@ -540,15 +640,15 @@ func ModifyMintAuthority(e cldf.Environment, cfg NewMintTokenPoolConfig) (cldf.C
540640
case solTestTokenPool.LockAndRelease_PoolType:
541641
return cldf.ChangesetOutput{}, nil
542642
default:
543-
panic("unhandled default case")
643+
return cldf.ChangesetOutput{}, fmt.Errorf("invalid token pool type: %w", err)
544644
}
545645

546646
newMintAuthority := cfg.NewMintAuthority
547647
tokenPoolSigner, _ := solTokenUtil.TokenPoolSignerAddress(tokenPubKey, tokenPool)
548648

549649
poolConfig, err := solTokenUtil.TokenPoolConfigAddress(tokenPubKey, tokenPool)
550650
if err != nil {
551-
return cldf.ChangesetOutput{}, fmt.Errorf("failed to calculate the pool configg: %w", err)
651+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to calculate the pool config: %w", err)
552652
}
553653
programData, err := getSolProgramData(e, chain, tokenPool)
554654
if err != nil {
@@ -1870,7 +1970,7 @@ func InitializeStateVersion(e cldf.Environment, cfg TokenPoolConfigWithMCM) (cld
18701970
tokenPubKey,
18711971
poolConfig).ValidateAndBuild()
18721972
default:
1873-
panic("unhandled default case")
1973+
return cldf.ChangesetOutput{}, fmt.Errorf("invalid token pool type: %w", err)
18741974
}
18751975
if err != nil {
18761976
return cldf.ChangesetOutput{}, fmt.Errorf("failed to build ix to init global config: %w", err)
@@ -1914,7 +2014,7 @@ func InitializeStateVersion(e cldf.Environment, cfg TokenPoolConfigWithMCM) (cld
19142014
return cldf.ChangesetOutput{}, nil
19152015
}
19162016

1917-
func tokenPoolGlobalConfigPDA(programID solana.PublicKey) (solana.PublicKey, error) {
2017+
func TokenPoolGlobalConfigPDA(programID solana.PublicKey) (solana.PublicKey, error) {
19182018
addr, _, err := solana.FindProgramAddress([][]byte{[]byte("config")}, programID)
19192019
return addr, err
19202020
}

0 commit comments

Comments
 (0)