Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 669d420

Browse files
authored
feat: deposit event handler (#10)
1 parent 435cf46 commit 669d420

File tree

10 files changed

+792
-3
lines changed

10 files changed

+792
-3
lines changed

.github/workflows/mocks.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
with:
1717
go-version: "^1.17"
1818

19-
- run: go install github.com/golang/mock/mockgen@v1.6.0
19+
- run: go install go.uber.org/mock/mockgen@v0.3.0
2020

2121
- run: make genmocks
2222

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ test:
2121
./scripts/tests.sh
2222

2323
genmocks:
24-
echo ''
24+
mockgen -source=./chains/evm/listener/events/handlers/deposit.go -destination=./mock/handlers.go -package mock
2525

2626

2727
PLATFORMS := linux/amd64 darwin/amd64 darwin/arm64 linux/arm

chains/evm/abi/router.go

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// The Licensed Work is (c) 2023 Sygma
2+
// SPDX-License-Identifier: LGPL-3.0-only
3+
4+
package abi
5+
6+
const RouterABI = `[
7+
{
8+
"inputs": [
9+
{
10+
"internalType": "uint8",
11+
"name": "domainID",
12+
"type": "uint8"
13+
}
14+
],
15+
"stateMutability": "nonpayable",
16+
"type": "constructor"
17+
},
18+
{
19+
"inputs": [],
20+
"name": "DepositToCurrentDomain",
21+
"type": "error"
22+
},
23+
{
24+
"inputs": [],
25+
"name": "NonceDecrementsNotAllowed",
26+
"type": "error"
27+
},
28+
{
29+
"anonymous": false,
30+
"inputs": [
31+
{
32+
"indexed": false,
33+
"internalType": "uint8",
34+
"name": "destinationDomainID",
35+
"type": "uint8"
36+
},
37+
{
38+
"indexed": false,
39+
"internalType": "uint8",
40+
"name": "securityModel",
41+
"type": "uint8"
42+
},
43+
{
44+
"indexed": false,
45+
"internalType": "bytes32",
46+
"name": "resourceID",
47+
"type": "bytes32"
48+
},
49+
{
50+
"indexed": false,
51+
"internalType": "uint64",
52+
"name": "depositNonce",
53+
"type": "uint64"
54+
},
55+
{
56+
"indexed": true,
57+
"internalType": "address",
58+
"name": "user",
59+
"type": "address"
60+
},
61+
{
62+
"indexed": false,
63+
"internalType": "bytes",
64+
"name": "data",
65+
"type": "bytes"
66+
}
67+
],
68+
"name": "Deposit",
69+
"type": "event"
70+
},
71+
{
72+
"anonymous": false,
73+
"inputs": [
74+
{
75+
"indexed": true,
76+
"internalType": "address",
77+
"name": "previousOwner",
78+
"type": "address"
79+
},
80+
{
81+
"indexed": true,
82+
"internalType": "address",
83+
"name": "newOwner",
84+
"type": "address"
85+
}
86+
],
87+
"name": "OwnershipTransferred",
88+
"type": "event"
89+
},
90+
{
91+
"inputs": [
92+
{
93+
"internalType": "uint8",
94+
"name": "",
95+
"type": "uint8"
96+
}
97+
],
98+
"name": "_depositCounts",
99+
"outputs": [
100+
{
101+
"internalType": "uint64",
102+
"name": "",
103+
"type": "uint64"
104+
}
105+
],
106+
"stateMutability": "view",
107+
"type": "function"
108+
},
109+
{
110+
"inputs": [],
111+
"name": "_domainID",
112+
"outputs": [
113+
{
114+
"internalType": "uint8",
115+
"name": "",
116+
"type": "uint8"
117+
}
118+
],
119+
"stateMutability": "view",
120+
"type": "function"
121+
},
122+
{
123+
"inputs": [
124+
{
125+
"internalType": "uint8",
126+
"name": "destinationDomainID",
127+
"type": "uint8"
128+
},
129+
{
130+
"internalType": "uint8",
131+
"name": "securityModel",
132+
"type": "uint8"
133+
},
134+
{
135+
"internalType": "bytes32",
136+
"name": "resourceID",
137+
"type": "bytes32"
138+
},
139+
{
140+
"internalType": "bytes",
141+
"name": "depositData",
142+
"type": "bytes"
143+
},
144+
{
145+
"internalType": "bytes",
146+
"name": "feeData",
147+
"type": "bytes"
148+
}
149+
],
150+
"name": "deposit",
151+
"outputs": [
152+
{
153+
"internalType": "uint64",
154+
"name": "depositNonce",
155+
"type": "uint64"
156+
}
157+
],
158+
"stateMutability": "payable",
159+
"type": "function"
160+
},
161+
{
162+
"inputs": [],
163+
"name": "owner",
164+
"outputs": [
165+
{
166+
"internalType": "address",
167+
"name": "",
168+
"type": "address"
169+
}
170+
],
171+
"stateMutability": "view",
172+
"type": "function"
173+
},
174+
{
175+
"inputs": [],
176+
"name": "renounceOwnership",
177+
"outputs": [],
178+
"stateMutability": "nonpayable",
179+
"type": "function"
180+
},
181+
{
182+
"inputs": [
183+
{
184+
"internalType": "uint256",
185+
"name": "",
186+
"type": "uint256"
187+
}
188+
],
189+
"name": "transferHashes",
190+
"outputs": [
191+
{
192+
"internalType": "bytes32",
193+
"name": "",
194+
"type": "bytes32"
195+
}
196+
],
197+
"stateMutability": "view",
198+
"type": "function"
199+
},
200+
{
201+
"inputs": [
202+
{
203+
"internalType": "address",
204+
"name": "newOwner",
205+
"type": "address"
206+
}
207+
],
208+
"name": "transferOwnership",
209+
"outputs": [],
210+
"stateMutability": "nonpayable",
211+
"type": "function"
212+
}
213+
]`

chains/evm/listener/events/events.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// The Licensed Work is (c) 2023 Sygma
2+
// SPDX-License-Identifier: LGPL-3.0-only
3+
4+
package events
5+
6+
import (
7+
"github.com/ethereum/go-ethereum/common"
8+
"github.com/ethereum/go-ethereum/crypto"
9+
)
10+
11+
type EventSig string
12+
13+
func (es EventSig) GetTopic() common.Hash {
14+
return crypto.Keccak256Hash([]byte(es))
15+
}
16+
17+
const (
18+
DepositSig EventSig = "Deposit(uint8,uint8,bytes32,uint64,address,bytes)"
19+
)
20+
21+
// Deposit struct holds event data raised by Deposit event on-chain
22+
type Deposit struct {
23+
// ID of chain deposit will be bridged to
24+
DestinationDomainID uint8
25+
// SecurityModel is used to distringuish between block header oracles
26+
// on the destination network that verify this deposit
27+
SecurityModel uint8
28+
// ResourceID used to find address of handler to be used for deposit
29+
ResourceID [32]byte
30+
// Nonce of deposit
31+
DepositNonce uint64
32+
// Address of sender (msg.sender: user)
33+
SenderAddress common.Address
34+
// Additional data to be passed to specified handler
35+
Data []byte
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// The Licensed Work is (c) 2023 Sygma
2+
// SPDX-License-Identifier: LGPL-3.0-only
3+
4+
package handlers
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"math/big"
10+
"strings"
11+
12+
ethereumABI "github.com/ethereum/go-ethereum/accounts/abi"
13+
"github.com/ethereum/go-ethereum/common"
14+
"github.com/ethereum/go-ethereum/core/types"
15+
"github.com/rs/zerolog/log"
16+
"github.com/sygmaprotocol/spectre-node/chains/evm/abi"
17+
"github.com/sygmaprotocol/spectre-node/chains/evm/listener/events"
18+
evmMessage "github.com/sygmaprotocol/spectre-node/chains/evm/message"
19+
"github.com/sygmaprotocol/sygma-core/relayer/message"
20+
)
21+
22+
type EventFetcher interface {
23+
FetchEventLogs(ctx context.Context, contractAddress common.Address, event string, startBlock *big.Int, endBlock *big.Int) ([]types.Log, error)
24+
}
25+
26+
type StepProver interface {
27+
StepProof(blocknumber *big.Int) (interface{}, error)
28+
}
29+
30+
type DepositEventHandler struct {
31+
msgChan chan []*message.Message
32+
33+
eventFetcher EventFetcher
34+
stepProver StepProver
35+
36+
domainID uint8
37+
routerABI ethereumABI.ABI
38+
routerAddress common.Address
39+
}
40+
41+
func NewDepositEventHandler(
42+
msgChan chan []*message.Message,
43+
eventFetcher EventFetcher,
44+
stepProver StepProver,
45+
routerAddress common.Address,
46+
domainID uint8,
47+
) *DepositEventHandler {
48+
routerABI, _ := ethereumABI.JSON(strings.NewReader(abi.RouterABI))
49+
return &DepositEventHandler{
50+
eventFetcher: eventFetcher,
51+
stepProver: stepProver,
52+
routerAddress: routerAddress,
53+
routerABI: routerABI,
54+
msgChan: msgChan,
55+
domainID: domainID,
56+
}
57+
}
58+
59+
// HandleEvents fetches deposit events and if deposits exists, submits a step message
60+
// to be executed on the destination network
61+
func (h *DepositEventHandler) HandleEvents(startBlock *big.Int, endBlock *big.Int) error {
62+
deposits, err := h.fetchDeposits(startBlock, endBlock)
63+
if err != nil {
64+
return fmt.Errorf("unable to fetch deposit events because of: %+v", err)
65+
}
66+
domainDeposits := make(map[uint8][]*events.Deposit)
67+
for _, d := range deposits {
68+
domainDeposits[d.DestinationDomainID] = append(domainDeposits[d.DestinationDomainID], d)
69+
}
70+
if len(domainDeposits) == 0 {
71+
return nil
72+
}
73+
74+
proof, err := h.stepProver.StepProof(endBlock)
75+
if err != nil {
76+
return err
77+
}
78+
for _, deposits := range domainDeposits {
79+
h.msgChan <- []*message.Message{
80+
evmMessage.NewEvmStepMessage(
81+
h.domainID,
82+
deposits[0].DestinationDomainID,
83+
proof,
84+
),
85+
}
86+
}
87+
return nil
88+
}
89+
90+
func (h *DepositEventHandler) fetchDeposits(startBlock *big.Int, endBlock *big.Int) ([]*events.Deposit, error) {
91+
logs, err := h.eventFetcher.FetchEventLogs(context.Background(), h.routerAddress, string(events.DepositSig), startBlock, endBlock)
92+
if err != nil {
93+
return nil, err
94+
}
95+
96+
deposits := make([]*events.Deposit, 0)
97+
for _, dl := range logs {
98+
d, err := h.unpackDeposit(dl.Data)
99+
if err != nil {
100+
log.Error().Msgf("Failed unpacking deposit event log: %v", err)
101+
continue
102+
}
103+
d.SenderAddress = common.BytesToAddress(dl.Topics[1].Bytes())
104+
105+
log.Debug().Msgf("Found deposit log in block: %d, TxHash: %s, contractAddress: %s, sender: %s", dl.BlockNumber, dl.TxHash, dl.Address, d.SenderAddress)
106+
deposits = append(deposits, d)
107+
}
108+
109+
return deposits, nil
110+
}
111+
112+
func (h *DepositEventHandler) unpackDeposit(data []byte) (*events.Deposit, error) {
113+
fmt.Println(data)
114+
115+
var d events.Deposit
116+
err := h.routerABI.UnpackIntoInterface(&d, "Deposit", data)
117+
if err != nil {
118+
return &events.Deposit{}, err
119+
}
120+
121+
return &d, nil
122+
}

0 commit comments

Comments
 (0)