deployment/ccip/changeset/solana_v0_1_0/README.md
// deploy chain contracts on solana
registry.Add("0029_deploy_chain_contracts_on_solana",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.DeployChainContractsChangeset(e, ccipchangesetsolana.DeployChainContractsConfig{
HomeChainSelector: shared.HomeChainMainnet.Selector,
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
BuildConfig: &ccipchangesetsolana.BuildSolanaConfig{
DestinationDir: e.BlockChains.SolanaChains()[chainsel.SOLANA_MAINNET.Selector].ProgramsPath,
// there should be artifacts available with this commit sha here
// https://github.com/smartcontractkit/chainlink-ccip/releases
GitCommitSha: "be8d09930aaa",
},
MCMSWithTimelockConfig: &mcmsConfigs,
ContractParamsPerChain: ccipchangesetsolana.ChainContractParams{
FeeQuoterParams: shared.DeriveSolanaFeeQuoterInitParams(
shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].LinkToken,
nil,
),
OffRampParams: ccipchangesetsolana.OffRampParams{
// https://smartcontract-it.atlassian.net/browse/NONEVM-1717
EnableExecutionAfter: int64((20 * time.Minute).Seconds()),
},
},
})
},
).With(struct{}{}))
// upload idl
registry.Add("0030_deploy_idl_for_chain_contracts_on_solana",
migrations.ConfigureLegacy(ccipchangesetsolana.UploadIDL).
With(ccipchangesetsolana.IDLConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
GitCommitSha: "be8d09930aaa",
Router: true,
FeeQuoter: true,
OffRamp: true,
RMNRemote: true,
AccessController: true,
MCM: true,
Timelock: true,
BurnMintTokenPoolMetadata: []string{
ccipshared.CLLMetadata,
},
LockReleaseTokenPoolMetadata: []string{
ccipshared.CLLMetadata,
},
}))
// deploy chain contracts by building locally
registry.Add("0019_deploy_solana_ccip_contracts",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.DeployChainContractsChangeset(e, ccipchangesetsolana.DeployChainContractsConfig{
HomeChainSelector: shared.HomeChainMainnet.Selector,
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
MCMSWithTimelockConfig: &McmsConfigs,
BuildConfig: &ccipchangesetsolana.BuildSolanaConfig{
DestinationDir: e.BlockChains.SolanaChains()[chainsel.SOLANA_MAINNET.Selector].ProgramsPath,
GitCommitSha: "be8d09930aaa",
LocalBuild: ccipchangesetsolana.LocalBuildConfig{
CleanDestinationDir: true,
GenerateVanityKeys: true,
BuildLocally: true,
},
},
ContractParamsPerChain: ccipchangesetsolana.ChainContractParams{
FeeQuoterParams: shared.DeriveSolanaFeeQuoterInitParams(
shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].LinkToken,
nil,
),
OffRampParams: ccipchangesetsolana.OffRampParams{
EnableExecutionAfter: int64((20 * time.Minute).Seconds()),
},
},
})
},
).With(struct{}{}))
// upgrade contracts in place using remote resolution
registry.Add("0077_upgrade_chain_contracts_on_solana",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.DeployChainContractsChangeset(e, ccipchangesetsolana.DeployChainContractsConfig{
HomeChainSelector: shared.HomeChainMainnet.Selector,
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
BuildConfig: &ccipchangesetsolana.BuildSolanaConfig{
DestinationDir: e.BlockChains.SolanaChains()[chainsel.SOLANA_MAINNET.Selector].ProgramsPath,
GitCommitSha: "0ee732e80586",
},
UpgradeConfig: ccipchangesetsolana.UpgradeConfig{
NewFeeQuoterVersion: &deployment.Version1_0_0,
NewRouterVersion: &deployment.Version1_0_0,
NewBurnMintTokenPoolVersion: &deployment.Version1_0_0,
NewLockReleaseTokenPoolVersion: &deployment.Version1_0_0,
NewOffRampVersion: &deployment.Version1_0_0,
UpgradeAuthority: e.BlockChains.SolanaChains()[chainsel.SOLANA_MAINNET.Selector].DeployerKey.PublicKey(),
SpillAddress: e.BlockChains.SolanaChains()[chainsel.SOLANA_MAINNET.Selector].DeployerKey.PublicKey(),
MCMS: timelockConfig,
},
})
},
).With(struct{}{})
// upload idl for upgraded contracts
registry.Add("0079_upgrade_idl_for_chain_contracts_on_solana",
migrations.ConfigureLegacy(ccipchangesetsolana.UpgradeIDL).
With(ccipchangesetsolana.IDLConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
GitCommitSha: "0ee732e80586",
Router: true,
FeeQuoter: true,
OffRamp: true,
RMNRemote: true,
// AccessController: true,
// MCM: true,
// Timelock: true,
BurnMintTokenPoolMetadata: []string{
ccipshared.CLLMetadata,
},
LockReleaseTokenPoolMetadata: []string{
ccipshared.CLLMetadata,
},
}))
// upgrade partner token pool contracts using local build on CI
// this will do a local build for the partner token pool using the upgrade commit sha
// but it will retain the program_id of that token pool (by syncing the key with the upgraded rust file)
registry.Add("0305_update_ohm_token_pool_as_deployer",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.DeployChainContractsChangeset(e, ccipchangesetsolana.DeployChainContractsConfig{
HomeChainSelector: shared.HomeChainTestnet.Selector,
ChainSelector: chainsel.SOLANA_DEVNET.Selector,
BuildConfig: &ccipchangesetsolana.BuildSolanaConfig{
DestinationDir: e.BlockChains.SolanaChains()[chainsel.SOLANA_DEVNET.Selector].ProgramsPath,
GitCommitSha: "0ee732e80586",
LocalBuild: ccipchangesetsolana.LocalBuildConfig{
BuildLocally: true,
UpgradeKeys: map[cldf.ContractType]string{
// partner token pool address
ccipshared.BurnMintTokenPool: solana.MustPublicKeyFromBase58("GEu7tWV9LjtmwtJF661Ugv4wvx38aoEvyQiZzXHEnhRP").String(),
},
},
},
BurnMintTokenPoolMetadata: shared.OlympusWhitegloveMetadata,
UpgradeConfig: ccipchangesetsolana.UpgradeConfig{
NewBurnMintTokenPoolVersion: &deployment.Version1_0_0,
SpillAddress: e.BlockChains.SolanaChains()[chainsel.SOLANA_DEVNET.Selector].DeployerKey.PublicKey(),
UpgradeAuthority: e.BlockChains.SolanaChains()[chainsel.SOLANA_DEVNET.Selector].DeployerKey.PublicKey(),
},
})
},
).With(struct{}{}))
// this typically happens after setCandidate and promoteCandidate changesets
registry.Add("0036_set_ocr_configs_in_offramps_for_solana",
migrations.ConfigureLegacy(ccipchangesetsolana.SetOCR3ConfigSolana).
With(v1_6.SetOCR3OffRampConfig{
HomeChainSel: shared.HomeChainMainnet.Selector,
RemoteChainSels: []uint64{
chainsel.SOLANA_MAINNET.Selector,
},
CCIPHomeConfigType: globals.ConfigTypeActive,
}))
Use the below three changesets to add a remote chain to Solana
registry.Add("0040_add_remote_chains_solana_router",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.AddRemoteChainToRouter(e, ccipchangesetsolana.AddRemoteChainToRouterConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
UpdatesByChain: map[uint64]*ccipchangesetsolana.RouterConfig{
chainsel.ETHEREUM_MAINNET.Selector: {
RouterDestinationConfig: ccip_router.DestChainConfig{
AllowedSenders: [],
AllowListEnabled: true,
},
},
},
MCMS: mcmsConfig, // if router owned by timelock
})
},
).With(struct{}{}))
registry.Add("0041_add_remote_chains_solana_fq",
migrations.ConfigureLegacy(ccipchangesetsolana.AddRemoteChainToFeeQuoter).
With(
ccipchangesetsolana.AddRemoteChainToFeeQuoterConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
UpdatesByChain: map[uint64]*ccipchangesetsolana.FeeQuoterConfig{
chainsel.ETHEREUM_MAINNET.Selector: {
FeeQuoterDestinationConfig: shared.FeeQuoterSVMDestChainConfigByDestChain[chainsel.ETHEREUM_MAINNET.Selector],
},
},
MCMS: mcmsConfig, // if feeQuoter owned by timelock
},
))
registry.Add("0042_add_remote_chains_solana_offramp",
migrations.ConfigureLegacy(ccipchangesetsolana.AddRemoteChainToOffRamp).
With(
ccipchangesetsolana.AddRemoteChainToOffRampConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
UpdatesByChain: map[uint64]*ccipchangesetsolana.OffRampConfig{
chainsel.ETHEREUM_MAINNET.Selector: {
EnabledAsSource: true,
},
},
MCMS: mcmsConfig, // if offRamp owned by timelock
},
))
// use this changeset to disable a remote chain on solana
var _ cldf.ChangeSet[DisableRemoteChainConfig] = DisableRemoteChain
registry.Add("0127_enable_solana_sonic_lane",
migrations.Configure(crossfamily.AddEVMAndSolanaLaneChangeset).With(
crossfamily.AddMultiEVMSolanaLaneConfig{
MCMSConfig: mcmsConfig,
SolanaChainSelector: chainsel.SOLANA_MAINNET.Selector,
Configs: []crossfamily.AddRemoteChainE2EConfig{
{
EVMChainSelector: chainsel.SONIC_MAINNET.Selector,
IsTestRouter: true,
EVMFeeQuoterDestChainInput: shared.DeriveFeeQuoterDestChainConfigEVMToSolana(nil),
InitialSolanaGasPriceForEVMFeeQuoter: chainConfigs[chainsel.SOLANA_MAINNET.Selector].GasPrice,
InitialEVMTokenPricesForEVMFeeQuoter: chainConfigs[chainsel.SONIC_MAINNET.Selector].TokenPrices,
IsRMNVerificationDisabledOnEVMOffRamp: true,
SolanaRouterConfig: ccipchangesetsolana.RouterConfig{
RouterDestinationConfig: ccip_router.DestChainConfig{
AllowedSenders: []solana.PublicKey{},
AllowListEnabled: false,
},
},
SolanaOffRampConfig: ccipchangesetsolana.OffRampConfig{
EnabledAsSource: true,
},
SolanaFeeQuoterConfig: ccipchangesetsolana.FeeQuoterConfig{
FeeQuoterDestinationConfig: shared.FeeQuoterSVMDestChainConfigByDestChain[chainsel.SONIC_MAINNET.Selector],
},
},
},
}))
We always add WSOL and LINK as billing tokens during initial deployment as part of DeployChainContractsChangeset
// use this changeset to add a billing token to solana
var _ cldf.ChangeSet[BillingTokenConfig] = AddBillingTokenChangeset
// use this changeset to add a token transfer fee for a remote chain to solana (used for very specific cases)
var _ cldf.ChangeSet[TokenTransferFeeForRemoteChainConfig] = AddTokenTransferFeeForRemoteChain
// use this changeset to withdraw billed funds on solana
var _ cldf.ChangeSet[WithdrawBilledFundsConfig] = WithdrawBilledFunds
CLI Docs: https://spl.solana.com/token#example-creating-your-own-fungible-token You can use the cli if you have access to the deployer key of your env to make these token operations easier
// lets deploy -> create ATA -> mint
registry.Add("0107_deploy_solvbtc_token_solana",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
allowedSenders := shared.GetAllowedSendersSolToEVM(e)
allowedATAs := make([]string, 0, len(allowedSenders))
mintAmounts := make(map[string]uint64)
for _, allowedSender := range allowedSenders {
allowedATAs = append(allowedATAs, allowedSender.String())
}
return ccipchangesetsolana.DeploySolanaToken(e,
ccipchangesetsolana.DeploySolanaTokenConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
TokenProgramName: ccipshared.SPLTokens,
TokenDecimals: 8,
TokenSymbol: shared.SolvBTCToken,
MintPrivateKey: solana.MustPrivateKeyFromBase58("xxx"), // ignore if vanity address not required
ATAList: allowedATAs,
MintAmountToAddress: mintAmounts,
},
)
},
).With(struct{}{}))
NOTE:
{
"name": "SolvBTC",
"symbol": "SolvBTC",
"uri": "https://raw.githubusercontent.com/solv-finance/solv-btc-metadata-solana/refs/heads/main/SolvBTC/metadata.json"
}
// enable metaboss in domains/ccip/ci-dependencies.yaml
// you have to create another pr to disable it after that
// if you dont, then all other migrations inside domains/ccip will install metaboss
// initial upload
registry.Add("0116_add_solvbtc_token_metadata",
migrations.ConfigureLegacy(ccipchangesetsolana.UploadTokenMetadata).
With(ccipchangesetsolana.UploadTokenMetadataConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
TokenMetadata: []ccipchangesetsolana.TokenMetadata{
{
TokenPubkey: shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].SolvBTCToken,
MetadataJSONPath: "solvbtc.json", // dump this in domains/ccip/mainnet/inputs
},
},
}))
// use below inputs to UploadTokenMetadata to update metadata
type TokenMetadata struct {
TokenPubkey solana.PublicKey
// https://metaboss.dev/create.html#metadata
// only to be provided on initial upload, it takes in name, symbol, uri
// after initial upload, those fields can be updated using the update inputs
// put the json in ccip/env/input dir in CLD
MetadataJSONPath string
UpdateAuthority solana.PublicKey // used to set update authority of the token metadata PDA after initial upload
// https://metaboss.dev/update.html#update-name
UpdateName string // used to update the name of the token metadata PDA after initial upload
// https://metaboss.dev/update.html#update-symbol
UpdateSymbol string // used to update the symbol of the token metadata PDA after initial upload
// https://metaboss.dev/update.html#update-uri
UpdateURI string // used to update the uri of the token metadata PDA after initial upload
}
// use this changeset to mint the token to an address
var _ cldf.ChangeSet[MintSolanaTokenConfig] = MintSolanaToken
// use this changeset to create ATAs for a token
var _ cldf.ChangeSet[CreateSolanaTokenATAConfig] = CreateSolanaTokenATA
// use this changeset to set the authority of a token
var _ cldf.ChangeSet[SetTokenAuthorityConfig] = SetTokenAuthority
// this can deploy one token pool at a time based on the metadata you provide
// it will not re-deploy any other contracts
registry.Add("0091_deploy_partner_token_pool_for_solana_solv_bnm_zeus_lnr",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.DeployChainContractsChangeset(e, ccipchangesetsolana.DeployChainContractsConfig{
HomeChainSelector: shared.HomeChainMainnet.Selector,
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
BuildConfig: &ccipchangesetsolana.BuildSolanaConfig{
DestinationDir: e.BlockChains.SolanaChains()[chainsel.SOLANA_MAINNET.Selector].ProgramsPath,
GitCommitSha: "0ee732e80586",
LocalBuild: ccipchangesetsolana.LocalBuildConfig{
BuildLocally: true,
},
},
BurnMintTokenPoolMetadata: shared.SolvWhitegloveMetadata,
})
},
).With(struct{}{}))
You can use one changeset to
registry.Add("0321_deploy_CCIP_TEST_solana_token_pool",
migrations.ConfigureLegacy(ccipchangesetsolana.E2ETokenPoolv2).
With(ccipchangesetsolana.E2ETokenPoolConfigv2{
ChainSelector: chainsel.SOLANA_DEVNET.Selector,
MCMS: mcmsConfigForCS,
E2ETokens: []ccipchangesetsolana.E2ETokenConfig{
{
TokenPubKey: solana.MustPublicKeyFromBase58("3kffP9DNcWKBZFUqJkx5pgNMbHj1q73kzkgiuUiZJpq8"),
Metadata: shared.SoylanaManlettWhitegloveMetadata,
PoolType: shared.SolanaBnMTokenPoolEnumPtr,
SolanaToEVMRemoteConfigs: map[uint64]ccipchangesetsolana.EVMRemoteConfig{
chainsel.ETHEREUM_TESTNET_SEPOLIA_ARBITRUM_1.Selector: {
TokenSymbol: ccipshared.TokenSymbol("SOYMAN"),
PoolType: ccipshared.BurnMintTokenPool,
PoolVersion: ccipshared.CurrentTokenPoolVersion,
RateLimiterConfig: shared.DefaultRateLimiterConfigForTestTokensSolana,
},
chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector: {
TokenSymbol: ccipshared.TokenSymbol("SOYMAN"),
PoolType: ccipshared.BurnMintTokenPool,
PoolVersion: ccipshared.CurrentTokenPoolVersion,
RateLimiterConfig: shared.DefaultRateLimiterConfigForTestTokensSolana,
},
},
EVMToSolanaRemoteConfigs: v1_5_1.ConfigureTokenPoolContractsConfig{
MCMS: mcmsConfigForCS,
TokenSymbol: ccipshared.TokenSymbol("SOYMAN"),
PoolUpdates: map[uint64]v1_5_1.TokenPoolConfig{
chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector: {
Type: ccipshared.LockReleaseTokenPool,
Version: deployment.Version1_5_1,
SolChainUpdates: map[uint64]v1_5_1.SolChainUpdate{
chainsel.SOLANA_DEVNET.Selector: {
TokenAddress: shared.SolanaTokenAddress[chainsel.SOLANA_DEVNET.Selector].SolvBTCToken.String(),
Type: ccipshared.BurnMintTokenPool,
Metadata: shared.SolvWhitegloveMetadata,
RateLimiterConfig: shared.SolvRateLimitConfigEvmToSolana,
},
},
},
},
},
},
},
}),
migrations.OnlyLoadChainsFor(chainsel.SOLANA_DEVNET.Selector, chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector, chainsel.ETHEREUM_TESTNET_SEPOLIA_ARBITRUM_1.Selector),
)
This changeset allows you to generate one proposal for EVM + Solana rate limit changes for a particular token bridge.
registry.Add("0172_configure_pepe_pool_solana",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
timelockSignerPDA, err := ccipchangesetsolana.FetchTimelockSigner(e, chainsel.SOLANA_MAINNET.Selector)
if err != nil {
return cldf.ChangesetOutput{}, fmt.Errorf("failed to fetch timelock signer: %w", err)
}
return ccipchangesetsolana.E2ETokenPool(e, ccipchangesetsolana.E2ETokenPoolConfig{
RemoteChainTokenPool: []ccipchangesetsolana.SetupTokenPoolForRemoteChainConfig{
{
SolChainSelector: chainsel.SOLANA_MAINNET.Selector,
RemoteTokenPoolConfigs: []ccipchangesetsolana.RemoteChainTokenPoolConfig{
{
SolTokenPubKey: shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].PepeToken,
SolPoolType: shared.SolanaBnMTokenPoolEnumPtr,
Metadata: shared.PepeWhitegloveMetadata,
EVMRemoteConfigs: map[uint64]ccipchangesetsolana.EVMRemoteConfig{
chainsel.ETHEREUM_MAINNET.Selector: {
TokenSymbol: ccipshared.TokenSymbol(shared.PepeToken),
PoolType: ccipshared.LockReleaseTokenPool,
PoolVersion: ccipshared.CurrentTokenPoolVersion,
RateLimiterConfig: shared.DefaultRateLimiterConfigForTestTokensSolana, // circumvent bug
},
},
},
{
SolTokenPubKey: shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].PepeToken,
SolPoolType: shared.SolanaBnMTokenPoolEnumPtr,
Metadata: shared.PepeWhitegloveMetadata,
EVMRemoteConfigs: map[uint64]ccipchangesetsolana.EVMRemoteConfig{
chainsel.ETHEREUM_MAINNET.Selector: {
TokenSymbol: ccipshared.TokenSymbol(shared.PepeToken),
PoolType: ccipshared.LockReleaseTokenPool,
PoolVersion: ccipshared.CurrentTokenPoolVersion,
RateLimiterConfig: shared.PepeRateLimitConfigSolanaToEvm, // set actual value
},
},
},
},
},
},
MCMS: timelockConfig,
})
},
).With(struct{}{}))
// transfer contract owner to timelock
// owner here is the onchain authority that is enforced using rust code
registry.Add("0143_transfer_to_timelock_solana",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.TransferCCIPToMCMSWithTimelockSolana(e, ccipchangesetsolana.TransferCCIPToMCMSWithTimelockSolanaConfig{
MCMSCfg: *timelockConfig,
ContractsByChain: map[uint64]ccipchangesetsolana.CCIPContractsToTransfer{
chainsel.SOLANA_MAINNET.Selector: {
Router: true,
FeeQuoter: true,
OffRamp: true,
BurnMintTokenPools: map[string][]solana.PublicKey{
ccipshared.CLLMetadata: {shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].LinkToken},
shared.SolvWhitegloveMetadata: {
shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].SolvBTCToken,
shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].XSolvBTCToken,
shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].SolvBTCJUPToken,
},
shared.MapleWhitegloveMetadata: {shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].SyrupUSDCToken},
},
LockReleaseTokenPools: map[string][]solana.PublicKey{
shared.ZeusWhitegloveMetadata: {shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].ZBTCToken},
},
},
},
})
},
).With(struct{}{}))
// transfer upgrade authority of contract executable to timelock
// upgrade authority here is the authority allowed to perform an upgrade to the executable
registry.Add(
"0274_change_upgrade_authority_to_timelock_for_solana",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
timelockSignerPDA, err := ccipchangesetsolana.FetchTimelockSigner(e, chainsel.SOLANA_DEVNET.Selector)
if err != nil {
return cldf.ChangesetOutput{}, err
}
return ccipchangesetsolana.SetUpgradeAuthorityChangeset(e,
ccipchangesetsolana.SetUpgradeAuthorityConfig{
ChainSelector: chainsel.SOLANA_DEVNET.Selector,
NewUpgradeAuthority: timelockSignerPDA,
SetAfterInitialDeploy: true,
SetOffRamp: true,
SetMCMSPrograms: true,
TransferKeys: []solana.PublicKey{
// token pools go here
solana.MustPublicKeyFromBase58("GEu7tWV9LjtmwtJF661Ugv4wvx38aoEvyQiZzXHEnhRP"),
},
},
)
},
).With(struct{}{}))
// transfer back upgrade authority of contract executable to deployer key
registry.Add(
"0304_change_upgrade_authority_to_deployer_for_solana_ohm_pool",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.SetUpgradeAuthorityChangeset(e,
ccipchangesetsolana.SetUpgradeAuthorityConfig{
ChainSelector: chainsel.SOLANA_DEVNET.Selector,
NewUpgradeAuthority: e.BlockChains.SolanaChains()[chainsel.SOLANA_DEVNET.Selector].DeployerKey.PublicKey(),
TransferKeys: []solana.PublicKey{
// ohm token pool
solana.MustPublicKeyFromBase58("GEu7tWV9LjtmwtJF661Ugv4wvx38aoEvyQiZzXHEnhRP"),
},
MCMS: mcmsConfigForCS,
},
)
},
).With(struct{}{}))
// transfer IDL authority to timelock
registry.Add(
"0275_test_change_idl_authority_to_timelock_for_solana",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.SetAuthorityIDL(e,
ccipchangesetsolana.IDLConfig{
ChainSelector: chainsel.SOLANA_DEVNET.Selector,
Router: true,
OffRamp: true,
FeeQuoter: true,
RMNRemote: true,
MCM: true,
Timelock: true,
AccessController: true,
BurnMintTokenPoolMetadata: []string{
ccipshared.CLLMetadata,
},
LockReleaseTokenPoolMetadata: []string{
ccipshared.CLLMetadata,
},
MCMS: mcmsConfigForCS,
},
)
},
).With(struct{}{}))
// deploy token
registry.Add("0107_deploy_solvbtc_token_solana",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.DeploySolanaToken(e,
ccipchangesetsolana.DeploySolanaTokenConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
TokenProgramName: ccipshared.SPLTokens,
TokenDecimals: 8,
TokenSymbol: shared.SolvBTCToken,
MintPrivateKey: solana.MustPrivateKeyFromBase58("xxx"), // ignore if vanity address not required
},
)
},
).With(struct{}{}))
// enable metaboss in domains/ccip/ci-dependencies.yaml
// upload metadata
registry.Add("0116_add_solvbtc_token_metadata",
migrations.ConfigureLegacy(ccipchangesetsolana.UploadTokenMetadata).
With(ccipchangesetsolana.UploadTokenMetadataConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
TokenMetadata: []ccipchangesetsolana.TokenMetadata{
{
TokenPubkey: shared.SolanaTokenAddress[chainsel.SOLANA_MAINNET.Selector].SolvBTCToken,
MetadataJSONPath: "solvbtc.json", // dump this in domains/ccip/mainnet/inputs
},
},
}))
// deploy token pool executable
registry.Add("0091_deploy_partner_token_pool_for_solana_solv_bnm_zeus_lnr",
migrations.ConfigureLegacy(
func(e cldf.Environment, _ any) (cldf.ChangesetOutput, error) {
return ccipchangesetsolana.DeployChainContractsChangeset(e, ccipchangesetsolana.DeployChainContractsConfig{
HomeChainSelector: shared.HomeChainMainnet.Selector,
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
BuildConfig: &ccipchangesetsolana.BuildSolanaConfig{
DestinationDir: e.BlockChains.SolanaChains()[chainsel.SOLANA_MAINNET.Selector].ProgramsPath,
GitCommitSha: "0ee732e80586",
LocalBuild: ccipchangesetsolana.LocalBuildConfig{
BuildLocally: true,
},
},
BurnMintTokenPoolMetadata: shared.SolvWhitegloveMetadata,
})
},
).With(struct{}{}))
// setup token pool solana <> lane
registry.Add("0321_deploy_CCIP_TEST_solana_token_pool",
migrations.ConfigureLegacy(ccipchangesetsolana.E2ETokenPoolv2).
With(ccipchangesetsolana.E2ETokenPoolConfigv2{
ChainSelector: chainsel.SOLANA_DEVNET.Selector,
MCMS: mcmsConfigForCS,
E2ETokens: []ccipchangesetsolana.E2ETokenConfig{
{
TokenPubKey: solana.MustPublicKeyFromBase58("3kffP9DNcWKBZFUqJkx5pgNMbHj1q73kzkgiuUiZJpq8"),
Metadata: shared.SoylanaManlettWhitegloveMetadata,
PoolType: shared.SolanaBnMTokenPoolEnumPtr,
SolanaToEVMRemoteConfigs: map[uint64]ccipchangesetsolana.EVMRemoteConfig{
chainsel.ETHEREUM_TESTNET_SEPOLIA_ARBITRUM_1.Selector: {
TokenSymbol: ccipshared.TokenSymbol("SOYMAN"),
PoolType: ccipshared.BurnMintTokenPool,
PoolVersion: ccipshared.CurrentTokenPoolVersion,
RateLimiterConfig: shared.DefaultRateLimiterConfigForTestTokensSolana,
},
chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector: {
TokenSymbol: ccipshared.TokenSymbol("SOYMAN"),
PoolType: ccipshared.BurnMintTokenPool,
PoolVersion: ccipshared.CurrentTokenPoolVersion,
RateLimiterConfig: shared.DefaultRateLimiterConfigForTestTokensSolana,
},
},
EVMToSolanaRemoteConfigs: v1_5_1.ConfigureTokenPoolContractsConfig{
MCMS: mcmsConfigForCS,
TokenSymbol: ccipshared.TokenSymbol("SOYMAN"),
PoolUpdates: map[uint64]v1_5_1.TokenPoolConfig{
chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector: {
Type: ccipshared.LockReleaseTokenPool,
Version: deployment.Version1_5_1,
SolChainUpdates: map[uint64]v1_5_1.SolChainUpdate{
chainsel.SOLANA_DEVNET.Selector: {
TokenAddress: shared.SolanaTokenAddress[chainsel.SOLANA_DEVNET.Selector].SolvBTCToken.String(),
Type: ccipshared.BurnMintTokenPool,
Metadata: shared.SolvWhitegloveMetadata,
RateLimiterConfig: shared.SolvRateLimitConfigEvmToSolana,
},
},
},
},
},
},
},
}),
migrations.OnlyLoadChainsFor(chainsel.SOLANA_DEVNET.Selector, chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector, chainsel.ETHEREUM_TESTNET_SEPOLIA_ARBITRUM_1.Selector),
)
// initially verify programs afer deploy
registry.Add("0086_verify_solana_programs",
migrations.ConfigureLegacy(ccipchangesetsolana.VerifyBuild).
With(ccipchangesetsolana.VerifyBuildConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
GitCommitSha: "0ee732e80586",
VerifyFeeQuoter: true,
BurnMintTokenPoolMetadata: []string{
ccipshared.CLLMetadata,
},
LockReleaseTokenPoolMetadata: []string{
ccipshared.CLLMetadata,
},
}))
// 2 step process for verification after mcms transfer
// that is UpgradeAuthority of contract is transferred to mcms
// Step 1
// register verify ix on timelock
// this will spit out a proposal
// get it signed and executed
registry.Add("0086_verify_solana_programs",
migrations.ConfigureLegacy(ccipchangesetsolana.VerifyBuild).
With(ccipchangesetsolana.VerifyBuildConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
GitCommitSha: "0ee732e80586",
VerifyFeeQuoter: true,
MCMS: &proposalutils.TimelockConfig{
// if possible, we should make this very small, ideally 5 mins
// because otherwise we will non verified updated contracts for > 3 hours
MinDelay: minDelay,
}
UpgradeAuthority: timelockSignerPDA,
}))
// Step 2
registry.Add("0086_verify_solana_programs",
migrations.ConfigureLegacy(ccipchangesetsolana.VerifyBuild).
With(ccipchangesetsolana.VerifyBuildConfig{
ChainSelector: chainsel.SOLANA_MAINNET.Selector,
GitCommitSha: "0ee732e80586",
VerifyFeeQuoter: true,
MCMS: &proposalutils.TimelockConfig{
// if possible, we should make this very small, ideally 5 mins
// because otherwise we will non verified updated contracts for > 3 hours
MinDelay: minDelay,
},
UpgradeAuthority: timelockSignerPDA,
RemoteVerification: true // this is KEY in step 2
}))