/
call.go
132 lines (114 loc) · 2.93 KB
/
call.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
package eth
import (
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rpc"
"github.com/lmittmann/w3/core"
)
// Call requests the output data of the given message.
func Call(msg ethereum.CallMsg) *CallFactory {
return &CallFactory{msg: msg}
}
type CallFactory struct {
// args
msg ethereum.CallMsg
atBlock *big.Int
// returns
result hexutil.Bytes
returns *[]byte
}
func (f *CallFactory) AtBlock(blockNumber *big.Int) *CallFactory {
f.atBlock = blockNumber
return f
}
func (f *CallFactory) Returns(output *[]byte) *CallFactory {
f.returns = output
return f
}
// CreateRequest implements the core.RequestCreator interface.
func (f *CallFactory) CreateRequest() (rpc.BatchElem, error) {
return rpc.BatchElem{
Method: "eth_call",
Args: []interface{}{toCallArg(f.msg), toBlockNumberArg(f.atBlock)},
Result: &f.result,
}, nil
}
// HandleResponse implements the core.ResponseHandler interface.
func (f *CallFactory) HandleResponse(elem rpc.BatchElem) error {
if err := elem.Error; err != nil {
return err
}
*f.returns = []byte(f.result)
return nil
}
// CallFunc requests the returns of Func fn at common.Address to with the given
// args.
func CallFunc(fn core.Func, to common.Address, args ...interface{}) *CallFuncFactory {
return &CallFuncFactory{fn: fn, to: to, args: args}
}
type CallFuncFactory struct {
// args
fn core.Func
to common.Address
args []interface{}
atBlock *big.Int
// returns
result hexutil.Bytes
returns []interface{}
}
func (f *CallFuncFactory) AtBlock(blockNumber *big.Int) *CallFuncFactory {
f.atBlock = blockNumber
return f
}
func (f *CallFuncFactory) Returns(returns ...interface{}) *CallFuncFactory {
f.returns = returns
return f
}
// CreateRequest implements the core.RequestCreator interface.
func (f *CallFuncFactory) CreateRequest() (rpc.BatchElem, error) {
input, err := f.fn.EncodeArgs(f.args...)
if err != nil {
return rpc.BatchElem{}, err
}
msg := ethereum.CallMsg{
To: &f.to,
Data: input,
}
return rpc.BatchElem{
Method: "eth_call",
Args: []interface{}{toCallArg(msg), toBlockNumberArg(f.atBlock)},
Result: &f.result,
}, nil
}
// HandleResponse implements the core.ResponseHandler interface.
func (f *CallFuncFactory) HandleResponse(elem rpc.BatchElem) error {
if err := elem.Error; err != nil {
return err
}
output := []byte(f.result)
if err := f.fn.DecodeReturns(output, f.returns...); err != nil {
return err
}
return nil
}
func toCallArg(msg ethereum.CallMsg) interface{} {
arg := map[string]interface{}{
"from": msg.From,
"to": msg.To,
}
if len(msg.Data) > 0 {
arg["data"] = hexutil.Bytes(msg.Data)
}
if msg.Value != nil {
arg["value"] = (*hexutil.Big)(msg.Value)
}
if msg.Gas != 0 {
arg["gas"] = hexutil.Uint64(msg.Gas)
}
if msg.GasPrice != nil {
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
}
return arg
}