/
wrapper.go
235 lines (220 loc) · 7.29 KB
/
wrapper.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
package factory
import (
"context"
"errors"
"fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// TokenContractWrapper for external wrapping
type TokenContractWrapper struct {
abi abi.ABI
address common.Address
backend bind.ContractBackend
contract *bind.BoundContract
}
// NewTokenContractWrapper creates TokenContract wrapper for reference
func NewTokenContractWrapper(address common.Address, backend bind.ContractBackend) (*TokenContractWrapper, error) {
parsed, err := abi.JSON(strings.NewReader(TokenABI))
if err != nil {
return nil, err
}
contract, err := bindToken(address, backend, backend, backend)
if err != nil {
return nil, err
}
return &TokenContractWrapper{
abi: parsed,
address: address,
backend: backend,
contract: contract,
}, nil
}
// BalanceOfByBlockNumber with given block number
func (_Token *TokenContractWrapper) BalanceOfByBlockNumber(opts *bind.CallOpts,
account common.Address, blockNumber *big.Int) (*big.Int, error) {
var (
ret0 = new(*big.Int)
)
out := ret0
err := _Token.call(opts, blockNumber, out, "balanceOf", account)
return *ret0, err
}
// RawTransfer is a paid mutator transaction binding the contract method 0xa9059cbb.
//
// Solidity: function transfer(_to address, _value uint256) returns()
func (_Token *TokenContractWrapper) RawTransfer(opts *bind.TransactOpts, _to common.Address, _value *big.Int) (*types.Transaction, error) {
return _Token.RawTransact(opts, "transfer", _to, _value)
}
// ParseTransferLogs parses log binding the contract event Transfer.
func (_Token *TokenContractWrapper) ParseTransferLogs(receipt *types.Receipt) (
fromList []common.Address, toList []common.Address, valueList []*big.Int, err error) {
for _, l := range receipt.Logs {
event := new(TokenTransfer)
if len(l.Data) > 0 {
err = _Token.contract.UnpackLog(event, "Transfer", *l)
if err == nil {
fromList = append(fromList, event.From)
toList = append(toList, event.To)
valueList = append(valueList, event.Value)
}
}
}
if len(fromList) <= 0 && err != nil {
return
}
err = nil
return
}
type transferParams struct {
To common.Address
Value *big.Int
}
// UnpackTransfer unpack parameters binding the contract method 0xa9059cbb.
//
// Solidity: function transfer(_to address, _value uint256) returns()
func (_Token *TokenContractWrapper) UnpackTransfer(data []byte) (to common.Address, value *big.Int, err error) {
params := transferParams{}
method, err := _Token.abi.MethodById(data)
if err != nil {
return
}
if method.Name != "transfer" {
err = errors.New("invalid method, not for transfer")
return
}
err = _Token.unpackInput(¶ms, "transfer", data[4:])
if err != nil {
return
}
to, value = params.To, params.Value
return
}
// call invokes the (constant) contract method with params as input values and
// sets the output to result. The result type might be a single field for simple
// returns, a slice of interfaces for anonymous returns and a struct for named
// returns.
// from go-ethereum/accounts/abi/bind/solana.go
func (_Token *TokenContractWrapper) call(opts *bind.CallOpts, blockNumber *big.Int,
result interface{}, method string, params ...interface{}) error {
// Don't crash on a lazy user
if opts == nil {
opts = new(bind.CallOpts)
}
// Pack the input, call and unpack the results
input, err := _Token.abi.Pack(method, params...)
if err != nil {
return err
}
var (
msg = ethereum.CallMsg{From: opts.From, To: &_Token.address, Data: input}
ctx = ensureContext(opts.Context)
code []byte
output []byte
)
if opts.Pending {
pb, ok := _Token.backend.(bind.PendingContractCaller)
if !ok {
return bind.ErrNoPendingState
}
output, err = pb.PendingCallContract(ctx, msg)
if err == nil && len(output) == 0 {
// Make sure we have a contract to operate on, and bail out otherwise.
if code, err = pb.PendingCodeAt(ctx, _Token.address); err != nil {
return err
} else if len(code) == 0 {
return bind.ErrNoCode
}
}
} else {
output, err = _Token.backend.CallContract(ctx, msg, blockNumber)
if err == nil && len(output) == 0 {
// Make sure we have a contract to operate on, and bail out otherwise.
if code, err = _Token.backend.CodeAt(ctx, _Token.address, nil); err != nil {
return err
} else if len(code) == 0 {
return bind.ErrNoCode
}
}
}
if err != nil {
return err
}
result, err = _Token.abi.Unpack(method, output)
return err
}
// RawTransact invokes the (paid) contract method with params as input values.
// from go-ethereum/accounts/abi/bind/solana.go
// modification: do not sign or send the transaction
func (_Token *TokenContractWrapper) RawTransact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
// Otherwise pack up the parameters and invoke the contract
input, err := _Token.abi.Pack(method, params...)
if err != nil {
return nil, err
}
return _Token.rawTransact(opts, &_Token.address, input)
}
// rawTransact executes an actual transaction invocation, first deriving any missing
// authorization fields, and then scheduling the transaction for execution.
// from go-ethereum/accounts/abi/bind/solana.go
// modification: do not sign or send the transaction
func (_Token *TokenContractWrapper) rawTransact(opts *bind.TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
// Ensure a valid value field and resolve the account nonce
value := opts.Value
if value == nil {
value = new(big.Int)
}
var nonce uint64
if opts.Nonce == nil {
return nil, errors.New("failed to retrieve account nonce")
}
nonce = opts.Nonce.Uint64()
// Figure out the gas allowance and gas price values
gasPrice := opts.GasPrice
if gasPrice == nil {
return nil, errors.New("failed to suggest gas price")
}
gasLimit := opts.GasLimit
if gasLimit == 0 {
return nil, errors.New("failed to estimate gas needed: %v")
}
// Create the transaction, sign it and schedule it for execution
var rawTx *types.Transaction
if contract == nil {
rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input)
} else {
rawTx = types.NewTransaction(nonce, _Token.address, value, gasLimit, gasPrice, input)
}
return rawTx, nil
}
// unpackInput input in v according to the abi specification
// from Unpack() in go-ethereum/accounts/abi/abi.go
func (_Token *TokenContractWrapper) unpackInput(v interface{}, name string, input []byte) (err error) {
if len(input) == 0 {
return fmt.Errorf("abi: unmarshalling empty input")
}
// since there can't be naming collisions with contracts and events,
// we need to decide whether we're calling a method or an event
if method, ok := _Token.abi.Methods[name]; ok {
if len(input)%32 != 0 {
return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(input), input)
}
v, err = method.Inputs.Unpack(input)
return nil
}
return fmt.Errorf("abi: could not locate named method")
}
// ensureContext is a helper method to ensure a context is not nil, even if the
// user specified it as such.
// from go-ethereum/accounts/abi/bind/solana.go
func ensureContext(ctx context.Context) context.Context {
if ctx == nil {
return context.TODO()
}
return ctx
}