multicall

package module
v0.0.0-...-7e9c199 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2024 License: MIT Imports: 10 Imported by: 0

README

Multicall Client for Ethereum

Tests Passing codecov

This package provides a Go implementation of the Ethereum Multicall3 contract, enabling efficient batched calls to on-chain contracts using the Ethereum JSON-RPC API. It simplifies making multiple contract read-only (view) calls in a single network request.

Features

  • Multicall Support: Aggregate multiple contract calls into a single request, saving on network requests and gas.
  • Batching: Automatically handles batching of requests when the size exceeds a defined limit.
  • Customizable: Supports custom block height, batching sizes, and deserialization functions.

Table of Contents

Installation

Install the Go package via:

go get github.com/jbrower95/multicall-go

Usage

Creating the Client

To create a MulticallClient, pass a context.Context, an ethclient.Client, and optional settings.

client, _ := ethclient.Dial("https://your_rpc_url")
ctx := context.Background()
mc, _ := multicall.NewMulticallClient(ctx, client, nil)
Performing two RPC calls at once

You can perform three kinds of actions;

  • Checking the balance of an address
  • Fetching the block number that the multicall was read from, and
  • Performing an arbitrary smart contract read

In this example, we fetch the balance of 0xdeadbeefdeadbeef while also fetching the current block number. We use Do() for this.

balanceCall := multicallClient.GetBalance(common.HexToAddress("0xdeadbeefdeadbeef"))
blockNumberCall := multicallClient.GetBlockNumber()

balance, blockNumber, _ := multicall.Do(multicallClient, balanceCall, blockNumberCall)
fmt.Println("Balance:", balance, "Block Number:", blockNumber)
Performing list of RPC calls

Use DoMany to perform many similarly-typed RPC calls at once:

calls := []*multicall.MultiCallMetaData[big.Int]{
    multicallClient.GetBalance(common.HexToAddress("0xAddress1")),
    multicallClient.GetBalance(common.HexToAddress("0xAddress2")),
}

results, _ := multicall.DoMany(multicallClient, calls...)
for i, result := range *results {
    fmt.Printf("Call %d result: %v\n", i+1, result)
}

Testing

go test is run automatically in CI.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Do

func Do[A any, B any](mc *MulticallClient, a *MultiCallMetaData[A], b *MultiCallMetaData[B]) (*A, *B, error)

func Do3

func Do3[A any, B any, C any](mc *MulticallClient, a *MultiCallMetaData[A], b *MultiCallMetaData[B], c *MultiCallMetaData[C]) (*A, *B, *C, error)

func Do4

func Do4[A any, B any, C any, D any](mc *MulticallClient, a *MultiCallMetaData[A], b *MultiCallMetaData[B], c *MultiCallMetaData[C], d *MultiCallMetaData[D]) (*A, *B, *C, *D, error)

func Do5

func Do5[A any, B any, C any, D any, E any](mc *MulticallClient, a *MultiCallMetaData[A], b *MultiCallMetaData[B], c *MultiCallMetaData[C], d *MultiCallMetaData[D], e *MultiCallMetaData[E]) (*A, *B, *C, *D, *E, error)

func Do6

func Do6[A any, B any, C any, D any, E any, F any](mc *MulticallClient, a *MultiCallMetaData[A], b *MultiCallMetaData[B], c *MultiCallMetaData[C], d *MultiCallMetaData[D], e *MultiCallMetaData[E], f *MultiCallMetaData[F]) (*A, *B, *C, *D, *E, *F, error)

func DoMany

func DoMany[A any](mc *MulticallClient, requests ...*MultiCallMetaData[A]) (*[]*A, error)

func DoManyAllowFailures

func DoManyAllowFailures[A any](mc *MulticallClient, requests ...*MultiCallMetaData[A]) (*[]TypedMulticall3Result[*A], error)

//////////////////////

func DoManyAllowFailuresWithOptions

func DoManyAllowFailuresWithOptions[A any](mc *MulticallClient, overrideOpts *bind.CallOpts, requests ...*MultiCallMetaData[A]) (*[]TypedMulticall3Result[*A], error)

func DoManyWithOptions

func DoManyWithOptions[A any](mc *MulticallClient, options *bind.CallOpts, requests ...*MultiCallMetaData[A]) (*[]*A, error)

Types

type DeserializedMulticall3Result

type DeserializedMulticall3Result struct {
	Success bool
	Value   any
}

type MultiCallMetaData

type MultiCallMetaData[T interface{}] struct {
	Address      common.Address
	Data         []byte
	FunctionName string
	Deserialize  func([]byte) (*T, error)
}

func Describe

func Describe[T any](contractAddress common.Address, contractAbi abi.ABI, method string, params ...interface{}) (*MultiCallMetaData[T], error)

Describes a call that invokes the (constant) contract method with params as input values and sets the output to result. The result type might be a single field for simple returns, a slice of interfaces for anonymous returns and a struct for named returns.

func DescribeWithDeserialize

func DescribeWithDeserialize[T any](contractAddress common.Address, abi abi.ABI, deserialize func([]byte) (*T, error), method string, params ...interface{}) (*MultiCallMetaData[T], error)

func (*MultiCallMetaData[T]) Raw

func (md *MultiCallMetaData[T]) Raw() RawMulticall

type Multicall3Result

type Multicall3Result struct {
	Success    bool
	ReturnData []byte
}

type MulticallClient

type MulticallClient struct {
	Contract            *bind.BoundContract
	Address             common.Address
	ABI                 *abi.ABI
	Context             context.Context
	MaxBatchSize        uint64
	OverrideCallOptions *bind.CallOpts
}

func NewMulticallClient

func NewMulticallClient(ctx context.Context, eth *ethclient.Client, options *TMulticallClientOptions) (*MulticallClient, error)

*

  • Initializes a multicall client. You'll need one of these to make any calls.
  • ctx: network context for operations
  • eth: the geth client to use for interacting with your node
  • options [optional]: additional options to specify when making your request.
  • - WARNING: these parameters take sceond precedence to any `overrideOptions` provided by the `Do*WithInfo()` functions.

func (*MulticallClient) GetBalance

func (mc *MulticallClient) GetBalance(address common.Address) *MultiCallMetaData[big.Int]

////////////////// Other transactions you can run at the same time as your multicall.

func (*MulticallClient) GetBlockNumber

func (mc *MulticallClient) GetBlockNumber() *MultiCallMetaData[big.Int]

type ParamMulticall3Call3

type ParamMulticall3Call3 struct {
	Target       common.Address
	AllowFailure bool
	CallData     []byte
}

type RawMulticall

type RawMulticall struct {
	Address      common.Address
	Data         []byte
	FunctionName string
	Deserialize  func([]byte) (any, error)
}

type TMulticallClientOptions

type TMulticallClientOptions struct {
	OverrideContractAddress *common.Address
	MaxBatchSizeBytes       uint64
	OverrideCallOptions     *bind.CallOpts
}

type TypedMulticall3Result

type TypedMulticall3Result[A any] struct {
	Success bool
	Value   A
	Error   error
}

Jump to

Keyboard shortcuts

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