github.com/lmittmann/w3@v0.20.0/internal/module/factory.go (about)

     1  package module
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math/big"
     8  
     9  	"github.com/ethereum/go-ethereum/common/hexutil"
    10  	"github.com/ethereum/go-ethereum/rpc"
    11  	"github.com/lmittmann/w3/w3types"
    12  )
    13  
    14  var null = []byte("null")
    15  
    16  type Option[T any] func(*Factory[T])
    17  
    18  type ArgsWrapperFunc func([]any) ([]any, error)
    19  
    20  type RetWrapperFunc[T any] func(*T) any
    21  
    22  type Factory[T any] struct {
    23  	method string
    24  	args   []any
    25  	ret    *T
    26  
    27  	argsWrapper ArgsWrapperFunc
    28  	retWrapper  RetWrapperFunc[T]
    29  }
    30  
    31  func NewFactory[T any](method string, args []any, opts ...Option[T]) *Factory[T] {
    32  	f := &Factory[T]{
    33  		method: method,
    34  		args:   args,
    35  
    36  		argsWrapper: func(args []any) ([]any, error) { return args, nil },
    37  		retWrapper:  func(ret *T) any { return ret },
    38  	}
    39  	for _, opt := range opts {
    40  		opt(f)
    41  	}
    42  	return f
    43  }
    44  
    45  func (f Factory[T]) Returns(ret *T) w3types.RPCCaller {
    46  	f.ret = ret
    47  	return f
    48  }
    49  
    50  func (f Factory[T]) CreateRequest() (rpc.BatchElem, error) {
    51  	args, err := f.argsWrapper(f.args)
    52  	if err != nil {
    53  		return rpc.BatchElem{}, err
    54  	}
    55  	if f.ret == nil {
    56  		return rpc.BatchElem{}, fmt.Errorf("w3: cannot return Go value of type %T: value must be passed as a non-nil pointer reference", f.ret)
    57  	}
    58  
    59  	return rpc.BatchElem{
    60  		Method: f.method,
    61  		Args:   args,
    62  		Result: &json.RawMessage{},
    63  	}, nil
    64  }
    65  
    66  func (f Factory[T]) HandleResponse(elem rpc.BatchElem) error {
    67  	if err := elem.Error; err != nil {
    68  		return err
    69  	}
    70  
    71  	ret := *(elem.Result.(*json.RawMessage))
    72  	if len(ret) == 0 || bytes.Equal(ret, null) {
    73  		return errNotFound
    74  	}
    75  
    76  	if err := json.Unmarshal(ret, f.retWrapper(f.ret)); err != nil {
    77  		return err
    78  	}
    79  	return nil
    80  }
    81  
    82  func WithArgsWrapper[T any](fn ArgsWrapperFunc) Option[T] {
    83  	return func(f *Factory[T]) {
    84  		f.argsWrapper = fn
    85  	}
    86  }
    87  
    88  func WithRetWrapper[T any](fn RetWrapperFunc[T]) Option[T] {
    89  	return func(f *Factory[T]) {
    90  		f.retWrapper = fn
    91  	}
    92  }
    93  
    94  func HexBigRetWrapper(ret **big.Int) any {
    95  	*ret = new(big.Int)
    96  	return (*hexutil.Big)(*ret)
    97  }
    98  func HexUintRetWrapper(ret *uint) any     { return (*hexutil.Uint)(ret) }
    99  func HexUint64RetWrapper(ret *uint64) any { return (*hexutil.Uint64)(ret) }
   100  func HexBytesRetWrapper(ret *[]byte) any  { return (*hexutil.Bytes)(ret) }