Skip to content
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

solana ccip contract split #16159

Merged
merged 46 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
ceaadeb
clean commit history
tt-cll Feb 3, 2025
b0a07ae
Merge remote-tracking branch 'origin/develop' into deploy-transferabl…
tt-cll Feb 3, 2025
1f54d12
merging
yashnevatia Feb 4, 2025
71b1083
adding test for setpool and pool lookuptable
yashnevatia Feb 4, 2025
38792b7
fee quoter changes barring tests
yashnevatia Feb 5, 2025
f405018
fixing after fee quoter
yashnevatia Jan 14, 2025
dc19cdc
updating receiver
yashnevatia Feb 5, 2025
b39d51d
bug fixes
yashnevatia Feb 6, 2025
5c07022
go mods
yashnevatia Feb 6, 2025
37a1af3
logs
yashnevatia Feb 6, 2025
3a0dd90
bug fix
yashnevatia Feb 6, 2025
280c6f5
offramp changes
yashnevatia Feb 6, 2025
461d94a
Bump chainlink-solana
archseer Feb 7, 2025
b8428ac
Merge remote-tracking branch 'origin/develop' into deploy-transferabl…
tt-cll Feb 7, 2025
f461167
merging with bump-chainlink-solana
yashnevatia Feb 7, 2025
cb9fe10
merging
yashnevatia Feb 7, 2025
db0f8bf
bug fix
yashnevatia Feb 7, 2025
8f470d5
linting
yashnevatia Feb 7, 2025
201402a
bug fix
yashnevatia Feb 7, 2025
e6a2fb5
Revert "solana tooling dev"
tt-cll Feb 7, 2025
26de28b
Merge remote-tracking branch 'origin/develop' into deploy-transferabl…
tt-cll Feb 7, 2025
684a9dc
revert smoke
tt-cll Feb 7, 2025
2007899
fix tests
tt-cll Feb 7, 2025
18267f4
lint
tt-cll Feb 7, 2025
8cca8ef
change address table init
tt-cll Feb 7, 2025
95d877d
fix tests
tt-cll Feb 7, 2025
148ff22
pass offramp in CCIP home
tt-cll Feb 7, 2025
d0040f9
Merge branch 'deploy-transferable-solana' of github.com:smartcontract…
yashnevatia Feb 8, 2025
9b311a5
Merge remote-tracking branch 'origin/develop' into deploy-transferabl…
tt-cll Feb 8, 2025
a0312a4
rename addresslookup to offrampaddresslookup
yashnevatia Feb 8, 2025
1a26763
Merge branch 'deploy-transferable-solana' of github.com:smartcontract…
yashnevatia Feb 8, 2025
5fdc155
semantics
yashnevatia Feb 8, 2025
93ca26f
file split and extending lookup table
yashnevatia Feb 8, 2025
d77b530
append pool instruction
yashnevatia Feb 8, 2025
c2cf9ca
fix chainlink_models_test.go
archseer Feb 10, 2025
76a1803
fix lint
archseer Feb 10, 2025
7f82d87
Fix more tests
archseer Feb 10, 2025
4a578e3
remove prints
tt-cll Feb 10, 2025
d96978e
remove deploy transferable
tt-cll Feb 10, 2025
4e4ca64
bug fix
yashnevatia Feb 10, 2025
849eec2
const
yashnevatia Feb 10, 2025
5727ff9
lint
tt-cll Feb 10, 2025
a2a324a
rename func
yashnevatia Feb 10, 2025
1822ce1
Merge branch 'deploy-transferable-solana' of github.com:smartcontract…
yashnevatia Feb 10, 2025
aa23442
lint
tt-cll Feb 10, 2025
8b105b5
Merge remote-tracking branch 'origin/develop' into deploy-transferabl…
tt-cll Feb 10, 2025
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
12 changes: 9 additions & 3 deletions deployment/ccip/changeset/cs_chain_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -1615,15 +1615,21 @@ func isOCR3ConfigSetOnOffRamp(

// DefaultFeeQuoterDestChainConfig returns the default FeeQuoterDestChainConfig
// with the config enabled/disabled based on the configEnabled flag.
func DefaultFeeQuoterDestChainConfig(configEnabled bool) fee_quoter.FeeQuoterDestChainConfig {
func DefaultFeeQuoterDestChainConfig(configEnabled bool, destChainSelector ...uint64) fee_quoter.FeeQuoterDestChainConfig {
// https://github.com/smartcontractkit/ccip/blob/c4856b64bd766f1ddbaf5d13b42d3c4b12efde3a/contracts/src/v0.8/ccip/libraries/Internal.sol#L337-L337
/*
```Solidity
// bytes4(keccak256("CCIP ChainFamilySelector EVM"))
bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;
```
*/
evmFamilySelector, _ := hex.DecodeString("2812d52c")
familySelector, _ := hex.DecodeString("2812d52c") // evm
if len(destChainSelector) > 0 {
destFamily, _ := chain_selectors.GetSelectorFamily(destChainSelector[0])
if destFamily == chain_selectors.FamilySolana {
familySelector, _ = hex.DecodeString("1e10bdc4") // solana
}
}
return fee_quoter.FeeQuoterDestChainConfig{
IsEnabled: configEnabled,
MaxNumberOfTokensPerMsg: 10,
Expand All @@ -1641,6 +1647,6 @@ func DefaultFeeQuoterDestChainConfig(configEnabled bool) fee_quoter.FeeQuoterDes
DefaultTxGasLimit: 200_000,
GasMultiplierWeiPerEth: 11e17, // Gas multiplier in wei per eth is scaled by 1e18, so 11e17 is 1.1 = 110%
NetworkFeeUSDCents: 1,
ChainFamilySelector: [4]byte(evmFamilySelector),
ChainFamilySelector: [4]byte(familySelector),
}
}
1 change: 1 addition & 0 deletions deployment/ccip/changeset/cs_deploy_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ func deployChainContractsSolana(
solana.TokenProgramID,
solana.SPLAssociatedTokenAccountProgramID,
})
// TODO: can we use solCommonUtil.AwaitSlotChange here?
if err != nil {
return fmt.Errorf("failed to create lookup table: %w", err)
}
Expand Down
137 changes: 134 additions & 3 deletions deployment/ccip/changeset/solana/cs_chain_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@

func validateRouterConfig(chain deployment.SolChain, chainState cs.SolCCIPChainState) error {
if chainState.Router.IsZero() {
return fmt.Errorf("router not found in existing state, deploy the router first chain %d", chain.Selector)
return fmt.Errorf("router not found in existing state, deploy the router first for chain %d", chain.Selector)
}
// addressing errcheck in the next PR
var routerConfigAccount solRouter.Config
Expand Down Expand Up @@ -421,10 +421,10 @@
tokenprogramID,
poolSigner,
tokenPubKey,
chain.DeployerKey.PublicKey(),
authorityPubKey,
)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", err)
return deployment.ChangesetOutput{}, err
}
instructions := []solana.Instruction{createI, poolInitI, authI}

Expand Down Expand Up @@ -926,3 +926,134 @@
// Update look up tables with tokens and pools
// Set Pool (https://smartcontract-it.atlassian.net/browse/INTAUTO-437)
// NewAppendRemotePoolAddressesInstruction (https://smartcontract-it.atlassian.net/browse/INTAUTO-436)

type SetPoolConfig struct {
ChainSelector uint64
TokenPubKey string
TokenAdminRegistryAdminPrivateKey string
PoolLookupTable string
WritableIndexes []uint8
}

func (cfg SetPoolConfig) Validate(e deployment.Environment) error {
tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)
if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil {
return err
}
state, _ := cs.LoadOnchainState(e)
chainState := state.SolChains[cfg.ChainSelector]
chain := e.SolChains[cfg.ChainSelector]
if chainState.TokenPool.IsZero() {
return fmt.Errorf("token pool not found in existing state, deploy the token pool first for chain %d", cfg.ChainSelector)
}
if err := validateRouterConfig(chain, chainState); err != nil {
return err
}
tokenAdminRegistryPDA, _, err := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router)
if err != nil {
return fmt.Errorf("failed to find token admin registry pda (mint: %s, router: %s): %w", tokenPubKey.String(), chainState.Router.String(), err)
}
var tokenAdminRegistryAccount solRouter.TokenAdminRegistry
if err := chain.GetAccountDataBorshInto(context.Background(), tokenAdminRegistryPDA, &tokenAdminRegistryAccount); err != nil {
return fmt.Errorf("token admin registry not found for (mint: %s, router: %s), cannot set pool", tokenPubKey.String(), chainState.Router.String())
}
return nil
}

// this sets the writable indexes of the token pool lookup table
func SetPool(e deployment.Environment, cfg SetPoolConfig) (deployment.ChangesetOutput, error) {
if err := cfg.Validate(e); err != nil {
return deployment.ChangesetOutput{}, err
}

chain := e.SolChains[cfg.ChainSelector]
state, _ := cs.LoadOnchainState(e)
chainState := state.SolChains[cfg.ChainSelector]
tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)
routerConfigPDA, _, _ := solState.FindConfigPDA(chainState.Router)
tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router)
tokenAdminRegistryAdminPrivKey := solana.MustPrivateKeyFromBase58(cfg.TokenAdminRegistryAdminPrivateKey)
lookupTablePubKey := solana.MustPublicKeyFromBase58(cfg.PoolLookupTable)

base := solRouter.NewSetPoolInstruction(
tokenPubKey,
cfg.WritableIndexes,
routerConfigPDA,
tokenAdminRegistryPDA,
lookupTablePubKey,
tokenAdminRegistryAdminPrivKey.PublicKey(),
)

base.AccountMetaSlice = append(base.AccountMetaSlice, solana.Meta(lookupTablePubKey))
instruction, err := base.ValidateAndBuild()
if err != nil {
return deployment.ChangesetOutput{}, err
}

instructions := []solana.Instruction{instruction}
err = chain.Confirm(instructions, solCommonUtil.AddSigners(tokenAdminRegistryAdminPrivKey))
if err != nil {
return deployment.ChangesetOutput{}, err
}
return deployment.ChangesetOutput{}, nil
}

type TokenPoolLookupTableConfig struct {
ChainSelector uint64
TokenPubKey string
TokenProgram string // this can go as a address book tag
}

func (cfg TokenPoolLookupTableConfig) Validate(e deployment.Environment) error {
tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)
if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil {

Check failure on line 1009 in deployment/ccip/changeset/solana/cs_chain_contracts.go

View workflow job for this annotation

GitHub Actions / GolangCI Lint (deployment)

if-return: redundant if ...; err != nil check, just return error instead. (revive)
return err
}
return nil
}

func AddTokenPoolLookupTable(e deployment.Environment, cfg TokenPoolLookupTableConfig) (deployment.ChangesetOutput, error) {
if err := cfg.Validate(e); err != nil {
return deployment.ChangesetOutput{}, err
}
chain := e.SolChains[cfg.ChainSelector]
// pool lookup table
// the last arg is the private key of the authority
ctx := e.GetContext()
client := chain.Client
state, _ := cs.LoadOnchainState(e)
chainState := state.SolChains[cfg.ChainSelector]
authorityPrivKey := chain.DeployerKey
tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)

tokenAdminRegistryPDA, _, _ := solState.FindTokenAdminRegistryPDA(tokenPubKey, chainState.Router)
tokenPoolChainConfigPDA, _ := solTokenUtil.TokenPoolConfigAddress(tokenPubKey, chainState.Router)
tokenPoolSigner, _ := solTokenUtil.TokenPoolSignerAddress(tokenPubKey, chainState.Router)
tokenProgram, _ := GetTokenProgramID(cfg.TokenProgram)
poolTokenAccount, _, _ := solana.FindAssociatedTokenAddress(tokenPoolSigner, tokenPubKey)
feeTokenConfigPDA, _, _ := solState.FindFeeBillingTokenConfigPDA(tokenPubKey, chainState.Router)

// TODO: this needs to be saved in the addressbook, its not derivable
table, err := solCommonUtil.CreateLookupTable(ctx, client, *authorityPrivKey)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to create lookup table for token pool (mint: %s): %w", tokenPubKey.String(), err)
}
list := solana.PublicKeySlice{
table, // 0
tokenAdminRegistryPDA, // 1
chainState.TokenPool, // 2
tokenPoolChainConfigPDA, // 3 - writable
poolTokenAccount, // 4 - writable
tokenPoolSigner, // 5
tokenProgram, // 6
tokenPubKey, // 7 - writable
feeTokenConfigPDA, // 8
}
if err = solCommonUtil.ExtendLookupTable(ctx, client, table, *authorityPrivKey, list); err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to extend lookup table for token pool (mint: %s): %w", tokenPubKey.String(), err)
}
if err := solCommonUtil.AwaitSlotChange(ctx, client); err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to await slot change while extending lookup table: %w", err)
}
return deployment.ChangesetOutput{}, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ func TestAddTokenPool(t *testing.T) {
RemoteChainSelector: evmChain,
TokenPubKey: tokenAddress.String(),
RemoteConfig: token_pool.RemoteConfig{
// this can be potentially read from the state if we are given the token symbol
PoolAddresses: []token_pool.RemoteAddress{{Address: []byte{1, 2, 3}}},
TokenAddress: token_pool.RemoteAddress{Address: []byte{4, 5, 6}},
Decimals: 9,
Expand Down
6 changes: 4 additions & 2 deletions deployment/ccip/changeset/solana/cs_solana_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ var _ deployment.ChangeSet[DeploySolanaTokenConfig] = DeploySolanaToken
var _ deployment.ChangeSet[MintSolanaTokenConfig] = MintSolanaToken
var _ deployment.ChangeSet[CreateSolanaTokenATAConfig] = CreateSolanaTokenATA

// TODO: add option to set token mint authority by taking in its public key
// might need to take is private key if it needs to sign that
type DeploySolanaTokenConfig struct {
ChainSelector uint64
TokenProgramName string
Expand All @@ -27,7 +29,7 @@ func NewTokenInstruction(chain deployment.SolChain, cfg DeploySolanaTokenConfig)
if err != nil {
return nil, nil, err
}
tokenAdminPubKey := chain.DeployerKey.PublicKey()
tokenAdminPubKey := chain.DeployerKey.PublicKey() // token mint authority
mint, _ := solana.NewRandomPrivateKey()
mintPublicKey := mint.PublicKey() // this is the token address
instructions, err := solTokenUtil.CreateToken(
Expand All @@ -54,7 +56,7 @@ func DeploySolanaToken(e deployment.Environment, cfg DeploySolanaTokenConfig) (d
if err != nil {
return deployment.ChangesetOutput{}, err
}

// do i need to add the mint as a signer here ?
err = chain.Confirm(instructions, solCommomUtil.AddSigners(mint))
if err != nil {
e.Logger.Errorw("Failed to confirm instructions for link token deployment", "chain", chain.String(), "err", err)
Expand Down
65 changes: 65 additions & 0 deletions deployment/ccip/changeset/solana/cs_solana_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,68 @@ func TestSolanaTokenOps(t *testing.T) {
func TestDeployLinkToken(t *testing.T) {
testhelpers.DeployLinkTokenTest(t, 1)
}

func TestSolanaTokenBalance(t *testing.T) {
t.Parallel()
lggr := logger.TestLogger(t)
e := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{
SolChains: 1,
})
solChain1 := e.AllChainSelectorsSolana()[0]
e, err := commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{
{
Changeset: commonchangeset.WrapChangeSet(changeset_solana.DeploySolanaToken),
Config: changeset_solana.DeploySolanaTokenConfig{
ChainSelector: solChain1,
TokenProgramName: deployment.SPL2022Tokens,
TokenDecimals: 9,
},
},
})
require.NoError(t, err)

state, err := ccipChangeset.LoadOnchainStateSolana(e)
require.NoError(t, err)
tokenAddress := state.SolChains[solChain1].SPL2022Tokens[0]
deployerKey := e.SolChains[solChain1].DeployerKey.PublicKey()
// testUser, _ := solana.NewRandomPrivateKey()
// testUserPubKey := testUser.PublicKey()

e, err = changeset.ApplyChangesets(t, e, nil, []changeset.ChangesetApplication{
{
Changeset: changeset.WrapChangeSet(changeset_solana.CreateSolanaTokenATA),
Config: changeset_solana.CreateSolanaTokenATAConfig{
ChainSelector: solChain1,
TokenPubkey: tokenAddress,
TokenProgram: deployment.SPL2022Tokens,
ATAList: []string{deployerKey.String()},
// ATAList: []string{testUserPubKey.String()},
},
},
{
Changeset: commonchangeset.WrapChangeSet(changeset_solana.MintSolanaToken),
Config: changeset_solana.MintSolanaTokenConfig{
ChainSelector: solChain1,
TokenPubkey: tokenAddress,
TokenProgram: deployment.SPL2022Tokens,
AmountToAddress: map[string]uint64{
deployerKey.String(): uint64(1000),
},
},
},
})
require.NoError(t, err)

// ata, _, _ := solTokenUtil.FindAssociatedTokenAddress(solana.Token2022ProgramID, tokenAddress, testUserPubKey)
ata, _, _ := solTokenUtil.FindAssociatedTokenAddress(
solana.Token2022ProgramID,
tokenAddress,
e.SolChains[solChain1].DeployerKey.PublicKey(),
)

outDec, outVal, err := solTokenUtil.TokenBalance(context.Background(), e.SolChains[solChain1].Client, ata, solRpc.CommitmentConfirmed)
require.NoError(t, err)
t.Logf("outDec: %d, outVal: %d", outDec, outVal)
// require.Equal(t, int(1000), outVal)
// require.Equal(t, 9, int(outDec))
}
Loading
Loading