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

feat: add Whitelist message ability to whitelist SPL tokens on Solana #2984

Merged
merged 26 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion e2e/runner/setup_solana.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (r *E2ERunner) SetupSolana(deployerPrivateKey string) {
inst.AccountValues = accountSlice

inst.DataBytes, err = borsh.Serialize(solanacontracts.InitializeParams{
Discriminator: solanacontracts.DiscriminatorInitialize(),
Discriminator: solanacontracts.DiscriminatorInitialize,
TssAddress: r.TSSAddress,
// #nosec G115 chain id always positive
ChainID: uint64(chains.SolanaLocalnet.ChainId),
Expand Down
2 changes: 1 addition & 1 deletion e2e/runner/solana.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (r *E2ERunner) CreateDepositInstruction(

var err error
inst.DataBytes, err = borsh.Serialize(solanacontract.DepositInstructionParams{
Discriminator: solanacontract.DiscriminatorDeposit(),
Discriminator: solanacontract.DiscriminatorDeposit,
Amount: amount,
Memo: append(receiver.Bytes(), data...),
})
Expand Down
4 changes: 2 additions & 2 deletions pkg/chains/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@
return chain.Vm == Vm_evm
}

func (chain Chain) IsSVMChain() bool {
return chain.Vm == Vm_svm
func (chain Chain) IsSolanaChain() bool {
return chain.Consensus == Consensus_solana_consensus

Check warning on line 100 in pkg/chains/chain.go

View check run for this annotation

Codecov / codecov/patch

pkg/chains/chain.go#L99-L100

Added lines #L99 - L100 were not covered by tests
}

func (chain Chain) IsBitcoinChain() bool {
Expand Down
43 changes: 14 additions & 29 deletions pkg/contracts/solana/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,20 @@ const (
AccountsNumDeposit = 3
)

// DiscriminatorInitialize returns the discriminator for Solana gateway 'initialize' instruction
func DiscriminatorInitialize() [8]byte {
return idlgateway.IDLGateway.GetDiscriminator("initialize")
}

// DiscriminatorDeposit returns the discriminator for Solana gateway 'deposit' instruction
func DiscriminatorDeposit() [8]byte {
return idlgateway.IDLGateway.GetDiscriminator("deposit")
}

// DiscriminatorDepositSPL returns the discriminator for Solana gateway 'deposit_spl_token' instruction
func DiscriminatorDepositSPL() [8]byte {
return idlgateway.IDLGateway.GetDiscriminator("deposit_spl_token")
}

// DiscriminatorWithdraw returns the discriminator for Solana gateway 'withdraw' instruction
func DiscriminatorWithdraw() [8]byte {
return idlgateway.IDLGateway.GetDiscriminator("withdraw")
}

// DiscriminatorWithdrawSPL returns the discriminator for Solana gateway 'withdraw_spl_token' instruction
func DiscriminatorWithdrawSPL() [8]byte {
return idlgateway.IDLGateway.GetDiscriminator("withdraw_spl_token")
}

// DiscriminatorWhitelist returns the discriminator for Solana gateway 'whitelist_spl_mint' instruction
func DiscriminatorWhitelistSplMint() [8]byte {
return idlgateway.IDLGateway.GetDiscriminator("whitelist_spl_mint")
}
var (
// DiscriminatorInitialize returns the discriminator for Solana gateway 'initialize' instruction
skosito marked this conversation as resolved.
Show resolved Hide resolved
DiscriminatorInitialize = idlgateway.IDLGateway.GetDiscriminator("initialize")
// DiscriminatorDeposit returns the discriminator for Solana gateway 'deposit' instruction
DiscriminatorDeposit = idlgateway.IDLGateway.GetDiscriminator("deposit")
// DiscriminatorDepositSPL returns the discriminator for Solana gateway 'deposit_spl_token' instruction
DiscriminatorDepositSPL = idlgateway.IDLGateway.GetDiscriminator("deposit_spl_token")
// DiscriminatorWithdraw returns the discriminator for Solana gateway 'withdraw' instruction
DiscriminatorWithdraw = idlgateway.IDLGateway.GetDiscriminator("withdraw")
// DiscriminatorWithdrawSPL returns the discriminator for Solana gateway 'withdraw_spl_token' instruction
DiscriminatorWithdrawSPL = idlgateway.IDLGateway.GetDiscriminator("withdraw_spl_token")
// DiscriminatorWhitelist returns the discriminator for Solana gateway 'whitelist_spl_mint' instruction
DiscriminatorWhitelistSplMint = idlgateway.IDLGateway.GetDiscriminator("whitelist_spl_mint")
)

// ParseGatewayAddressAndPda parses the gateway id and program derived address from the given string
func ParseGatewayIDAndPda(address string) (solana.PublicKey, solana.PublicKey, error) {
Expand Down
6 changes: 4 additions & 2 deletions pkg/contracts/solana/gateway_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,11 @@

// MsgWhitelist is the message for the Solana gateway whitelist_spl_mint instruction
type MsgWhitelist struct {
// whitelistCandidate is the whitelist candidate
// whitelistCandidate is the SPL token to be whitelisted in gateway program
whitelistCandidate solana.PublicKey
skosito marked this conversation as resolved.
Show resolved Hide resolved
whitelistEntry solana.PublicKey

// whitelistEntry is the entry in gateway program representing whitelisted SPL token
skosito marked this conversation as resolved.
Show resolved Hide resolved
whitelistEntry solana.PublicKey

// chainID is the chain ID of Solana chain
chainID uint64
skosito marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -139,22 +141,22 @@
}

// To returns the recipient address of the message
func (msg *MsgWhitelist) WhitelistCandidate() solana.PublicKey {
return msg.whitelistCandidate

Check warning on line 145 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L144-L145

Added lines #L144 - L145 were not covered by tests
}

func (msg *MsgWhitelist) WhitelistEntry() solana.PublicKey {
return msg.whitelistEntry

Check warning on line 149 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L148-L149

Added lines #L148 - L149 were not covered by tests
}

// ChainID returns the chain ID of the message
func (msg *MsgWhitelist) ChainID() uint64 {
return msg.chainID

Check warning on line 154 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L153-L154

Added lines #L153 - L154 were not covered by tests
}

// Nonce returns the nonce of the message
func (msg *MsgWhitelist) Nonce() uint64 {
return msg.nonce

Check warning on line 159 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L158-L159

Added lines #L158 - L159 were not covered by tests
}

// Hash packs the whitelist message and computes the hash
Expand All @@ -176,32 +178,32 @@
}

// SetSignature attaches the signature to the message
func (msg *MsgWhitelist) SetSignature(signature [65]byte) *MsgWhitelist {
msg.signature = signature
return msg

Check warning on line 183 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L181-L183

Added lines #L181 - L183 were not covered by tests
}

// SigRSV returns the full 65-byte [R+S+V] signature
func (msg *MsgWhitelist) SigRSV() [65]byte {
return msg.signature

Check warning on line 188 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L187-L188

Added lines #L187 - L188 were not covered by tests
}

// SigRS returns the 64-byte [R+S] core part of the signature
func (msg *MsgWhitelist) SigRS() [64]byte {
var sig [64]byte
copy(sig[:], msg.signature[:64])
return sig

Check warning on line 195 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L192-L195

Added lines #L192 - L195 were not covered by tests
}

// SigV returns the V part (recovery ID) of the signature
func (msg *MsgWhitelist) SigV() uint8 {
return msg.signature[64]

Check warning on line 200 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L199-L200

Added lines #L199 - L200 were not covered by tests
}

// Signer returns the signer of the message
func (msg *MsgWhitelist) Signer() (common.Address, error) {
msgHash := msg.Hash()
msgSig := msg.SigRSV()

return RecoverSigner(msgHash[:], msgSig[:])

Check warning on line 208 in pkg/contracts/solana/gateway_message.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/gateway_message.go#L204-L208

Added lines #L204 - L208 were not covered by tests
}
18 changes: 18 additions & 0 deletions pkg/contracts/solana/gateway_message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,21 @@ func Test_MsgWithdrawHash(t *testing.T) {
require.True(t, bytes.Equal(hash[:], wantHashBytes))
})
}

func Test_MsgWhitelistHash(t *testing.T) {
t.Run("should pass for archived inbound, receipt and cctx", func(t *testing.T) {
// #nosec G115 always positive
chainID := uint64(chains.SolanaLocalnet.ChainId)
nonce := uint64(0)
whitelistCandidate := solana.MustPublicKeyFromBase58("37yGiHAnLvWZUNVwu9esp74YQFqxU1qHCbABkDvRddUQ")
whitelistEntry := solana.MustPublicKeyFromBase58("2kJndCL9NBR36ySiQ4bmArs4YgWQu67LmCDfLzk5Gb7s")

wantHash := "cde8fa3ab24b50320db1c47f30492e789177d28e76208176f0a52b8ed54ce2dd"
wantHashBytes, err := hex.DecodeString(wantHash)
require.NoError(t, err)

// create new withdraw message
hash := contracts.NewMsgWhitelist(whitelistCandidate, whitelistEntry, chainID, nonce).Hash()
require.True(t, bytes.Equal(hash[:], wantHashBytes))
})
}
4 changes: 2 additions & 2 deletions pkg/contracts/solana/instruction.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
}

// check the discriminator to ensure it's a 'withdraw' instruction
if inst.Discriminator != DiscriminatorWithdraw() {
if inst.Discriminator != DiscriminatorWithdraw {

Check warning on line 102 in pkg/contracts/solana/instruction.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/instruction.go#L102

Added line #L102 was not covered by tests
return nil, fmt.Errorf("not a withdraw instruction: %v", inst.Discriminator)
}

Expand Down Expand Up @@ -138,38 +138,38 @@
}

// Signer returns the signer of the signature contained
func (inst *WhitelistInstructionParams) Signer() (signer common.Address, err error) {
var signature [65]byte
copy(signature[:], inst.Signature[:64])
signature[64] = inst.RecoveryID

return RecoverSigner(inst.MessageHash[:], signature[:])

Check warning on line 146 in pkg/contracts/solana/instruction.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/instruction.go#L141-L146

Added lines #L141 - L146 were not covered by tests
}

// GatewayNonce returns the nonce of the instruction
func (inst *WhitelistInstructionParams) GatewayNonce() uint64 {
skosito marked this conversation as resolved.
Show resolved Hide resolved
return inst.Nonce

Check warning on line 151 in pkg/contracts/solana/instruction.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/instruction.go#L150-L151

Added lines #L150 - L151 were not covered by tests
}

// TokenAmount returns the amount of the instruction
func (inst *WhitelistInstructionParams) TokenAmount() uint64 {
return 0

Check warning on line 156 in pkg/contracts/solana/instruction.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/instruction.go#L155-L156

Added lines #L155 - L156 were not covered by tests
}

// ParseInstructionWhitelist tries to parse the instruction as a 'whitelist_spl_mint'.
// It returns nil if the instruction can't be parsed as a 'whitelist_spl_mint'.
func ParseInstructionWhitelist(instruction solana.CompiledInstruction) (*WhitelistInstructionParams, error) {
// try deserializing instruction as a 'whitelist_spl_mint'
inst := &WhitelistInstructionParams{}
err := borsh.Deserialize(inst, instruction.Data)
if err != nil {
return nil, errors.Wrap(err, "error deserializing instruction")
}

Check warning on line 167 in pkg/contracts/solana/instruction.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/instruction.go#L161-L167

Added lines #L161 - L167 were not covered by tests

// check the discriminator to ensure it's a 'whitelist_spl_mint' instruction
if inst.Discriminator != DiscriminatorWhitelistSplMint() {
if inst.Discriminator != DiscriminatorWhitelistSplMint {
return nil, fmt.Errorf("not a whitelist_spl_mint instruction: %v", inst.Discriminator)
}

Check warning on line 172 in pkg/contracts/solana/instruction.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/instruction.go#L170-L172

Added lines #L170 - L172 were not covered by tests

return inst, nil

Check warning on line 174 in pkg/contracts/solana/instruction.go

View check run for this annotation

Codecov / codecov/patch

pkg/contracts/solana/instruction.go#L174

Added line #L174 was not covered by tests
}
2 changes: 1 addition & 1 deletion x/crosschain/keeper/msg_server_whitelist_erc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (k msgServer) WhitelistERC20(
)
}

case chain.IsSVMChain():
case chain.IsSolanaChain():
_, err := solana.PublicKeyFromBase58(msg.Erc20Address)
if err != nil {
return nil, errorsmod.Wrapf(
Expand Down
2 changes: 1 addition & 1 deletion zetaclient/chains/solana/observer/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func (ob *Observer) ParseInboundAsDeposit(
}

// check if the instruction is a deposit or not
if inst.Discriminator != solanacontracts.DiscriminatorDeposit() {
if inst.Discriminator != solanacontracts.DiscriminatorDeposit {
return nil, nil
}

Expand Down
63 changes: 63 additions & 0 deletions zetaclient/chains/solana/observer/outbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ const (

// tssAddressTest is the TSS address for testing
tssAddressTest = "0x05C7dBdd1954D59c9afaB848dA7d8DD3F35e69Cd"

// whitelistTxTest is local devnet tx result for testing
whitelistTxTest = "phM9bESbiqojmpkkUxgjed8EABkxvPGNau9q31B8Yk1sXUtsxJvd6G9VbZZQPsEyn6RiTH4YBtqJ89omqfbbNNY"
)

// createTestObserver creates a test observer for testing
Expand Down Expand Up @@ -294,3 +297,63 @@ func Test_ParseInstructionWithdraw(t *testing.T) {
require.Nil(t, inst)
})
}

func Test_ParseInstructionWhitelist(t *testing.T) {
// the test chain and transaction hash
chain := chains.SolanaDevnet
txHash := whitelistTxTest
txAmount := uint64(0)

t.Run("should parse instruction whitelist", func(t *testing.T) {
// tss address used in local devnet
tssAddress := "0x7E8c7bAcd3c6220DDC35A4EA1141BE14F2e1dFEB"
// load and unmarshal archived transaction
txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash)
tx, err := txResult.Transaction.GetTransaction()
require.NoError(t, err)

instruction := tx.Message.Instructions[0]
inst, err := contracts.ParseInstructionWhitelist(instruction)
require.NoError(t, err)

// check sender, nonce and amount
sender, err := inst.Signer()
require.NoError(t, err)
require.Equal(t, tssAddress, sender.String())
require.EqualValues(t, inst.GatewayNonce(), 3)
require.EqualValues(t, inst.TokenAmount(), txAmount)
})

t.Run("should return error on invalid instruction data", func(t *testing.T) {
// load and unmarshal archived transaction
txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash)
txFake, err := txResult.Transaction.GetTransaction()
require.NoError(t, err)

// set invalid instruction data
instruction := txFake.Message.Instructions[0]
instruction.Data = []byte("invalid instruction data")

inst, err := contracts.ParseInstructionWhitelist(instruction)
require.ErrorContains(t, err, "error deserializing instruction")
require.Nil(t, inst)
})

t.Run("should return error on discriminator mismatch", func(t *testing.T) {
// load and unmarshal archived transaction
txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash)
txFake, err := txResult.Transaction.GetTransaction()
require.NoError(t, err)

// overwrite discriminator (first 8 bytes)
instruction := txFake.Message.Instructions[0]
fakeDiscriminator := "b712469c946da12100980d0000000000"
fakeDiscriminatorBytes, err := hex.DecodeString(fakeDiscriminator)
require.NoError(t, err)
copy(instruction.Data, fakeDiscriminatorBytes)

inst, err := contracts.ParseInstructionWhitelist(instruction)
require.ErrorContains(t, err, "not a whitelist_spl_mint instruction")
require.Nil(t, inst)
})
}
16 changes: 8 additions & 8 deletions zetaclient/chains/solana/signer/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,62 +124,62 @@
chainID := signer.Chain().ChainId
nonce := params.TssNonce
coinType := cctx.InboundParams.CoinType

// skip relaying the transaction if this signer hasn't set the relayer key
if !signer.HasRelayerKey() {
logger.Warn().Msgf("TryProcessOutbound: no relayer key configured")
return
skosito marked this conversation as resolved.
Show resolved Hide resolved
}

Check warning on line 132 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L127-L132

Added lines #L127 - L132 were not covered by tests

var tx *solana.Transaction

switch coinType {
case coin.CoinType_Cmd:
skosito marked this conversation as resolved.
Show resolved Hide resolved
whitelistTx, err := signer.prepareWhitelistTx(ctx, cctx, height)
if err != nil {
logger.Error().Err(err).Msgf("TryProcessOutbound: Fail to sign whitelist outbound")
return
}

Check warning on line 142 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L134-L142

Added lines #L134 - L142 were not covered by tests

tx = whitelistTx

Check warning on line 144 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L144

Added line #L144 was not covered by tests

case coin.CoinType_Gas:
withdrawTx, err := signer.prepareWithdrawTx(ctx, cctx, height, logger)
if err != nil {
logger.Error().Err(err).Msgf("TryProcessOutbound: Fail to sign withdraw outbound")
return
}

Check warning on line 151 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L146-L151

Added lines #L146 - L151 were not covered by tests

tx = withdrawTx
default:
logger.Error().
Msgf("TryProcessOutbound: can only send SOL to the Solana network for chain %d nonce %d", chainID, nonce)
Msgf("TryProcessOutbound: can only send SOL to the Solana network")
skosito marked this conversation as resolved.
Show resolved Hide resolved
return

Check warning on line 157 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L153-L157

Added lines #L153 - L157 were not covered by tests
}

// set relayer balance metrics
signer.SetRelayerBalanceMetrics(ctx)

// broadcast the signed tx to the Solana network with preflight check
txSig, err := signer.client.SendTransactionWithOpts(
ctx,
tx,
// Commitment "finalized" is too conservative for preflight check and
// it results in repeated broadcast attempts that only 1 will succeed.
// Commitment "processed" will simulate tx against more recent state
// thus fails faster once a tx is already broadcasted and processed by the cluster.
// This reduces the number of "failed" txs due to repeated broadcast attempts.
rpc.TransactionOpts{PreflightCommitment: rpc.CommitmentProcessed},
)
if err != nil {

Check warning on line 174 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L161-L174

Added lines #L161 - L174 were not covered by tests
signer.Logger().
Std.Warn().
logger.Error().
Err(err).
Msgf("TryProcessOutbound: broadcast error for chain %d nonce %d", chainID, nonce)
Msgf("TryProcessOutbound: broadcast error")

Check warning on line 177 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L176-L177

Added lines #L176 - L177 were not covered by tests
skosito marked this conversation as resolved.
Show resolved Hide resolved
return
}

// report the outbound to the outbound tracker
signer.reportToOutboundTracker(ctx, zetacoreClient, chainID, nonce, txSig, logger)

Check warning on line 182 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L182

Added line #L182 was not covered by tests
}

func (signer *Signer) prepareWithdrawTx(
Expand All @@ -187,8 +187,8 @@
cctx *types.CrossChainTx,
height uint64,
logger zerolog.Logger,
) (*solana.Transaction, error) {
params := cctx.GetCurrentOutboundParam()

Check warning on line 191 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L190-L191

Added lines #L190 - L191 were not covered by tests
// compliance check
cancelTx := compliance.IsCctxRestricted(cctx)
if cancelTx {
Expand All @@ -196,7 +196,7 @@
logger,
signer.Logger().Compliance,
true,
signer.Chain().ChainId,

Check warning on line 199 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L199

Added line #L199 was not covered by tests
cctx.Index,
cctx.InboundParams.Sender,
params.Receiver,
Expand All @@ -205,55 +205,55 @@
}

// sign gateway withdraw message by TSS
msg, err := signer.SignMsgWithdraw(ctx, params, height, cancelTx)
msg, err := signer.createAndSignMsgWithdraw(ctx, params, height, cancelTx)

Check warning on line 208 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L208

Added line #L208 was not covered by tests
if err != nil {
return nil, err

Check warning on line 210 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L210

Added line #L210 was not covered by tests
}

// sign the withdraw transaction by relayer key
tx, err := signer.SignWithdrawTx(ctx, *msg)
tx, err := signer.signWithdrawTx(ctx, *msg)
if err != nil {
return nil, err

Check warning on line 216 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L214-L216

Added lines #L214 - L216 were not covered by tests
}

return tx, nil

Check warning on line 219 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L219

Added line #L219 was not covered by tests
}

func (signer *Signer) prepareWhitelistTx(
ctx context.Context,
cctx *types.CrossChainTx,
height uint64,
) (*solana.Transaction, error) {
params := cctx.GetCurrentOutboundParam()
relayedMsg := strings.Split(cctx.RelayedMessage, ":")
if len(relayedMsg) != 2 {
return nil, fmt.Errorf("TryProcessOutbound: invalid relayed msg")
}

Check warning on line 231 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L226-L231

Added lines #L226 - L231 were not covered by tests

pk, err := solana.PublicKeyFromBase58(relayedMsg[1])

Check warning on line 233 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L233

Added line #L233 was not covered by tests
if err != nil {
return nil, err

Check warning on line 235 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L235

Added line #L235 was not covered by tests
}

seed := [][]byte{[]byte("whitelist"), pk.Bytes()}
whitelistEntryPDA, _, err := solana.FindProgramAddress(seed, signer.gatewayID)

Check warning on line 239 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L238-L239

Added lines #L238 - L239 were not covered by tests
if err != nil {
return nil, err

Check warning on line 241 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L241

Added line #L241 was not covered by tests
}

// sign gateway whitelist message by TSS
msg, err := signer.SignMsgWhitelist(ctx, params, height, pk, whitelistEntryPDA)
msg, err := signer.createAndSignMsgWhitelist(ctx, params, height, pk, whitelistEntryPDA)
if err != nil {
return nil, err
}

Check warning on line 248 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L245-L248

Added lines #L245 - L248 were not covered by tests

// sign the whitelist transaction by relayer key
tx, err := signer.SignWhitelistTx(ctx, msg)
tx, err := signer.signWhitelistTx(ctx, msg)
if err != nil {
return nil, err
}

Check warning on line 254 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L251-L254

Added lines #L251 - L254 were not covered by tests

return tx, nil

Check warning on line 256 in zetaclient/chains/solana/signer/signer.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/signer.go#L256

Added line #L256 was not covered by tests
}

// SetGatewayAddress sets the gateway address
Expand Down
10 changes: 5 additions & 5 deletions zetaclient/chains/solana/signer/whitelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,95 +12,95 @@
"github.com/zeta-chain/node/x/crosschain/types"
)

// SignMsgWhitelist signs a whitelist message (for gateway whitelist_spl_mint instruction) with TSS.
func (signer *Signer) SignMsgWhitelist(
// createAndSignMsgWhitelist creates and signs a whitelist message (for gateway whitelist_spl_mint instruction) with TSS.
func (signer *Signer) createAndSignMsgWhitelist(
ctx context.Context,
params *types.OutboundParams,
height uint64,
whitelistCandidate solana.PublicKey,
whitelistEntry solana.PublicKey,
) (*contracts.MsgWhitelist, error) {
chain := signer.Chain()
// #nosec G115 always positive
chainID := uint64(signer.Chain().ChainId)
nonce := params.TssNonce

// prepare whitelist msg and compute hash
msg := contracts.NewMsgWhitelist(whitelistCandidate, whitelistEntry, chainID, nonce)
msgHash := msg.Hash()

// sign the message with TSS to get an ECDSA signature.
// the produced signature is in the [R || S || V] format where V is 0 or 1.
signature, err := signer.TSS().Sign(ctx, msgHash[:], height, nonce, chain.ChainId, "")
if err != nil {
return nil, errors.Wrap(err, "Key-sign failed")
}
signer.Logger().Std.Info().Msgf("Key-sign succeed for chain %d nonce %d", chainID, nonce)

// attach the signature and return
return msg.SetSignature(signature), nil

Check warning on line 41 in zetaclient/chains/solana/signer/whitelist.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/whitelist.go#L22-L41

Added lines #L22 - L41 were not covered by tests
}

// SignWhitelistTx wraps the whitelist 'msg' into a Solana transaction and signs it with the relayer key.
func (signer *Signer) SignWhitelistTx(ctx context.Context, msg *contracts.MsgWhitelist) (*solana.Transaction, error) {
// signWhitelistTx wraps the whitelist 'msg' into a Solana transaction and signs it with the relayer key.
func (signer *Signer) signWhitelistTx(ctx context.Context, msg *contracts.MsgWhitelist) (*solana.Transaction, error) {
// create whitelist_spl_mint instruction with program call data
var err error
var inst solana.GenericInstruction
inst.DataBytes, err = borsh.Serialize(contracts.WhitelistInstructionParams{
Discriminator: contracts.DiscriminatorWhitelistSplMint(),
Discriminator: contracts.DiscriminatorWhitelistSplMint,
Signature: msg.SigRS(),
RecoveryID: msg.SigV(),
MessageHash: msg.Hash(),
Nonce: msg.Nonce(),
})
if err != nil {
return nil, errors.Wrap(err, "cannot serialize whitelist_spl_mint instruction")
}

Check warning on line 58 in zetaclient/chains/solana/signer/whitelist.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/whitelist.go#L45-L58

Added lines #L45 - L58 were not covered by tests

// attach required accounts to the instruction
privkey := signer.relayerKey
attachWhitelistAccounts(
&inst,
privkey.PublicKey(),
signer.pda,
msg.WhitelistCandidate(),
msg.WhitelistEntry(),
signer.gatewayID,
)

// get a recent blockhash
recent, err := signer.client.GetLatestBlockhash(ctx, rpc.CommitmentFinalized)
skosito marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, errors.Wrap(err, "GetLatestBlockhash error")
}

Check warning on line 75 in zetaclient/chains/solana/signer/whitelist.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/whitelist.go#L61-L75

Added lines #L61 - L75 were not covered by tests

// create a transaction that wraps the instruction
tx, err := solana.NewTransaction(
[]solana.Instruction{
// TODO: outbound now uses 5K lamports as the fixed fee, we could explore priority fee and compute budget
// https://github.com/zeta-chain/node/issues/2599
// programs.ComputeBudgetSetComputeUnitLimit(computeUnitLimit),
// programs.ComputeBudgetSetComputeUnitPrice(computeUnitPrice),
&inst},
recent.Value.Blockhash,
solana.TransactionPayer(privkey.PublicKey()),
)
if err != nil {
return nil, errors.Wrap(err, "NewTransaction error")
}

Check warning on line 90 in zetaclient/chains/solana/signer/whitelist.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/whitelist.go#L78-L90

Added lines #L78 - L90 were not covered by tests

// relayer signs the transaction
_, err = tx.Sign(func(key solana.PublicKey) *solana.PrivateKey {
if key.Equals(privkey.PublicKey()) {
return privkey
}
return nil

Check warning on line 97 in zetaclient/chains/solana/signer/whitelist.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/whitelist.go#L93-L97

Added lines #L93 - L97 were not covered by tests
})
if err != nil {
return nil, errors.Wrap(err, "signer unable to sign transaction")
}

Check warning on line 101 in zetaclient/chains/solana/signer/whitelist.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/whitelist.go#L99-L101

Added lines #L99 - L101 were not covered by tests

return tx, nil

Check warning on line 103 in zetaclient/chains/solana/signer/whitelist.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/whitelist.go#L103

Added line #L103 was not covered by tests
}

// attachWhitelistAccounts attaches the required accounts for the gateway whitelist instruction.
Expand All @@ -111,15 +111,15 @@
whitelistCandidate solana.PublicKey,
whitelistEntry solana.PublicKey,
gatewayID solana.PublicKey,
) {
// attach required accounts to the instruction
var accountSlice []*solana.AccountMeta
accountSlice = append(accountSlice, solana.Meta(whitelistEntry).WRITE())
accountSlice = append(accountSlice, solana.Meta(whitelistCandidate))
accountSlice = append(accountSlice, solana.Meta(pda).WRITE())
accountSlice = append(accountSlice, solana.Meta(signer).WRITE().SIGNER())
accountSlice = append(accountSlice, solana.Meta(solana.SystemProgramID))
inst.ProgID = gatewayID

inst.AccountValues = accountSlice

Check warning on line 124 in zetaclient/chains/solana/signer/whitelist.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/whitelist.go#L114-L124

Added lines #L114 - L124 were not covered by tests
}
10 changes: 5 additions & 5 deletions zetaclient/chains/solana/signer/withdraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"github.com/zeta-chain/node/x/crosschain/types"
)

// SignMsgWithdraw signs a withdraw message (for gateway withdraw/withdraw_spl instruction) with TSS.
func (signer *Signer) SignMsgWithdraw(
// createAndSignMsgWithdraw creates and signs a withdraw message (for gateway withdraw/withdraw_spl instruction) with TSS.
func (signer *Signer) createAndSignMsgWithdraw(
ctx context.Context,
params *types.OutboundParams,
height uint64,
Expand Down Expand Up @@ -53,13 +53,13 @@
return msg.SetSignature(signature), nil
}

// SignWithdrawTx wraps the withdraw 'msg' into a Solana transaction and signs it with the relayer key.
func (signer *Signer) SignWithdrawTx(ctx context.Context, msg contracts.MsgWithdraw) (*solana.Transaction, error) {
// signWithdrawTx wraps the withdraw 'msg' into a Solana transaction and signs it with the relayer key.
func (signer *Signer) signWithdrawTx(ctx context.Context, msg contracts.MsgWithdraw) (*solana.Transaction, error) {

Check warning on line 57 in zetaclient/chains/solana/signer/withdraw.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/withdraw.go#L57

Added line #L57 was not covered by tests
// create withdraw instruction with program call data
var err error
var inst solana.GenericInstruction
inst.DataBytes, err = borsh.Serialize(contracts.WithdrawInstructionParams{
Discriminator: contracts.DiscriminatorWithdraw(),
Discriminator: contracts.DiscriminatorWithdraw,

Check warning on line 62 in zetaclient/chains/solana/signer/withdraw.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/chains/solana/signer/withdraw.go#L62

Added line #L62 was not covered by tests
Amount: msg.Amount(),
Signature: msg.SigRS(),
RecoveryID: msg.SigV(),
Expand Down
Loading
Loading