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