Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: EVM event and deposit handlers refactor #243

Merged
merged 12 commits into from
Jan 18, 2024
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@ genmocks:
mockgen --package mock_tss -destination=./tss/mock/storer.go -source=./tss/resharing/resharing.go
mockgen -source=./tss/coordinator.go -destination=./tss/mock/coordinator.go
mockgen -source=./comm/communication.go -destination=./comm/mock/communication.go
mockgen -source=./chains/evm/listener/event-handler.go -destination=./chains/evm/listener/mock/listener.go
mockgen -source=./chains/evm/listener/eventHandlers/event-handler.go -destination=./chains/evm/listener/eventHandlers/mock/listener.go
mockgen -source=./chains/evm/calls/events/listener.go -destination=./chains/evm/calls/events/mock/listener.go
mockgen -source=./chains/substrate/listener/listener.go -destination=./chains/substrate/listener/mock/listener.go
mockgen -source=./chains/substrate/listener/event-handlers.go -destination=./chains/substrate/listener/mock/handlers.go
mockgen -destination=chains/evm/listener/mock/core/listener.go github.com/ChainSafe/chainbridge-core/chains/evm/listener EventListener,DepositHandler
mockgen -source=./topology/topology.go -destination=./topology/mock/topology.go


Expand Down
55 changes: 37 additions & 18 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@
"syscall"
"time"

coreEvents "github.com/ChainSafe/chainbridge-core/chains/evm/calls/events"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/evmclient"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/evmgaspricer"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/evmtransaction"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/transactor/monitored"
coreListener "github.com/ChainSafe/chainbridge-core/chains/evm/listener"
"github.com/ChainSafe/chainbridge-core/crypto/secp256k1"
"github.com/ChainSafe/chainbridge-core/flags"
"github.com/ChainSafe/chainbridge-core/logger"
Expand All @@ -32,15 +27,20 @@
"github.com/ChainSafe/sygma-relayer/chains/evm/calls/contracts/bridge"
"github.com/ChainSafe/sygma-relayer/chains/evm/calls/events"
"github.com/ChainSafe/sygma-relayer/chains/evm/executor"
"github.com/ChainSafe/sygma-relayer/chains/evm/listener"
"github.com/ChainSafe/sygma-relayer/chains/evm/listener/depositHandlers"
hubEventHandlers "github.com/ChainSafe/sygma-relayer/chains/evm/listener/eventHandlers"
"github.com/ChainSafe/sygma-relayer/chains/substrate"
"github.com/ChainSafe/sygma-relayer/chains/substrate/client"
"github.com/ChainSafe/sygma-relayer/chains/substrate/connection"
substrateExecutor "github.com/ChainSafe/sygma-relayer/chains/substrate/executor"

Check failure on line 35 in app/app.go

View workflow job for this annotation

GitHub Actions / linter-check

could not import github.com/ChainSafe/sygma-relayer/chains/substrate/executor (-: # github.com/ChainSafe/sygma-relayer/chains/substrate/executor
substrate_listener "github.com/ChainSafe/sygma-relayer/chains/substrate/listener"
substrate_pallet "github.com/ChainSafe/sygma-relayer/chains/substrate/pallet"

Check failure on line 37 in app/app.go

View workflow job for this annotation

GitHub Actions / linter-check

could not import github.com/ChainSafe/sygma-relayer/chains/substrate/pallet (-: # github.com/ChainSafe/sygma-relayer/chains/substrate/pallet
"github.com/ChainSafe/sygma-relayer/metrics"
"github.com/centrifuge/go-substrate-rpc-client/v4/signature"
coreClient "github.com/sygmaprotocol/sygma-core/chains/evm/client"
"github.com/sygmaprotocol/sygma-core/chains/evm/listener"
"github.com/sygmaprotocol/sygma-core/chains/evm/transactor/monitored"
"github.com/sygmaprotocol/sygma-core/chains/evm/transactor/transaction"

"github.com/ChainSafe/sygma-relayer/comm/elector"
"github.com/ChainSafe/sygma-relayer/comm/p2p"
Expand Down Expand Up @@ -161,7 +161,7 @@
kp, err := secp256k1.NewKeypairFromString(config.GeneralChainConfig.Key)
panicOnError(err)

client, err := evmclient.NewEVMClient(config.GeneralChainConfig.Endpoint, kp)
client, err := coreClient.NewEVMClient(config.GeneralChainConfig.Endpoint, kp)
panicOnError(err)

log.Info().Str("domain", config.String()).Msgf("Registering EVM domain")
Expand All @@ -171,29 +171,48 @@
UpperLimitFeePerGas: config.MaxGasPrice,
GasPriceFactor: config.GasMultiplier,
})
t := monitored.NewMonitoredTransactor(evmtransaction.NewTransaction, gasPricer, client, config.MaxGasPrice, config.GasIncreasePercentage)
t := monitored.NewMonitoredTransactor(transaction.NewTransaction, gasPricer, client, config.MaxGasPrice, config.GasIncreasePercentage)
go t.Monitor(ctx, time.Minute*3, time.Minute*10, time.Minute)
bridgeContract := bridge.NewBridgeContract(client, bridgeAddress, t)

depositHandler := coreListener.NewETHDepositHandler(bridgeContract)
depositHandler := depositHandlers.NewETHDepositHandler(bridgeContract)
mh := coreMessage.NewMessageHandler()
for _, handler := range config.Handlers {
depositHandler.RegisterDepositHandler(handler.Address, listener.PermissionlessGenericDepositHandler)
mh.RegisterMessageHandler("transfer", &executor.TransferMessageHandler{})

mh.RegisterMessageHandler("Transfer", &executor.TransferMessageHandler{})

switch handler.Type {
case "erc20":
{
depositHandler.RegisterDepositHandler(handler.Address, &depositHandlers.Erc20DepositHandler{})
}
case "permissionedGeneric":
{
depositHandler.RegisterDepositHandler(handler.Address, &depositHandlers.GenericDepositHandler{})
}
case "permissionlessGeneric":
{
depositHandler.RegisterDepositHandler(handler.Address, &depositHandlers.PermissionlessGenericDepositHandler{})
}
case "erc721":
{
depositHandler.RegisterDepositHandler(handler.Address, &depositHandlers.Erc721DepositHandler{})
}
}
}
depositListener := coreEvents.NewListener(client)
depositListener := events.NewListener(client)
tssListener := events.NewListener(client)
eventHandlers := make([]coreListener.EventHandler, 0)
eventHandlers := make([]listener.EventHandler, 0)
l := log.With().Str("chain", fmt.Sprintf("%v", config.GeneralChainConfig.Name)).Uint8("domainID", *config.GeneralChainConfig.Id)
eventHandlers = append(eventHandlers, coreListener.NewDepositEventHandler(depositListener, depositHandler, bridgeAddress, *config.GeneralChainConfig.Id))
eventHandlers = append(eventHandlers, listener.NewKeygenEventHandler(l, tssListener, coordinator, host, communication, keyshareStore, bridgeAddress, networkTopology.Threshold))
eventHandlers = append(eventHandlers, listener.NewRefreshEventHandler(l, topologyProvider, topologyStore, tssListener, coordinator, host, communication, connectionGate, keyshareStore, bridgeAddress))
eventHandlers = append(eventHandlers, listener.NewRetryEventHandler(l, tssListener, depositHandler, bridgeAddress, *config.GeneralChainConfig.Id, config.BlockConfirmations))
evmListener := coreListener.NewEVMListener(client, eventHandlers, blockstore, sygmaMetrics, *config.GeneralChainConfig.Id, config.BlockRetryInterval, config.BlockConfirmations, config.BlockInterval)
eventHandlers = append(eventHandlers, hubEventHandlers.NewDepositEventHandler(depositListener, depositHandler, bridgeAddress, *config.GeneralChainConfig.Id, make(chan []*coreMessage.Message, 1)))
eventHandlers = append(eventHandlers, hubEventHandlers.NewKeygenEventHandler(l, tssListener, coordinator, host, communication, keyshareStore, bridgeAddress, networkTopology.Threshold))
eventHandlers = append(eventHandlers, hubEventHandlers.NewRefreshEventHandler(l, topologyProvider, topologyStore, tssListener, coordinator, host, communication, connectionGate, keyshareStore, bridgeAddress))
eventHandlers = append(eventHandlers, hubEventHandlers.NewRetryEventHandler(l, tssListener, depositHandler, bridgeAddress, *config.GeneralChainConfig.Id, config.BlockConfirmations, make(chan []*coreMessage.Message, 1)))
evmListener := listener.NewEVMListener(client, eventHandlers, blockstore, sygmaMetrics, *config.GeneralChainConfig.Id, config.BlockRetryInterval, config.BlockConfirmations, config.BlockInterval)
executor := executor.NewExecutor(host, communication, coordinator, bridgeContract, keyshareStore, exitLock, config.GasLimit.Uint64())

chain := evm.NewEVMChain(
client, evmListener, executor, blockstore, *config.GeneralChainConfig.Id, config.StartBlock,

Check failure on line 215 in app/app.go

View workflow job for this annotation

GitHub Actions / linter-check

cannot use client (variable of type *"github.com/sygmaprotocol/sygma-core/chains/evm/client".EVMClient) as *evmclient.EVMClient value in argument to evm.NewEVMChain (typecheck)
config.BlockInterval, config.GeneralChainConfig.FreshStart, config.GeneralChainConfig.LatestBlock,
)

Expand Down
47 changes: 26 additions & 21 deletions chains/evm/calls/contracts/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ import (
"strconv"
"strings"

"github.com/ChainSafe/chainbridge-core/chains/evm/calls"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/contracts"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/contracts/deposit"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/transactor"

"github.com/ChainSafe/chainbridge-core/types"
"github.com/ChainSafe/sygma-relayer/chains"
"github.com/ChainSafe/sygma-relayer/chains/evm/calls/consts"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/rs/zerolog/log"

"github.com/sygmaprotocol/sygma-core/chains/evm/client"
"github.com/sygmaprotocol/sygma-core/chains/evm/contracts"
"github.com/sygmaprotocol/sygma-core/chains/evm/transactor"
)

const bridgeVersion = "3.1.0"
Expand All @@ -32,7 +34,7 @@ type BridgeProposal struct {
}

type ChainClient interface {
calls.ContractCallerDispatcher
client.Client
ChainID(ctx context.Context) (*big.Int, error)
}

Expand Down Expand Up @@ -182,33 +184,35 @@ func (c *BridgeContract) PermissionlessGenericDeposit(
}

func (c *BridgeContract) ExecuteProposal(
proposal *chains.Proposal,
proposal *chains.TransferProposal,
signature []byte,
opts transactor.TransactOptions,
) (*common.Hash, error) {
log.Debug().
Str("depositNonce", strconv.FormatUint(proposal.DepositNonce, 10)).
Str("resourceID", hexutil.Encode(proposal.ResourceID[:])).
Str("depositNonce", strconv.FormatUint(proposal.Data.DepositNonce, 10)).
Str("resourceID", hexutil.Encode(proposal.Data.ResourceId[:])).
Msgf("Execute proposal")
return c.ExecuteTransaction(
"executeProposal",
opts,
proposal.OriginDomainID, proposal.DepositNonce, proposal.Data, proposal.ResourceID, signature,
proposal.Source, proposal.Data.DepositNonce, proposal.Data, proposal.Data.ResourceId, signature,
)
}

func (c *BridgeContract) ExecuteProposals(
proposals []*chains.Proposal,
proposals []*chains.TransferProposal,
signature []byte,
opts transactor.TransactOptions,
) (*common.Hash, error) {
bridgeProposals := make([]chains.Proposal, 0)
bridgeProposals := make([]chains.TransferProposal, 0)
for _, prop := range proposals {
bridgeProposals = append(bridgeProposals, chains.Proposal{
OriginDomainID: prop.OriginDomainID,
DepositNonce: prop.DepositNonce,
ResourceID: prop.ResourceID,
Data: prop.Data,
bridgeProposals = append(bridgeProposals, chains.TransferProposal{
Source: prop.Source,
Data: chains.TransferProposalData{
DepositNonce: prop.Data.DepositNonce,
ResourceId: prop.Data.ResourceId,
Data: prop.Data.Data,
},
})
}

Expand All @@ -220,20 +224,21 @@ func (c *BridgeContract) ExecuteProposals(
)
}

func (c *BridgeContract) ProposalsHash(proposals []*chains.Proposal) ([]byte, error) {
func (c *BridgeContract) ProposalsHash(proposals []*chains.TransferProposal) ([]byte, error) {
chainID, err := c.client.ChainID(context.Background())
if err != nil {
return []byte{}, err
}
return chains.ProposalsHash(proposals, chainID.Int64(), c.ContractAddress().Hex(), bridgeVersion)
}

func (c *BridgeContract) IsProposalExecuted(p *chains.Proposal) (bool, error) {
func (c *BridgeContract) IsProposalExecuted(p *chains.TransferProposal) (bool, error) {

log.Debug().
Str("depositNonce", strconv.FormatUint(p.DepositNonce, 10)).
Str("resourceID", hexutil.Encode(p.ResourceID[:])).
Str("depositNonce", strconv.FormatUint(p.Data.DepositNonce, 10)).
Str("resourceID", hexutil.Encode(p.Data.ResourceId[:])).
Msg("Getting is proposal executed")
res, err := c.CallContract("isProposalExecuted", p.OriginDomainID, big.NewInt(int64(p.DepositNonce)))
res, err := c.CallContract("isProposalExecuted", p.Source, big.NewInt(int64(p.Data.DepositNonce)))
if err != nil {
return false, err
}
Expand All @@ -242,7 +247,7 @@ func (c *BridgeContract) IsProposalExecuted(p *chains.Proposal) (bool, error) {
}

func (c *BridgeContract) GetHandlerAddressForResourceID(
resourceID types.ResourceID,
resourceID [32]byte,
) (common.Address, error) {
log.Debug().Msgf("Getting handler address for resource %s", hexutil.Encode(resourceID[:]))
res, err := c.CallContract("_resourceIDToHandlerAddress", resourceID)
Expand Down
44 changes: 44 additions & 0 deletions chains/evm/calls/contracts/bridge/deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
)

func ConstructPermissionlessGenericDepositData(metadata []byte, executionFunctionSig []byte, executeContractAddress []byte, metadataDepositor []byte, maxFee *big.Int) []byte {
Expand All @@ -21,3 +22,46 @@ func ConstructPermissionlessGenericDepositData(metadata []byte, executionFunctio
data = append(data, metadata...)
return data
}

func constructMainDepositData(tokenStats *big.Int, destRecipient []byte) []byte {
var data []byte
data = append(data, math.PaddedBigBytes(tokenStats, 32)...) // Amount (ERC20) or Token Id (ERC721)
data = append(data, math.PaddedBigBytes(big.NewInt(int64(len(destRecipient))), 32)...) // length of recipient
data = append(data, destRecipient...) // Recipient
return data
}

func ConstructErc20DepositData(destRecipient []byte, amount *big.Int) []byte {
data := constructMainDepositData(amount, destRecipient)
return data
}

func ConstructErc20DepositDataWithPriority(destRecipient []byte, amount *big.Int, priority uint8) []byte {
mj52951 marked this conversation as resolved.
Show resolved Hide resolved
data := constructMainDepositData(amount, destRecipient)
data = append(data, math.PaddedBigBytes(big.NewInt(int64(len([]uint8{priority}))), 1)...) // Length of priority
data = append(data, math.PaddedBigBytes(big.NewInt(int64(priority)), 1)...) // Priority
return data
}

func ConstructErc721DepositData(destRecipient []byte, tokenId *big.Int, metadata []byte) []byte {
data := constructMainDepositData(tokenId, destRecipient)
data = append(data, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 32)...) // Length of metadata
data = append(data, metadata...) // Metadata
return data
}

func ConstructErc721DepositDataWithPriority(destRecipient []byte, tokenId *big.Int, metadata []byte, priority uint8) []byte {
data := constructMainDepositData(tokenId, destRecipient)
data = append(data, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 32)...) // Length of metadata
data = append(data, metadata...) // Metadata
data = append(data, math.PaddedBigBytes(big.NewInt(int64(len([]uint8{priority}))), 1)...) // Length of priority
data = append(data, math.PaddedBigBytes(big.NewInt(int64(priority)), 1)...) // Priority
return data
}

func ConstructGenericDepositData(metadata []byte) []byte {
var data []byte
data = append(data, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 32)...) // Length of metadata
data = append(data, metadata...) // Metadata
return data
}
17 changes: 17 additions & 0 deletions chains/evm/calls/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,20 @@ type Refresh struct {
type RetryEvent struct {
TxHash string
}

type Deposit struct {
// ID of chain deposit will be bridged to
DestinationDomainID uint8
// ResourceID used to find address of handler to be used for deposit
ResourceID [32]byte
// Nonce of deposit
DepositNonce uint64
// Address of sender (msg.sender: user)
SenderAddress common.Address
// Additional data to be passed to specified handler
Data []byte
// ERC20Handler: responds with empty data
// ERC721Handler: responds with deposited token metadata acquired by calling a tokenURI method in the token contract
// GenericHandler: responds with the raw bytes returned from the call to the target contract
HandlerResponse []byte
}
42 changes: 37 additions & 5 deletions chains/evm/calls/events/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import (
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/rs/zerolog/log"

"github.com/ChainSafe/chainbridge-core/chains/evm/calls/events"

"github.com/ChainSafe/sygma-relayer/chains/evm/calls/consts"
)

Expand All @@ -38,8 +36,42 @@ func NewListener(client ChainClient) *Listener {
}
}

func (l *Listener) FetchDepositEvent(event RetryEvent, bridgeAddress common.Address, blockConfirmations *big.Int) ([]events.Deposit, error) {
depositEvents := make([]events.Deposit, 0)
func (l *Listener) UnpackDeposit(abi abi.ABI, data []byte) (*Deposit, error) {
mj52951 marked this conversation as resolved.
Show resolved Hide resolved
var dl Deposit

err := abi.UnpackIntoInterface(&dl, "Deposit", data)
if err != nil {
return &Deposit{}, err
}

return &dl, nil
}

func (l *Listener) FetchDeposits(ctx context.Context, contractAddress common.Address, startBlock *big.Int, endBlock *big.Int) ([]*Deposit, error) {
logs, err := l.client.FetchEventLogs(ctx, contractAddress, string(DepositSig), startBlock, endBlock)
if err != nil {
return nil, err
}
deposits := make([]*Deposit, 0)

for _, dl := range logs {
d, err := l.UnpackDeposit(l.abi, dl.Data)
if err != nil {
log.Error().Msgf("failed unpacking deposit event log: %v", err)
continue
}

d.SenderAddress = common.BytesToAddress(dl.Topics[1].Bytes())
log.Debug().Msgf("Found deposit log in block: %d, TxHash: %s, contractAddress: %s, sender: %s", dl.BlockNumber, dl.TxHash, dl.Address, d.SenderAddress)

deposits = append(deposits, d)
}

return deposits, nil
}

func (l *Listener) FetchDepositEvent(event RetryEvent, bridgeAddress common.Address, blockConfirmations *big.Int) ([]Deposit, error) {
mj52951 marked this conversation as resolved.
Show resolved Hide resolved
depositEvents := make([]Deposit, 0)
retryDepositTxHash := common.HexToHash(event.TxHash)
receipt, err := l.client.WaitAndReturnTxReceipt(retryDepositTxHash)
if err != nil {
Expand All @@ -64,7 +96,7 @@ func (l *Listener) FetchDepositEvent(event RetryEvent, bridgeAddress common.Addr
continue
}

var depositEvent events.Deposit
var depositEvent Deposit
err := l.abi.UnpackIntoInterface(&depositEvent, "Deposit", lg.Data)
if err == nil {
depositEvents = append(depositEvents, depositEvent)
Expand Down
Loading
Loading