Skip to content

Commit

Permalink
TokenPool split and other QOL (#16472)
Browse files Browse the repository at this point in the history
* modularising billing to be reused in cs_deploy

* adding offramp instruction

* adding remote billing for token transfers

* loading bytes

* Adding tp types to state

* deploy and preload tps

* bug fix

* adding spltokens array and func to map tokenaddress to program

* token pool split in changesets

* deprecating old token pool, just commenting first

* lint

* adding wsol to spltokens

* removing consts

* using same type

* changes

* removing token program name from billinh

* removing old consts

* changing type and using index 1

* renaming and adding config

* cascading changes

* removing redundant const

* cascading changes and adding billing through config

* adding validate

* renaming packages

* linting

* include spltokens in validation

* abstract deployToken in test

* fix logging

* dont add link and wsol to token array

* use token symbol as input

* lint and bug

* bug

* lint

* fix
  • Loading branch information
yashnevatia authored Feb 24, 2025
1 parent 3c01f57 commit aefb2b7
Show file tree
Hide file tree
Showing 20 changed files with 855 additions and 565 deletions.
67 changes: 36 additions & 31 deletions deployment/ccip/changeset/solana/cs_add_remote_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ import (
solCommonUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common"
solState "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/state"

chainsel "github.com/smartcontractkit/chain-selectors"

"github.com/smartcontractkit/chainlink/deployment"
cs "github.com/smartcontractkit/chainlink/deployment/ccip/changeset"
ccipChangeset "github.com/smartcontractkit/chainlink/deployment/ccip/changeset"
commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset"
commonState "github.com/smartcontractkit/chainlink/deployment/common/changeset/state"
)
Expand All @@ -30,7 +28,7 @@ type AddRemoteChainToSolanaConfig struct {
UpdatesByChain map[uint64]RemoteChainConfigSolana
// Disallow mixing MCMS/non-MCMS per chain for simplicity.
// (can still be achieved by calling this function multiple times)
MCMS *cs.MCMSConfig
MCMS *ccipChangeset.MCMSConfig
}

type RemoteChainConfigSolana struct {
Expand All @@ -42,7 +40,7 @@ type RemoteChainConfigSolana struct {
}

func (cfg AddRemoteChainToSolanaConfig) Validate(e deployment.Environment) error {
state, err := cs.LoadOnchainState(e)
state, err := ccipChangeset.LoadOnchainState(e)
if err != nil {
return fmt.Errorf("failed to load onchain state: %w", err)
}
Expand Down Expand Up @@ -84,7 +82,7 @@ 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 {
if err := state.ValidateRamp(remote, ccipChangeset.OnRamp); err != nil {
return err
}
routerDestChainPDA, err := solState.FindDestChainStatePDA(remote, chainState.Router)
Expand All @@ -106,7 +104,7 @@ func AddRemoteChainToSolana(e deployment.Environment, cfg AddRemoteChainToSolana
return deployment.ChangesetOutput{}, err
}

s, err := cs.LoadOnchainState(e)
s, err := ccipChangeset.LoadOnchainState(e)
if err != nil {
return deployment.ChangesetOutput{}, err
}
Expand All @@ -121,7 +119,7 @@ func AddRemoteChainToSolana(e deployment.Environment, cfg AddRemoteChainToSolana

func doAddRemoteChainToSolana(
e deployment.Environment,
s cs.CCIPOnChainState,
s ccipChangeset.CCIPOnChainState,
chainSel uint64,
updates map[uint64]RemoteChainConfigSolana,
ab deployment.AddressBook) error {
Expand All @@ -134,33 +132,39 @@ func doAddRemoteChainToSolana(
for remoteChainSel, update := range updates {
var onRampBytes [64]byte
// already verified, skipping errcheck
remoteChainFamily, _ := chainsel.GetSelectorFamily(remoteChainSel)
var addressBytes []byte
switch remoteChainFamily {
case chainsel.FamilySolana:
addressBytes, _ = s.SolChains[remoteChainSel].OnRampBytes()
case chainsel.FamilyEVM:
addressBytes, _ = s.Chains[remoteChainSel].OnRampBytes()
}
addressBytes, _ := s.GetOnRampAddressBytes(remoteChainSel)
addressBytes = common.LeftPadBytes(addressBytes, 64)
copy(onRampBytes[:], addressBytes)

// verified while loading state
fqDestChainPDA, _, _ := solState.FindFqDestChainPDA(remoteChainSel, feeQuoterID)
routerDestChainPDA, _ := solState.FindDestChainStatePDA(remoteChainSel, ccipRouterID)
offRampSourceChainPDA, _, _ := solState.FindOfframpSourceChainPDA(remoteChainSel, s.SolChains[chainSel].OffRamp)
fqRemoteChainPDA, _, _ := solState.FindFqDestChainPDA(remoteChainSel, feeQuoterID)
routerRemoteStatePDA, _ := solState.FindDestChainStatePDA(remoteChainSel, ccipRouterID)
offRampRemoteStatePDA, _, _ := solState.FindOfframpSourceChainPDA(remoteChainSel, offRampID)
allowedOffRampRemotePDA, _ := solState.FindAllowedOfframpPDA(remoteChainSel, offRampID, ccipRouterID)

lookUpTableEntries = append(lookUpTableEntries,
fqDestChainPDA,
routerDestChainPDA,
offRampSourceChainPDA,
fqRemoteChainPDA,
routerRemoteStatePDA,
offRampRemoteStatePDA,
)

solRouter.SetProgramID(ccipRouterID)
routerIx, err := solRouter.NewAddChainSelectorInstruction(
remoteChainSel,
update.RouterDestinationConfig,
routerDestChainPDA,
routerRemoteStatePDA,
s.SolChains[chainSel].RouterConfigPDA,
chain.DeployerKey.PublicKey(),
solana.SystemProgramID,
).ValidateAndBuild()
if err != nil {
return fmt.Errorf("failed to generate instructions: %w", err)
}

routerOfframpIx, err := solRouter.NewAddOfframpInstruction(
remoteChainSel,
offRampID,
allowedOffRampRemotePDA,
s.SolChains[chainSel].RouterConfigPDA,
chain.DeployerKey.PublicKey(),
solana.SystemProgramID,
Expand All @@ -174,7 +178,7 @@ func doAddRemoteChainToSolana(
remoteChainSel,
update.FeeQuoterDestinationConfig,
s.SolChains[chainSel].FeeQuoterConfigPDA,
fqDestChainPDA,
fqRemoteChainPDA,
chain.DeployerKey.PublicKey(),
solana.SystemProgramID,
).ValidateAndBuild()
Expand All @@ -190,37 +194,38 @@ func doAddRemoteChainToSolana(
offRampIx, err := solOffRamp.NewAddSourceChainInstruction(
remoteChainSel,
validSourceChainConfig,
offRampSourceChainPDA,
offRampRemoteStatePDA,
s.SolChains[chainSel].OffRampConfigPDA,
chain.DeployerKey.PublicKey(),
solana.SystemProgramID,
).ValidateAndBuild()

if err != nil {
return fmt.Errorf("failed to generate instructions: %w", err)
}

err = chain.Confirm([]solana.Instruction{routerIx, feeQuoterIx, offRampIx})
err = chain.Confirm([]solana.Instruction{routerIx, routerOfframpIx, feeQuoterIx, offRampIx})
if err != nil {
return fmt.Errorf("failed to confirm instructions: %w", err)
}

tv := deployment.NewTypeAndVersion(cs.RemoteDest, deployment.Version1_0_0)
tv := deployment.NewTypeAndVersion(ccipChangeset.RemoteDest, deployment.Version1_0_0)
remoteChainSelStr := strconv.FormatUint(remoteChainSel, 10)
tv.AddLabel(remoteChainSelStr)
err = ab.Save(chainSel, routerDestChainPDA.String(), tv)
err = ab.Save(chainSel, routerRemoteStatePDA.String(), tv)
if err != nil {
return fmt.Errorf("failed to save dest chain state to address book: %w", err)
}

tv = deployment.NewTypeAndVersion(cs.RemoteSource, deployment.Version1_0_0)
tv = deployment.NewTypeAndVersion(ccipChangeset.RemoteSource, deployment.Version1_0_0)
tv.AddLabel(remoteChainSelStr)
err = ab.Save(chainSel, offRampSourceChainPDA.String(), tv)
err = ab.Save(chainSel, allowedOffRampRemotePDA.String(), tv)
if err != nil {
return fmt.Errorf("failed to save source chain state to address book: %w", err)
}
}

addressLookupTable, err := cs.FetchOfframpLookupTable(e.GetContext(), chain, offRampID)
addressLookupTable, err := ccipChangeset.FetchOfframpLookupTable(e.GetContext(), chain, offRampID)
if err != nil {
return fmt.Errorf("failed to get offramp reference addresses: %w", err)
}
Expand Down
86 changes: 47 additions & 39 deletions deployment/ccip/changeset/solana/cs_billing.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,34 @@ import (
ata "github.com/gagliardetto/solana-go/programs/associated-token-account"

"github.com/smartcontractkit/chainlink/deployment"
cs "github.com/smartcontractkit/chainlink/deployment/ccip/changeset"
ccipChangeset "github.com/smartcontractkit/chainlink/deployment/ccip/changeset"
)

var _ deployment.ChangeSet[BillingTokenConfig] = AddBillingToken
var _ deployment.ChangeSet[BillingTokenConfig] = AddBillingTokenChangeset
var _ deployment.ChangeSet[BillingTokenForRemoteChainConfig] = AddBillingTokenForRemoteChain

// ADD BILLING TOKEN
type BillingTokenConfig struct {
ChainSelector uint64
TokenPubKey string
TokenProgramName string
Config solFeeQuoter.BillingTokenConfig
ChainSelector uint64
TokenPubKey string
Config solFeeQuoter.BillingTokenConfig
}

func (cfg BillingTokenConfig) Validate(e deployment.Environment) error {
tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)
if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil {
return err
}
if _, err := GetTokenProgramID(cfg.TokenProgramName); err != nil {
return err
}

chain := e.SolChains[cfg.ChainSelector]
state, _ := cs.LoadOnchainState(e)
state, _ := ccipChangeset.LoadOnchainState(e)
chainState := state.SolChains[cfg.ChainSelector]
if err := validateFeeQuoterConfig(chain, chainState); err != nil {
return err
}
if _, err := chainState.TokenToTokenProgram(tokenPubKey); err != nil {
return err
}
// check if already setup
billingConfigPDA, _, err := solState.FindFqBillingTokenConfigPDA(tokenPubKey, chainState.FeeQuoter)
if err != nil {
Expand All @@ -55,32 +54,23 @@ func (cfg BillingTokenConfig) Validate(e deployment.Environment) error {
return nil
}

func AddBillingToken(e deployment.Environment, cfg BillingTokenConfig) (deployment.ChangesetOutput, error) {
if err := cfg.Validate(e); err != nil {
return deployment.ChangesetOutput{}, err
}
chain, ok := e.SolChains[cfg.ChainSelector]
if !ok {
return deployment.ChangesetOutput{}, fmt.Errorf("chain selector %d not found in environment", cfg.ChainSelector)
}
state, _ := cs.LoadOnchainState(e)
chainState := state.SolChains[cfg.ChainSelector]
tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)
// verified
tokenprogramID, _ := GetTokenProgramID(cfg.TokenProgramName)
func AddBillingToken(
e deployment.Environment,
chain deployment.SolChain,
chainState ccipChangeset.SolCCIPChainState,
billingConfig solFeeQuoter.BillingTokenConfig,
) error {
tokenPubKey := solana.MustPublicKeyFromBase58(billingConfig.Mint.String())
tokenBillingPDA, _, _ := solState.FindFqBillingTokenConfigPDA(tokenPubKey, chainState.FeeQuoter)

// addressing errcheck in the next PR
billingSignerPDA, _, _ := solState.FindFeeBillingSignerPDA(chainState.Router)
token2022Receiver, _, _ := solTokenUtil.FindAssociatedTokenAddress(tokenprogramID, tokenPubKey, billingSignerPDA)

e.Logger.Infow("chainState.FeeQuoterConfigPDA", "feeQuoterConfigPDA", chainState.FeeQuoterConfigPDA.String())
solFeeQuoter.SetProgramID(chainState.FeeQuoter)
tokenProgramID, _ := chainState.TokenToTokenProgram(tokenPubKey)
token2022Receiver, _, _ := solTokenUtil.FindAssociatedTokenAddress(tokenProgramID, tokenPubKey, billingSignerPDA)
feeQuoterConfigPDA, _, _ := solState.FindFqConfigPDA(chainState.FeeQuoter)
ixConfig, cerr := solFeeQuoter.NewAddBillingTokenConfigInstruction(
cfg.Config,
chainState.FeeQuoterConfigPDA,
billingConfig,
feeQuoterConfigPDA,
tokenBillingPDA,
tokenprogramID,
tokenProgramID,
tokenPubKey,
token2022Receiver,
chain.DeployerKey.PublicKey(), // ccip admin
Expand All @@ -89,15 +79,33 @@ func AddBillingToken(e deployment.Environment, cfg BillingTokenConfig) (deployme
solana.SystemProgramID,
).ValidateAndBuild()
if cerr != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate instructions: %w", cerr)
return fmt.Errorf("failed to generate instructions: %w", cerr)
}

instructions := []solana.Instruction{ixConfig}
if err := chain.Confirm(instructions); err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err)
return fmt.Errorf("failed to confirm instructions: %w", err)
}
return nil
}

func AddBillingTokenChangeset(e deployment.Environment, cfg BillingTokenConfig) (deployment.ChangesetOutput, error) {
if err := cfg.Validate(e); err != nil {
return deployment.ChangesetOutput{}, err
}
chain := e.SolChains[cfg.ChainSelector]
state, _ := ccipChangeset.LoadOnchainState(e)
chainState := state.SolChains[cfg.ChainSelector]

solFeeQuoter.SetProgramID(chainState.FeeQuoter)

if err := AddBillingToken(e, chain, chainState, cfg.Config); err != nil {
return deployment.ChangesetOutput{}, err
}

tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)
tokenBillingPDA, _, _ := solState.FindFqBillingTokenConfigPDA(tokenPubKey, chainState.FeeQuoter)

addressLookupTable, err := cs.FetchOfframpLookupTable(e.GetContext(), chain, chainState.OffRamp)
addressLookupTable, err := ccipChangeset.FetchOfframpLookupTable(e.GetContext(), chain, chainState.OffRamp)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to get offramp reference addresses: %w", err)
}
Expand Down Expand Up @@ -129,7 +137,7 @@ func (cfg BillingTokenForRemoteChainConfig) Validate(e deployment.Environment) e
if err := commonValidation(e, cfg.ChainSelector, tokenPubKey); err != nil {
return err
}
state, _ := cs.LoadOnchainState(e)
state, _ := ccipChangeset.LoadOnchainState(e)
chainState := state.SolChains[cfg.ChainSelector]
chain := e.SolChains[cfg.ChainSelector]
if err := validateFeeQuoterConfig(chain, chainState); err != nil {
Expand All @@ -153,7 +161,7 @@ func AddBillingTokenForRemoteChain(e deployment.Environment, cfg BillingTokenFor
}

chain := e.SolChains[cfg.ChainSelector]
state, _ := cs.LoadOnchainState(e)
state, _ := ccipChangeset.LoadOnchainState(e)
chainState := state.SolChains[cfg.ChainSelector]
tokenPubKey := solana.MustPublicKeyFromBase58(cfg.TokenPubKey)
remoteBillingPDA, _, _ := solState.FindFqPerChainPerTokenConfigPDA(cfg.RemoteChainSelector, tokenPubKey, chainState.FeeQuoter)
Expand All @@ -175,7 +183,7 @@ func AddBillingTokenForRemoteChain(e deployment.Environment, cfg BillingTokenFor
return deployment.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err)
}

addressLookupTable, err := cs.FetchOfframpLookupTable(e.GetContext(), chain, chainState.OffRamp)
addressLookupTable, err := ccipChangeset.FetchOfframpLookupTable(e.GetContext(), chain, chainState.OffRamp)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to get offramp reference addresses: %w", err)
}
Expand Down
Loading

0 comments on commit aefb2b7

Please sign in to comment.