-
Notifications
You must be signed in to change notification settings - Fork 9
/
reader_multicall.go
138 lines (119 loc) · 2.71 KB
/
reader_multicall.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package reader
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
. "github.com/tranvictor/jarvis/common"
)
var DO_NOTHING_MC_ONE_RESULT_HANDLER MCOneResultHandler = func(result interface{}) error { return nil }
type MCOneResultHandler func(result interface{}) error
type MultipleCall struct {
r *EthReader
contract string
mcABI *abi.ABI
results []interface{}
caddrs []string
abis []*abi.ABI
methods []string
argLists [][]interface{}
hooks []MCOneResultHandler
}
func NewMultiCall(r *EthReader, mcContract string) *MultipleCall {
return &MultipleCall{
r,
mcContract,
GetMultiCallABI(),
[]interface{}{},
[]string{},
[]*abi.ABI{},
[]string{},
[][]interface{}{},
[]MCOneResultHandler{},
}
}
func (mc *MultipleCall) RegisterWithHook(
result interface{},
hook MCOneResultHandler,
caddr string,
abi *abi.ABI,
method string,
args ...interface{},
) *MultipleCall {
mc.results = append(mc.results, result)
mc.caddrs = append(mc.caddrs, caddr)
mc.abis = append(mc.abis, abi)
mc.methods = append(mc.methods, method)
mc.argLists = append(mc.argLists, args)
mc.hooks = append(mc.hooks, hook)
return mc
}
func (mc *MultipleCall) Register(
result interface{},
caddr string,
abi *abi.ABI,
method string,
args ...interface{},
) *MultipleCall {
return mc.RegisterWithHook(
result,
DO_NOTHING_MC_ONE_RESULT_HANDLER,
caddr,
abi,
method,
args...,
)
}
type multicallres struct {
BlockNumber *big.Int
ReturnData [][]byte
}
type call struct {
Target common.Address
CallData []byte
}
func (mc *MultipleCall) callMCContract(atBlock int64) (block int64, err error) {
res := multicallres{}
calls := []call{}
for i, caddr := range mc.caddrs {
data, err := mc.abis[i].Pack(mc.methods[i], mc.argLists[i]...)
if err != nil {
return 0, err
}
calls = append(calls, call{HexToAddress(caddr), data})
}
err = mc.r.ReadHistoryContract(
atBlock,
&res,
mc.contract,
"aggregate",
calls,
)
if err != nil {
return 0, fmt.Errorf("reading mc.aggregate failed: %w", err)
}
for i, _ := range mc.results {
err = mc.abis[i].UnpackIntoInterface(
mc.results[i],
mc.methods[i],
res.ReturnData[i],
)
if err != nil {
return 0, fmt.Errorf("unpacking call index %d failed: %w", i, err)
}
}
return res.BlockNumber.Int64(), nil
}
func (mc *MultipleCall) Do(atBlock int64) (block int64, err error) {
block, err = mc.callMCContract(atBlock)
if err != nil {
return 0, fmt.Errorf("calling mc contract failed: %w", err)
}
for i, result := range mc.results {
err = mc.hooks[i](result)
if err != nil {
return 0, fmt.Errorf("calling hook at index %d failed: %w", i, err)
}
}
return block, nil
}