Skip to content

Commit b8c608c

Browse files
authored
Merge pull request #135 from centrifuge/update-event-parsing
listener: Update event parsing
2 parents fec96ed + 85ed235 commit b8c608c

File tree

6 files changed

+319
-99
lines changed

6 files changed

+319
-99
lines changed

chains/substrate/chain.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@ As the writer receives messages from the router, it constructs proposals. If a p
2424
package substrate
2525

2626
import (
27+
"fmt"
2728
"github.com/ChainSafe/log15"
2829
"github.com/centrifuge/chainbridge-utils/blockstore"
2930
"github.com/centrifuge/chainbridge-utils/core"
3031
"github.com/centrifuge/chainbridge-utils/crypto/sr25519"
3132
"github.com/centrifuge/chainbridge-utils/keystore"
3233
metrics "github.com/centrifuge/chainbridge-utils/metrics/types"
3334
"github.com/centrifuge/chainbridge-utils/msg"
35+
"github.com/centrifuge/go-substrate-rpc-client/v4/registry/retriever"
36+
"github.com/centrifuge/go-substrate-rpc-client/v4/registry/state"
3437
)
3538

3639
var _ core.Chain = &Chain{}
@@ -102,8 +105,14 @@ func InitializeChain(cfg *core.ChainConfig, logger log15.Logger, sysErr chan<- e
102105

103106
ue := parseUseExtended(cfg)
104107

108+
eventRetriever, err := retriever.NewDefaultEventRetriever(state.NewEventProvider(conn.api.RPC.State), conn.api.RPC.State)
109+
110+
if err != nil {
111+
return nil, fmt.Errorf("event retriever creation: %w", err)
112+
}
113+
105114
// Setup listener & writer
106-
l := NewListener(conn, cfg.Name, cfg.Id, startBlock, logger, bs, stop, sysErr, m)
115+
l := NewListener(conn, cfg.Name, cfg.Id, startBlock, logger, bs, stop, sysErr, m, eventRetriever)
107116
w := NewWriter(conn, logger, sysErr, m, ue)
108117
return &Chain{
109118
cfg: cfg,

chains/substrate/connection.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (c *Connection) getMetadata() (meta types.Metadata) {
4343
return meta
4444
}
4545

46-
func (c *Connection) updateMetatdata() error {
46+
func (c *Connection) updateMetadata() error {
4747
c.metaLock.Lock()
4848
meta, err := c.api.RPC.State.GetMetadataLatest()
4949
if err != nil {

chains/substrate/events.go

Lines changed: 235 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@
44
package substrate
55

66
import (
7+
"errors"
78
"fmt"
89
"math/big"
910

1011
"github.com/ChainSafe/log15"
11-
events "github.com/centrifuge/chainbridge-substrate-events"
1212
"github.com/centrifuge/chainbridge-utils/msg"
13+
"github.com/centrifuge/go-substrate-rpc-client/v4/types"
14+
"github.com/centrifuge/go-substrate-rpc-client/v4/types/codec"
1315
)
1416

1517
type eventName string
16-
type eventHandler func(interface{}, log15.Logger) (msg.Message, error)
18+
type eventHandler func(map[string]any, log15.Logger) (msg.Message, error)
1719

18-
const FungibleTransfer eventName = "FungibleTransfer"
19-
const NonFungibleTransfer eventName = "NonFungibleTransfer"
20-
const GenericTransfer eventName = "GenericTransfer"
20+
const FungibleTransfer eventName = "ChainBridge.FungibleTransfer"
21+
const NonFungibleTransfer eventName = "ChainBridge.NonFungibleTransfer"
22+
const GenericTransfer eventName = "ChainBridge.GenericTransfer"
2123

2224
var Subscriptions = []struct {
2325
name eventName
@@ -28,57 +30,250 @@ var Subscriptions = []struct {
2830
{GenericTransfer, genericTransferHandler},
2931
}
3032

31-
func fungibleTransferHandler(evtI interface{}, log log15.Logger) (msg.Message, error) {
32-
evt, ok := evtI.(events.EventFungibleTransfer)
33-
if !ok {
34-
return msg.Message{}, fmt.Errorf("failed to cast EventFungibleTransfer type")
33+
func fungibleTransferHandler(eventFields map[string]any, log log15.Logger) (msg.Message, error) {
34+
chainID, err := getFieldValueAsType[types.U8]("ChainId", eventFields)
35+
if err != nil {
36+
return msg.Message{}, err
3537
}
3638

37-
resourceId := msg.ResourceId(evt.ResourceId)
38-
log.Info("Got fungible transfer event!", "destination", evt.Destination, "resourceId", resourceId.Hex(), "amount", evt.Amount)
39+
depositNonce, err := getFieldValueAsType[types.U64]("DepositNonce", eventFields)
40+
if err != nil {
41+
return msg.Message{}, err
42+
}
43+
44+
resID, err := getFieldValueAsSliceOfType[types.U8]("ResourceId", eventFields)
45+
if err != nil {
46+
return msg.Message{}, err
47+
}
48+
49+
resourceID, err := to32Bytes(resID)
50+
if err != nil {
51+
return msg.Message{}, err
52+
}
53+
54+
amount, err := getU256(eventFields)
55+
if err != nil {
56+
return msg.Message{}, err
57+
}
58+
59+
recipient, err := getFieldValueAsByteSlice("Vec<u8>", eventFields)
60+
if err != nil {
61+
return msg.Message{}, err
62+
}
63+
64+
log.Info("Got fungible transfer event!", "destination", recipient, "resourceId", fmt.Sprintf("%x", resourceID), "amount", amount)
3965

4066
return msg.NewFungibleTransfer(
4167
0, // Unset
42-
msg.ChainId(evt.Destination),
43-
msg.Nonce(evt.DepositNonce),
44-
evt.Amount.Int,
45-
resourceId,
46-
evt.Recipient,
68+
msg.ChainId(chainID),
69+
msg.Nonce(depositNonce),
70+
amount.Int,
71+
resourceID,
72+
recipient,
4773
), nil
4874
}
4975

50-
func nonFungibleTransferHandler(evtI interface{}, log log15.Logger) (msg.Message, error) {
51-
evt, ok := evtI.(events.EventNonFungibleTransfer)
52-
if !ok {
53-
return msg.Message{}, fmt.Errorf("failed to cast EventNonFungibleTransfer type")
76+
func nonFungibleTransferHandler(_ map[string]any, log log15.Logger) (msg.Message, error) {
77+
log.Warn("Got non-fungible transfer event!")
78+
79+
return msg.Message{}, errors.New("non-fungible transfer not supported")
80+
}
81+
82+
func genericTransferHandler(eventFields map[string]any, log log15.Logger) (msg.Message, error) {
83+
chainID, err := getFieldValueAsType[types.U8]("ChainId", eventFields)
84+
if err != nil {
85+
return msg.Message{}, err
5486
}
5587

56-
log.Info("Got non-fungible transfer event!", "destination", evt.Destination, "resourceId", evt.ResourceId)
88+
depositNonce, err := getFieldValueAsType[types.U64]("DepositNonce", eventFields)
89+
if err != nil {
90+
return msg.Message{}, err
91+
}
5792

58-
return msg.NewNonFungibleTransfer(
59-
0, // Unset
60-
msg.ChainId(evt.Destination),
61-
msg.Nonce(evt.DepositNonce),
62-
msg.ResourceId(evt.ResourceId),
63-
big.NewInt(0).SetBytes(evt.TokenId[:]),
64-
evt.Recipient,
65-
evt.Metadata,
66-
), nil
67-
}
93+
resID, err := getFieldValueAsSliceOfType[types.U8]("ResourceId", eventFields)
94+
if err != nil {
95+
return msg.Message{}, err
96+
}
97+
98+
resourceID, err := to32Bytes(resID)
99+
if err != nil {
100+
return msg.Message{}, err
101+
}
68102

69-
func genericTransferHandler(evtI interface{}, log log15.Logger) (msg.Message, error) {
70-
evt, ok := evtI.(events.EventGenericTransfer)
71-
if !ok {
72-
return msg.Message{}, fmt.Errorf("failed to cast EventGenericTransfer type")
103+
metadata, err := getFieldValueAsByteSlice("Vec<u8>", eventFields)
104+
if err != nil {
105+
return msg.Message{}, err
73106
}
74107

75-
log.Info("Got generic transfer event!", "destination", evt.Destination, "resourceId", evt.ResourceId)
108+
log.Info("Got generic transfer event!", "destination", chainID, "resourceId", fmt.Sprintf("%x", resourceID))
76109

77110
return msg.NewGenericTransfer(
78111
0, // Unset
79-
msg.ChainId(evt.Destination),
80-
msg.Nonce(evt.DepositNonce),
81-
msg.ResourceId(evt.ResourceId),
82-
evt.Metadata,
112+
msg.ChainId(chainID),
113+
msg.Nonce(depositNonce),
114+
resourceID,
115+
metadata,
83116
), nil
84117
}
118+
119+
func to32Bytes(array []types.U8) ([32]byte, error) {
120+
var res [32]byte
121+
122+
if len(array) != 32 {
123+
return res, errors.New("array length mismatch")
124+
}
125+
126+
for i, item := range array {
127+
res[i] = byte(item)
128+
}
129+
130+
return res, nil
131+
}
132+
133+
func getFieldValueAsType[T any](fieldName string, eventFields map[string]any) (T, error) {
134+
var t T
135+
136+
for name, value := range eventFields {
137+
if name == fieldName {
138+
if v, ok := value.(T); ok {
139+
return v, nil
140+
}
141+
142+
return t, fmt.Errorf("field type mismatch, expected %T, got %T", t, value)
143+
}
144+
}
145+
146+
return t, fmt.Errorf("field with name '%s' not found", fieldName)
147+
}
148+
149+
func getFieldValueAsSliceOfType[T any](fieldName string, eventFields map[string]any) ([]T, error) {
150+
for name, value := range eventFields {
151+
if name == fieldName {
152+
value, ok := value.([]any)
153+
154+
if !ok {
155+
return nil, errors.New("field value not an array")
156+
}
157+
158+
res, err := convertSliceToType[T](value)
159+
160+
if err != nil {
161+
return nil, err
162+
}
163+
164+
return res, nil
165+
}
166+
}
167+
168+
return nil, fmt.Errorf("field with name '%s' not found", fieldName)
169+
}
170+
171+
func getFieldValueAsByteSlice(fieldName string, eventFields map[string]any) ([]byte, error) {
172+
for name, value := range eventFields {
173+
if name == fieldName {
174+
value, ok := value.([]any)
175+
176+
if !ok {
177+
return nil, errors.New("field value not an array")
178+
}
179+
180+
slice, err := convertSliceToType[types.U8](value)
181+
182+
if err != nil {
183+
return nil, err
184+
}
185+
186+
res, err := convertToByteSlice(slice)
187+
188+
if err != nil {
189+
return nil, err
190+
}
191+
192+
return res, nil
193+
}
194+
}
195+
196+
return nil, fmt.Errorf("field with name '%s' not found", fieldName)
197+
}
198+
199+
func convertSliceToType[T any](array []any) ([]T, error) {
200+
res := make([]T, 0)
201+
202+
for _, item := range array {
203+
if v, ok := item.(T); ok {
204+
res = append(res, v)
205+
continue
206+
}
207+
208+
var t T
209+
210+
return nil, fmt.Errorf("couldn't cast '%T' to '%T'", item, t)
211+
}
212+
213+
return res, nil
214+
}
215+
216+
func convertToByteSlice(array []types.U8) ([]byte, error) {
217+
res := make([]byte, 0)
218+
219+
for _, item := range array {
220+
res = append(res, byte(item))
221+
}
222+
223+
return res, nil
224+
}
225+
226+
func getU256(eventFields map[string]any) (types.U256, error) {
227+
for fieldName, fieldValue := range eventFields {
228+
if fieldName != "primitive_types.U256.U256" {
229+
continue
230+
}
231+
232+
innerField, ok := fieldValue.(map[string]any)
233+
if !ok {
234+
return types.NewU256(*big.NewInt(0)), errors.New("unexpected amount field structure")
235+
}
236+
237+
innerFieldVal, ok := innerField["[u64; 4]"]
238+
if !ok {
239+
return types.NewU256(*big.NewInt(0)), errors.New("amount field key not found")
240+
}
241+
242+
slice, ok := innerFieldVal.([]any)
243+
if !ok {
244+
return types.NewU256(*big.NewInt(0)), errors.New("inner field value not a slice")
245+
}
246+
247+
val, err := convertSliceToType[types.U64](slice)
248+
249+
if err != nil {
250+
return types.NewU256(*big.NewInt(0)), err
251+
}
252+
253+
if len(val) != 4 {
254+
return types.NewU256(*big.NewInt(0)), errors.New("slice length mismatch")
255+
}
256+
257+
var r [4]types.U64
258+
259+
for i, item := range val {
260+
r[i] = item
261+
}
262+
263+
encVal, err := codec.Encode(r)
264+
265+
if err != nil {
266+
return types.NewU256(*big.NewInt(0)), errors.New("couldn't encode amount val")
267+
}
268+
269+
var res types.U256
270+
271+
if err := codec.Decode(encVal, &res); err != nil {
272+
return types.NewU256(*big.NewInt(0)), errors.New("couldn't decode amount")
273+
}
274+
275+
return res, nil
276+
}
277+
278+
return types.NewU256(*big.NewInt(0)), errors.New("amount field not found")
279+
}

0 commit comments

Comments
 (0)