diff --git a/Makefile b/Makefile index 21431513..2f1066c5 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/app/app.go b/app/app.go index 7eeb47be..00016936 100644 --- a/app/app.go +++ b/app/app.go @@ -14,12 +14,7 @@ import ( "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" @@ -32,7 +27,8 @@ import ( "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" @@ -41,6 +37,11 @@ import ( 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" + coreEvm "github.com/sygmaprotocol/sygma-core/chains/evm" + 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" @@ -161,7 +162,7 @@ func Run() error { 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") @@ -171,31 +172,47 @@ func Run() error { 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, - config.BlockInterval, config.GeneralChainConfig.FreshStart, config.GeneralChainConfig.LatestBlock, - ) + chain := coreEvm.NewEVMChain(evmListener, mh, executor, *config.GeneralChainConfig.Id, config.StartBlock) chains = append(chains, chain) } diff --git a/chains/evm/calls/contracts/bridge/bridge.go b/chains/evm/calls/contracts/bridge/bridge.go index 4593efa8..575c7d61 100644 --- a/chains/evm/calls/contracts/bridge/bridge.go +++ b/chains/evm/calls/contracts/bridge/bridge.go @@ -9,17 +9,16 @@ 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" @@ -32,7 +31,7 @@ type BridgeProposal struct { } type ChainClient interface { - calls.ContractCallerDispatcher + client.Client ChainID(ctx context.Context) (*big.Int, error) } @@ -53,162 +52,36 @@ func NewBridgeContract( } } -func (c *BridgeContract) deposit( - resourceID types.ResourceID, - destDomainID uint8, - data []byte, - feeData []byte, - opts transactor.TransactOptions, -) (*common.Hash, error) { - return c.ExecuteTransaction( - "deposit", - opts, - destDomainID, resourceID, data, feeData, - ) -} - -func (c *BridgeContract) Erc20Deposit( - recipient []byte, - amount *big.Int, - resourceID types.ResourceID, - destDomainID uint8, - feeData []byte, - opts transactor.TransactOptions, -) (*common.Hash, error) { - log.Debug(). - Str("recipient", hexutil.Encode(recipient)). - Str("resourceID", hexutil.Encode(resourceID[:])). - Str("amount", amount.String()). - Uint8("destDomainID", destDomainID). - Hex("feeData", feeData). - Msgf("ERC20 deposit") - var data []byte - if opts.Priority == 0 { - data = deposit.ConstructErc20DepositData(recipient, amount) - } else { - data = deposit.ConstructErc20DepositDataWithPriority(recipient, amount, opts.Priority) - } - - txHash, err := c.deposit(resourceID, destDomainID, data, feeData, opts) - if err != nil { - log.Error().Err(err) - return nil, err - } - return txHash, err -} - -func (c *BridgeContract) Erc721Deposit( - tokenId *big.Int, - metadata string, - recipient common.Address, - resourceID types.ResourceID, - destDomainID uint8, - feeData []byte, - opts transactor.TransactOptions, -) (*common.Hash, error) { - log.Debug(). - Str("recipient", recipient.String()). - Str("resourceID", hexutil.Encode(resourceID[:])). - Str("tokenID", tokenId.String()). - Uint8("destDomainID", destDomainID). - Hex("feeData", feeData). - Msgf("ERC721 deposit") - var data []byte - if opts.Priority == 0 { - data = deposit.ConstructErc721DepositData(recipient.Bytes(), tokenId, []byte(metadata)) - } else { - data = deposit.ConstructErc721DepositDataWithPriority(recipient.Bytes(), tokenId, []byte(metadata), opts.Priority) - } - - txHash, err := c.deposit(resourceID, destDomainID, data, feeData, opts) - if err != nil { - log.Error().Err(err) - return nil, err - } - return txHash, err -} - -func (c *BridgeContract) GenericDeposit( - metadata []byte, - resourceID types.ResourceID, - destDomainID uint8, - feeData []byte, - opts transactor.TransactOptions, -) (*common.Hash, error) { - log.Debug(). - Str("resourceID", hexutil.Encode(resourceID[:])). - Uint8("destDomainID", destDomainID). - Hex("feeData", feeData). - Msgf("Generic deposit") - data := deposit.ConstructGenericDepositData(metadata) - - txHash, err := c.deposit(resourceID, destDomainID, data, feeData, opts) - if err != nil { - log.Error().Err(err) - return nil, err - } - return txHash, err -} - -func (c *BridgeContract) PermissionlessGenericDeposit( - metadata []byte, - executeFunctionSig string, - executeContractAddress *common.Address, - depositor *common.Address, - maxFee *big.Int, - resourceID types.ResourceID, - destDomainID uint8, - feeData []byte, - opts transactor.TransactOptions, -) (*common.Hash, error) { - log.Debug(). - Str("resourceID", hexutil.Encode(resourceID[:])). - Uint8("destDomainID", destDomainID). - Hex("feeData", feeData). - Msgf("Permissionless Generic deposit") - data := ConstructPermissionlessGenericDepositData(metadata, []byte(executeFunctionSig), executeContractAddress.Bytes(), depositor.Bytes(), maxFee) - txHash, err := c.deposit( - resourceID, - destDomainID, - data, - feeData, - opts, - ) - if err != nil { - log.Error().Err(err) - return nil, err - } - return txHash, err -} - 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, + }, }) } @@ -220,7 +93,7 @@ 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 @@ -228,12 +101,13 @@ func (c *BridgeContract) ProposalsHash(proposals []*chains.Proposal) ([]byte, er 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 } @@ -242,7 +116,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) diff --git a/chains/evm/calls/contracts/bridge/deposit.go b/chains/evm/calls/contracts/bridge/deposit.go deleted file mode 100644 index 883e9d4d..00000000 --- a/chains/evm/calls/contracts/bridge/deposit.go +++ /dev/null @@ -1,23 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -package bridge - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -func ConstructPermissionlessGenericDepositData(metadata []byte, executionFunctionSig []byte, executeContractAddress []byte, metadataDepositor []byte, maxFee *big.Int) []byte { - var data []byte - data = append(data, common.LeftPadBytes(maxFee.Bytes(), 32)...) - data = append(data, common.LeftPadBytes(big.NewInt(int64(len(executionFunctionSig))).Bytes(), 2)...) - data = append(data, executionFunctionSig...) - data = append(data, byte(len(executeContractAddress))) - data = append(data, executeContractAddress...) - data = append(data, byte(len(metadataDepositor))) - data = append(data, metadataDepositor...) - data = append(data, metadata...) - return data -} diff --git a/chains/evm/calls/events/events.go b/chains/evm/calls/events/events.go index 0f86e470..0f190e3a 100644 --- a/chains/evm/calls/events/events.go +++ b/chains/evm/calls/events/events.go @@ -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 +} diff --git a/chains/evm/calls/events/listener.go b/chains/evm/calls/events/listener.go index 26c32019..2ff0d372 100644 --- a/chains/evm/calls/events/listener.go +++ b/chains/evm/calls/events/listener.go @@ -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" ) @@ -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) 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) unpackDeposit(abi abi.ABI, data []byte) (*Deposit, error) { + var dl Deposit + + err := abi.UnpackIntoInterface(&dl, "Deposit", data) + if err != nil { + return &Deposit{}, err + } + + return &dl, nil +} + +func (l *Listener) FetchRetryDepositEvents(event RetryEvent, bridgeAddress common.Address, blockConfirmations *big.Int) ([]Deposit, error) { + depositEvents := make([]Deposit, 0) retryDepositTxHash := common.HexToHash(event.TxHash) receipt, err := l.client.WaitAndReturnTxReceipt(retryDepositTxHash) if err != nil { @@ -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) diff --git a/chains/evm/calls/events/listener_test.go b/chains/evm/calls/events/listener_test.go index decb0bfe..0e020921 100644 --- a/chains/evm/calls/events/listener_test.go +++ b/chains/evm/calls/events/listener_test.go @@ -13,7 +13,6 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" - coreEvents "github.com/ChainSafe/chainbridge-core/chains/evm/calls/events" "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" mock_listener "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events/mock" ) @@ -34,21 +33,21 @@ func (s *ListenerTestSuite) SetupTest() { s.listener = events.NewListener(s.mockClient) } -func (s *ListenerTestSuite) Test_FetchDepositEvent_FetchingTxFails() { +func (s *ListenerTestSuite) Test_FetchRetryDepositEvents_FetchingTxFails() { s.mockClient.EXPECT().WaitAndReturnTxReceipt(common.HexToHash("0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c")).Return(nil, fmt.Errorf("error")) - _, err := s.listener.FetchDepositEvent(events.RetryEvent{TxHash: "0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c"}, common.Address{}, big.NewInt(5)) + _, err := s.listener.FetchRetryDepositEvents(events.RetryEvent{TxHash: "0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c"}, common.Address{}, big.NewInt(5)) s.NotNil(err) } -func (s *ListenerTestSuite) Test_FetchDepositEvent_EventTooNew() { +func (s *ListenerTestSuite) Test_FetchRetryDepositEvents_EventTooNew() { s.mockClient.EXPECT().WaitAndReturnTxReceipt(common.HexToHash("0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c")).Return(&types.Receipt{ BlockNumber: big.NewInt(14), }, nil) s.mockClient.EXPECT().LatestBlock().Return(big.NewInt(10), nil) - _, err := s.listener.FetchDepositEvent( + _, err := s.listener.FetchRetryDepositEvents( events.RetryEvent{TxHash: "0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c"}, common.HexToAddress("0x5798e01f4b1d8f6a5d91167414f3a915d021bc4a"), big.NewInt(5), @@ -57,23 +56,23 @@ func (s *ListenerTestSuite) Test_FetchDepositEvent_EventTooNew() { s.NotNil(err) } -func (s *ListenerTestSuite) Test_FetchDepositEvent_NoDepositEvent() { +func (s *ListenerTestSuite) Test_FetchRetryDepositEvents_NoDepositEvent() { s.mockClient.EXPECT().WaitAndReturnTxReceipt(common.HexToHash("0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c")).Return(&types.Receipt{ BlockNumber: big.NewInt(14), }, nil) s.mockClient.EXPECT().LatestBlock().Return(big.NewInt(20), nil) - deposits, err := s.listener.FetchDepositEvent( + deposits, err := s.listener.FetchRetryDepositEvents( events.RetryEvent{TxHash: "0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c"}, common.HexToAddress("0x5798e01f4b1d8f6a5d91167414f3a915d021bc4a"), big.NewInt(5), ) s.Nil(err) - s.Equal(deposits, []coreEvents.Deposit{}) + s.Equal(deposits, []events.Deposit{}) } -func (s *ListenerTestSuite) Test_FetchDepositEvent_NoMatchingEvent() { +func (s *ListenerTestSuite) Test_FetchRetryDepositEvents_NoMatchingEvent() { s.mockClient.EXPECT().WaitAndReturnTxReceipt(common.HexToHash("0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c")).Return(&types.Receipt{ BlockNumber: big.NewInt(14), Logs: []*types.Log{ @@ -89,17 +88,17 @@ func (s *ListenerTestSuite) Test_FetchDepositEvent_NoMatchingEvent() { }, nil) s.mockClient.EXPECT().LatestBlock().Return(big.NewInt(20), nil) - deposits, err := s.listener.FetchDepositEvent( + deposits, err := s.listener.FetchRetryDepositEvents( events.RetryEvent{TxHash: "0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c"}, common.HexToAddress("0x5798e01f4b1d8f6a5d91167414f3a915d021bc4a"), big.NewInt(5), ) s.Nil(err) - s.Equal(deposits, []coreEvents.Deposit{}) + s.Equal(deposits, []events.Deposit{}) } -func (s *ListenerTestSuite) Test_FetchDepositEvent_ValidEvent() { +func (s *ListenerTestSuite) Test_FetchRetryDepositEvents_ValidEvent() { depositEvent := common.Hex2Bytes("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000001d00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000148e0a907331554af72563bd8d43051c2e64be5d350102000000000000000000000000000000000000000000000000000000000000000000000000000000000000") s.mockClient.EXPECT().WaitAndReturnTxReceipt(common.HexToHash("0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c")).Return(&types.Receipt{ BlockNumber: big.NewInt(14), @@ -116,7 +115,7 @@ func (s *ListenerTestSuite) Test_FetchDepositEvent_ValidEvent() { }, nil) s.mockClient.EXPECT().LatestBlock().Return(big.NewInt(20), nil) - deposits, err := s.listener.FetchDepositEvent( + deposits, err := s.listener.FetchRetryDepositEvents( events.RetryEvent{TxHash: "0xf25ed4a14bf7ad20354b46fe38d7d4525f2ea3042db9a9954ef8d73c558b500c"}, common.HexToAddress("0x5798e01f4b1d8f6a5d91167414f3a915d021bc4a"), big.NewInt(5), diff --git a/chains/evm/executor/executor.go b/chains/evm/executor/executor.go index 0afd22b7..f3086e3f 100644 --- a/chains/evm/executor/executor.go +++ b/chains/evm/executor/executor.go @@ -17,6 +17,7 @@ import ( "github.com/libp2p/go-libp2p/core/host" "github.com/rs/zerolog/log" + "github.com/ChainSafe/sygma-relayer/chains" "github.com/ChainSafe/sygma-relayer/comm" "github.com/ChainSafe/sygma-relayer/tss" "github.com/ChainSafe/sygma-relayer/tss/signing" @@ -27,7 +28,7 @@ import ( const TRANSFER_GAS_COST = 200000 type Batch struct { - proposals []*proposal.Proposal + proposals []*chains.TransferProposal gasLimit uint64 } @@ -37,9 +38,9 @@ var ( ) type BridgeContract interface { - IsProposalExecuted(p *proposal.Proposal) (bool, error) - ExecuteProposals(proposals []*proposal.Proposal, signature []byte, opts transactor.TransactOptions) (*ethCommon.Hash, error) - ProposalsHash(proposals []*proposal.Proposal) ([]byte, error) + IsProposalExecuted(p *chains.TransferProposal) (bool, error) + ExecuteProposals(proposals []*chains.TransferProposal, signature []byte, opts transactor.TransactOptions) (*ethCommon.Hash, error) + ProposalsHash(proposals []*chains.TransferProposal) ([]byte, error) } type Executor struct { @@ -74,6 +75,7 @@ func NewExecutor( // Execute starts a signing process and executes proposals when signature is generated func (e *Executor) Execute(proposals []*proposal.Proposal) error { + e.exitLock.RLock() defer e.exitLock.RUnlock() @@ -176,24 +178,30 @@ func (e *Executor) watchExecution(ctx context.Context, cancelExecution context.C func (e *Executor) proposalBatches(proposals []*proposal.Proposal) ([]*Batch, error) { batches := make([]*Batch, 1) currentBatch := &Batch{ - proposals: make([]*proposal.Proposal, 0), + proposals: make([]*chains.TransferProposal, 0), gasLimit: 0, } batches[0] = currentBatch for _, prop := range proposals { + transferProposal := &chains.TransferProposal{ + Source: prop.Source, + Destination: prop.Destination, + Data: prop.Data.(chains.TransferProposalData), + Type: prop.Type, + } - isExecuted, err := e.bridge.IsProposalExecuted(prop) + isExecuted, err := e.bridge.IsProposalExecuted(transferProposal) if err != nil { return nil, err } if isExecuted { - log.Info().Msgf("Proposal %p already executed", prop) + log.Info().Msgf("Proposal %p already executed", transferProposal) continue } var propGasLimit uint64 - l, ok := prop.Data.(TransferMessageData).Metadata["gasLimit"] + l, ok := transferProposal.Data.Metadata["gasLimit"] if ok { propGasLimit = l.(uint64) } else { @@ -202,13 +210,13 @@ func (e *Executor) proposalBatches(proposals []*proposal.Proposal) ([]*Batch, er currentBatch.gasLimit += propGasLimit if currentBatch.gasLimit >= e.transactionMaxGas { currentBatch = &Batch{ - proposals: make([]*proposal.Proposal, 0), + proposals: make([]*chains.TransferProposal, 0), gasLimit: 0, } batches = append(batches, currentBatch) } - currentBatch.proposals = append(currentBatch.proposals, prop) + currentBatch.proposals = append(currentBatch.proposals, transferProposal) } return batches, nil @@ -231,7 +239,7 @@ func (e *Executor) executeBatch(batch *Batch, signatureData *common.SignatureDat return hash, err } -func (e *Executor) areProposalsExecuted(proposals []*proposal.Proposal, sessionID string) bool { +func (e *Executor) areProposalsExecuted(proposals []*chains.TransferProposal, sessionID string) bool { for _, prop := range proposals { isExecuted, err := e.bridge.IsProposalExecuted(prop) if err != nil || !isExecuted { diff --git a/chains/evm/executor/message-handler.go b/chains/evm/executor/message-handler.go index 3cab2b75..57d72c9b 100644 --- a/chains/evm/executor/message-handler.go +++ b/chains/evm/executor/message-handler.go @@ -17,11 +17,10 @@ import ( ) const ( - TransferProposalType proposal.ProposalType = "Transfer" - ERC20 message.MessageType = "erc20" - ERC721 message.MessageType = "erc721" - PermissionedGeneric message.MessageType = "permissionedGeneric" - PermissionlessGeneric message.MessageType = "permissionlessGeneric" + ERC20 message.MessageType = "erc20" + ERC721 message.MessageType = "erc721" + PermissionedGeneric message.MessageType = "permissionedGeneric" + PermissionlessGeneric message.MessageType = "permissionlessGeneric" ) type TransferMessageData struct { @@ -98,8 +97,12 @@ func PermissionlessGenericMessageHandler(msg *TransferMessage) (*proposal.Propos data.Write(depositor) data.Write(executionData) - return chains.NewTransferProposal(msg.Source, msg.Destination, msg.Data.DepositNonce, - msg.Data.ResourceId, msg.Data.Metadata, data.Bytes(), TransferProposalType), nil + return chains.NewProposal(msg.Source, msg.Destination, chains.TransferProposalData{ + DepositNonce: msg.Data.DepositNonce, + ResourceId: msg.Data.ResourceId, + Metadata: msg.Data.Metadata, + Data: data.Bytes(), + }, chains.TransferProposalType), nil } func ERC20MessageHandler(msg *TransferMessage) (*proposal.Proposal, error) { @@ -120,8 +123,12 @@ func ERC20MessageHandler(msg *TransferMessage) (*proposal.Proposal, error) { data = append(data, common.LeftPadBytes(recipientLen, 32)...) // length of recipient (uint256) data = append(data, recipient...) // recipient ([]byte) - return chains.NewTransferProposal(msg.Source, msg.Destination, msg.Data.DepositNonce, - msg.Data.ResourceId, msg.Data.Metadata, data, TransferProposalType), nil + return chains.NewProposal(msg.Source, msg.Destination, chains.TransferProposalData{ + DepositNonce: msg.Data.DepositNonce, + ResourceId: msg.Data.ResourceId, + Metadata: msg.Data.Metadata, + Data: data, + }, chains.TransferProposalType), nil } func ERC721MessageHandler(msg *TransferMessage) (*proposal.Proposal, error) { @@ -149,8 +156,12 @@ func ERC721MessageHandler(msg *TransferMessage) (*proposal.Proposal, error) { metadataLen := big.NewInt(int64(len(metadata))).Bytes() data.Write(common.LeftPadBytes(metadataLen, 32)) data.Write(metadata) - return chains.NewTransferProposal(msg.Source, msg.Destination, msg.Data.DepositNonce, - msg.Data.ResourceId, msg.Data.Metadata, data.Bytes(), TransferProposalType), nil + return chains.NewProposal(msg.Source, msg.Destination, chains.TransferProposalData{ + DepositNonce: msg.Data.DepositNonce, + ResourceId: msg.Data.ResourceId, + Metadata: msg.Data.Metadata, + Data: data.Bytes(), + }, chains.TransferProposalType), nil } func GenericMessageHandler(msg *TransferMessage) (*proposal.Proposal, error) { @@ -165,6 +176,10 @@ func GenericMessageHandler(msg *TransferMessage) (*proposal.Proposal, error) { metadataLen := big.NewInt(int64(len(metadata))).Bytes() data.Write(common.LeftPadBytes(metadataLen, 32)) // length of metadata (uint256) data.Write(metadata) - return chains.NewTransferProposal(msg.Source, msg.Destination, msg.Data.DepositNonce, - msg.Data.ResourceId, msg.Data.Metadata, data.Bytes(), TransferProposalType), nil + return chains.NewProposal(msg.Source, msg.Destination, chains.TransferProposalData{ + DepositNonce: msg.Data.DepositNonce, + ResourceId: msg.Data.ResourceId, + Metadata: msg.Data.Metadata, + Data: data.Bytes(), + }, chains.TransferProposalType), nil } diff --git a/chains/evm/executor/message-handler_test.go b/chains/evm/executor/message-handler_test.go index be016bec..a02728e7 100644 --- a/chains/evm/executor/message-handler_test.go +++ b/chains/evm/executor/message-handler_test.go @@ -14,8 +14,8 @@ import ( "github.com/sygmaprotocol/sygma-core/relayer/message" "github.com/ChainSafe/sygma-relayer/chains" - "github.com/ChainSafe/sygma-relayer/chains/evm/calls/contracts/bridge" "github.com/ChainSafe/sygma-relayer/chains/evm/executor" + "github.com/ChainSafe/sygma-relayer/e2e/evm" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/suite" ) @@ -362,7 +362,7 @@ func (s *PermissionlessGenericHandlerTestSuite) Test_HandleMessage() { maxFee := big.NewInt(200000) var metadata []byte metadata = append(metadata, hash[:]...) - calldata := bridge.ConstructPermissionlessGenericDepositData( + calldata := evm.ConstructPermissionlessGenericDepositData( metadata, functionSig, contractAddress.Bytes(), @@ -399,14 +399,16 @@ func (s *PermissionlessGenericHandlerTestSuite) Test_HandleMessage() { prop, err := mh.HandleMessage(message) expectedData, _ := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000030d4000001402091eeff969b33a5ce8a729dae325879bf76f90145c1f5961696bad2e73f73417f07ef55c62a2dc5b307868617368") - expected := chains.NewTransferProposal( + expected := chains.NewProposal( message.Source, message.Destination, - message.Data.(executor.TransferMessageData).DepositNonce, - message.Data.(executor.TransferMessageData).ResourceId, - message.Data.(executor.TransferMessageData).Metadata, - expectedData, - executor.TransferProposalType, + chains.TransferProposalData{ + DepositNonce: message.Data.(executor.TransferMessageData).DepositNonce, + ResourceId: message.Data.(executor.TransferMessageData).ResourceId, + Metadata: message.Data.(executor.TransferMessageData).Metadata, + Data: expectedData, + }, + chains.TransferProposalType, ) s.Nil(err) s.Equal(expected, prop) diff --git a/chains/evm/listener/deposit-handler.go b/chains/evm/listener/deposit-handler.go deleted file mode 100644 index 1bd05a9b..00000000 --- a/chains/evm/listener/deposit-handler.go +++ /dev/null @@ -1,81 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -package listener - -import ( - "errors" - "math/big" - - "github.com/ChainSafe/chainbridge-core/relayer/message" - "github.com/ChainSafe/chainbridge-core/types" -) - -const ( - PermissionlessGenericTransfer message.TransferType = "PermissionlessGenericTransfer" -) - -// GenericDepositHandler converts data pulled from generic deposit event logs into message -func PermissionlessGenericDepositHandler(sourceID, destId uint8, nonce uint64, resourceID types.ResourceID, calldata, handlerResponse []byte) (*message.Message, error) { - if len(calldata) < 76 { - err := errors.New("invalid calldata length: less than 76 bytes") - return nil, err - } - - maxFee := calldata[:32] - - functionSigLen := big.NewInt(0).SetBytes(calldata[32:34]) - functionSigEnd := 34 + functionSigLen.Int64() - functionSig := calldata[34:functionSigEnd] - - contractAddressLen := big.NewInt(0).SetBytes(calldata[functionSigEnd : functionSigEnd+1]) - contractAddressEnd := functionSigEnd + 1 + contractAddressLen.Int64() - contractAddress := calldata[functionSigEnd+1 : contractAddressEnd] - - depositorLen := big.NewInt(0).SetBytes(calldata[contractAddressEnd : contractAddressEnd+1]) - depositorEnd := contractAddressEnd + 1 + depositorLen.Int64() - depositorAddress := calldata[contractAddressEnd+1 : depositorEnd] - executionData := calldata[depositorEnd:] - - payload := []interface{}{ - functionSig, - contractAddress, - maxFee, - depositorAddress, - executionData, - } - - metadata := message.Metadata{ - Data: make(map[string]interface{}), - } - metadata.Data["gasLimit"] = uint64(big.NewInt(0).SetBytes(maxFee).Int64()) - - return message.NewMessage(sourceID, destId, nonce, resourceID, PermissionlessGenericTransfer, payload, metadata), nil -} - -// Erc20DepositHandler converts data pulled from event logs into message. -// handlerResponse contains converted amount into 18 decimals if the token does not have 18 decimals. -func Erc20DepositHandler(sourceID, destId uint8, nonce uint64, resourceID types.ResourceID, calldata, handlerResponse []byte) (*message.Message, error) { - if len(calldata) < 84 { - err := errors.New("invalid calldata length: less than 84 bytes") - return nil, err - } - - // amount: first 32 bytes of calldata - // handlerResponse: 32 bytes amount if handler converted amounts - var amount []byte - if len(handlerResponse) > 0 { - amount = handlerResponse[:32] - } else { - amount = calldata[:32] - } - - recipientAddressLength := big.NewInt(0).SetBytes(calldata[32:64]) - recipientAddress := calldata[64:(64 + recipientAddressLength.Int64())] - payload := []interface{}{ - amount, - recipientAddress, - } - - return message.NewMessage(sourceID, destId, nonce, resourceID, message.FungibleTransfer, payload, message.Metadata{}), nil -} diff --git a/chains/evm/listener/deposit-handler_test.go b/chains/evm/listener/deposit-handler_test.go deleted file mode 100644 index 3d221060..00000000 --- a/chains/evm/listener/deposit-handler_test.go +++ /dev/null @@ -1,226 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -package listener_test - -import ( - "encoding/hex" - "errors" - "math/big" - "testing" - - "github.com/ChainSafe/chainbridge-core/chains/evm/calls/contracts/deposit" - "github.com/ChainSafe/chainbridge-core/chains/evm/calls/events" - "github.com/ChainSafe/chainbridge-core/relayer/message" - - "github.com/ChainSafe/sygma-relayer/chains/evm/calls/contracts/bridge" - "github.com/ChainSafe/sygma-relayer/chains/evm/listener" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/stretchr/testify/suite" -) - -type PermissionlessGenericHandlerTestSuite struct { - suite.Suite -} - -func TestRunPermissionlessGenericHandlerTestSuite(t *testing.T) { - suite.Run(t, new(PermissionlessGenericHandlerTestSuite)) -} - -func (s *PermissionlessGenericHandlerTestSuite) TestHandleEvent() { - hash := []byte("0xhash") - functionSig, _ := hex.DecodeString("654cf88c") - contractAddress := common.HexToAddress("0x02091EefF969b33A5CE8A729DaE325879bf76f90") - depositor := common.HexToAddress("0x5C1F5961696BaD2e73f73417f07EF55C62a2dC5b") - maxFee := big.NewInt(200000) - var executionData []byte - executionData = append(executionData, hash[:]...) - metadata := make(map[string]interface{}) - metadata["gasLimit"] = uint64(200000) - - calldata := bridge.ConstructPermissionlessGenericDepositData( - hash[:], - functionSig, - contractAddress.Bytes(), - depositor.Bytes(), - maxFee, - ) - depositLog := &events.Deposit{ - DestinationDomainID: 0, - ResourceID: [32]byte{0}, - DepositNonce: 1, - SenderAddress: common.HexToAddress("0x5C1F5961696BaD2e73f73417f07EF55C62a2dC5b"), - Data: calldata, - HandlerResponse: []byte{}, - } - - sourceID := uint8(1) - expected := &message.Message{ - Source: sourceID, - Destination: depositLog.DestinationDomainID, - DepositNonce: depositLog.DepositNonce, - ResourceId: depositLog.ResourceID, - Type: listener.PermissionlessGenericTransfer, - Payload: []interface{}{ - functionSig, - contractAddress.Bytes(), - common.LeftPadBytes(maxFee.Bytes(), 32), - depositor.Bytes(), - executionData, - }, - Metadata: message.Metadata{ - Data: metadata, - }, - } - - message, err := listener.PermissionlessGenericDepositHandler( - sourceID, - depositLog.DestinationDomainID, - depositLog.DepositNonce, - depositLog.ResourceID, - depositLog.Data, - depositLog.HandlerResponse, - ) - - s.Nil(err) - s.NotNil(message) - s.Equal(message, expected) -} - -func (s *PermissionlessGenericHandlerTestSuite) Test_HandleEvent_IncorrectDataLen() { - metadata := make(map[string]interface{}) - metadata["gasLimit"] = uint64(200000) - var calldata []byte - calldata = append(calldata, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 32)...) - depositLog := &events.Deposit{ - DestinationDomainID: 0, - ResourceID: [32]byte{0}, - DepositNonce: 1, - SenderAddress: common.HexToAddress("0x5C1F5961696BaD2e73f73417f07EF55C62a2dC5b"), - Data: calldata, - HandlerResponse: []byte{}, - } - - sourceID := uint8(1) - _, err := listener.PermissionlessGenericDepositHandler( - sourceID, - depositLog.DestinationDomainID, - depositLog.DepositNonce, - depositLog.ResourceID, - depositLog.Data, - depositLog.HandlerResponse, - ) - - s.NotNil(err) -} - -var errIncorrectDataLen = errors.New("invalid calldata length: less than 84 bytes") - -type Erc20HandlerTestSuite struct { - suite.Suite -} - -func TestRunErc20HandlerTestSuite(t *testing.T) { - suite.Run(t, new(Erc20HandlerTestSuite)) -} - -func (s *Erc20HandlerTestSuite) TestErc20HandleEvent() { - // 0xf1e58fb17704c2da8479a533f9fad4ad0993ca6b - recipientByteSlice := []byte{241, 229, 143, 177, 119, 4, 194, 218, 132, 121, 165, 51, 249, 250, 212, 173, 9, 147, 202, 107} - - calldata := deposit.ConstructErc20DepositData(recipientByteSlice, big.NewInt(2)) - depositLog := &events.Deposit{ - DestinationDomainID: 0, - ResourceID: [32]byte{0}, - DepositNonce: 1, - SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), - Data: calldata, - HandlerResponse: []byte{}, - } - - sourceID := uint8(1) - amountParsed := calldata[:32] - recipientAddressParsed := calldata[64:] - - expected := &message.Message{ - Source: sourceID, - Destination: depositLog.DestinationDomainID, - DepositNonce: depositLog.DepositNonce, - ResourceId: depositLog.ResourceID, - Type: message.FungibleTransfer, - Payload: []interface{}{ - amountParsed, - recipientAddressParsed, - }, - } - - message, err := listener.Erc20DepositHandler(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) - - s.Nil(err) - s.NotNil(message) - s.Equal(message, expected) -} - -func (s *Erc20HandlerTestSuite) TestErc20HandleEventIncorrectDataLen() { - metadata := []byte("0xdeadbeef") - - var calldata []byte - calldata = append(calldata, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 32)...) - calldata = append(calldata, metadata...) - - depositLog := &events.Deposit{ - DestinationDomainID: 0, - ResourceID: [32]byte{0}, - DepositNonce: 1, - SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), - Data: calldata, - HandlerResponse: []byte{}, - } - - sourceID := uint8(1) - - message, err := listener.Erc20DepositHandler(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) - - s.Nil(message) - s.EqualError(err, errIncorrectDataLen.Error()) -} - -func (s *Erc20HandlerTestSuite) TestErc20HandleEventAlternativeAmount() { - // 0xf1e58fb17704c2da8479a533f9fad4ad0993ca6b - recipientByteSlice := []byte{241, 229, 143, 177, 119, 4, 194, 218, 132, 121, 165, 51, 249, 250, 212, 173, 9, 147, 202, 107} - - var handlerResponse []byte - handlerResponse = append(handlerResponse, math.PaddedBigBytes(big.NewInt(200), 32)...) // Amount (ERC20) - calldata := deposit.ConstructErc20DepositData(recipientByteSlice, big.NewInt(2)) - depositLog := &events.Deposit{ - DestinationDomainID: 0, - ResourceID: [32]byte{0}, - DepositNonce: 1, - SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), - Data: calldata, - HandlerResponse: handlerResponse, - } - - sourceID := uint8(1) - recipientAddressParsed := calldata[64:] - - expected := &message.Message{ - Source: sourceID, - Destination: depositLog.DestinationDomainID, - DepositNonce: depositLog.DepositNonce, - ResourceId: depositLog.ResourceID, - Type: message.FungibleTransfer, - Payload: []interface{}{ - handlerResponse[:32], - recipientAddressParsed, - }, - } - - message, err := listener.Erc20DepositHandler(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) - - s.Nil(err) - s.NotNil(message) - s.Equal(message, expected) - s.Equal(big.NewInt(200), new(big.Int).SetBytes(message.Payload[0].([]byte))) -} diff --git a/chains/evm/listener/depositHandlers/deposit-handler.go b/chains/evm/listener/depositHandlers/deposit-handler.go new file mode 100644 index 00000000..d9b89ea7 --- /dev/null +++ b/chains/evm/listener/depositHandlers/deposit-handler.go @@ -0,0 +1,72 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +package depositHandlers + +import ( + "errors" + + "github.com/ChainSafe/sygma-relayer/chains/evm/listener/eventHandlers" + "github.com/ethereum/go-ethereum/common" + "github.com/rs/zerolog/log" + "github.com/sygmaprotocol/sygma-core/relayer/message" +) + +const ( + PermissionlessGenericTransfer message.MessageType = "PermissionlessGenericTransfer" + ERC20Transfer message.MessageType = "ERC20Transfer" + ERC721Transfer message.MessageType = "ERC721Transfer" + GenericTransfer message.MessageType = "GenericTransfer" +) + +type DepositHandlers map[common.Address]eventHandlers.DepositHandler +type HandlerMatcher interface { + GetHandlerAddressForResourceID(resourceID [32]byte) (common.Address, error) +} + +type ETHDepositHandler struct { + handlerMatcher HandlerMatcher + depositHandlers DepositHandlers +} + +// NewETHDepositHandler creates an instance of ETHDepositHandler that contains +// handler functions for processing deposit events +func NewETHDepositHandler(handlerMatcher HandlerMatcher) *ETHDepositHandler { + return ÐDepositHandler{ + handlerMatcher: handlerMatcher, + depositHandlers: make(map[common.Address]eventHandlers.DepositHandler), + } +} + +func (e *ETHDepositHandler) HandleDeposit(sourceID, destID uint8, depositNonce uint64, resourceID [32]byte, calldata, handlerResponse []byte) (*message.Message, error) { + handlerAddr, err := e.handlerMatcher.GetHandlerAddressForResourceID(resourceID) + if err != nil { + return nil, err + } + + depositHandler, err := e.matchAddressWithHandlerFunc(handlerAddr) + if err != nil { + return nil, err + } + + return depositHandler.HandleDeposit(sourceID, destID, depositNonce, resourceID, calldata, handlerResponse) +} + +// matchAddressWithHandlerFunc matches a handler address with an associated handler function +func (e *ETHDepositHandler) matchAddressWithHandlerFunc(handlerAddress common.Address) (eventHandlers.DepositHandler, error) { + hf, ok := e.depositHandlers[handlerAddress] + if !ok { + return nil, errors.New("no corresponding deposit handler for this address exists") + } + return hf, nil +} + +// RegisterDepositHandler registers an event handler by associating a handler function to a specified address +func (e *ETHDepositHandler) RegisterDepositHandler(handlerAddress string, handler eventHandlers.DepositHandler) { + if handlerAddress == "" { + return + } + + log.Debug().Msgf("Registered deposit handler for address %s", handlerAddress) + e.depositHandlers[common.HexToAddress(handlerAddress)] = handler +} diff --git a/chains/evm/listener/depositHandlers/erc20.go b/chains/evm/listener/depositHandlers/erc20.go new file mode 100644 index 00000000..edecddf7 --- /dev/null +++ b/chains/evm/listener/depositHandlers/erc20.go @@ -0,0 +1,42 @@ +package depositHandlers + +import ( + "errors" + "math/big" + + "github.com/ChainSafe/sygma-relayer/chains" + "github.com/sygmaprotocol/sygma-core/relayer/message" +) + +type Erc20DepositHandler struct{} + +// Erc20DepositHandler converts data pulled from event logs into message +// handlerResponse can be an empty slice +func (dh *Erc20DepositHandler) HandleDeposit(sourceID, destId uint8, nonce uint64, resourceID [32]byte, calldata, handlerResponse []byte) (*message.Message, error) { + if len(calldata) < 84 { + err := errors.New("invalid calldata length: less than 84 bytes") + return nil, err + } + + // amount: first 32 bytes of calldata + // handlerResponse: 32 bytes amount if handler converted amounts + var amount []byte + if len(handlerResponse) > 0 { + amount = handlerResponse[:32] + } else { + amount = calldata[:32] + } + + recipientAddressLength := big.NewInt(0).SetBytes(calldata[32:64]) + recipientAddress := calldata[64:(64 + recipientAddressLength.Int64())] + payload := []interface{}{ + amount, + recipientAddress, + } + return chains.NewMessage(sourceID, destId, chains.TransferMessageData{ + DepositNonce: nonce, + ResourceId: resourceID, + Metadata: nil, + Payload: payload, + }, ERC20Transfer), nil +} diff --git a/chains/evm/listener/depositHandlers/erc20_test.go b/chains/evm/listener/depositHandlers/erc20_test.go new file mode 100644 index 00000000..3bc539b2 --- /dev/null +++ b/chains/evm/listener/depositHandlers/erc20_test.go @@ -0,0 +1,139 @@ +package depositHandlers_test + +import ( + "errors" + "math/big" + "testing" + + "github.com/ChainSafe/sygma-relayer/e2e/evm" + "github.com/sygmaprotocol/sygma-core/relayer/message" + + "github.com/ChainSafe/sygma-relayer/chains" + "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" + "github.com/ChainSafe/sygma-relayer/chains/evm/listener/depositHandlers" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/suite" +) + +var errIncorrectDataLen = errors.New("invalid calldata length: less than 84 bytes") + +type Erc20HandlerTestSuite struct { + suite.Suite +} + +func TestRunErc20HandlerTestSuite(t *testing.T) { + suite.Run(t, new(Erc20HandlerTestSuite)) +} + +func (s *Erc20HandlerTestSuite) SetupSuite() {} +func (s *Erc20HandlerTestSuite) TearDownSuite() {} +func (s *Erc20HandlerTestSuite) SetupTest() {} +func (s *Erc20HandlerTestSuite) TearDownTest() {} + +func (s *Erc20HandlerTestSuite) TestErc20HandleEvent() { + // 0xf1e58fb17704c2da8479a533f9fad4ad0993ca6b + recipientByteSlice := []byte{241, 229, 143, 177, 119, 4, 194, 218, 132, 121, 165, 51, 249, 250, 212, 173, 9, 147, 202, 107} + + calldata := evm.ConstructErc20DepositData(recipientByteSlice, big.NewInt(2)) + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + amountParsed := calldata[:32] + recipientAddressParsed := calldata[64:] + + expected := &message.Message{ + Source: sourceID, + Destination: depositLog.DestinationDomainID, + Data: chains.TransferMessageData{ + DepositNonce: depositLog.DepositNonce, + ResourceId: depositLog.ResourceID, + Payload: []interface{}{ + amountParsed, + recipientAddressParsed, + }, + }, + Type: depositHandlers.ERC20Transfer, + } + erc20DepositHandler := depositHandlers.Erc20DepositHandler{} + message, err := erc20DepositHandler.HandleDeposit(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) + + s.Nil(err) + s.NotNil(message) + s.Equal(message, expected) +} + +func (s *Erc20HandlerTestSuite) TestErc20HandleEventWithPriority() { + // 0xf1e58fb17704c2da8479a533f9fad4ad0993ca6b + recipientByteSlice := []byte{241, 229, 143, 177, 119, 4, 194, 218, 132, 121, 165, 51, 249, 250, 212, 173, 9, 147, 202, 107} + + calldata := evm.ConstructErc20DepositData(recipientByteSlice, big.NewInt(2)) + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + amountParsed := calldata[:32] + // 32-64 is recipient address length + recipientAddressLength := big.NewInt(0).SetBytes(calldata[32:64]) + + // 64 - (64 + recipient address length) is recipient address + recipientAddressParsed := calldata[64:(64 + recipientAddressLength.Int64())] + expected := &message.Message{ + Source: sourceID, + Destination: depositLog.DestinationDomainID, + Data: chains.TransferMessageData{ + DepositNonce: depositLog.DepositNonce, + ResourceId: depositLog.ResourceID, + Payload: []interface{}{ + amountParsed, + recipientAddressParsed, + }, + }, + Type: depositHandlers.ERC20Transfer, + } + + erc20DepositHandler := depositHandlers.Erc20DepositHandler{} + message, err := erc20DepositHandler.HandleDeposit(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) + + s.Nil(err) + s.NotNil(message) + s.Equal(message, expected) +} + +func (s *Erc20HandlerTestSuite) TestErc20HandleEventIncorrectDataLen() { + metadata := []byte("0xdeadbeef") + + var calldata []byte + calldata = append(calldata, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 32)...) + calldata = append(calldata, metadata...) + + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + + erc20DepositHandler := depositHandlers.Erc20DepositHandler{} + message, err := erc20DepositHandler.HandleDeposit(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) + + s.Nil(message) + s.EqualError(err, errIncorrectDataLen.Error()) +} diff --git a/chains/evm/listener/depositHandlers/erc721.go b/chains/evm/listener/depositHandlers/erc721.go new file mode 100644 index 00000000..34f6cb86 --- /dev/null +++ b/chains/evm/listener/depositHandlers/erc721.go @@ -0,0 +1,56 @@ +package depositHandlers + +import ( + "errors" + "math/big" + + "github.com/sygmaprotocol/sygma-core/relayer/message" + + "github.com/ChainSafe/sygma-relayer/chains" +) + +type Erc721DepositHandler struct{} + +// Erc721DepositHandler converts data pulled from ERC721 deposit event logs into message +func (dh *Erc721DepositHandler) HandleDeposit(sourceID, destId uint8, nonce uint64, resourceID [32]byte, calldata, handlerResponse []byte) (*message.Message, error) { + if len(calldata) < 64 { + err := errors.New("invalid calldata length: less than 84 bytes") + return nil, err + } + + // first 32 bytes are tokenId + tokenId := calldata[:32] + + // 32 - 64 is recipient address length + recipientAddressLength := big.NewInt(0).SetBytes(calldata[32:64]) + + // 64 - (64 + recipient address length) is recipient address + recipientAddress := calldata[64:(64 + recipientAddressLength.Int64())] + + // (64 + recipient address length) - ((64 + recipient address length) + 32) is metadata length + metadataLength := big.NewInt(0).SetBytes( + calldata[(64 + recipientAddressLength.Int64()):((64 + recipientAddressLength.Int64()) + 32)], + ) + // ((64 + recipient address length) + 32) - ((64 + recipient address length) + 32 + metadata length) is metadata + var metadata []byte + var metadataStart int64 + if metadataLength.Cmp(big.NewInt(0)) == 1 { + metadataStart = (64 + recipientAddressLength.Int64()) + 32 + metadata = calldata[metadataStart : metadataStart+metadataLength.Int64()] + } + // arbitrary metadata that will be most likely be used by the relayer + var meta map[string]interface{} + + payload := []interface{}{ + tokenId, + recipientAddress, + metadata, + } + + return chains.NewMessage(sourceID, destId, chains.TransferMessageData{ + DepositNonce: nonce, + ResourceId: resourceID, + Metadata: meta, + Payload: payload, + }, ERC721Transfer), nil +} diff --git a/chains/evm/listener/depositHandlers/erc721_test.go b/chains/evm/listener/depositHandlers/erc721_test.go new file mode 100644 index 00000000..faec3a29 --- /dev/null +++ b/chains/evm/listener/depositHandlers/erc721_test.go @@ -0,0 +1,186 @@ +package depositHandlers_test + +import ( + "math/big" + "testing" + + "github.com/ChainSafe/sygma-relayer/chains" + "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" + "github.com/ChainSafe/sygma-relayer/chains/evm/listener/depositHandlers" + "github.com/ChainSafe/sygma-relayer/e2e/evm" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/suite" + "github.com/sygmaprotocol/sygma-core/relayer/message" +) + +type Erc721HandlerTestSuite struct { + suite.Suite +} + +func TestRunErc721HandlerTestSuite(t *testing.T) { + suite.Run(t, new(Erc721HandlerTestSuite)) +} + +func (s *Erc721HandlerTestSuite) SetupSuite() {} +func (s *Erc721HandlerTestSuite) TearDownSuite() {} +func (s *Erc721HandlerTestSuite) SetupTest() {} +func (s *Erc721HandlerTestSuite) TearDownTest() {} + +func (s *Erc721HandlerTestSuite) TestErc721DepositHandlerEmptyMetadata() { + recipient := common.HexToAddress("0xf1e58fb17704c2da8479a533f9fad4ad0993ca6b") + + calldata := evm.ConstructErc721DepositData(recipient.Bytes(), big.NewInt(2), []byte{}) + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + tokenId := calldata[:32] + recipientAddressParsed := calldata[64:84] + var metadata []byte + + expected := &message.Message{ + Source: sourceID, + Destination: depositLog.DestinationDomainID, + Data: chains.TransferMessageData{ + DepositNonce: depositLog.DepositNonce, + ResourceId: depositLog.ResourceID, + Payload: []interface{}{ + tokenId, + recipientAddressParsed, + metadata, + }, + }, + + Type: depositHandlers.ERC721Transfer, + } + + erc721DepositHandler := depositHandlers.Erc721DepositHandler{} + m, err := erc721DepositHandler.HandleDeposit(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) + + s.Nil(err) + s.NotNil(m) + s.Equal(expected, m) +} + +func (s *Erc721HandlerTestSuite) TestErc721DepositHandlerIncorrectDataLen() { + metadata := []byte("0xdeadbeef") + + var calldata []byte + calldata = append(calldata, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 16)...) + calldata = append(calldata, metadata...) + + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + + erc721DepositHandler := depositHandlers.Erc721DepositHandler{} + m, err := erc721DepositHandler.HandleDeposit(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) + s.Nil(m) + s.EqualError(err, "invalid calldata length: less than 84 bytes") +} + +func (s *Erc721HandlerTestSuite) TestErc721DepositHandler() { + recipient := common.HexToAddress("0xf1e58fb17704c2da8479a533f9fad4ad0993ca6b") + metadata := []byte("metadata.url") + + calldata := evm.ConstructErc721DepositData(recipient.Bytes(), big.NewInt(2), metadata) + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + tokenId := calldata[:32] + recipientAddressParsed := calldata[64:84] + parsedMetadata := calldata[116:128] + + expected := &message.Message{ + Source: sourceID, + Destination: depositLog.DestinationDomainID, + Data: chains.TransferMessageData{ + DepositNonce: depositLog.DepositNonce, + ResourceId: depositLog.ResourceID, + Payload: []interface{}{ + tokenId, + recipientAddressParsed, + parsedMetadata, + }, + }, + + Type: depositHandlers.ERC721Transfer, + } + + erc721DepositHandler := depositHandlers.Erc721DepositHandler{} + m, err := erc721DepositHandler.HandleDeposit(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) + s.Nil(err) + s.NotNil(m) + s.Equal(expected, m) +} +func (s *Erc721HandlerTestSuite) TestErc721DepositHandlerWithPriority() { + recipient := common.HexToAddress("0xf1e58fb17704c2da8479a533f9fad4ad0993ca6b") + metadata := []byte("metadata.url") + + calldata := evm.ConstructErc721DepositData(recipient.Bytes(), big.NewInt(2), metadata) + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + tokenId := calldata[:32] + + // 32 - 64 is recipient address length + recipientAddressLength := big.NewInt(0).SetBytes(calldata[32:64]) + + // 64 - (64 + recipient address length) is recipient address + recipientAddressParsed := calldata[64:(64 + recipientAddressLength.Int64())] + + // (64 + recipient address length) - ((64 + recipient address length) + 32) is metadata length + metadataLength := big.NewInt(0).SetBytes( + calldata[(64 + recipientAddressLength.Int64()):((64 + recipientAddressLength.Int64()) + 32)], + ) + + metadataStart := (64 + recipientAddressLength.Int64()) + 32 + parsedMetadata := calldata[metadataStart : metadataStart+metadataLength.Int64()] + + expected := &message.Message{ + Source: sourceID, + Destination: depositLog.DestinationDomainID, + Data: chains.TransferMessageData{ + DepositNonce: depositLog.DepositNonce, + ResourceId: depositLog.ResourceID, + Payload: []interface{}{ + tokenId, + recipientAddressParsed, + parsedMetadata, + }, + }, + + Type: depositHandlers.ERC721Transfer, + } + + erc721DepositHandler := depositHandlers.Erc721DepositHandler{} + m, err := erc721DepositHandler.HandleDeposit(sourceID, depositLog.DestinationDomainID, depositLog.DepositNonce, depositLog.ResourceID, depositLog.Data, depositLog.HandlerResponse) + s.Nil(err) + s.NotNil(m) + s.Equal(expected, m) +} diff --git a/chains/evm/listener/depositHandlers/generic.go b/chains/evm/listener/depositHandlers/generic.go new file mode 100644 index 00000000..25632bf2 --- /dev/null +++ b/chains/evm/listener/depositHandlers/generic.go @@ -0,0 +1,34 @@ +package depositHandlers + +import ( + "errors" + "math/big" + + "github.com/ChainSafe/sygma-relayer/chains" + "github.com/sygmaprotocol/sygma-core/relayer/message" +) + +type GenericDepositHandler struct{} + +// GenericDepositHandler converts data pulled from generic deposit event logs into message +func (dh *GenericDepositHandler) HandleDeposit(sourceID, destId uint8, nonce uint64, resourceID [32]byte, calldata, handlerResponse []byte) (*message.Message, error) { + if len(calldata) < 32 { + err := errors.New("invalid calldata length: less than 32 bytes") + return nil, err + } + + // first 32 bytes are metadata length + metadataLen := big.NewInt(0).SetBytes(calldata[:32]) + metadata := calldata[32 : 32+metadataLen.Int64()] + payload := []interface{}{ + metadata, + } + + // generic handler has specific payload length and doesn't support arbitrary metadata + return chains.NewMessage(sourceID, destId, chains.TransferMessageData{ + DepositNonce: nonce, + ResourceId: resourceID, + Metadata: nil, + Payload: payload, + }, GenericTransfer), nil +} diff --git a/chains/evm/listener/depositHandlers/generic_test.go b/chains/evm/listener/depositHandlers/generic_test.go new file mode 100644 index 00000000..61e86daf --- /dev/null +++ b/chains/evm/listener/depositHandlers/generic_test.go @@ -0,0 +1,147 @@ +package depositHandlers_test + +import ( + "math/big" + "testing" + + "github.com/ChainSafe/sygma-relayer/chains" + "github.com/ChainSafe/sygma-relayer/e2e/evm" + "github.com/sygmaprotocol/sygma-core/relayer/message" + + "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" + "github.com/ChainSafe/sygma-relayer/chains/evm/listener/depositHandlers" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/suite" +) + +type GenericHandlerTestSuite struct { + suite.Suite +} + +func TestRunGenericHandlerTestSuite(t *testing.T) { + suite.Run(t, new(GenericHandlerTestSuite)) +} + +func (s *GenericHandlerTestSuite) SetupSuite() {} +func (s *GenericHandlerTestSuite) TearDownSuite() {} +func (s *GenericHandlerTestSuite) SetupTest() {} +func (s *GenericHandlerTestSuite) TearDownTest() {} + +func (s *GenericHandlerTestSuite) TestGenericHandleEventIncorrectDataLen() { + metadata := []byte("0xdeadbeef") + + var calldata []byte + calldata = append(calldata, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 16)...) + calldata = append(calldata, metadata...) + + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + + genericDepositHandler := depositHandlers.GenericDepositHandler{} + message, err := genericDepositHandler.HandleDeposit( + sourceID, + depositLog.DestinationDomainID, + depositLog.DepositNonce, + depositLog.ResourceID, + depositLog.Data, + depositLog.HandlerResponse, + ) + + s.Nil(message) + s.EqualError(err, "invalid calldata length: less than 32 bytes") +} + +func (s *GenericHandlerTestSuite) TestGenericHandleEventEmptyMetadata() { + metadata := []byte("") + calldata := evm.ConstructGenericDepositData(metadata) + + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + expected := &message.Message{ + Source: sourceID, + Destination: depositLog.DestinationDomainID, + Data: chains.TransferMessageData{ + DepositNonce: depositLog.DepositNonce, + ResourceId: depositLog.ResourceID, + Payload: []interface{}{ + metadata, + }, + }, + + Type: depositHandlers.GenericTransfer, + } + + genericDepositHandler := depositHandlers.GenericDepositHandler{} + message, err := genericDepositHandler.HandleDeposit( + sourceID, + depositLog.DestinationDomainID, + depositLog.DepositNonce, + depositLog.ResourceID, + depositLog.Data, + depositLog.HandlerResponse, + ) + + s.Nil(err) + s.NotNil(message) + s.Equal(message, expected) +} + +func (s *GenericHandlerTestSuite) TestGenericHandleEvent() { + metadata := []byte("0xdeadbeef") + calldata := evm.ConstructGenericDepositData(metadata) + + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x4CEEf6139f00F9F4535Ad19640Ff7A0137708485"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + expected := &message.Message{ + Source: sourceID, + Destination: depositLog.DestinationDomainID, + Data: chains.TransferMessageData{ + DepositNonce: depositLog.DepositNonce, + ResourceId: depositLog.ResourceID, + Payload: []interface{}{ + metadata, + }, + }, + + Type: depositHandlers.GenericTransfer, + } + + genericDepositHandler := depositHandlers.GenericDepositHandler{} + message, err := genericDepositHandler.HandleDeposit( + sourceID, + depositLog.DestinationDomainID, + depositLog.DepositNonce, + depositLog.ResourceID, + depositLog.Data, + depositLog.HandlerResponse, + ) + + s.Nil(err) + s.NotNil(message) + s.Equal(message, expected) +} diff --git a/chains/evm/listener/depositHandlers/permissionless.go b/chains/evm/listener/depositHandlers/permissionless.go new file mode 100644 index 00000000..6e4636f5 --- /dev/null +++ b/chains/evm/listener/depositHandlers/permissionless.go @@ -0,0 +1,53 @@ +package depositHandlers + +import ( + "errors" + "math/big" + + "github.com/ChainSafe/sygma-relayer/chains" + "github.com/sygmaprotocol/sygma-core/relayer/message" +) + +type PermissionlessGenericDepositHandler struct{} + +// GenericDepositHandler converts data pulled from generic deposit event logs into message +func (dh *PermissionlessGenericDepositHandler) HandleDeposit(sourceID, destId uint8, nonce uint64, resourceID [32]byte, calldata, handlerResponse []byte) (*message.Message, error) { + if len(calldata) < 76 { + err := errors.New("invalid calldata length: less than 76 bytes") + return nil, err + } + + maxFee := calldata[:32] + + functionSigLen := big.NewInt(0).SetBytes(calldata[32:34]) + functionSigEnd := 34 + functionSigLen.Int64() + functionSig := calldata[34:functionSigEnd] + + contractAddressLen := big.NewInt(0).SetBytes(calldata[functionSigEnd : functionSigEnd+1]) + contractAddressEnd := functionSigEnd + 1 + contractAddressLen.Int64() + contractAddress := calldata[functionSigEnd+1 : contractAddressEnd] + + depositorLen := big.NewInt(0).SetBytes(calldata[contractAddressEnd : contractAddressEnd+1]) + depositorEnd := contractAddressEnd + 1 + depositorLen.Int64() + depositorAddress := calldata[contractAddressEnd+1 : depositorEnd] + executionData := calldata[depositorEnd:] + + payload := []interface{}{ + functionSig, + contractAddress, + maxFee, + depositorAddress, + executionData, + } + + metadata := make(map[string]interface{}) + + metadata["gasLimit"] = uint64(big.NewInt(0).SetBytes(maxFee).Int64()) + + return chains.NewMessage(sourceID, destId, chains.TransferMessageData{ + DepositNonce: nonce, + ResourceId: resourceID, + Metadata: metadata, + Payload: payload, + }, PermissionlessGenericTransfer), nil +} diff --git a/chains/evm/listener/depositHandlers/permissionless_test.go b/chains/evm/listener/depositHandlers/permissionless_test.go new file mode 100644 index 00000000..81eeff62 --- /dev/null +++ b/chains/evm/listener/depositHandlers/permissionless_test.go @@ -0,0 +1,120 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +package depositHandlers_test + +import ( + "encoding/hex" + "math/big" + "testing" + + "github.com/sygmaprotocol/sygma-core/relayer/message" + + "github.com/ChainSafe/sygma-relayer/chains" + "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" + "github.com/ChainSafe/sygma-relayer/e2e/evm" + + "github.com/ChainSafe/sygma-relayer/chains/evm/listener/depositHandlers" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/suite" +) + +type PermissionlessGenericHandlerTestSuite struct { + suite.Suite +} + +func TestRunPermissionlessGenericHandlerTestSuite(t *testing.T) { + suite.Run(t, new(PermissionlessGenericHandlerTestSuite)) +} + +func (s *PermissionlessGenericHandlerTestSuite) TestHandleEvent() { + hash := []byte("0xhash") + functionSig, _ := hex.DecodeString("654cf88c") + contractAddress := common.HexToAddress("0x02091EefF969b33A5CE8A729DaE325879bf76f90") + depositor := common.HexToAddress("0x5C1F5961696BaD2e73f73417f07EF55C62a2dC5b") + maxFee := big.NewInt(200000) + var executionData []byte + executionData = append(executionData, hash[:]...) + metadata := make(map[string]interface{}) + metadata["gasLimit"] = uint64(200000) + + calldata := evm.ConstructPermissionlessGenericDepositData( + hash[:], + functionSig, + contractAddress.Bytes(), + depositor.Bytes(), + maxFee, + ) + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x5C1F5961696BaD2e73f73417f07EF55C62a2dC5b"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + expected := &message.Message{ + Source: sourceID, + Destination: depositLog.DestinationDomainID, + Data: chains.TransferMessageData{ + DepositNonce: depositLog.DepositNonce, + ResourceId: depositLog.ResourceID, + Payload: []interface{}{ + functionSig, + contractAddress.Bytes(), + common.LeftPadBytes(maxFee.Bytes(), 32), + depositor.Bytes(), + executionData, + }, + Metadata: metadata, + }, + Type: depositHandlers.PermissionlessGenericTransfer, + } + + permissionlessGenericHandler := depositHandlers.PermissionlessGenericDepositHandler{} + + message, err := permissionlessGenericHandler.HandleDeposit( + sourceID, + depositLog.DestinationDomainID, + depositLog.DepositNonce, + depositLog.ResourceID, + depositLog.Data, + depositLog.HandlerResponse, + ) + + s.Nil(err) + s.NotNil(message) + s.Equal(message, expected) +} + +func (s *PermissionlessGenericHandlerTestSuite) Test_HandleEvent_IncorrectDataLen() { + metadata := make(map[string]interface{}) + metadata["gasLimit"] = uint64(200000) + var calldata []byte + calldata = append(calldata, math.PaddedBigBytes(big.NewInt(int64(len(metadata))), 32)...) + depositLog := &events.Deposit{ + DestinationDomainID: 0, + ResourceID: [32]byte{0}, + DepositNonce: 1, + SenderAddress: common.HexToAddress("0x5C1F5961696BaD2e73f73417f07EF55C62a2dC5b"), + Data: calldata, + HandlerResponse: []byte{}, + } + + sourceID := uint8(1) + + permissionlessGenericHandler := depositHandlers.PermissionlessGenericDepositHandler{} + _, err := permissionlessGenericHandler.HandleDeposit( + sourceID, + depositLog.DestinationDomainID, + depositLog.DepositNonce, + depositLog.ResourceID, + depositLog.Data, + depositLog.HandlerResponse, + ) + + s.NotNil(err) +} diff --git a/chains/evm/listener/event-handler_test.go b/chains/evm/listener/event-handler_test.go deleted file mode 100644 index 33a228fd..00000000 --- a/chains/evm/listener/event-handler_test.go +++ /dev/null @@ -1,221 +0,0 @@ -// The Licensed Work is (c) 2022 Sygma -// SPDX-License-Identifier: LGPL-3.0-only - -package listener_test - -import ( - "fmt" - "math/big" - "testing" - - "github.com/rs/zerolog/log" - - "github.com/ethereum/go-ethereum/common" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/suite" - - coreEvents "github.com/ChainSafe/chainbridge-core/chains/evm/calls/events" - "github.com/ChainSafe/chainbridge-core/relayer/message" - "github.com/ChainSafe/chainbridge-core/types" - - "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" - "github.com/ChainSafe/sygma-relayer/chains/evm/listener" - mock_listener "github.com/ChainSafe/sygma-relayer/chains/evm/listener/mock" - mock_coreListener "github.com/ChainSafe/sygma-relayer/chains/evm/listener/mock/core" -) - -type RetryEventHandlerTestSuite struct { - suite.Suite - retryEventHandler *listener.RetryEventHandler - mockDepositHandler *mock_coreListener.MockDepositHandler - mockEventListener *mock_listener.MockEventListener - domainID uint8 -} - -func TestRunRetryEventHandlerTestSuite(t *testing.T) { - suite.Run(t, new(RetryEventHandlerTestSuite)) -} - -func (s *RetryEventHandlerTestSuite) SetupTest() { - ctrl := gomock.NewController(s.T()) - s.domainID = 1 - s.mockEventListener = mock_listener.NewMockEventListener(ctrl) - s.mockDepositHandler = mock_coreListener.NewMockDepositHandler(ctrl) - s.retryEventHandler = listener.NewRetryEventHandler(log.With(), s.mockEventListener, s.mockDepositHandler, common.Address{}, s.domainID, big.NewInt(5)) -} - -func (s *RetryEventHandlerTestSuite) Test_FetchDepositFails() { - s.mockEventListener.EXPECT().FetchRetryEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]events.RetryEvent{}, fmt.Errorf("error")) - - msgChan := make(chan []*message.Message, 1) - err := s.retryEventHandler.HandleEvent(big.NewInt(0), big.NewInt(5), msgChan) - - s.NotNil(err) - s.Equal(len(msgChan), 0) -} - -func (s *RetryEventHandlerTestSuite) Test_FetchDepositFails_ExecutionContinues() { - d := coreEvents.Deposit{ - DepositNonce: 2, - DestinationDomainID: 2, - ResourceID: types.ResourceID{}, - HandlerResponse: []byte{}, - Data: []byte{}, - } - s.mockEventListener.EXPECT().FetchRetryEvents( - gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - ).Return([]events.RetryEvent{{TxHash: "event1"}, {TxHash: "event2"}}, nil) - s.mockEventListener.EXPECT().FetchDepositEvent(events.RetryEvent{TxHash: "event1"}, gomock.Any(), big.NewInt(5)).Return([]coreEvents.Deposit{}, fmt.Errorf("error")) - s.mockEventListener.EXPECT().FetchDepositEvent(events.RetryEvent{TxHash: "event2"}, gomock.Any(), big.NewInt(5)).Return([]coreEvents.Deposit{d}, nil) - s.mockDepositHandler.EXPECT().HandleDeposit( - s.domainID, - d.DestinationDomainID, - d.DepositNonce, - d.ResourceID, - d.Data, - d.HandlerResponse, - ).Return(&message.Message{DepositNonce: 2}, nil) - - msgChan := make(chan []*message.Message, 2) - err := s.retryEventHandler.HandleEvent(big.NewInt(0), big.NewInt(5), msgChan) - msgs := <-msgChan - - s.Nil(err) - s.Equal(msgs, []*message.Message{{DepositNonce: 2}}) -} - -func (s *RetryEventHandlerTestSuite) Test_HandleDepositFails_ExecutionContinues() { - d1 := coreEvents.Deposit{ - DepositNonce: 1, - DestinationDomainID: 2, - ResourceID: types.ResourceID{}, - HandlerResponse: []byte{}, - Data: []byte{}, - } - d2 := coreEvents.Deposit{ - DepositNonce: 2, - DestinationDomainID: 2, - ResourceID: types.ResourceID{}, - HandlerResponse: []byte{}, - Data: []byte{}, - } - s.mockEventListener.EXPECT().FetchRetryEvents( - gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - ).Return([]events.RetryEvent{{TxHash: "event1"}, {TxHash: "event2"}}, nil) - s.mockEventListener.EXPECT().FetchDepositEvent(events.RetryEvent{TxHash: "event1"}, gomock.Any(), big.NewInt(5)).Return([]coreEvents.Deposit{d1}, nil) - s.mockEventListener.EXPECT().FetchDepositEvent(events.RetryEvent{TxHash: "event2"}, gomock.Any(), big.NewInt(5)).Return([]coreEvents.Deposit{d2}, nil) - s.mockDepositHandler.EXPECT().HandleDeposit( - s.domainID, - d1.DestinationDomainID, - d1.DepositNonce, - d1.ResourceID, - d1.Data, - d1.HandlerResponse, - ).Return(&message.Message{DepositNonce: 1}, fmt.Errorf("error")) - s.mockDepositHandler.EXPECT().HandleDeposit( - s.domainID, - d2.DestinationDomainID, - d2.DepositNonce, - d2.ResourceID, - d2.Data, - d2.HandlerResponse, - ).Return(&message.Message{DepositNonce: 2}, nil) - - msgChan := make(chan []*message.Message, 2) - err := s.retryEventHandler.HandleEvent(big.NewInt(0), big.NewInt(5), msgChan) - msgs := <-msgChan - - s.Nil(err) - s.Equal(msgs, []*message.Message{{DepositNonce: 2}}) -} - -func (s *RetryEventHandlerTestSuite) Test_HandlingRetryPanics_ExecutionContinue() { - d1 := coreEvents.Deposit{ - DepositNonce: 1, - DestinationDomainID: 2, - ResourceID: types.ResourceID{}, - HandlerResponse: []byte{}, - Data: []byte{}, - } - d2 := coreEvents.Deposit{ - DepositNonce: 2, - DestinationDomainID: 2, - ResourceID: types.ResourceID{}, - HandlerResponse: []byte{}, - Data: []byte{}, - } - s.mockEventListener.EXPECT().FetchRetryEvents( - gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - ).Return([]events.RetryEvent{{TxHash: "event1"}, {TxHash: "event2"}}, nil) - s.mockEventListener.EXPECT().FetchDepositEvent(events.RetryEvent{TxHash: "event1"}, gomock.Any(), big.NewInt(5)).Return([]coreEvents.Deposit{d1}, nil) - s.mockEventListener.EXPECT().FetchDepositEvent(events.RetryEvent{TxHash: "event2"}, gomock.Any(), big.NewInt(5)).Return([]coreEvents.Deposit{d2}, nil) - s.mockDepositHandler.EXPECT().HandleDeposit( - s.domainID, - d1.DestinationDomainID, - d1.DepositNonce, - d1.ResourceID, - d1.Data, - d1.HandlerResponse, - ).Do(func(sourceID, destID, nonce, resourceID, calldata, handlerResponse interface{}) { - panic("error") - }) - s.mockDepositHandler.EXPECT().HandleDeposit( - s.domainID, - d2.DestinationDomainID, - d2.DepositNonce, - d2.ResourceID, - d2.Data, - d2.HandlerResponse, - ).Return(&message.Message{DepositNonce: 2}, nil) - - msgChan := make(chan []*message.Message, 2) - err := s.retryEventHandler.HandleEvent(big.NewInt(0), big.NewInt(5), msgChan) - msgs := <-msgChan - - s.Nil(err) - s.Equal(msgs, []*message.Message{{DepositNonce: 2}}) -} - -func (s *RetryEventHandlerTestSuite) Test_MultipleDeposits() { - d1 := coreEvents.Deposit{ - DepositNonce: 1, - DestinationDomainID: 2, - ResourceID: types.ResourceID{}, - HandlerResponse: []byte{}, - Data: []byte{}, - } - d2 := coreEvents.Deposit{ - DepositNonce: 2, - DestinationDomainID: 2, - ResourceID: types.ResourceID{}, - HandlerResponse: []byte{}, - Data: []byte{}, - } - s.mockEventListener.EXPECT().FetchRetryEvents( - gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - ).Return([]events.RetryEvent{{TxHash: "event1"}}, nil) - s.mockEventListener.EXPECT().FetchDepositEvent(events.RetryEvent{TxHash: "event1"}, gomock.Any(), big.NewInt(5)).Return([]coreEvents.Deposit{d1, d2}, nil) - s.mockDepositHandler.EXPECT().HandleDeposit( - s.domainID, - d1.DestinationDomainID, - d1.DepositNonce, - d1.ResourceID, - d1.Data, - d1.HandlerResponse, - ).Return(&message.Message{DepositNonce: 1}, nil) - s.mockDepositHandler.EXPECT().HandleDeposit( - s.domainID, - d2.DestinationDomainID, - d2.DepositNonce, - d2.ResourceID, - d2.Data, - d2.HandlerResponse, - ).Return(&message.Message{DepositNonce: 2}, nil) - - msgChan := make(chan []*message.Message, 2) - err := s.retryEventHandler.HandleEvent(big.NewInt(0), big.NewInt(5), msgChan) - msgs := <-msgChan - - s.Nil(err) - s.Equal(msgs, []*message.Message{{DepositNonce: 1}, {DepositNonce: 2}}) -} diff --git a/chains/evm/listener/event-handler.go b/chains/evm/listener/eventHandlers/event-handler.go similarity index 71% rename from chains/evm/listener/event-handler.go rename to chains/evm/listener/eventHandlers/event-handler.go index 9b838f00..9b9f90cc 100644 --- a/chains/evm/listener/event-handler.go +++ b/chains/evm/listener/eventHandlers/event-handler.go @@ -1,7 +1,7 @@ // The Licensed Work is (c) 2022 Sygma // SPDX-License-Identifier: LGPL-3.0-only -package listener +package eventHandlers import ( "context" @@ -10,14 +10,13 @@ import ( "strings" "github.com/rs/zerolog" + "github.com/rs/zerolog/log" - "github.com/ChainSafe/chainbridge-core/chains/evm/calls/events" - "github.com/ChainSafe/chainbridge-core/chains/evm/listener" - "github.com/ChainSafe/chainbridge-core/relayer/message" "github.com/ChainSafe/sygma-relayer/chains/evm/calls/consts" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/sygmaprotocol/sygma-core/relayer/message" - hubEvents "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" + "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" "github.com/ChainSafe/sygma-relayer/comm" "github.com/ChainSafe/sygma-relayer/comm/p2p" "github.com/ChainSafe/sygma-relayer/topology" @@ -31,28 +30,31 @@ import ( type EventListener interface { FetchKeygenEvents(ctx context.Context, address common.Address, startBlock *big.Int, endBlock *big.Int) ([]ethTypes.Log, error) - FetchRefreshEvents(ctx context.Context, address common.Address, startBlock *big.Int, endBlock *big.Int) ([]*hubEvents.Refresh, error) - FetchRetryEvents(ctx context.Context, contractAddress common.Address, startBlock *big.Int, endBlock *big.Int) ([]hubEvents.RetryEvent, error) - FetchDepositEvent(event hubEvents.RetryEvent, bridgeAddress common.Address, blockConfirmations *big.Int) ([]events.Deposit, error) + FetchRefreshEvents(ctx context.Context, address common.Address, startBlock *big.Int, endBlock *big.Int) ([]*events.Refresh, error) + FetchRetryEvents(ctx context.Context, contractAddress common.Address, startBlock *big.Int, endBlock *big.Int) ([]events.RetryEvent, error) + FetchRetryDepositEvents(event events.RetryEvent, bridgeAddress common.Address, blockConfirmations *big.Int) ([]events.Deposit, error) + FetchDeposits(ctx context.Context, address common.Address, startBlock *big.Int, endBlock *big.Int) ([]*events.Deposit, error) } type RetryEventHandler struct { log zerolog.Logger eventListener EventListener - depositHandler listener.DepositHandler + depositHandler DepositHandler bridgeAddress common.Address bridgeABI abi.ABI domainID uint8 blockConfirmations *big.Int + msgChan chan []*message.Message } func NewRetryEventHandler( logC zerolog.Context, eventListener EventListener, - depositHandler listener.DepositHandler, + depositHandler DepositHandler, bridgeAddress common.Address, domainID uint8, blockConfirmations *big.Int, + msgChan chan []*message.Message, ) *RetryEventHandler { bridgeABI, _ := abi.JSON(strings.NewReader(consts.BridgeABI)) return &RetryEventHandler{ @@ -63,13 +65,13 @@ func NewRetryEventHandler( bridgeABI: bridgeABI, domainID: domainID, blockConfirmations: blockConfirmations, + msgChan: msgChan, } } -func (eh *RetryEventHandler) HandleEvent( +func (eh *RetryEventHandler) HandleEvents( startBlock *big.Int, endBlock *big.Int, - msgChan chan []*message.Message, ) error { retryEvents, err := eh.eventListener.FetchRetryEvents(context.Background(), eh.bridgeAddress, startBlock, endBlock) if err != nil { @@ -78,14 +80,14 @@ func (eh *RetryEventHandler) HandleEvent( retriesByDomain := make(map[uint8][]*message.Message) for _, event := range retryEvents { - func(event hubEvents.RetryEvent) { + func(event events.RetryEvent) { defer func() { if r := recover(); r != nil { eh.log.Error().Err(err).Msgf("panic occured while handling retry event %+v", event) } }() - deposits, err := eh.eventListener.FetchDepositEvent(event, eh.bridgeAddress, eh.blockConfirmations) + deposits, err := eh.eventListener.FetchRetryDepositEvents(event, eh.bridgeAddress, eh.blockConfirmations) if err != nil { eh.log.Error().Err(err).Msgf("Unable to fetch deposit events from event %+v", event) return @@ -110,7 +112,7 @@ func (eh *RetryEventHandler) HandleEvent( } for _, retries := range retriesByDomain { - msgChan <- retries + eh.msgChan <- retries } return nil @@ -149,10 +151,9 @@ func NewKeygenEventHandler( } } -func (eh *KeygenEventHandler) HandleEvent( +func (eh *KeygenEventHandler) HandleEvents( startBlock *big.Int, endBlock *big.Int, - msgChan chan []*message.Message, ) error { key, err := eh.storer.GetKeyshare() if (key.Threshold != 0) && (err == nil) { @@ -224,10 +225,9 @@ func NewRefreshEventHandler( // HandleEvent fetches refresh events and in case of an event retrieves and stores the latest topology // and starts a resharing tss process -func (eh *RefreshEventHandler) HandleEvent( +func (eh *RefreshEventHandler) HandleEvents( startBlock *big.Int, endBlock *big.Int, - msgChan chan []*message.Message, ) error { refreshEvents, err := eh.eventListener.FetchRefreshEvents( context.Background(), eh.bridgeAddress, startBlock, endBlock, @@ -268,3 +268,60 @@ func (eh *RefreshEventHandler) HandleEvent( func (eh *RefreshEventHandler) sessionID(block *big.Int) string { return fmt.Sprintf("resharing-%s", block.String()) } + +type DepositHandler interface { + HandleDeposit(sourceID, destID uint8, nonce uint64, resourceID [32]byte, calldata, handlerResponse []byte) (*message.Message, error) +} + +type DepositEventHandler struct { + eventListener EventListener + depositHandler DepositHandler + bridgeAddress common.Address + domainID uint8 + msgChan chan []*message.Message +} + +func NewDepositEventHandler(eventListener EventListener, depositHandler DepositHandler, bridgeAddress common.Address, domainID uint8, msgChan chan []*message.Message) *DepositEventHandler { + return &DepositEventHandler{ + eventListener: eventListener, + depositHandler: depositHandler, + bridgeAddress: bridgeAddress, + domainID: domainID, + msgChan: msgChan, + } +} + +func (eh *DepositEventHandler) HandleEvents(startBlock *big.Int, endBlock *big.Int) error { + deposits, err := eh.eventListener.FetchDeposits(context.Background(), eh.bridgeAddress, startBlock, endBlock) + if err != nil { + return fmt.Errorf("unable to fetch deposit events because of: %+v", err) + } + + domainDeposits := make(map[uint8][]*message.Message) + for _, d := range deposits { + func(d *events.Deposit) { + defer func() { + if r := recover(); r != nil { + log.Error().Err(err).Msgf("panic occured while handling deposit %+v", d) + } + }() + + m, err := eh.depositHandler.HandleDeposit(eh.domainID, d.DestinationDomainID, d.DepositNonce, d.ResourceID, d.Data, d.HandlerResponse) + if err != nil { + log.Error().Err(err).Str("start block", startBlock.String()).Str("end block", endBlock.String()).Uint8("domainID", eh.domainID).Msgf("%v", err) + return + } + + log.Debug().Msgf("Resolved message %+v in block range: %s-%s", m, startBlock.String(), endBlock.String()) + domainDeposits[m.Destination] = append(domainDeposits[m.Destination], m) + }(d) + } + + for _, deposits := range domainDeposits { + go func(d []*message.Message) { + eh.msgChan <- d + }(deposits) + } + + return nil +} diff --git a/chains/evm/listener/eventHandlers/event-handler_test.go b/chains/evm/listener/eventHandlers/event-handler_test.go new file mode 100644 index 00000000..21cfe962 --- /dev/null +++ b/chains/evm/listener/eventHandlers/event-handler_test.go @@ -0,0 +1,412 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +package eventHandlers_test + +import ( + "fmt" + "math/big" + "testing" + + "github.com/rs/zerolog/log" + + "github.com/ethereum/go-ethereum/common" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/suite" + + "github.com/ChainSafe/sygma-relayer/chains" + "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/eventHandlers" + mock_listener "github.com/ChainSafe/sygma-relayer/chains/evm/listener/eventHandlers/mock" + "github.com/sygmaprotocol/sygma-core/relayer/message" +) + +type RetryEventHandlerTestSuite struct { + suite.Suite + retryEventHandler *eventHandlers.RetryEventHandler + mockDepositHandler *mock_listener.MockDepositHandler + mockEventListener *mock_listener.MockEventListener + domainID uint8 + msgChan chan []*message.Message +} + +func TestRunRetryEventHandlerTestSuite(t *testing.T) { + suite.Run(t, new(RetryEventHandlerTestSuite)) +} + +func (s *RetryEventHandlerTestSuite) SetupTest() { + ctrl := gomock.NewController(s.T()) + s.domainID = 1 + s.mockEventListener = mock_listener.NewMockEventListener(ctrl) + s.mockDepositHandler = mock_listener.NewMockDepositHandler(ctrl) + s.msgChan = make(chan []*message.Message, 2) + s.retryEventHandler = eventHandlers.NewRetryEventHandler(log.With(), s.mockEventListener, s.mockDepositHandler, common.Address{}, s.domainID, big.NewInt(5), s.msgChan) +} + +func (s *RetryEventHandlerTestSuite) Test_FetchDepositFails() { + s.mockEventListener.EXPECT().FetchRetryEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]events.RetryEvent{}, fmt.Errorf("error")) + + err := s.retryEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + + s.NotNil(err) + s.Equal(len(s.msgChan), 0) +} + +func (s *RetryEventHandlerTestSuite) Test_FetchDepositFails_ExecutionContinues() { + d := events.Deposit{ + DepositNonce: 2, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + s.mockEventListener.EXPECT().FetchRetryEvents( + gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + ).Return([]events.RetryEvent{{TxHash: "event1"}, {TxHash: "event2"}}, nil) + s.mockEventListener.EXPECT().FetchRetryDepositEvents(events.RetryEvent{TxHash: "event1"}, gomock.Any(), big.NewInt(5)).Return([]events.Deposit{}, fmt.Errorf("error")) + s.mockEventListener.EXPECT().FetchRetryDepositEvents(events.RetryEvent{TxHash: "event2"}, gomock.Any(), big.NewInt(5)).Return([]events.Deposit{d}, nil) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d.DestinationDomainID, + d.DepositNonce, + d.ResourceID, + d.Data, + d.HandlerResponse, + ).Return(&message.Message{ + Data: executor.TransferMessageData{ + DepositNonce: 2, + }, + }, nil) + + err := s.retryEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + msgs := <-s.msgChan + + s.Nil(err) + s.Equal(msgs, []*message.Message{{Data: executor.TransferMessageData{ + DepositNonce: 2, + }}}) +} + +func (s *RetryEventHandlerTestSuite) Test_HandleDepositFails_ExecutionContinues() { + d1 := events.Deposit{ + DepositNonce: 1, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + d2 := events.Deposit{ + DepositNonce: 2, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + s.mockEventListener.EXPECT().FetchRetryEvents( + gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + ).Return([]events.RetryEvent{{TxHash: "event1"}, {TxHash: "event2"}}, nil) + s.mockEventListener.EXPECT().FetchRetryDepositEvents(events.RetryEvent{TxHash: "event1"}, gomock.Any(), big.NewInt(5)).Return([]events.Deposit{d1}, nil) + s.mockEventListener.EXPECT().FetchRetryDepositEvents(events.RetryEvent{TxHash: "event2"}, gomock.Any(), big.NewInt(5)).Return([]events.Deposit{d2}, nil) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d1.DestinationDomainID, + d1.DepositNonce, + d1.ResourceID, + d1.Data, + d1.HandlerResponse, + ).Return(&message.Message{Data: executor.TransferMessageData{ + DepositNonce: 1, + }}, fmt.Errorf("error")) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d2.DestinationDomainID, + d2.DepositNonce, + d2.ResourceID, + d2.Data, + d2.HandlerResponse, + ).Return(&message.Message{Data: executor.TransferMessageData{ + DepositNonce: 2, + }}, nil) + + err := s.retryEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + msgs := <-s.msgChan + + s.Nil(err) + s.Equal(msgs, []*message.Message{{Data: executor.TransferMessageData{ + DepositNonce: 2, + }}}) +} + +func (s *RetryEventHandlerTestSuite) Test_HandlingRetryPanics_ExecutionContinue() { + d1 := events.Deposit{ + DepositNonce: 1, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + d2 := events.Deposit{ + DepositNonce: 2, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + s.mockEventListener.EXPECT().FetchRetryEvents( + gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + ).Return([]events.RetryEvent{{TxHash: "event1"}, {TxHash: "event2"}}, nil) + s.mockEventListener.EXPECT().FetchRetryDepositEvents(events.RetryEvent{TxHash: "event1"}, gomock.Any(), big.NewInt(5)).Return([]events.Deposit{d1}, nil) + s.mockEventListener.EXPECT().FetchRetryDepositEvents(events.RetryEvent{TxHash: "event2"}, gomock.Any(), big.NewInt(5)).Return([]events.Deposit{d2}, nil) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d1.DestinationDomainID, + d1.DepositNonce, + d1.ResourceID, + d1.Data, + d1.HandlerResponse, + ).Do(func(sourceID, destID, nonce, resourceID, calldata, handlerResponse interface{}) { + panic("error") + }) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d2.DestinationDomainID, + d2.DepositNonce, + d2.ResourceID, + d2.Data, + d2.HandlerResponse, + ).Return(&message.Message{Data: executor.TransferMessageData{ + DepositNonce: 2, + }}, nil) + + err := s.retryEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + msgs := <-s.msgChan + + s.Nil(err) + s.Equal(msgs, []*message.Message{{Data: executor.TransferMessageData{ + DepositNonce: 2, + }}}) +} + +func (s *RetryEventHandlerTestSuite) Test_MultipleDeposits() { + d1 := events.Deposit{ + DepositNonce: 1, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + d2 := events.Deposit{ + DepositNonce: 2, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + s.mockEventListener.EXPECT().FetchRetryEvents( + gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + ).Return([]events.RetryEvent{{TxHash: "event1"}}, nil) + s.mockEventListener.EXPECT().FetchRetryDepositEvents(events.RetryEvent{TxHash: "event1"}, gomock.Any(), big.NewInt(5)).Return([]events.Deposit{d1, d2}, nil) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d1.DestinationDomainID, + d1.DepositNonce, + d1.ResourceID, + d1.Data, + d1.HandlerResponse, + ).Return(&message.Message{Data: executor.TransferMessageData{ + DepositNonce: 1, + }}, nil) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d2.DestinationDomainID, + d2.DepositNonce, + d2.ResourceID, + d2.Data, + d2.HandlerResponse, + ).Return(&message.Message{Data: executor.TransferMessageData{ + DepositNonce: 2, + }}, nil) + + err := s.retryEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + msgs := <-s.msgChan + + s.Nil(err) + s.Equal(msgs, []*message.Message{{Data: executor.TransferMessageData{ + DepositNonce: 1, + }}, {Data: executor.TransferMessageData{ + DepositNonce: 2, + }}}) +} + +type DepositHandlerTestSuite struct { + suite.Suite + depositEventHandler *eventHandlers.DepositEventHandler + mockDepositHandler *mock_listener.MockDepositHandler + mockEventListener *mock_listener.MockEventListener + domainID uint8 + msgChan chan []*message.Message +} + +func TestRunDepositHandlerTestSuite(t *testing.T) { + suite.Run(t, new(DepositHandlerTestSuite)) +} + +func (s *DepositHandlerTestSuite) SetupTest() { + ctrl := gomock.NewController(s.T()) + s.domainID = 1 + s.mockEventListener = mock_listener.NewMockEventListener(ctrl) + s.mockDepositHandler = mock_listener.NewMockDepositHandler(ctrl) + s.msgChan = make(chan []*message.Message, 2) + s.depositEventHandler = eventHandlers.NewDepositEventHandler(s.mockEventListener, s.mockDepositHandler, common.Address{}, s.domainID, s.msgChan) +} + +func (s *DepositHandlerTestSuite) Test_FetchDepositFails() { + s.mockEventListener.EXPECT().FetchDeposits(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]*events.Deposit{}, fmt.Errorf("error")) + + err := s.depositEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + + s.NotNil(err) + s.Equal(len(s.msgChan), 0) +} + +func (s *DepositHandlerTestSuite) Test_HandleDepositFails_ExecutionContinue() { + d1 := &events.Deposit{ + DepositNonce: 1, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + d2 := &events.Deposit{ + DepositNonce: 2, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + deposits := []*events.Deposit{d1, d2} + s.mockEventListener.EXPECT().FetchDeposits(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(deposits, nil) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d1.DestinationDomainID, + d1.DepositNonce, + d1.ResourceID, + d1.Data, + d1.HandlerResponse, + ).Return(&message.Message{}, fmt.Errorf("error")) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d2.DestinationDomainID, + d2.DepositNonce, + d2.ResourceID, + d2.Data, + d2.HandlerResponse, + ).Return( + &message.Message{ + Data: chains.TransferMessageData{ + DepositNonce: 2, + }, + }, + nil, + ) + + err := s.depositEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + msgs := <-s.msgChan + + s.Nil(err) + s.Equal(msgs, []*message.Message{{Data: chains.TransferMessageData{DepositNonce: 2}}}) +} + +func (s *DepositHandlerTestSuite) Test_HandleDepositPanis_ExecutionContinues() { + d1 := &events.Deposit{ + DepositNonce: 1, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + d2 := &events.Deposit{ + DepositNonce: 2, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + deposits := []*events.Deposit{d1, d2} + s.mockEventListener.EXPECT().FetchDeposits(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(deposits, nil) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d1.DestinationDomainID, + d1.DepositNonce, + d1.ResourceID, + d1.Data, + d1.HandlerResponse, + ).Do(func(sourceID, destID, nonce, resourceID, calldata, handlerResponse interface{}) { + panic("error") + }) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d2.DestinationDomainID, + d2.DepositNonce, + d2.ResourceID, + d2.Data, + d2.HandlerResponse, + ).Return( + &message.Message{Data: chains.TransferMessageData{DepositNonce: 2}}, + nil, + ) + + err := s.depositEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + msgs := <-s.msgChan + + s.Nil(err) + s.Equal(msgs, []*message.Message{{Data: chains.TransferMessageData{DepositNonce: 2}}}) +} + +func (s *DepositHandlerTestSuite) Test_SuccessfulHandleDeposit() { + d1 := &events.Deposit{ + DepositNonce: 1, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + d2 := &events.Deposit{ + DepositNonce: 2, + DestinationDomainID: 2, + ResourceID: [32]byte{}, + HandlerResponse: []byte{}, + Data: []byte{}, + } + deposits := []*events.Deposit{d1, d2} + s.mockEventListener.EXPECT().FetchDeposits(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(deposits, nil) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d1.DestinationDomainID, + d1.DepositNonce, + d1.ResourceID, + d1.Data, + d1.HandlerResponse, + ).Return( + &message.Message{Data: chains.TransferMessageData{DepositNonce: 1}}, + nil, + ) + s.mockDepositHandler.EXPECT().HandleDeposit( + s.domainID, + d2.DestinationDomainID, + d2.DepositNonce, + d2.ResourceID, + d2.Data, + d2.HandlerResponse, + ).Return( + &message.Message{Data: chains.TransferMessageData{DepositNonce: 2}}, + nil, + ) + + err := s.depositEventHandler.HandleEvents(big.NewInt(0), big.NewInt(5)) + msgs := <-s.msgChan + + s.Nil(err) + s.Equal(msgs, []*message.Message{{Data: chains.TransferMessageData{DepositNonce: 1}}, {Data: chains.TransferMessageData{DepositNonce: 2}}}) +} diff --git a/chains/evm/listener/eventHandlers/mock/listener.go b/chains/evm/listener/eventHandlers/mock/listener.go new file mode 100644 index 00000000..4180094e --- /dev/null +++ b/chains/evm/listener/eventHandlers/mock/listener.go @@ -0,0 +1,153 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./chains/evm/listener/eventHandlers/event-handler.go + +// Package mock_eventHandlers is a generated GoMock package. +package mock_eventHandlers + +import ( + context "context" + big "math/big" + reflect "reflect" + + events "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" + common "github.com/ethereum/go-ethereum/common" + types "github.com/ethereum/go-ethereum/core/types" + gomock "github.com/golang/mock/gomock" + message "github.com/sygmaprotocol/sygma-core/relayer/message" +) + +// MockEventListener is a mock of EventListener interface. +type MockEventListener struct { + ctrl *gomock.Controller + recorder *MockEventListenerMockRecorder +} + +// MockEventListenerMockRecorder is the mock recorder for MockEventListener. +type MockEventListenerMockRecorder struct { + mock *MockEventListener +} + +// NewMockEventListener creates a new mock instance. +func NewMockEventListener(ctrl *gomock.Controller) *MockEventListener { + mock := &MockEventListener{ctrl: ctrl} + mock.recorder = &MockEventListenerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEventListener) EXPECT() *MockEventListenerMockRecorder { + return m.recorder +} + +// FetchDeposits mocks base method. +func (m *MockEventListener) FetchDeposits(ctx context.Context, address common.Address, startBlock, endBlock *big.Int) ([]*events.Deposit, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchDeposits", ctx, address, startBlock, endBlock) + ret0, _ := ret[0].([]*events.Deposit) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchDeposits indicates an expected call of FetchDeposits. +func (mr *MockEventListenerMockRecorder) FetchDeposits(ctx, address, startBlock, endBlock interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchDeposits", reflect.TypeOf((*MockEventListener)(nil).FetchDeposits), ctx, address, startBlock, endBlock) +} + +// FetchKeygenEvents mocks base method. +func (m *MockEventListener) FetchKeygenEvents(ctx context.Context, address common.Address, startBlock, endBlock *big.Int) ([]types.Log, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchKeygenEvents", ctx, address, startBlock, endBlock) + ret0, _ := ret[0].([]types.Log) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchKeygenEvents indicates an expected call of FetchKeygenEvents. +func (mr *MockEventListenerMockRecorder) FetchKeygenEvents(ctx, address, startBlock, endBlock interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchKeygenEvents", reflect.TypeOf((*MockEventListener)(nil).FetchKeygenEvents), ctx, address, startBlock, endBlock) +} + +// FetchRefreshEvents mocks base method. +func (m *MockEventListener) FetchRefreshEvents(ctx context.Context, address common.Address, startBlock, endBlock *big.Int) ([]*events.Refresh, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchRefreshEvents", ctx, address, startBlock, endBlock) + ret0, _ := ret[0].([]*events.Refresh) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchRefreshEvents indicates an expected call of FetchRefreshEvents. +func (mr *MockEventListenerMockRecorder) FetchRefreshEvents(ctx, address, startBlock, endBlock interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchRefreshEvents", reflect.TypeOf((*MockEventListener)(nil).FetchRefreshEvents), ctx, address, startBlock, endBlock) +} + +// FetchRetryDepositEvents mocks base method. +func (m *MockEventListener) FetchRetryDepositEvents(event events.RetryEvent, bridgeAddress common.Address, blockConfirmations *big.Int) ([]events.Deposit, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchRetryDepositEvents", event, bridgeAddress, blockConfirmations) + ret0, _ := ret[0].([]events.Deposit) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchRetryDepositEvents indicates an expected call of FetchRetryDepositEvents. +func (mr *MockEventListenerMockRecorder) FetchRetryDepositEvents(event, bridgeAddress, blockConfirmations interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchRetryDepositEvents", reflect.TypeOf((*MockEventListener)(nil).FetchRetryDepositEvents), event, bridgeAddress, blockConfirmations) +} + +// FetchRetryEvents mocks base method. +func (m *MockEventListener) FetchRetryEvents(ctx context.Context, contractAddress common.Address, startBlock, endBlock *big.Int) ([]events.RetryEvent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchRetryEvents", ctx, contractAddress, startBlock, endBlock) + ret0, _ := ret[0].([]events.RetryEvent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchRetryEvents indicates an expected call of FetchRetryEvents. +func (mr *MockEventListenerMockRecorder) FetchRetryEvents(ctx, contractAddress, startBlock, endBlock interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchRetryEvents", reflect.TypeOf((*MockEventListener)(nil).FetchRetryEvents), ctx, contractAddress, startBlock, endBlock) +} + +// MockDepositHandler is a mock of DepositHandler interface. +type MockDepositHandler struct { + ctrl *gomock.Controller + recorder *MockDepositHandlerMockRecorder +} + +// MockDepositHandlerMockRecorder is the mock recorder for MockDepositHandler. +type MockDepositHandlerMockRecorder struct { + mock *MockDepositHandler +} + +// NewMockDepositHandler creates a new mock instance. +func NewMockDepositHandler(ctrl *gomock.Controller) *MockDepositHandler { + mock := &MockDepositHandler{ctrl: ctrl} + mock.recorder = &MockDepositHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDepositHandler) EXPECT() *MockDepositHandlerMockRecorder { + return m.recorder +} + +// HandleDeposit mocks base method. +func (m *MockDepositHandler) HandleDeposit(sourceID, destID uint8, nonce uint64, resourceID [32]byte, calldata, handlerResponse []byte) (*message.Message, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HandleDeposit", sourceID, destID, nonce, resourceID, calldata, handlerResponse) + ret0, _ := ret[0].(*message.Message) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HandleDeposit indicates an expected call of HandleDeposit. +func (mr *MockDepositHandlerMockRecorder) HandleDeposit(sourceID, destID, nonce, resourceID, calldata, handlerResponse interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleDeposit", reflect.TypeOf((*MockDepositHandler)(nil).HandleDeposit), sourceID, destID, nonce, resourceID, calldata, handlerResponse) +} diff --git a/chains/evm/listener/mock/core/listener.go b/chains/evm/listener/mock/core/listener.go deleted file mode 100644 index 15a93af1..00000000 --- a/chains/evm/listener/mock/core/listener.go +++ /dev/null @@ -1,93 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ChainSafe/chainbridge-core/chains/evm/listener (interfaces: EventListener,DepositHandler) - -// Package mock_listener is a generated GoMock package. -package mock_listener - -import ( - context "context" - big "math/big" - reflect "reflect" - - events "github.com/ChainSafe/chainbridge-core/chains/evm/calls/events" - message "github.com/ChainSafe/chainbridge-core/relayer/message" - types "github.com/ChainSafe/chainbridge-core/types" - common "github.com/ethereum/go-ethereum/common" - gomock "github.com/golang/mock/gomock" -) - -// MockEventListener is a mock of EventListener interface. -type MockEventListener struct { - ctrl *gomock.Controller - recorder *MockEventListenerMockRecorder -} - -// MockEventListenerMockRecorder is the mock recorder for MockEventListener. -type MockEventListenerMockRecorder struct { - mock *MockEventListener -} - -// NewMockEventListener creates a new mock instance. -func NewMockEventListener(ctrl *gomock.Controller) *MockEventListener { - mock := &MockEventListener{ctrl: ctrl} - mock.recorder = &MockEventListenerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockEventListener) EXPECT() *MockEventListenerMockRecorder { - return m.recorder -} - -// FetchDeposits mocks base method. -func (m *MockEventListener) FetchDeposits(arg0 context.Context, arg1 common.Address, arg2, arg3 *big.Int) ([]*events.Deposit, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchDeposits", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].([]*events.Deposit) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FetchDeposits indicates an expected call of FetchDeposits. -func (mr *MockEventListenerMockRecorder) FetchDeposits(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchDeposits", reflect.TypeOf((*MockEventListener)(nil).FetchDeposits), arg0, arg1, arg2, arg3) -} - -// MockDepositHandler is a mock of DepositHandler interface. -type MockDepositHandler struct { - ctrl *gomock.Controller - recorder *MockDepositHandlerMockRecorder -} - -// MockDepositHandlerMockRecorder is the mock recorder for MockDepositHandler. -type MockDepositHandlerMockRecorder struct { - mock *MockDepositHandler -} - -// NewMockDepositHandler creates a new mock instance. -func NewMockDepositHandler(ctrl *gomock.Controller) *MockDepositHandler { - mock := &MockDepositHandler{ctrl: ctrl} - mock.recorder = &MockDepositHandlerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDepositHandler) EXPECT() *MockDepositHandlerMockRecorder { - return m.recorder -} - -// HandleDeposit mocks base method. -func (m *MockDepositHandler) HandleDeposit(arg0, arg1 byte, arg2 uint64, arg3 types.ResourceID, arg4, arg5 []byte) (*message.Message, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HandleDeposit", arg0, arg1, arg2, arg3, arg4, arg5) - ret0, _ := ret[0].(*message.Message) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// HandleDeposit indicates an expected call of HandleDeposit. -func (mr *MockDepositHandlerMockRecorder) HandleDeposit(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleDeposit", reflect.TypeOf((*MockDepositHandler)(nil).HandleDeposit), arg0, arg1, arg2, arg3, arg4, arg5) -} diff --git a/chains/evm/listener/mock/listener.go b/chains/evm/listener/mock/listener.go deleted file mode 100644 index 7100d396..00000000 --- a/chains/evm/listener/mock/listener.go +++ /dev/null @@ -1,100 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: ./chains/evm/listener/event-handler.go - -// Package mock_listener is a generated GoMock package. -package mock_listener - -import ( - context "context" - big "math/big" - reflect "reflect" - - events "github.com/ChainSafe/chainbridge-core/chains/evm/calls/events" - events0 "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" - common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" - gomock "github.com/golang/mock/gomock" -) - -// MockEventListener is a mock of EventListener interface. -type MockEventListener struct { - ctrl *gomock.Controller - recorder *MockEventListenerMockRecorder -} - -// MockEventListenerMockRecorder is the mock recorder for MockEventListener. -type MockEventListenerMockRecorder struct { - mock *MockEventListener -} - -// NewMockEventListener creates a new mock instance. -func NewMockEventListener(ctrl *gomock.Controller) *MockEventListener { - mock := &MockEventListener{ctrl: ctrl} - mock.recorder = &MockEventListenerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockEventListener) EXPECT() *MockEventListenerMockRecorder { - return m.recorder -} - -// FetchDepositEvent mocks base method. -func (m *MockEventListener) FetchDepositEvent(event events0.RetryEvent, bridgeAddress common.Address, blockConfirmations *big.Int) ([]events.Deposit, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchDepositEvent", event, bridgeAddress, blockConfirmations) - ret0, _ := ret[0].([]events.Deposit) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FetchDepositEvent indicates an expected call of FetchDepositEvent. -func (mr *MockEventListenerMockRecorder) FetchDepositEvent(event, bridgeAddress, blockConfirmations interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchDepositEvent", reflect.TypeOf((*MockEventListener)(nil).FetchDepositEvent), event, bridgeAddress, blockConfirmations) -} - -// FetchKeygenEvents mocks base method. -func (m *MockEventListener) FetchKeygenEvents(ctx context.Context, address common.Address, startBlock, endBlock *big.Int) ([]types.Log, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchKeygenEvents", ctx, address, startBlock, endBlock) - ret0, _ := ret[0].([]types.Log) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FetchKeygenEvents indicates an expected call of FetchKeygenEvents. -func (mr *MockEventListenerMockRecorder) FetchKeygenEvents(ctx, address, startBlock, endBlock interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchKeygenEvents", reflect.TypeOf((*MockEventListener)(nil).FetchKeygenEvents), ctx, address, startBlock, endBlock) -} - -// FetchRefreshEvents mocks base method. -func (m *MockEventListener) FetchRefreshEvents(ctx context.Context, address common.Address, startBlock, endBlock *big.Int) ([]*events0.Refresh, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchRefreshEvents", ctx, address, startBlock, endBlock) - ret0, _ := ret[0].([]*events0.Refresh) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FetchRefreshEvents indicates an expected call of FetchRefreshEvents. -func (mr *MockEventListenerMockRecorder) FetchRefreshEvents(ctx, address, startBlock, endBlock interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchRefreshEvents", reflect.TypeOf((*MockEventListener)(nil).FetchRefreshEvents), ctx, address, startBlock, endBlock) -} - -// FetchRetryEvents mocks base method. -func (m *MockEventListener) FetchRetryEvents(ctx context.Context, contractAddress common.Address, startBlock, endBlock *big.Int) ([]events0.RetryEvent, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchRetryEvents", ctx, contractAddress, startBlock, endBlock) - ret0, _ := ret[0].([]events0.RetryEvent) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FetchRetryEvents indicates an expected call of FetchRetryEvents. -func (mr *MockEventListenerMockRecorder) FetchRetryEvents(ctx, contractAddress, startBlock, endBlock interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchRetryEvents", reflect.TypeOf((*MockEventListener)(nil).FetchRetryEvents), ctx, contractAddress, startBlock, endBlock) -} diff --git a/chains/proposal.go b/chains/proposal.go index 1e95ce40..5a05cfb8 100644 --- a/chains/proposal.go +++ b/chains/proposal.go @@ -8,6 +8,8 @@ import ( "github.com/ChainSafe/chainbridge-core/relayer/message" "github.com/ChainSafe/chainbridge-core/types" + coreMessage "github.com/sygmaprotocol/sygma-core/relayer/message" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" @@ -15,16 +17,10 @@ import ( "github.com/sygmaprotocol/sygma-core/relayer/proposal" ) -func NewProposal(source, destination uint8, depositNonce uint64, resourceId types.ResourceID, data []byte, metadata message.Metadata) *Proposal { - return &Proposal{ - OriginDomainID: source, - DepositNonce: depositNonce, - ResourceID: resourceId, - Destination: destination, - Data: data, - Metadata: metadata, - } -} +const ( + TransferProposalType proposal.ProposalType = "Transfer" + TransferMessageType coreMessage.MessageType = "Transfer" +) type TransferProposal struct { Source uint8 @@ -41,19 +37,28 @@ type TransferProposalData struct { } func NewTransferProposal(source, destination uint8, depositNonce uint64, - resourceId [32]byte, metadata map[string]interface{}, data []byte, propType proposal.ProposalType) *proposal.Proposal { + resourceId [32]byte, metadata map[string]interface{}, data []byte, propType proposal.ProposalType) *TransferProposal { - transferProposal := TransferProposalData{ + transferProposalData := TransferProposalData{ DepositNonce: depositNonce, ResourceId: resourceId, Metadata: metadata, Data: data, } + return &TransferProposal{ + Source: source, + Destination: destination, + Data: transferProposalData, + Type: propType, + } +} + +func NewProposal(source uint8, destination uint8, data interface{}, propType proposal.ProposalType) *proposal.Proposal { return &proposal.Proposal{ Source: source, Destination: destination, - Data: transferProposal, + Data: data, Type: propType, } } @@ -67,13 +72,25 @@ type Proposal struct { Metadata message.Metadata } -func ProposalsHash(proposals []*Proposal, chainID int64, verifContract string, bridgeVersion string) ([]byte, error) { +func ProposalsHash(proposals []*TransferProposal, chainID int64, verifContract string, bridgeVersion string) ([]byte, error) { + formattedProps := make([]interface{}, len(proposals)) for i, prop := range proposals { + transferProposal := &TransferProposal{ + Source: prop.Source, + Destination: prop.Destination, + Data: TransferProposalData{ + DepositNonce: prop.Data.DepositNonce, + ResourceId: prop.Data.ResourceId, + Metadata: prop.Data.Metadata, + Data: prop.Data.Data, + }, + Type: prop.Type, + } formattedProps[i] = map[string]interface{}{ - "originDomainID": math.NewHexOrDecimal256(int64(prop.OriginDomainID)), - "depositNonce": math.NewHexOrDecimal256(int64(prop.DepositNonce)), - "resourceID": hexutil.Encode(prop.ResourceID[:]), + "originDomainID": math.NewHexOrDecimal256(int64(transferProposal.Source)), + "depositNonce": math.NewHexOrDecimal256(int64(transferProposal.Data.DepositNonce)), + "resourceID": hexutil.Encode(transferProposal.Data.ResourceId[:]), "data": prop.Data, } } @@ -121,3 +138,20 @@ func ProposalsHash(proposals []*Proposal, chainID int64, verifContract string, b rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) return crypto.Keccak256(rawData), nil } + +type TransferMessageData struct { + DepositNonce uint64 + ResourceId [32]byte + Metadata map[string]interface{} + Payload []interface{} +} + +func NewMessage(source, destination uint8, data interface{}, msgType coreMessage.MessageType) *coreMessage.Message { + + return &coreMessage.Message{ + Source: source, + Destination: destination, + Data: data, + Type: msgType, + } +} diff --git a/chains/proposal_test.go b/chains/proposal_test.go index 761f4cb8..5b8e1d6f 100644 --- a/chains/proposal_test.go +++ b/chains/proposal_test.go @@ -4,7 +4,6 @@ package chains import ( - "github.com/ChainSafe/chainbridge-core/relayer/message" "github.com/stretchr/testify/suite" ) @@ -17,7 +16,7 @@ type ProposalTestSuite struct { func (s *ProposalTestSuite) Test_ProposalsHash() { data := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 243, 16, 122, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 1, 1, 0, 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125} - prop := []*Proposal{NewProposal(1, 2, 3, [32]byte{3}, data, message.Metadata{})} + prop := []*TransferProposal{NewTransferProposal(1, 2, 3, [32]byte{3}, nil, data, TransferProposalType)} correctRes := []byte{253, 216, 81, 25, 46, 239, 181, 138, 51, 225, 165, 111, 156, 95, 27, 239, 160, 87, 89, 84, 50, 22, 97, 185, 132, 200, 201, 210, 204, 99, 94, 131} res, err := ProposalsHash(prop, 5, verifyingContract, bridgeVersion) diff --git a/e2e/evm/evm_test.go b/e2e/evm/evm_test.go index 5b6f0f7a..3fe1abe7 100644 --- a/e2e/evm/evm_test.go +++ b/e2e/evm/evm_test.go @@ -26,11 +26,11 @@ import ( "github.com/ChainSafe/chainbridge-core/chains/evm/calls/contracts/erc721" "github.com/ChainSafe/chainbridge-core/chains/evm/calls/evmclient" "github.com/ChainSafe/chainbridge-core/chains/evm/calls/evmtransaction" - "github.com/ChainSafe/chainbridge-core/chains/evm/calls/transactor" "github.com/ChainSafe/chainbridge-core/chains/evm/calls/transactor/signAndSend" "github.com/ChainSafe/chainbridge-core/crypto/secp256k1" "github.com/ChainSafe/chainbridge-core/e2e/dummy" "github.com/ChainSafe/chainbridge-core/keystore" + "github.com/sygmaprotocol/sygma-core/chains/evm/transactor" "github.com/ChainSafe/sygma-relayer/chains/evm/calls/contracts/bridge" "github.com/ChainSafe/sygma-relayer/e2e/evm" @@ -208,10 +208,9 @@ func (s *IntegrationTestSuite) Test_Erc20Deposit() { var feeDataHash = "00000000000000000000000000000000000000000000000000011f667bbfc00000000000000000000000000000000000000000000000000006bb5a99744a9000000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000698d283a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" var feeData = evm.ConstructFeeData(feeOracleSignature, feeDataHash, amountToDeposit) - depositTxHash, err := bridgeContract1.Erc20Deposit(dstAddr.Bytes(), amountToDeposit, s.config1.Erc20ResourceID, 2, feeData, - transactor.TransactOptions{ - Priority: uint8(2), // fast - }) + erc20DepositData := evm.ConstructErc20DepositData(dstAddr.Bytes(), amountToDeposit) + depositTxHash, err := bridgeContract1.ExecuteTransaction("deposit", transactor.TransactOptions{}, 2, s.config1.Erc20ResourceID, erc20DepositData, feeData) + s.Nil(err) log.Debug().Msgf("deposit hash %s", depositTxHash.Hex()) @@ -269,11 +268,9 @@ func (s *IntegrationTestSuite) Test_Erc721Deposit() { _, err = erc721Contract2.Owner(tokenId) s.Error(err) - depositTxHash, err := bridgeContract1.Erc721Deposit( - tokenId, metadata, dstAddr, s.config1.Erc721ResourceID, 2, nil, transactor.TransactOptions{ - Value: s.config1.BasicFee, - }, - ) + erc721DepositData := evm.ConstructErc721DepositData(dstAddr.Bytes(), tokenId, []byte(metadata)) + depositTxHash, err := bridgeContract1.ExecuteTransaction("deposit", transactor.TransactOptions{Value: s.config1.BasicFee}, 2, s.config1.Erc721ResourceID, erc721DepositData, nil) + s.Nil(err) depositTx, _, err := s.client1.TransactionByHash(context.Background(), *depositTxHash) @@ -307,9 +304,9 @@ func (s *IntegrationTestSuite) Test_GenericDeposit() { handlerBalanceBefore, err := s.client1.BalanceAt(context.TODO(), s.config1.BasicFeeHandlerAddr, nil) s.Nil(err) - depositTxHash, err := bridgeContract1.GenericDeposit(hash[:], s.config1.GenericResourceID, 2, nil, transactor.TransactOptions{ - Value: s.config1.BasicFee, - }) + genericDepositData := evm.ConstructGenericDepositData(hash[:]) + depositTxHash, err := bridgeContract1.ExecuteTransaction("deposit", transactor.TransactOptions{Value: s.config1.BasicFee}, 2, s.config1.GenericResourceID, genericDepositData, nil) + s.Nil(err) depositTx, _, err := s.client1.TransactionByHash(context.Background(), *depositTxHash) @@ -346,9 +343,8 @@ func (s *IntegrationTestSuite) Test_PermissionlessGenericDeposit() { metadata = append(metadata, common.LeftPadBytes(hash[:], 32)...) metadata = append(metadata, common.LeftPadBytes(depositor.Bytes(), 32)...) - _, err := bridgeContract1.PermissionlessGenericDeposit(metadata, functionSig, contractAddress, &depositor, maxFee, s.config1.PermissionlessGenericResourceID, 2, nil, transactor.TransactOptions{ - Value: s.config1.BasicFee, - }) + permissionlessGenericDepositData := evm.ConstructPermissionlessGenericDepositData(metadata, []byte(functionSig), contractAddress.Bytes(), depositor.Bytes(), maxFee) + _, err := bridgeContract1.ExecuteTransaction("deposit", transactor.TransactOptions{Value: s.config1.BasicFee}, 2, s.config1.PermissionlessGenericResourceID, permissionlessGenericDepositData, nil) s.Nil(err) err = evm.WaitForProposalExecuted(s.client2, s.config2.BridgeAddr) @@ -372,11 +368,9 @@ func (s *IntegrationTestSuite) Test_RetryDeposit() { destBalanceBefore, err := erc20Contract2.GetBalance(dstAddr) s.Nil(err) - depositTxHash, err := bridgeContract1.Erc20Deposit(dstAddr.Bytes(), amountToDeposit, s.config1.Erc20LockReleaseResourceID, 2, nil, - transactor.TransactOptions{ - Priority: uint8(2), // fast - Value: s.config1.BasicFee, - }) + erc20DepositData := evm.ConstructErc20DepositData(dstAddr.Bytes(), amountToDeposit) + depositTxHash, err := bridgeContract1.ExecuteTransaction("deposit", transactor.TransactOptions{Value: s.config1.BasicFee}, 2, s.config1.Erc20LockReleaseResourceID, erc20DepositData, nil) + s.Nil(err) log.Debug().Msgf("deposit hash %s", depositTxHash.Hex()) @@ -429,10 +423,10 @@ func (s *IntegrationTestSuite) Test_MultipleDeposits() { var wg sync.WaitGroup for i := 0; i < numOfDeposits; i++ { go func() { - _, err := bridgeContract1.Erc20Deposit(dstAddr.Bytes(), amountToDeposit, s.config1.Erc20ResourceID, 2, feeData, - transactor.TransactOptions{ - Priority: uint8(2), // fast - }) + + erc20DepositData := evm.ConstructErc20DepositData(dstAddr.Bytes(), amountToDeposit) + _, err := bridgeContract1.ExecuteTransaction("deposit", transactor.TransactOptions{}, 2, s.config1.Erc20ResourceID, erc20DepositData, feeData) + wg.Add(1) defer wg.Done() s.Nil(err) diff --git a/e2e/evm/util.go b/e2e/evm/util.go index a49cc189..7e8bab0b 100644 --- a/e2e/evm/util.go +++ b/e2e/evm/util.go @@ -17,6 +17,7 @@ import ( "github.com/ChainSafe/sygma-relayer/chains/evm/calls/events" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" ethereumTypes "github.com/ethereum/go-ethereum/core/types" ) @@ -107,3 +108,43 @@ func ConstructFeeData(feeOracleSignature string, feeDataHash string, amountToDep feeData = append(feeData, amountToDepositBytes[:]...) return feeData } + +func ConstructPermissionlessGenericDepositData(metadata []byte, executionFunctionSig []byte, executeContractAddress []byte, metadataDepositor []byte, maxFee *big.Int) []byte { + var data []byte + data = append(data, common.LeftPadBytes(maxFee.Bytes(), 32)...) + data = append(data, common.LeftPadBytes(big.NewInt(int64(len(executionFunctionSig))).Bytes(), 2)...) + data = append(data, executionFunctionSig...) + data = append(data, byte(len(executeContractAddress))) + data = append(data, executeContractAddress...) + data = append(data, byte(len(metadataDepositor))) + data = append(data, metadataDepositor...) + 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 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 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 +} diff --git a/e2e/substrate/substrate_test.go b/e2e/substrate/substrate_test.go index fefa8c43..e5c8886e 100644 --- a/e2e/substrate/substrate_test.go +++ b/e2e/substrate/substrate_test.go @@ -7,12 +7,12 @@ import ( "context" "encoding/binary" - "github.com/ChainSafe/chainbridge-core/chains/evm/calls/transactor" "github.com/ChainSafe/chainbridge-core/crypto/secp256k1" "github.com/ChainSafe/sygma-relayer/chains/substrate/client" "github.com/ChainSafe/sygma-relayer/chains/substrate/connection" substrateTypes "github.com/centrifuge/go-substrate-rpc-client/v4/types" "github.com/ethereum/go-ethereum/core/types" + "github.com/sygmaprotocol/sygma-core/chains/evm/transactor" "math/big" "testing" @@ -206,9 +206,10 @@ func (s *IntegrationTestSuite) Test_Erc20Deposit_EVM_to_Substrate() { pk := []substrateTypes.U8{0xd4, 0x35, 0x93, 0xc7, 0x15, 0xfd, 0xd3, 0x1c, 0x61, 0x14, 0x1a, 0xbd, 0x4, 0xa9, 0x9f, 0xd6, 0x82, 0x2c, 0x85, 0x58, 0x85, 0x4c, 0xcd, 0xe3, 0x9a, 0x56, 0x84, 0xe7, 0xa5, 0x6d, 0xa2, 0x7d} recipientMultilocation := substrate.ConstructRecipientData(pk) - _, err = bridgeContract1.Erc20Deposit(recipientMultilocation, amountToDeposit, s.evmConfig.Erc20LockReleaseResourceID, 3, nil, transactor.TransactOptions{ - Value: s.evmConfig.BasicFee, - }) + + erc20DepositData := evm.ConstructErc20DepositData(recipientMultilocation, amountToDeposit) + _, err = bridgeContract1.ExecuteTransaction("deposit", transactor.TransactOptions{Value: s.evmConfig.BasicFee}, 3, s.evmConfig.Erc20LockReleaseResourceID, erc20DepositData, nil) + s.Nil(err) err = substrate.WaitForProposalExecuted(s.substrateConnection, destBalanceBefore.Balance, substrate.SubstratePK.PublicKey) diff --git a/example/app/app.go b/example/app/app.go index 5504a461..1e1de1d3 100644 --- a/example/app/app.go +++ b/example/app/app.go @@ -48,7 +48,6 @@ import ( "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/comm/elector" "github.com/ChainSafe/sygma-relayer/comm/p2p" "github.com/ChainSafe/sygma-relayer/config" diff --git a/go.sum b/go.sum index 07ffa42e..c3dbf99a 100644 --- a/go.sum +++ b/go.sum @@ -102,9 +102,7 @@ github.com/btcsuite/btcutil v1.0.3-0.20211129182920-9c4bbabe7acd h1:vAwk2PCYxzUU github.com/btcsuite/btcutil v1.0.3-0.20211129182920-9c4bbabe7acd/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -116,7 +114,6 @@ github.com/centrifuge/go-substrate-rpc-client v2.0.0+incompatible/go.mod h1:GBML github.com/centrifuge/go-substrate-rpc-client/v4 v4.1.0 h1:GEvub7kU5YFAcn5A2uOo4AZSM1/cWZCOvfu7E3gQmK8= github.com/centrifuge/go-substrate-rpc-client/v4 v4.1.0/go.mod h1:szA5wf9suAIcNg/1S3rGeFITHqrnqH5TC6b+O0SEQ94= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -183,13 +180,10 @@ github.com/decred/dcrd/dcrec/edwards/v2 v2.0.2 h1:bX7rtGTMBDJxujZ29GNqtn7YCAdINj github.com/decred/dcrd/dcrec/edwards/v2 v2.0.2/go.mod h1:d0H8xGMWbiIQP7gN3v2rByWUcuZPm9YsgmnfoxgbINc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= @@ -209,7 +203,6 @@ github.com/ethereum/go-ethereum v1.13.4/go.mod h1:I0U5VewuuTzvBtVzKo7b3hJzDhXOUt github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= -github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= @@ -222,7 +215,6 @@ github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmV github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -244,7 +236,6 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= @@ -319,7 +310,6 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= -github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= @@ -369,7 +359,6 @@ github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/ github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= -github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -383,7 +372,6 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -392,7 +380,6 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= -github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -406,8 +393,6 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= @@ -423,8 +408,6 @@ github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABo github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -460,11 +443,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= @@ -549,7 +529,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= -github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= @@ -587,15 +566,12 @@ github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2 github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -627,7 +603,6 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2D github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pierrec/xxHash v0.1.5 h1:n/jBpwTHiER4xYvK3/CdPVnLDPchj8eTJFFLUb4QHBo= github.com/pierrec/xxHash v0.1.5/go.mod h1:w2waW5Zoa/Wc4Yqe0wgrIYAGKqRMf7czn2HNKXmuL+I= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -668,11 +643,9 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -761,14 +734,6 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/sygmaprotocol/sygma-core v0.0.0-20231023115554-62219e098d0d h1:S2129X3uNculIdDae6J88ekiPWfzpcYhnVAeEuNRLQg= -github.com/sygmaprotocol/sygma-core v0.0.0-20231023115554-62219e098d0d/go.mod h1:b4RZCyYr20Mp4WAAj4TkC6gU2KZ0ZWcpSGmKc6n8NKc= -github.com/sygmaprotocol/sygma-core v0.0.0-20240104100450-afa68196ac4b h1:czluw0nos2T3Y/P56320RI1SqgMvIj/wsEy1uWi4lm4= -github.com/sygmaprotocol/sygma-core v0.0.0-20240104100450-afa68196ac4b/go.mod h1:b4RZCyYr20Mp4WAAj4TkC6gU2KZ0ZWcpSGmKc6n8NKc= -github.com/sygmaprotocol/sygma-core v0.0.0-20240104105922-862b0234ddf3 h1:SBDVA3/x+XK0w6l+kaVHmO3V5Cuk6DbEbJEyk9WsyQE= -github.com/sygmaprotocol/sygma-core v0.0.0-20240104105922-862b0234ddf3/go.mod h1:b4RZCyYr20Mp4WAAj4TkC6gU2KZ0ZWcpSGmKc6n8NKc= -github.com/sygmaprotocol/sygma-core v0.0.0-20240104110947-6683673f732f h1:9IXiXq1yYzKlTZrzYpN/HyeaApHdQgKHs05L2lhQjj4= -github.com/sygmaprotocol/sygma-core v0.0.0-20240104110947-6683673f732f/go.mod h1:b4RZCyYr20Mp4WAAj4TkC6gU2KZ0ZWcpSGmKc6n8NKc= github.com/sygmaprotocol/sygma-core v0.0.0-20240104134009-a7865e7a9ad6 h1:J/Xa/kBbXTjg0wZRPrUvolLoe2MnTtldG8Srt0In5HI= github.com/sygmaprotocol/sygma-core v0.0.0-20240104134009-a7865e7a9ad6/go.mod h1:b4RZCyYr20Mp4WAAj4TkC6gU2KZ0ZWcpSGmKc6n8NKc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI=