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) }