Categorygithub.com/athanorlabs/go-relayer
module
0.2.0
Repository: https://github.com/athanorlabs/go-relayer.git
Documentation: pkg.go.dev

# README

go-relayer

EIP2771-compatible transaction relayer library for Ethereum. The core of the library is bindings to a compatible forwarder contract.

Components:

  • cmd/relayer: example CLI that uses impls/minimal_forwarder
  • impls: example implementations of forwarder and recipient contracts, as well as Go bindings, required interface implementations, and unit tests
  • examples/mock_recipient: an implementation of a EIP2771-compatible recipient contract which can receive calls from a forwarder.
  • relayer: functionality to call forwarder contracts
  • rpc: rpc server for an end-user to submit txs to, accepts a *relayer.Relayer

Requirements

  • go 1.20+
  • abigen: can install using ./scripts/install-abigen.sh

Usage

As an application

See cmd/relayer/main.go for an example app using the impls/gsnforwarder package.

The app can be built using make build.

First, install and run ganache using:

ganache --deterministic --accounts=50

Create a key file using a deterministic ganache key

echo "4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" > eth.key

To run and automatically deploy the relayer contract to the ganache network, you can use:

$ ./bin/relayer --deploy
2022-09-24T07:43:32.499-0400	INFO	main	cmd/main.go:131	starting relayer with ethereum endpoint http://localhost:8545 and chain ID 1337
2022-09-24T07:43:32.541-0400	INFO	main	cmd/main.go:207	deployed Forwarder.sol to 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
2022-09-24T07:43:32.542-0400	INFO	rpc	rpc/server.go:62	starting RPC server on http://localhost:7799

By default, the relayer server runs on port 7799.

Implementing a custom forwarder

See the forwarder examples in impls/ for a full implementation.

There are three main components needed:

  • Go bindings to the forwarder contract (generated by abigen)
  • implementing the Forwarder interface below (by the forwarder contract)
  • implementing the ForwardRequest interface below (by the request type contained in the contract)
// Forwarder must be implemented by a forwarder contract used by a *relayer.Relayer.
// These methods are wrappers around the methods auto-generated by abigen.
//
// See `impls/gsn_forwarder/i_forwarder_wrapped.go` or 
// `impls/minimal_forwarder/i_minimal_forwarder_wrapped.go`for examples.
type Forwarder interface {
	GetNonce(opts *bind.CallOpts, from ethcommon.Address) (*big.Int, error)

	Verify(
		opts *bind.CallOpts,
		req ForwardRequest,
		domainSeparator,
		requestTypeHash [32]byte,
		suffixData,
		signature []byte,
	) (bool, error)

	Execute(
		opts *bind.TransactOpts,
		req ForwardRequest,
		domainSeparator,
		requestTypeHash [32]byte,
		suffixData,
		signature []byte,
	) (*types.Transaction, error)
}

// ForwardRequest must be implemented by a request type used by a forwarder contract.
//
// See `impls/gsn_forwarder/request.go` or `impls/minimal_forwarder/request.go`
// for examples.
type ForwardRequest interface {
	// FromSubmitTransactionRequest set the type underlying the ForwardRequest
	// using a *SubmitTransactionRequest.
	//
	// Note: not all fields in the *SubmitTransactionRequest need be used depending
	// on the implementation.
	FromSubmitTransactionRequest(*SubmitTransactionRequest)

	// Pack uses ABI encoding to pack the underlying ForwardRequest, appending
	// optional `suffixData` to the end.
	//
	// See examples/gsn_forwarder/IForwarderForwardRequest.Pack() or
	// examples/minimal_forwarder/IMinimalForwarderForwardRequest.Pack()
	// for details.
	Pack(suffixData []byte) ([]byte, error)
}

Additionally, to create a new *relayer.Relayer, you need to implement a function that returns your ForwardRequest. For example:

func NewIForwarderForwardRequest() common.ForwardRequest {
	return &IForwarderForwardRequest{}
}

cfg := &relayer.Config{
	// fields omitted
	NewForwardRequestFunc: NewIForwarderForwardRequest,
}

_, _ = relayer.NewRelayer(cfg)

Interacting with the relayer

When running a relayer with an RPC server, it accepts transactions submission requests, returning a transaction hash if the transaction is successfully submitted:

func (s *RelayerService) SubmitTransaction(
	_ *http.Request,
	req *common.SubmitTransactionRequest,
	resp *common.SubmitTransactionResponse,
) error 

See go-relayer-client for client library and example usage.

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author