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