From 798f5669fc1b7684fc6d17549e56d67aa539f588 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Tue, 15 Oct 2024 17:24:46 -0500 Subject: [PATCH] move legacy Bitcoin memo decoding to memo package --- pkg/chains/conversion.go | 25 ------------ pkg/chains/utils_test.go | 37 ----------------- pkg/memo/memo.go | 24 +++++++++++ pkg/memo/memo_test.go | 40 ++++++++++++++++++- x/crosschain/keeper/evm_deposit.go | 3 +- zetaclient/chains/bitcoin/observer/inbound.go | 4 +- zetaclient/chains/evm/observer/inbound.go | 6 +-- zetaclient/compliance/compliance.go | 4 +- 8 files changed, 71 insertions(+), 72 deletions(-) diff --git a/pkg/chains/conversion.go b/pkg/chains/conversion.go index 3200b76693..5d03b77007 100644 --- a/pkg/chains/conversion.go +++ b/pkg/chains/conversion.go @@ -1,10 +1,8 @@ package chains import ( - "encoding/hex" "fmt" - "cosmossdk.io/errors" "github.com/btcsuite/btcd/chaincfg/chainhash" ethcommon "github.com/ethereum/go-ethereum/common" ) @@ -28,26 +26,3 @@ func StringToHash(chainID int64, hash string, additionalChains []Chain) ([]byte, } return nil, fmt.Errorf("cannot convert hash to bytes for chain %d", chainID) } - -// ParseAddressAndData parses the message string into an address and data -// message is hex encoded byte array -// [ contractAddress calldata ] -// [ 20B, variable] -func ParseAddressAndData(message string) (ethcommon.Address, []byte, error) { - if len(message) == 0 { - return ethcommon.Address{}, nil, nil - } - - data, err := hex.DecodeString(message) - if err != nil { - return ethcommon.Address{}, nil, errors.Wrap(err, "message should be a hex encoded string") - } - - if len(data) < 20 { - return ethcommon.Address{}, data, nil - } - - address := ethcommon.BytesToAddress(data[:20]) - data = data[20:] - return address, data, nil -} diff --git a/pkg/chains/utils_test.go b/pkg/chains/utils_test.go index 915fa2b8ca..7552e10967 100644 --- a/pkg/chains/utils_test.go +++ b/pkg/chains/utils_test.go @@ -1,7 +1,6 @@ package chains import ( - "encoding/hex" "testing" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -66,39 +65,3 @@ func TestStringToHash(t *testing.T) { }) } } - -func TestParseAddressAndData(t *testing.T) { - expectedShortMsgResult, err := hex.DecodeString("1a2b3c4d5e6f708192a3b4c5d6e7f808") - require.NoError(t, err) - tests := []struct { - name string - message string - expectAddr ethcommon.Address - expectData []byte - wantErr bool - }{ - { - "valid msg", - "95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", - ethcommon.HexToAddress("95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5"), - []byte{}, - false, - }, - {"empty msg", "", ethcommon.Address{}, nil, false}, - {"invalid hex", "invalidHex", ethcommon.Address{}, nil, true}, - {"short msg", "1a2b3c4d5e6f708192a3b4c5d6e7f808", ethcommon.Address{}, expectedShortMsgResult, false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - addr, data, err := ParseAddressAndData(tt.message) - if tt.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.expectAddr, addr) - require.Equal(t, tt.expectData, data) - } - }) - } -} diff --git a/pkg/memo/memo.go b/pkg/memo/memo.go index 420bcac6fa..30670952b0 100644 --- a/pkg/memo/memo.go +++ b/pkg/memo/memo.go @@ -1,8 +1,10 @@ package memo import ( + "encoding/hex" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" ) @@ -72,3 +74,25 @@ func DecodeFromBytes(data []byte) (*InboundMemo, error) { return memo, nil } + +// DecodeLegacyMemoHex decodes hex encoded memo message into address and calldata +// +// The layout of legacy memo is: [20-byte address, variable calldata] +func DecodeLegacyMemoHex(message string) (common.Address, []byte, error) { + if len(message) == 0 { + return common.Address{}, nil, nil + } + + data, err := hex.DecodeString(message) + if err != nil { + return common.Address{}, nil, errors.Wrap(err, "message should be a hex encoded string") + } + + if len(data) < common.AddressLength { + return common.Address{}, data, nil + } + + address := common.BytesToAddress(data[:common.AddressLength]) + data = data[common.AddressLength:] + return address, data, nil +} diff --git a/pkg/memo/memo_test.go b/pkg/memo/memo_test.go index 1de361e267..50e240933e 100644 --- a/pkg/memo/memo_test.go +++ b/pkg/memo/memo_test.go @@ -1,8 +1,10 @@ package memo_test import ( + "encoding/hex" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "github.com/zeta-chain/node/pkg/memo" "github.com/zeta-chain/node/testutil/sample" @@ -153,8 +155,6 @@ func Test_Memo_DecodeFromBytes(t *testing.T) { name string head []byte data []byte - headHex string - dataHex string expectedMemo memo.InboundMemo errMsg string }{ @@ -269,3 +269,39 @@ func Test_Memo_DecodeFromBytes(t *testing.T) { }) } } + +func Test_DecodeLegacyMemoHex(t *testing.T) { + expectedShortMsgResult, err := hex.DecodeString("1a2b3c4d5e6f708192a3b4c5d6e7f808") + require.NoError(t, err) + tests := []struct { + name string + message string + expectAddr common.Address + expectData []byte + wantErr bool + }{ + { + "valid msg", + "95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", + common.HexToAddress("95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5"), + []byte{}, + false, + }, + {"empty msg", "", common.Address{}, nil, false}, + {"invalid hex", "invalidHex", common.Address{}, nil, true}, + {"short msg", "1a2b3c4d5e6f708192a3b4c5d6e7f808", common.Address{}, expectedShortMsgResult, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + addr, data, err := memo.DecodeLegacyMemoHex(tt.message) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expectAddr, addr) + require.Equal(t, tt.expectData, data) + } + }) + } +} diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index c672686c1a..be08873bba 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -14,6 +14,7 @@ import ( "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" + "github.com/zeta-chain/node/pkg/memo" "github.com/zeta-chain/node/x/crosschain/types" fungibletypes "github.com/zeta-chain/node/x/fungible/types" ) @@ -78,7 +79,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo // in protocol version 2, the destination of the deposit is always the to address, the message is the data to be sent to the contract if cctx.ProtocolContractVersion == types.ProtocolContractVersion_V1 { var parsedAddress ethcommon.Address - parsedAddress, message, err = chains.ParseAddressAndData(cctx.RelayedMessage) + parsedAddress, message, err = memo.DecodeLegacyMemoHex(cctx.RelayedMessage) if err != nil { return false, errors.Wrap(types.ErrUnableToParseAddress, err.Error()) } diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index fad3c87230..1461096763 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -14,8 +14,8 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog" - "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" + "github.com/zeta-chain/node/pkg/memo" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/zetaclient/chains/bitcoin" "github.com/zeta-chain/node/zetaclient/chains/interfaces" @@ -419,7 +419,7 @@ func (ob *Observer) GetInboundVoteMessageFromBtcEvent(inbound *BTCInboundEvent) // TODO(revamp): move all compliance related functions in a specific file func (ob *Observer) DoesInboundContainsRestrictedAddress(inTx *BTCInboundEvent) bool { receiver := "" - parsedAddress, _, err := chains.ParseAddressAndData(hex.EncodeToString(inTx.MemoBytes)) + parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(inTx.MemoBytes)) if err == nil && parsedAddress != (ethcommon.Address{}) { receiver = parsedAddress.Hex() } diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index c662fc2d60..aebd661ae3 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -20,9 +20,9 @@ import ( "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.non-eth.sol" - "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/pkg/constant" + "github.com/zeta-chain/node/pkg/memo" "github.com/zeta-chain/node/pkg/ticker" "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/zetaclient/chains/evm" @@ -622,7 +622,7 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent( ) *types.MsgVoteInbound { // compliance check maybeReceiver := "" - parsedAddress, _, err := chains.ParseAddressAndData(hex.EncodeToString(event.Message)) + parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Message)) if err == nil && parsedAddress != (ethcommon.Address{}) { maybeReceiver = parsedAddress.Hex() } @@ -732,7 +732,7 @@ func (ob *Observer) BuildInboundVoteMsgForTokenSentToTSS( // compliance check maybeReceiver := "" - parsedAddress, _, err := chains.ParseAddressAndData(message) + parsedAddress, _, err := memo.DecodeLegacyMemoHex(message) if err == nil && parsedAddress != (ethcommon.Address{}) { maybeReceiver = parsedAddress.Hex() } diff --git a/zetaclient/compliance/compliance.go b/zetaclient/compliance/compliance.go index 163cca65e4..f0135c3ad9 100644 --- a/zetaclient/compliance/compliance.go +++ b/zetaclient/compliance/compliance.go @@ -7,7 +7,7 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" - "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/pkg/memo" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/zetaclient/chains/base" "github.com/zeta-chain/node/zetaclient/config" @@ -66,7 +66,7 @@ func PrintComplianceLog( func DoesInboundContainsRestrictedAddress(event *clienttypes.InboundEvent, logger *base.ObserverLogger) bool { // parse memo-specified receiver receiver := "" - parsedAddress, _, err := chains.ParseAddressAndData(hex.EncodeToString(event.Memo)) + parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Memo)) if err == nil && parsedAddress != (ethcommon.Address{}) { receiver = parsedAddress.Hex() }