Skip to content

Commit

Permalink
fix: use the ZEVM address pulled from memo as Receiver in MsgVoteInbo…
Browse files Browse the repository at this point in the history
…und (#3267)

* fix: use the ZEVM address pulled from memo as Receiver in MsgVoteInbound (#3242)

* use the ZEVM address decoded from memo as Receiver in MsgVoteInbound

* add Receiver check in unit test

* add changelog entry

* fix unit test

* fix unit test

---------

Co-authored-by: Charlie Chen <[email protected]>
Co-authored-by: Lucas Bertrand <[email protected]>
  • Loading branch information
3 people authored Dec 16, 2024
1 parent 2ca464a commit cf747df
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 6 deletions.
1 change: 1 addition & 0 deletions e2e/e2etests/test_solana_deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestSolanaDeposit(r *runner.E2ERunner, args []string) {
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, sig.String(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "solana_deposit")
utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined)
require.Equal(r, cctx.GetCurrentOutboundParam().Receiver, r.EVMAddress().Hex())

// get ERC20 SOL balance after deposit
balanceAfter, err := r.SOLZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress())
Expand Down
1 change: 1 addition & 0 deletions e2e/e2etests/test_solana_deposit_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestSolanaDepositAndCall(r *runner.E2ERunner, args []string) {
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, sig.String(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "solana_deposit_and_call")
utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined)
require.Equal(r, cctx.GetCurrentOutboundParam().Receiver, contractAddr.Hex())

// check if example contract has been called, bar value should be set to amount
utils.MustHaveCalledExampleContractWithMsg(r, contract, depositAmount, data)
Expand Down
1 change: 1 addition & 0 deletions e2e/e2etests/test_spl_deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func TestSPLDeposit(r *runner.E2ERunner, args []string) {
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, sig.String(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "solana_deposit_spl")
utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined)
require.Equal(r, cctx.GetCurrentOutboundParam().Receiver, r.EVMAddress().Hex())

// verify balances are updated
pdaBalanceAfter, err := r.SolanaClient.GetTokenAccountBalance(r.Ctx, pdaAta, rpc.CommitmentFinalized)
Expand Down
1 change: 1 addition & 0 deletions e2e/e2etests/test_spl_deposit_and_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func TestSPLDepositAndCall(r *runner.E2ERunner, args []string) {
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, sig.String(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "solana_deposit_spl_and_call")
utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined)
require.Equal(r, cctx.GetCurrentOutboundParam().Receiver, contractAddr.Hex())

// check if example contract has been called, bar value should be set to amount
utils.MustHaveCalledExampleContractWithMsg(r, contract, big.NewInt(int64(amount)), data)
Expand Down
20 changes: 17 additions & 3 deletions zetaclient/chains/solana/observer/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
solanarpc "github.com/zeta-chain/node/zetaclient/chains/solana/rpc"
"github.com/zeta-chain/node/zetaclient/compliance"
zctx "github.com/zeta-chain/node/zetaclient/context"
"github.com/zeta-chain/node/zetaclient/logs"
clienttypes "github.com/zeta-chain/node/zetaclient/types"
"github.com/zeta-chain/node/zetaclient/zetacore"
)
Expand Down Expand Up @@ -213,7 +214,7 @@ func (ob *Observer) FilterInboundEvents(txResult *rpc.GetTransactionResult) ([]*
events = append(events, &clienttypes.InboundEvent{
SenderChainID: ob.Chain().ChainId,
Sender: deposit.Sender,
Receiver: deposit.Sender, // receiver is pulled out from memo
Receiver: "", // receiver will be pulled out from memo later
TxOrigin: deposit.Sender,
Amount: deposit.Amount,
Memo: deposit.Memo,
Expand Down Expand Up @@ -241,7 +242,7 @@ func (ob *Observer) FilterInboundEvents(txResult *rpc.GetTransactionResult) ([]*
events = append(events, &clienttypes.InboundEvent{
SenderChainID: ob.Chain().ChainId,
Sender: deposit.Sender,
Receiver: deposit.Sender, // receiver is pulled out from memo
Receiver: "", // receiver will be pulled out from memo later
TxOrigin: deposit.Sender,
Amount: deposit.Amount,
Memo: deposit.Memo,
Expand Down Expand Up @@ -277,11 +278,24 @@ func (ob *Observer) BuildInboundVoteMsgFromEvent(event *clienttypes.InboundEvent
return nil
}

// prepare logger fields
lf := map[string]any{
logs.FieldMethod: "BuildInboundVoteMsgFromEvent",
logs.FieldTx: event.TxHash,
}

// decode event memo bytes to get the receiver
err := event.DecodeMemo()
if err != nil {
ob.Logger().Inbound.Info().Fields(lf).Msgf("invalid memo bytes: %s", hex.EncodeToString(event.Memo))
return nil
}

return zetacore.GetInboundVoteMessage(
event.Sender,
event.SenderChainID,
event.Sender,
event.Sender,
event.Receiver,
ob.ZetacoreClient().Chain().ChainId,
cosmosmath.NewUint(event.Amount),
hex.EncodeToString(event.Memo),
Expand Down
8 changes: 5 additions & 3 deletions zetaclient/chains/solana/observer/inbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func Test_FilterInboundEvents(t *testing.T) {
eventExpected := &clienttypes.InboundEvent{
SenderChainID: chain.ChainId,
Sender: sender,
Receiver: sender,
Receiver: "",
TxOrigin: sender,
Amount: 100000000,
Memo: expectedMemo,
Expand Down Expand Up @@ -124,11 +124,13 @@ func Test_BuildInboundVoteMsgFromEvent(t *testing.T) {

t.Run("should return vote msg for valid event", func(t *testing.T) {
sender := sample.SolanaAddress(t)
memo := sample.EthAddress().Bytes()
event := sample.InboundEvent(chain.ChainId, sender, sender, 1280, []byte(memo))
receiver := sample.EthAddress()
event := sample.InboundEvent(chain.ChainId, sender, "", 1280, receiver.Bytes())

msg := ob.BuildInboundVoteMsgFromEvent(event)
require.NotNil(t, msg)
require.Equal(t, sender, msg.Sender)
require.Equal(t, receiver.Hex(), msg.Receiver)
})
t.Run("should return nil msg if sender is restricted", func(t *testing.T) {
sender := sample.SolanaAddress(t)
Expand Down
31 changes: 31 additions & 0 deletions zetaclient/types/event.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package types

import (
"bytes"
"encoding/hex"

"github.com/pkg/errors"

"github.com/zeta-chain/node/pkg/coin"
"github.com/zeta-chain/node/pkg/constant"
"github.com/zeta-chain/node/pkg/crypto"
"github.com/zeta-chain/node/pkg/memo"
)

// InboundEvent represents an inbound event
Expand Down Expand Up @@ -41,3 +49,26 @@ type InboundEvent struct {
// Asset is the asset of the inbound
Asset string
}

// DecodeMemo decodes the receiver from the memo bytes
func (event *InboundEvent) DecodeMemo() error {
// skip decoding donation tx as it won't go through zetacore
if bytes.Equal(event.Memo, []byte(constant.DonationMessage)) {
return nil
}

// decode receiver address from memo
parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Memo))
if err != nil { // unreachable code
return errors.Wrap(err, "invalid memo hex")
}

// ensure the receiver is valid
if crypto.IsEmptyAddress(parsedAddress) {
return errors.New("got empty receiver address from memo")
}

event.Receiver = parsedAddress.Hex()

return nil
}

0 comments on commit cf747df

Please sign in to comment.