go-relayer

module
v0.0.1-alpha Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 13, 2022 License: LGPL-3.0

README

go-relayer

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

Components:

  • cmd: example CLI that uses examples/minimal_forwarder
  • examples: example implementations of forwarder and recipient contracts, as well as Go bindings, required interface implementations, and unit tests
    • examples/gsn_forwarder: an implementation using OpenGSN's forwarder contract.
    • examples/minimal_forwarder: an implementation using OpenZeppelin's minimal forwarder.
    • 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.19+
  • abigen: can install with bash scripts/install-abigen.sh

Usage

As an application

See cmd/main.go for an example app using the examples/minimal_forwarder package.

The app can be built using make build.

To run it in dev mode (which auto-deploys a forwarder contract for you):

First, install and run ganache using:

NODE_OPTIONS="--max_old_space_size=8192" ganache --deterministic --accounts=50

Then:

$ ./bin/relayer --dev
2022-09-24T07:43:32.499-0400	INFO	cmd	cmd/main.go:131	starting relayer with ethereum endpoint http://localhost:8545 and chain ID 1337
2022-09-24T07:43:32.541-0400	INFO	cmd	cmd/main.go:207	deployed MinimalForwarder.sol to 0x8E7a8d3CAeEbbe9A92faC4db19424218aE6791a3
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 examples/ 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 `examples/gsn_forwarder/i_forwarder_wrapped.go` or 
// `examples/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 `examples/gsn_forwarder/request.go` or `examples/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.

Directories

Path Synopsis
cmd
examples
impls

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL