Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/noot/go-relayer

EIP2771-compatible ethereum transaction relayer
https://github.com/noot/go-relayer

eip2771 ethereum metatransactions relayer

Last synced: 2 months ago
JSON representation

EIP2771-compatible ethereum transaction relayer

Awesome Lists containing this project

README

        

# go-relayer

[EIP2771-compatible](https://eips.ethereum.org/EIPS/eip-2771) 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
- `impls/gsn_forwarder`: an implementation using OpenGSN's [forwarder contract](https://github.com/opengsn/gsn/tree/master/packages/contracts/src/forwarder).
- `impls/minimal_forwarder`: an implementation using OpenZeppelin's [minimal forwarder](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/metatx/MinimalForwarder.sol).
- `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
```bash
echo "4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" > eth.key
```

To run and automatically deploy the relayer contract to the ganache network, you can use:
```bash
$ ./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)

```go
// 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:

```go
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:

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

See [go-relayer-client](https://github.com/AthanorLabs/go-relayer-client) for client library and example usage.