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 todos #16391

Merged
merged 40 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
aaab52e
Adding solchains in NewEnv
yashnevatia Jan 3, 2025
f19598e
Revert "Adding solchains in NewEnv"
yashnevatia Jan 3, 2025
87f6e75
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
yashnevatia Jan 14, 2025
4bf2980
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
yashnevatia Jan 15, 2025
6712ecd
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
yashnevatia Jan 15, 2025
a1e15fa
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
yashnevatia Jan 29, 2025
827ccd6
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
yashnevatia Feb 12, 2025
29f6dc4
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
yashnevatia Feb 13, 2025
dfe582d
remove todo
yashnevatia Feb 13, 2025
4699cc9
remove todo
yashnevatia Feb 13, 2025
9b53d65
add cs to set fee agg
yashnevatia Feb 13, 2025
3e6ce6a
add cs
yashnevatia Feb 13, 2025
484898f
address comments
yashnevatia Feb 13, 2025
d44f0fd
validation on mint
yashnevatia Feb 13, 2025
89569b4
bump chains/solana
yashnevatia Feb 13, 2025
9f812a3
check for family
yashnevatia Feb 13, 2025
bfb4b4d
remove todo
yashnevatia Feb 13, 2025
d2dbd83
issetocr
yashnevatia Feb 13, 2025
2bcd2bb
enabling addtokenpool for wsol
yashnevatia Feb 13, 2025
933df94
adding fee agg to state
yashnevatia Feb 13, 2025
b0c3e65
feat: solana tooling dev
yashnevatia Feb 11, 2025
7815ee8
tidying
yashnevatia Feb 13, 2025
f111442
enable src/dest solana
yashnevatia Feb 13, 2025
ef7b6f3
making sol addLane agnostic to fam
yashnevatia Feb 13, 2025
efa54a2
lint
yashnevatia Feb 13, 2025
315659c
Revert "feat: solana tooling dev"
yashnevatia Feb 13, 2025
9c6497b
fixing
yashnevatia Feb 14, 2025
e3314a7
adding todos
yashnevatia Feb 14, 2025
fed8aba
Merge branch 'develop' of github.com:smartcontractkit/chainlink into …
yashnevatia Feb 14, 2025
659f04e
enabling sol -> evm
yashnevatia Feb 14, 2025
7a2b83f
tidying
yashnevatia Feb 14, 2025
243089f
removing commented func
yashnevatia Feb 14, 2025
e69844e
lint
yashnevatia Feb 14, 2025
1f6dd17
bug
yashnevatia Feb 14, 2025
a2e5f3e
tidying
yashnevatia Feb 17, 2025
565af6e
add method to get onrampbytes
yashnevatia Feb 17, 2025
94a7d69
making addlane modular
yashnevatia Feb 17, 2025
a352b09
Reverting something
yashnevatia Feb 17, 2025
a9e966d
fix
yashnevatia Feb 17, 2025
9eee32a
onramp bytes
yashnevatia Feb 18, 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
20 changes: 20 additions & 0 deletions deployment/ccip/changeset/cs_add_lane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,23 @@ func TestAddLanesWithTestRouter(t *testing.T) {
}] = []uint64{msgSentEvent.SequenceNumber}
testhelpers.ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks)
}

// dev is on going for sending request between solana and evm chains
// this test is there to ensure addLane works between solana and evm chains
func TestAddLanesWithSolana(t *testing.T) {
t.Parallel()
e, _ := testhelpers.NewMemoryEnvironment(t, testhelpers.WithSolChains(1))
// Here we have CR + nodes set up, but no CCIP contracts deployed.
state, err := changeset.LoadOnchainState(e.Env)
require.NoError(t, err)

evmSelectors := e.Env.AllChainSelectors()
chain1, chain2 := evmSelectors[0], evmSelectors[1]
solSelectors := e.Env.AllChainSelectorsSolana()
solChain := solSelectors[0]
testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, chain1, solChain, true)
// AddLaneWithDefaultPricesAndFeeQuoterConfig involves calling AddRemoteChainToSolana
Copy link
Contributor

@tt-cll tt-cll Feb 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should make AddRemoteChainToSolana idempotent. Doesn't have to be in this PR

// which adds chain1 to solana
// so we can not call AddRemoteChainToSolana again with chain1 again, hence using chain2 below
testhelpers.AddLaneWithDefaultPricesAndFeeQuoterConfig(t, &e, state, solChain, chain2, true)
}
4 changes: 2 additions & 2 deletions deployment/ccip/changeset/cs_ccip_home.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func (p PromoteCandidateChangesetConfig) Validate(e deployment.Environment) (map
if err := deployment.IsValidChainSelector(chainSelector); err != nil {
return nil, fmt.Errorf("don chain selector invalid: %w", err)
}
if err := state.ValidateOffRamp(chainSelector); err != nil {
if err := state.ValidateRamp(chainSelector, OffRamp); err != nil {
return nil, err
}

Expand Down Expand Up @@ -461,7 +461,7 @@ func (p SetCandidatePluginInfo) Validate(state CCIPOnChainState, homeChain uint6
if err := deployment.IsValidChainSelector(chainSelector); err != nil {
return fmt.Errorf("don chain selector invalid: %w", err)
}
if err := state.ValidateOffRamp(chainSelector); err != nil {
if err := state.ValidateRamp(chainSelector, OffRamp); err != nil {
return err
}
if p.PluginType == types.PluginTypeCCIPCommit && params.CommitOffChainConfig == nil {
Expand Down
30 changes: 17 additions & 13 deletions deployment/ccip/changeset/cs_chain_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -1057,11 +1057,9 @@ func (cfg UpdateOffRampSourcesConfig) Validate(e deployment.Environment, state C
if source == chainSel {
return fmt.Errorf("cannot update offramp source to the same chain %d", source)
}
sourceChain := state.Chains[source]
// Source chain must have the onramp deployed.
// Note this also validates the specified source selector.
if sourceChain.OnRamp == nil {
return fmt.Errorf("missing onramp for source %d", source)

if err := state.ValidateRamp(source, OnRamp); err != nil {
return err
}
}
}
Expand Down Expand Up @@ -1095,13 +1093,22 @@ func UpdateOffRampSourcesChangeset(e deployment.Environment, cfg UpdateOffRampSo
} else {
router = state.Chains[chainSel].Router.Address()
}
onRamp := state.Chains[source].OnRamp
sourceChainFamily, _ := chain_selectors.GetSelectorFamily(source)

onRampBytes := []byte{}
// can ignore err as validation checks for nil addresses
if sourceChainFamily == chain_selectors.FamilyEVM {
onRampBytes, _ = state.Chains[source].OnRampBytes()
} else if sourceChainFamily == chain_selectors.FamilySolana {
onRampBytes, _ = state.SolChains[source].OnRampBytes()
}

args = append(args, offramp.OffRampSourceChainConfigArgs{
SourceChainSelector: source,
Router: router,
IsEnabled: update.IsEnabled,
// TODO: how would this work when the onRamp is nonEVM?
OnRamp: common.LeftPadBytes(onRamp.Address().Bytes(), 32),
OnRamp: common.LeftPadBytes(onRampBytes, 32),
IsRMNVerificationDisabled: update.IsRMNVerificationDisabled,
})
}
Expand Down Expand Up @@ -1198,11 +1205,8 @@ func (cfg UpdateRouterRampsConfig) Validate(e deployment.Environment, state CCIP
if source == chainSel {
return fmt.Errorf("cannot update offramp source to the same chain %d", source)
}
sourceChain := state.Chains[source]
// Source chain must have the onramp deployed.
// Note this also validates the specified source selector.
if sourceChain.OnRamp == nil {
return fmt.Errorf("missing onramp for source %d", source)
if err := state.ValidateRamp(source, OnRamp); err != nil {
return err
}
}
for destination := range update.OnRampUpdates {
Expand All @@ -1213,7 +1217,7 @@ func (cfg UpdateRouterRampsConfig) Validate(e deployment.Environment, state CCIP
if destination == chainSel {
return fmt.Errorf("cannot update onRamp dest to the same chain %d", destination)
}
if err := state.ValidateOffRamp(destination); err != nil {
if err := state.ValidateRamp(destination, OffRamp); err != nil {
return err
}
}
Expand Down
26 changes: 18 additions & 8 deletions deployment/ccip/changeset/solana/cs_add_remote_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"strconv"

"github.com/ethereum/go-ethereum/common"
"github.com/gagliardetto/solana-go"

solOffRamp "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_offramp"
Expand Down Expand Up @@ -71,8 +72,19 @@ func (cfg AddRemoteChainToSolanaConfig) Validate(e deployment.Environment) error
if remote == routerConfigAccount.SvmChainSelector {
return fmt.Errorf("cannot add remote chain %d with same chain selector as current chain %d", remote, cfg.ChainSelector)
}
if err := state.ValidateRamp(remote, cs.OnRamp); err != nil {
return err
}
routerDestChainPDA, err := solState.FindDestChainStatePDA(remote, chainState.Router)
if err != nil {
return fmt.Errorf("failed to find dest chain state pda for remote chain %d: %w", remote, err)
}
var destChainStateAccount solRouter.DestChain
err = chain.GetAccountDataBorshInto(context.Background(), routerDestChainPDA, &destChainStateAccount)
if err == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this right condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, if the err is nil, that means the remote chain has already been configured and the routerDestChainPDA has already been initialised.
If the err is not nil (err="account not found"), that means the remote chain has not already been initialised and we can proceed with doing the same.

return fmt.Errorf("remote %d is already configured on solana chain %d", remote, cfg.ChainSelector)
}
}

return nil
}

Expand Down Expand Up @@ -111,17 +123,15 @@ func doAddRemoteChainToSolana(
var onRampBytes [64]byte
// already verified, skipping errcheck
remoteChainFamily, _ := chainsel.GetSelectorFamily(remoteChainSel)
var addressBytes []byte
switch remoteChainFamily {
case chainsel.FamilySolana:
return fmt.Errorf("support for solana chain as remote chain is not implemented yet %d", remoteChainSel)
addressBytes, _ = s.SolChains[remoteChainSel].OnRampBytes()
case chainsel.FamilyEVM:
onRampAddress := s.Chains[remoteChainSel].OnRamp.Address().String()
if onRampAddress == "" {
return fmt.Errorf("onramp address not found for chain %d", remoteChainSel)
}
addressBytes := []byte(onRampAddress)
copy(onRampBytes[:], addressBytes)
addressBytes, _ = s.Chains[remoteChainSel].OnRampBytes()
}
addressBytes = common.LeftPadBytes(addressBytes, 64)
copy(onRampBytes[:], addressBytes)

// verified while loading state
fqDestChainPDA, _, _ := solState.FindFqDestChainPDA(remoteChainSel, feeQuoterID)
Expand Down
1 change: 0 additions & 1 deletion deployment/ccip/changeset/solana/cs_billing.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ func AddBillingToken(e deployment.Environment, cfg BillingTokenConfig) (deployme
tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)
// verified
tokenprogramID, _ := GetTokenProgramID(cfg.TokenProgramName)
// TODO: add this to offramp address lookup table
tokenBillingPDA, _, _ := solState.FindFqBillingTokenConfigPDA(tokenPubKey, chainState.FeeQuoter)

// addressing errcheck in the next PR
Expand Down
1 change: 1 addition & 0 deletions deployment/ccip/changeset/solana/cs_chain_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var _ deployment.ChangeSet[BillingTokenForRemoteChainConfig] = AddBillingTokenFo
var _ deployment.ChangeSet[RegisterTokenAdminRegistryConfig] = RegisterTokenAdminRegistry
var _ deployment.ChangeSet[TransferAdminRoleTokenAdminRegistryConfig] = TransferAdminRoleTokenAdminRegistry
var _ deployment.ChangeSet[AcceptAdminRoleTokenAdminRegistryConfig] = AcceptAdminRoleTokenAdminRegistry
var _ deployment.ChangeSet[SetFeeAggregatorConfig] = SetFeeAggregator

// HELPER FUNCTIONS
// GetTokenProgramID returns the program ID for the given token program name
Expand Down
122 changes: 64 additions & 58 deletions deployment/ccip/changeset/solana/cs_chain_contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,65 +121,72 @@ func TestAddTokenPool(t *testing.T) {

state, err := ccipChangeset.LoadOnchainStateSolana(e)
require.NoError(t, err)
tokenAddress := state.SolChains[solChain].SPL2022Tokens[0]

// TODO: can test this with solana.SolMint as well (WSOL)
// https://smartcontract-it.atlassian.net/browse/INTAUTO-440
e, err = commonchangeset.Apply(t, e, nil,
commonchangeset.Configure(
deployment.CreateLegacyChangeSet(changeset_solana.AddTokenPool),
changeset_solana.TokenPoolConfig{
ChainSelector: solChain,
TokenPubKey: tokenAddress.String(),
TokenProgramName: deployment.SPL2022Tokens,
PoolType: solTestTokenPool.LockAndRelease_PoolType,
// this works for testing, but if we really want some other authority we need to pass in a private key for signing purposes
Authority: e.SolChains[solChain].DeployerKey.PublicKey().String(),
},
),
commonchangeset.Configure(
deployment.CreateLegacyChangeSet(changeset_solana.SetupTokenPoolForRemoteChain),
changeset_solana.RemoteChainTokenPoolConfig{
SolChainSelector: solChain,
RemoteChainSelector: evmChain,
SolTokenPubKey: tokenAddress.String(),
RemoteConfig: solTestTokenPool.RemoteConfig{
// TODO:this can be potentially read from the state if we are given the token symbol
PoolAddresses: []solTestTokenPool.RemoteAddress{{Address: []byte{1, 2, 3}}},
TokenAddress: solTestTokenPool.RemoteAddress{Address: []byte{4, 5, 6}},
Decimals: 9,
},
InboundRateLimit: solTestTokenPool.RateLimitConfig{
Enabled: true,
Capacity: uint64(1000),
Rate: 1,
newTokenAddress := state.SolChains[solChain].SPL2022Tokens[0]

remoteConfig := solTestTokenPool.RemoteConfig{
PoolAddresses: []solTestTokenPool.RemoteAddress{{Address: []byte{1, 2, 3}}},
TokenAddress: solTestTokenPool.RemoteAddress{Address: []byte{4, 5, 6}},
Decimals: 9,
}
inboundConfig := solTestTokenPool.RateLimitConfig{
Enabled: true,
Capacity: uint64(1000),
Rate: 1,
}
outboundConfig := solTestTokenPool.RateLimitConfig{
Enabled: false,
Capacity: 0,
Rate: 0,
}

tokenMap := map[string]solana.PublicKey{
deployment.SPL2022Tokens: newTokenAddress,
deployment.SPLTokens: state.SolChains[solChain].WSOL,
}

for tokenProgramName, tokenAddress := range tokenMap {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit : how about you update the CS input to receive multiple token programs and token addresses. IRL you might also need to do it for multiple tokens

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am refraining from doing that for token pool changesets as we should not be deploying more than a couple.
will leave as is for now if thats ok, and will add a couple of loops if we end up deploying for third parties.

e, err = commonchangeset.Apply(t, e, nil,
commonchangeset.Configure(
deployment.CreateLegacyChangeSet(changeset_solana.AddTokenPool),
changeset_solana.TokenPoolConfig{
ChainSelector: solChain,
TokenPubKey: tokenAddress.String(),
TokenProgramName: tokenProgramName,
PoolType: solTestTokenPool.LockAndRelease_PoolType,
// this works for testing, but if we really want some other authority we need to pass in a private key for signing purposes
Authority: e.SolChains[solChain].DeployerKey.PublicKey().String(),
},
OutboundRateLimit: solTestTokenPool.RateLimitConfig{
Enabled: false,
Capacity: 0,
Rate: 0,
),
commonchangeset.Configure(
deployment.CreateLegacyChangeSet(changeset_solana.SetupTokenPoolForRemoteChain),
changeset_solana.RemoteChainTokenPoolConfig{
SolChainSelector: solChain,
RemoteChainSelector: evmChain,
SolTokenPubKey: tokenAddress.String(),
RemoteConfig: remoteConfig,
InboundRateLimit: inboundConfig,
OutboundRateLimit: outboundConfig,
},
},
),
)
require.NoError(t, err)

// test AddTokenPool results
poolConfigPDA, err := solTokenUtil.TokenPoolConfigAddress(tokenAddress, state.SolChains[solChain].TokenPool)
require.NoError(t, err)
var configAccount solTestTokenPool.State
err = e.SolChains[solChain].GetAccountDataBorshInto(ctx, poolConfigPDA, &configAccount)
require.NoError(t, err)
require.Equal(t, solTestTokenPool.LockAndRelease_PoolType, configAccount.PoolType)
require.Equal(t, tokenAddress, configAccount.Config.Mint)
// try minting after this and see if the pool or the deployer key is the authority

// test SetupTokenPoolForRemoteChain results
remoteChainConfigPDA, _, _ := solTokenUtil.TokenPoolChainConfigPDA(evmChain, tokenAddress, state.SolChains[solChain].TokenPool)
var remoteChainConfigAccount solTestTokenPool.ChainConfig
err = e.SolChains[solChain].GetAccountDataBorshInto(ctx, remoteChainConfigPDA, &remoteChainConfigAccount)
require.NoError(t, err)
require.Equal(t, uint8(9), remoteChainConfigAccount.Base.Remote.Decimals)
),
)
require.NoError(t, err)

// test AddTokenPool results
poolConfigPDA, err := solTokenUtil.TokenPoolConfigAddress(tokenAddress, state.SolChains[solChain].TokenPool)
require.NoError(t, err)
var configAccount solTestTokenPool.State
err = e.SolChains[solChain].GetAccountDataBorshInto(ctx, poolConfigPDA, &configAccount)
require.NoError(t, err)
require.Equal(t, solTestTokenPool.LockAndRelease_PoolType, configAccount.PoolType)
require.Equal(t, tokenAddress, configAccount.Config.Mint)

// test SetupTokenPoolForRemoteChain results
remoteChainConfigPDA, _, _ := solTokenUtil.TokenPoolChainConfigPDA(evmChain, tokenAddress, state.SolChains[solChain].TokenPool)
var remoteChainConfigAccount solTestTokenPool.ChainConfig
err = e.SolChains[solChain].GetAccountDataBorshInto(ctx, remoteChainConfigPDA, &remoteChainConfigAccount)
require.NoError(t, err)
require.Equal(t, uint8(9), remoteChainConfigAccount.Base.Remote.Decimals)
}
}

func TestBilling(t *testing.T) {
Expand Down Expand Up @@ -345,7 +352,6 @@ func TestTokenAdminRegistry(t *testing.T) {
require.Equal(t, tokenAdminRegistryAdminPrivKey.PublicKey(), tokenAdminRegistryAccount.Administrator)
require.Equal(t, solana.PublicKey{}, tokenAdminRegistryAccount.PendingAdministrator)

// TODO: transfer and accept is breaking
newTokenAdminRegistryAdminPrivKey, _ := solana.NewRandomPrivateKey()
e, err = commonchangeset.Apply(t, e, nil,
commonchangeset.Configure(
Expand Down
Loading
Loading