github.com/ChainSafe/chainbridge-core@v1.4.2/chains/evm/executor/message-handler.go (about)

     1  package executor
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  
     9  	"github.com/ChainSafe/chainbridge-core/chains/evm/executor/proposal"
    10  	"github.com/ChainSafe/chainbridge-core/relayer/message"
    11  	"github.com/ChainSafe/chainbridge-core/types"
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/rs/zerolog/log"
    14  )
    15  
    16  type HandlerMatcher interface {
    17  	GetHandlerAddressForResourceID(resourceID types.ResourceID) (common.Address, error)
    18  	ContractAddress() *common.Address
    19  }
    20  
    21  type MessageHandlerFunc func(m *message.Message, handlerAddr, bridgeAddress common.Address) (*proposal.Proposal, error)
    22  
    23  // NewEVMMessageHandler creates an instance of EVMMessageHandler that contains
    24  // message handler functions for converting deposit message into a chain specific
    25  // proposal
    26  func NewEVMMessageHandler(handlerMatcher HandlerMatcher) *EVMMessageHandler {
    27  	return &EVMMessageHandler{
    28  		handlerMatcher: handlerMatcher,
    29  	}
    30  }
    31  
    32  type EVMMessageHandler struct {
    33  	handlerMatcher HandlerMatcher
    34  	handlers       map[common.Address]MessageHandlerFunc
    35  }
    36  
    37  func (mh *EVMMessageHandler) HandleMessage(m *message.Message) (*proposal.Proposal, error) {
    38  	// Matching resource ID with handler.
    39  	addr, err := mh.handlerMatcher.GetHandlerAddressForResourceID(m.ResourceId)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	// Based on handler that registered on BridgeContract
    44  	handleMessage, err := mh.MatchAddressWithHandlerFunc(addr)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	log.Info().Str("type", string(m.Type)).Uint8("src", m.Source).Uint8("dst", m.Destination).Uint64("nonce", m.DepositNonce).Str("resourceID", fmt.Sprintf("%x", m.ResourceId)).Msg("Handling new message")
    49  	prop, err := handleMessage(m, addr, *mh.handlerMatcher.ContractAddress())
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	return prop, nil
    54  }
    55  
    56  func (mh *EVMMessageHandler) MatchAddressWithHandlerFunc(addr common.Address) (MessageHandlerFunc, error) {
    57  	h, ok := mh.handlers[addr]
    58  	if !ok {
    59  		return nil, fmt.Errorf("no corresponding message handler for this address %s exists", addr.Hex())
    60  	}
    61  	return h, nil
    62  }
    63  
    64  // RegisterEventHandler registers an message handler by associating a handler function to a specified address
    65  func (mh *EVMMessageHandler) RegisterMessageHandler(address string, handler MessageHandlerFunc) {
    66  	if address == "" {
    67  		return
    68  	}
    69  	if mh.handlers == nil {
    70  		mh.handlers = make(map[common.Address]MessageHandlerFunc)
    71  	}
    72  
    73  	log.Debug().Msgf("Registered message handler for address %s", address)
    74  
    75  	mh.handlers[common.HexToAddress(address)] = handler
    76  }
    77  
    78  func ERC20MessageHandler(m *message.Message, handlerAddr, bridgeAddress common.Address) (*proposal.Proposal, error) {
    79  	if len(m.Payload) != 2 {
    80  		return nil, errors.New("malformed payload. Len  of payload should be 2")
    81  	}
    82  	amount, ok := m.Payload[0].([]byte)
    83  	if !ok {
    84  		return nil, errors.New("wrong payload amount format")
    85  	}
    86  	recipient, ok := m.Payload[1].([]byte)
    87  	if !ok {
    88  		return nil, errors.New("wrong payload recipient format")
    89  	}
    90  	var data []byte
    91  	data = append(data, common.LeftPadBytes(amount, 32)...) // amount (uint256)
    92  	recipientLen := big.NewInt(int64(len(recipient))).Bytes()
    93  	data = append(data, common.LeftPadBytes(recipientLen, 32)...) // length of recipient (uint256)
    94  	data = append(data, recipient...)                             // recipient ([]byte)
    95  	return proposal.NewProposal(m.Source, m.Destination, m.DepositNonce, m.ResourceId, data, handlerAddr, bridgeAddress, m.Metadata), nil
    96  }
    97  
    98  func ERC721MessageHandler(msg *message.Message, handlerAddr, bridgeAddress common.Address) (*proposal.Proposal, error) {
    99  
   100  	if len(msg.Payload) != 3 {
   101  		return nil, errors.New("malformed payload. Len  of payload should be 3")
   102  	}
   103  	tokenID, ok := msg.Payload[0].([]byte)
   104  	if !ok {
   105  		return nil, errors.New("wrong payload tokenID format")
   106  	}
   107  	recipient, ok := msg.Payload[1].([]byte)
   108  	if !ok {
   109  		return nil, errors.New("wrong payload recipient format")
   110  	}
   111  	metadata, ok := msg.Payload[2].([]byte)
   112  	if !ok {
   113  		return nil, errors.New("wrong payload metadata format")
   114  	}
   115  	data := bytes.Buffer{}
   116  	data.Write(common.LeftPadBytes(tokenID, 32))
   117  	recipientLen := big.NewInt(int64(len(recipient))).Bytes()
   118  	data.Write(common.LeftPadBytes(recipientLen, 32))
   119  	data.Write(recipient)
   120  	metadataLen := big.NewInt(int64(len(metadata))).Bytes()
   121  	data.Write(common.LeftPadBytes(metadataLen, 32))
   122  	data.Write(metadata)
   123  	return proposal.NewProposal(msg.Source, msg.Destination, msg.DepositNonce, msg.ResourceId, data.Bytes(), handlerAddr, bridgeAddress, msg.Metadata), nil
   124  }
   125  
   126  func GenericMessageHandler(msg *message.Message, handlerAddr, bridgeAddress common.Address) (*proposal.Proposal, error) {
   127  	if len(msg.Payload) != 1 {
   128  		return nil, errors.New("malformed payload. Len  of payload should be 1")
   129  	}
   130  	metadata, ok := msg.Payload[0].([]byte)
   131  	if !ok {
   132  		return nil, errors.New("wrong payload metadata format")
   133  	}
   134  	data := bytes.Buffer{}
   135  	metadataLen := big.NewInt(int64(len(metadata))).Bytes()
   136  	data.Write(common.LeftPadBytes(metadataLen, 32)) // length of metadata (uint256)
   137  	data.Write(metadata)
   138  	return proposal.NewProposal(msg.Source, msg.Destination, msg.DepositNonce, msg.ResourceId, data.Bytes(), handlerAddr, bridgeAddress, msg.Metadata), nil
   139  }