diff --git a/README.md b/README.md index a5eb2ea..69bced3 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ go get github.com/forta-network/go-multicall (See other examples under the `examples` directory!) +#### Multicall ```go package main @@ -91,3 +92,64 @@ func main() { } } ``` + +#### SingleCall +```go +package main + +import ( + "context" + "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/forta-network/go-multicall" +) + +const ( + APIURL = "https://cloudflare-eth.com" + ERC20ABI = `[ + { + "constant":true, + "inputs":[ + { + "name":"tokenOwner", + "type":"address" + } + ], + "name":"balanceOf", + "outputs":[ + { + "name":"balance", + "type":"uint256" + } + ], + "payable":false, + "stateMutability":"view", + "type":"function" + } + ]` +) + +func main() { + caller, err := multicall.Dial(context.Background(), APIURL) + if err != nil { + panic(err) + } + + contract, err := multicall.NewContract(ERC20ABI, "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") + if err != nil { + panic(err) + } + + single, err := caller.CallSingle(nil, + contract.NewCall( + nil, + "balanceOf", + common.HexToAddress("0xcEe284F754E854890e311e3280b767F80797180d"), // Arbitrum One gateway + ).Name("Arbitrum One gateway balance")) + if err != nil { + return + } + + fmt.Println(single.CallName, ":", single.Outputs, err) +} +``` diff --git a/call.go b/call.go index b89a9e4..a4c6b54 100644 --- a/call.go +++ b/call.go @@ -2,7 +2,6 @@ package multicall import ( "bytes" - "errors" "fmt" "reflect" @@ -80,15 +79,16 @@ func (call *Call) Unpack(b []byte) error { if t.Kind() == reflect.Pointer { t = t.Elem() } - if t.Kind() != reflect.Struct { - return errors.New("outputs type is not a struct") - } - out, err := call.Contract.ABI.Unpack(call.Method, b) if err != nil { return fmt.Errorf("failed to unpack '%s' outputs: %v", call.Method, err) } + if t.Kind() != reflect.Struct { + call.Outputs = out + return nil + } + fieldCount := t.NumField() for i := 0; i < fieldCount; i++ { field := t.Field(i) diff --git a/caller.go b/caller.go index eb2e10d..0d8c078 100644 --- a/caller.go +++ b/caller.go @@ -47,6 +47,19 @@ func Dial(ctx context.Context, rawUrl string, multicallAddr ...string) (*Caller, // Call makes multicalls. func (caller *Caller) Call(opts *bind.CallOpts, calls ...*Call) ([]*Call, error) { + return caller.calls(opts, calls...) +} + +func (caller *Caller) CallSingle(opts *bind.CallOpts, call *Call) (*Call, error) { + + calls, err := caller.calls(opts, call) + if err != nil { + return call, fmt.Errorf("CallSingle failed: %v", err) + } + return calls[0], nil +} + +func (caller *Caller) calls(opts *bind.CallOpts, calls ...*Call) ([]*Call, error) { var multiCalls []contract_multicall.Multicall3Call3 for i, call := range calls { @@ -86,7 +99,7 @@ func (caller *Caller) CallChunked(opts *bind.CallOpts, chunkSize int, cooldown t time.Sleep(cooldown) } - chunk, err := caller.Call(opts, chunk...) + chunk, err := caller.calls(opts, chunk...) if err != nil { return calls, fmt.Errorf("call chunk [%d] failed: %v", i, err) }