-
-
Save nanom1t/15c316579cea15c4e698a4d6ed2f57ae to your computer and use it in GitHub Desktop.
Go go-ethereum watch ERC-20 token transfer events
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Code generated - DO NOT EDIT. | |
// This file is a generated binding and any manual changes will be lost. | |
package token | |
import ( | |
"math/big" | |
"strings" | |
ethereum "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" | |
"github.com/ethereum/go-ethereum/event" | |
) | |
// TokenABI is the input ABI used to generate the binding from. | |
const TokenABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"}]" | |
// Token is an auto generated Go binding around an Ethereum contract. | |
type Token struct { | |
TokenCaller // Read-only binding to the contract | |
TokenTransactor // Write-only binding to the contract | |
TokenFilterer // Log filterer for contract events | |
} | |
// TokenCaller is an auto generated read-only Go binding around an Ethereum contract. | |
type TokenCaller struct { | |
contract *bind.BoundContract // Generic contract wrapper for the low level calls | |
} | |
// TokenTransactor is an auto generated write-only Go binding around an Ethereum contract. | |
type TokenTransactor struct { | |
contract *bind.BoundContract // Generic contract wrapper for the low level calls | |
} | |
// TokenFilterer is an auto generated log filtering Go binding around an Ethereum contract events. | |
type TokenFilterer struct { | |
contract *bind.BoundContract // Generic contract wrapper for the low level calls | |
} | |
// TokenSession is an auto generated Go binding around an Ethereum contract, | |
// with pre-set call and transact options. | |
type TokenSession struct { | |
Contract *Token // Generic contract binding to set the session for | |
CallOpts bind.CallOpts // Call options to use throughout this session | |
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session | |
} | |
// TokenCallerSession is an auto generated read-only Go binding around an Ethereum contract, | |
// with pre-set call options. | |
type TokenCallerSession struct { | |
Contract *TokenCaller // Generic contract caller binding to set the session for | |
CallOpts bind.CallOpts // Call options to use throughout this session | |
} | |
// TokenTransactorSession is an auto generated write-only Go binding around an Ethereum contract, | |
// with pre-set transact options. | |
type TokenTransactorSession struct { | |
Contract *TokenTransactor // Generic contract transactor binding to set the session for | |
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session | |
} | |
// TokenRaw is an auto generated low-level Go binding around an Ethereum contract. | |
type TokenRaw struct { | |
Contract *Token // Generic contract binding to access the raw methods on | |
} | |
// TokenCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. | |
type TokenCallerRaw struct { | |
Contract *TokenCaller // Generic read-only contract binding to access the raw methods on | |
} | |
// TokenTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. | |
type TokenTransactorRaw struct { | |
Contract *TokenTransactor // Generic write-only contract binding to access the raw methods on | |
} | |
// NewToken creates a new instance of Token, bound to a specific deployed contract. | |
func NewToken(address common.Address, backend bind.ContractBackend) (*Token, error) { | |
contract, err := bindToken(address, backend, backend, backend) | |
if err != nil { | |
return nil, err | |
} | |
return &Token{TokenCaller: TokenCaller{contract: contract}, TokenTransactor: TokenTransactor{contract: contract}, TokenFilterer: TokenFilterer{contract: contract}}, nil | |
} | |
// NewTokenCaller creates a new read-only instance of Token, bound to a specific deployed contract. | |
func NewTokenCaller(address common.Address, caller bind.ContractCaller) (*TokenCaller, error) { | |
contract, err := bindToken(address, caller, nil, nil) | |
if err != nil { | |
return nil, err | |
} | |
return &TokenCaller{contract: contract}, nil | |
} | |
// NewTokenTransactor creates a new write-only instance of Token, bound to a specific deployed contract. | |
func NewTokenTransactor(address common.Address, transactor bind.ContractTransactor) (*TokenTransactor, error) { | |
contract, err := bindToken(address, nil, transactor, nil) | |
if err != nil { | |
return nil, err | |
} | |
return &TokenTransactor{contract: contract}, nil | |
} | |
// NewTokenFilterer creates a new log filterer instance of Token, bound to a specific deployed contract. | |
func NewTokenFilterer(address common.Address, filterer bind.ContractFilterer) (*TokenFilterer, error) { | |
contract, err := bindToken(address, nil, nil, filterer) | |
if err != nil { | |
return nil, err | |
} | |
return &TokenFilterer{contract: contract}, nil | |
} | |
// bindToken binds a generic wrapper to an already deployed contract. | |
func bindToken(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { | |
parsed, err := abi.JSON(strings.NewReader(TokenABI)) | |
if err != nil { | |
return nil, err | |
} | |
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil | |
} | |
// 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. | |
func (_Token *TokenRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { | |
return _Token.Contract.TokenCaller.contract.Call(opts, result, method, params...) | |
} | |
// Transfer initiates a plain transaction to move funds to the contract, calling | |
// its default method if one is available. | |
func (_Token *TokenRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { | |
return _Token.Contract.TokenTransactor.contract.Transfer(opts) | |
} | |
// Transact invokes the (paid) contract method with params as input values. | |
func (_Token *TokenRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { | |
return _Token.Contract.TokenTransactor.contract.Transact(opts, method, params...) | |
} | |
// 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. | |
func (_Token *TokenCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { | |
return _Token.Contract.contract.Call(opts, result, method, params...) | |
} | |
// Transfer initiates a plain transaction to move funds to the contract, calling | |
// its default method if one is available. | |
func (_Token *TokenTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { | |
return _Token.Contract.contract.Transfer(opts) | |
} | |
// Transact invokes the (paid) contract method with params as input values. | |
func (_Token *TokenTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { | |
return _Token.Contract.contract.Transact(opts, method, params...) | |
} | |
// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. | |
// | |
// Solidity: function allowance(_owner address, _spender address) constant returns(uint256) | |
func (_Token *TokenCaller) Allowance(opts *bind.CallOpts, _owner common.Address, _spender common.Address) (*big.Int, error) { | |
var ( | |
ret0 = new(*big.Int) | |
) | |
out := ret0 | |
err := _Token.contract.Call(opts, out, "allowance", _owner, _spender) | |
return *ret0, err | |
} | |
// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. | |
// | |
// Solidity: function allowance(_owner address, _spender address) constant returns(uint256) | |
func (_Token *TokenSession) Allowance(_owner common.Address, _spender common.Address) (*big.Int, error) { | |
return _Token.Contract.Allowance(&_Token.CallOpts, _owner, _spender) | |
} | |
// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. | |
// | |
// Solidity: function allowance(_owner address, _spender address) constant returns(uint256) | |
func (_Token *TokenCallerSession) Allowance(_owner common.Address, _spender common.Address) (*big.Int, error) { | |
return _Token.Contract.Allowance(&_Token.CallOpts, _owner, _spender) | |
} | |
// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. | |
// | |
// Solidity: function balanceOf(_owner address) constant returns(uint256) | |
func (_Token *TokenCaller) BalanceOf(opts *bind.CallOpts, _owner common.Address) (*big.Int, error) { | |
var ( | |
ret0 = new(*big.Int) | |
) | |
out := ret0 | |
err := _Token.contract.Call(opts, out, "balanceOf", _owner) | |
return *ret0, err | |
} | |
// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. | |
// | |
// Solidity: function balanceOf(_owner address) constant returns(uint256) | |
func (_Token *TokenSession) BalanceOf(_owner common.Address) (*big.Int, error) { | |
return _Token.Contract.BalanceOf(&_Token.CallOpts, _owner) | |
} | |
// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. | |
// | |
// Solidity: function balanceOf(_owner address) constant returns(uint256) | |
func (_Token *TokenCallerSession) BalanceOf(_owner common.Address) (*big.Int, error) { | |
return _Token.Contract.BalanceOf(&_Token.CallOpts, _owner) | |
} | |
// Decimals is a free data retrieval call binding the contract method 0x313ce567. | |
// | |
// Solidity: function decimals() constant returns(uint8) | |
func (_Token *TokenCaller) Decimals(opts *bind.CallOpts) (uint8, error) { | |
var ( | |
ret0 = new(uint8) | |
) | |
out := ret0 | |
err := _Token.contract.Call(opts, out, "decimals") | |
return *ret0, err | |
} | |
// Decimals is a free data retrieval call binding the contract method 0x313ce567. | |
// | |
// Solidity: function decimals() constant returns(uint8) | |
func (_Token *TokenSession) Decimals() (uint8, error) { | |
return _Token.Contract.Decimals(&_Token.CallOpts) | |
} | |
// Decimals is a free data retrieval call binding the contract method 0x313ce567. | |
// | |
// Solidity: function decimals() constant returns(uint8) | |
func (_Token *TokenCallerSession) Decimals() (uint8, error) { | |
return _Token.Contract.Decimals(&_Token.CallOpts) | |
} | |
// Name is a free data retrieval call binding the contract method 0x06fdde03. | |
// | |
// Solidity: function name() constant returns(string) | |
func (_Token *TokenCaller) Name(opts *bind.CallOpts) (string, error) { | |
var ( | |
ret0 = new(string) | |
) | |
out := ret0 | |
err := _Token.contract.Call(opts, out, "name") | |
return *ret0, err | |
} | |
// Name is a free data retrieval call binding the contract method 0x06fdde03. | |
// | |
// Solidity: function name() constant returns(string) | |
func (_Token *TokenSession) Name() (string, error) { | |
return _Token.Contract.Name(&_Token.CallOpts) | |
} | |
// Name is a free data retrieval call binding the contract method 0x06fdde03. | |
// | |
// Solidity: function name() constant returns(string) | |
func (_Token *TokenCallerSession) Name() (string, error) { | |
return _Token.Contract.Name(&_Token.CallOpts) | |
} | |
// Symbol is a free data retrieval call binding the contract method 0x95d89b41. | |
// | |
// Solidity: function symbol() constant returns(string) | |
func (_Token *TokenCaller) Symbol(opts *bind.CallOpts) (string, error) { | |
var ( | |
ret0 = new(string) | |
) | |
out := ret0 | |
err := _Token.contract.Call(opts, out, "symbol") | |
return *ret0, err | |
} | |
// Symbol is a free data retrieval call binding the contract method 0x95d89b41. | |
// | |
// Solidity: function symbol() constant returns(string) | |
func (_Token *TokenSession) Symbol() (string, error) { | |
return _Token.Contract.Symbol(&_Token.CallOpts) | |
} | |
// Symbol is a free data retrieval call binding the contract method 0x95d89b41. | |
// | |
// Solidity: function symbol() constant returns(string) | |
func (_Token *TokenCallerSession) Symbol() (string, error) { | |
return _Token.Contract.Symbol(&_Token.CallOpts) | |
} | |
// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. | |
// | |
// Solidity: function totalSupply() constant returns(uint256) | |
func (_Token *TokenCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { | |
var ( | |
ret0 = new(*big.Int) | |
) | |
out := ret0 | |
err := _Token.contract.Call(opts, out, "totalSupply") | |
return *ret0, err | |
} | |
// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. | |
// | |
// Solidity: function totalSupply() constant returns(uint256) | |
func (_Token *TokenSession) TotalSupply() (*big.Int, error) { | |
return _Token.Contract.TotalSupply(&_Token.CallOpts) | |
} | |
// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. | |
// | |
// Solidity: function totalSupply() constant returns(uint256) | |
func (_Token *TokenCallerSession) TotalSupply() (*big.Int, error) { | |
return _Token.Contract.TotalSupply(&_Token.CallOpts) | |
} | |
// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. | |
// | |
// Solidity: function approve(_spender address, _value uint256) returns(bool) | |
func (_Token *TokenTransactor) Approve(opts *bind.TransactOpts, _spender common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.contract.Transact(opts, "approve", _spender, _value) | |
} | |
// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. | |
// | |
// Solidity: function approve(_spender address, _value uint256) returns(bool) | |
func (_Token *TokenSession) Approve(_spender common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.Contract.Approve(&_Token.TransactOpts, _spender, _value) | |
} | |
// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. | |
// | |
// Solidity: function approve(_spender address, _value uint256) returns(bool) | |
func (_Token *TokenTransactorSession) Approve(_spender common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.Contract.Approve(&_Token.TransactOpts, _spender, _value) | |
} | |
// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. | |
// | |
// Solidity: function transfer(_to address, _value uint256) returns(bool) | |
func (_Token *TokenTransactor) Transfer(opts *bind.TransactOpts, _to common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.contract.Transact(opts, "transfer", _to, _value) | |
} | |
// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. | |
// | |
// Solidity: function transfer(_to address, _value uint256) returns(bool) | |
func (_Token *TokenSession) Transfer(_to common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.Contract.Transfer(&_Token.TransactOpts, _to, _value) | |
} | |
// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. | |
// | |
// Solidity: function transfer(_to address, _value uint256) returns(bool) | |
func (_Token *TokenTransactorSession) Transfer(_to common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.Contract.Transfer(&_Token.TransactOpts, _to, _value) | |
} | |
// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. | |
// | |
// Solidity: function transferFrom(_from address, _to address, _value uint256) returns(bool) | |
func (_Token *TokenTransactor) TransferFrom(opts *bind.TransactOpts, _from common.Address, _to common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.contract.Transact(opts, "transferFrom", _from, _to, _value) | |
} | |
// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. | |
// | |
// Solidity: function transferFrom(_from address, _to address, _value uint256) returns(bool) | |
func (_Token *TokenSession) TransferFrom(_from common.Address, _to common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.Contract.TransferFrom(&_Token.TransactOpts, _from, _to, _value) | |
} | |
// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. | |
// | |
// Solidity: function transferFrom(_from address, _to address, _value uint256) returns(bool) | |
func (_Token *TokenTransactorSession) TransferFrom(_from common.Address, _to common.Address, _value *big.Int) (*types.Transaction, error) { | |
return _Token.Contract.TransferFrom(&_Token.TransactOpts, _from, _to, _value) | |
} | |
// TokenApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Token contract. | |
type TokenApprovalIterator struct { | |
Event *TokenApproval // Event containing the contract specifics and raw log | |
contract *bind.BoundContract // Generic contract to use for unpacking event data | |
event string // Event name to use for unpacking event data | |
logs chan types.Log // Log channel receiving the found contract events | |
sub ethereum.Subscription // Subscription for errors, completion and termination | |
done bool // Whether the subscription completed delivering logs | |
fail error // Occurred error to stop iteration | |
} | |
// Next advances the iterator to the subsequent event, returning whether there | |
// are any more events found. In case of a retrieval or parsing error, false is | |
// returned and Error() can be queried for the exact failure. | |
func (it *TokenApprovalIterator) Next() bool { | |
// If the iterator failed, stop iterating | |
if it.fail != nil { | |
return false | |
} | |
// If the iterator completed, deliver directly whatever's available | |
if it.done { | |
select { | |
case log := <-it.logs: | |
it.Event = new(TokenApproval) | |
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { | |
it.fail = err | |
return false | |
} | |
it.Event.Raw = log | |
return true | |
default: | |
return false | |
} | |
} | |
// Iterator still in progress, wait for either a data or an error event | |
select { | |
case log := <-it.logs: | |
it.Event = new(TokenApproval) | |
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { | |
it.fail = err | |
return false | |
} | |
it.Event.Raw = log | |
return true | |
case err := <-it.sub.Err(): | |
it.done = true | |
it.fail = err | |
return it.Next() | |
} | |
} | |
// Error returns any retrieval or parsing error occurred during filtering. | |
func (it *TokenApprovalIterator) Error() error { | |
return it.fail | |
} | |
// Close terminates the iteration process, releasing any pending underlying | |
// resources. | |
func (it *TokenApprovalIterator) Close() error { | |
it.sub.Unsubscribe() | |
return nil | |
} | |
// TokenApproval represents a Approval event raised by the Token contract. | |
type TokenApproval struct { | |
Owner common.Address | |
Spender common.Address | |
Value *big.Int | |
Raw types.Log // Blockchain specific contextual infos | |
} | |
// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. | |
// | |
// Solidity: event Approval(_owner indexed address, _spender indexed address, _value uint256) | |
func (_Token *TokenFilterer) FilterApproval(opts *bind.FilterOpts, _owner []common.Address, _spender []common.Address) (*TokenApprovalIterator, error) { | |
var _ownerRule []interface{} | |
for _, _ownerItem := range _owner { | |
_ownerRule = append(_ownerRule, _ownerItem) | |
} | |
var _spenderRule []interface{} | |
for _, _spenderItem := range _spender { | |
_spenderRule = append(_spenderRule, _spenderItem) | |
} | |
logs, sub, err := _Token.contract.FilterLogs(opts, "Approval", _ownerRule, _spenderRule) | |
if err != nil { | |
return nil, err | |
} | |
return &TokenApprovalIterator{contract: _Token.contract, event: "Approval", logs: logs, sub: sub}, nil | |
} | |
// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. | |
// | |
// Solidity: event Approval(_owner indexed address, _spender indexed address, _value uint256) | |
func (_Token *TokenFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *TokenApproval, _owner []common.Address, _spender []common.Address) (event.Subscription, error) { | |
var _ownerRule []interface{} | |
for _, _ownerItem := range _owner { | |
_ownerRule = append(_ownerRule, _ownerItem) | |
} | |
var _spenderRule []interface{} | |
for _, _spenderItem := range _spender { | |
_spenderRule = append(_spenderRule, _spenderItem) | |
} | |
logs, sub, err := _Token.contract.WatchLogs(opts, "Approval", _ownerRule, _spenderRule) | |
if err != nil { | |
return nil, err | |
} | |
return event.NewSubscription(func(quit <-chan struct{}) error { | |
defer sub.Unsubscribe() | |
for { | |
select { | |
case log := <-logs: | |
// New log arrived, parse the event and forward to the user | |
event := new(TokenApproval) | |
if err := _Token.contract.UnpackLog(event, "Approval", log); err != nil { | |
return err | |
} | |
event.Raw = log | |
select { | |
case sink <- event: | |
case err := <-sub.Err(): | |
return err | |
case <-quit: | |
return nil | |
} | |
case err := <-sub.Err(): | |
return err | |
case <-quit: | |
return nil | |
} | |
} | |
}), nil | |
} | |
// TokenTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Token contract. | |
type TokenTransferIterator struct { | |
Event *TokenTransfer // Event containing the contract specifics and raw log | |
contract *bind.BoundContract // Generic contract to use for unpacking event data | |
event string // Event name to use for unpacking event data | |
logs chan types.Log // Log channel receiving the found contract events | |
sub ethereum.Subscription // Subscription for errors, completion and termination | |
done bool // Whether the subscription completed delivering logs | |
fail error // Occurred error to stop iteration | |
} | |
// Next advances the iterator to the subsequent event, returning whether there | |
// are any more events found. In case of a retrieval or parsing error, false is | |
// returned and Error() can be queried for the exact failure. | |
func (it *TokenTransferIterator) Next() bool { | |
// If the iterator failed, stop iterating | |
if it.fail != nil { | |
return false | |
} | |
// If the iterator completed, deliver directly whatever's available | |
if it.done { | |
select { | |
case log := <-it.logs: | |
it.Event = new(TokenTransfer) | |
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { | |
it.fail = err | |
return false | |
} | |
it.Event.Raw = log | |
return true | |
default: | |
return false | |
} | |
} | |
// Iterator still in progress, wait for either a data or an error event | |
select { | |
case log := <-it.logs: | |
it.Event = new(TokenTransfer) | |
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { | |
it.fail = err | |
return false | |
} | |
it.Event.Raw = log | |
return true | |
case err := <-it.sub.Err(): | |
it.done = true | |
it.fail = err | |
return it.Next() | |
} | |
} | |
// Error returns any retrieval or parsing error occurred during filtering. | |
func (it *TokenTransferIterator) Error() error { | |
return it.fail | |
} | |
// Close terminates the iteration process, releasing any pending underlying | |
// resources. | |
func (it *TokenTransferIterator) Close() error { | |
it.sub.Unsubscribe() | |
return nil | |
} | |
// TokenTransfer represents a Transfer event raised by the Token contract. | |
type TokenTransfer struct { | |
From common.Address | |
To common.Address | |
Value *big.Int | |
Raw types.Log // Blockchain specific contextual infos | |
} | |
// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. | |
// | |
// Solidity: event Transfer(_from indexed address, _to indexed address, _value uint256) | |
func (_Token *TokenFilterer) FilterTransfer(opts *bind.FilterOpts, _from []common.Address, _to []common.Address) (*TokenTransferIterator, error) { | |
var _fromRule []interface{} | |
for _, _fromItem := range _from { | |
_fromRule = append(_fromRule, _fromItem) | |
} | |
var _toRule []interface{} | |
for _, _toItem := range _to { | |
_toRule = append(_toRule, _toItem) | |
} | |
logs, sub, err := _Token.contract.FilterLogs(opts, "Transfer", _fromRule, _toRule) | |
if err != nil { | |
return nil, err | |
} | |
return &TokenTransferIterator{contract: _Token.contract, event: "Transfer", logs: logs, sub: sub}, nil | |
} | |
// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. | |
// | |
// Solidity: event Transfer(_from indexed address, _to indexed address, _value uint256) | |
func (_Token *TokenFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *TokenTransfer, _from []common.Address, _to []common.Address) (event.Subscription, error) { | |
var _fromRule []interface{} | |
for _, _fromItem := range _from { | |
_fromRule = append(_fromRule, _fromItem) | |
} | |
var _toRule []interface{} | |
for _, _toItem := range _to { | |
_toRule = append(_toRule, _toItem) | |
} | |
logs, sub, err := _Token.contract.WatchLogs(opts, "Transfer", _fromRule, _toRule) | |
if err != nil { | |
return nil, err | |
} | |
return event.NewSubscription(func(quit <-chan struct{}) error { | |
defer sub.Unsubscribe() | |
for { | |
select { | |
case log := <-logs: | |
// New log arrived, parse the event and forward to the user | |
event := new(TokenTransfer) | |
if err := _Token.contract.UnpackLog(event, "Transfer", log); err != nil { | |
return err | |
} | |
event.Raw = log | |
select { | |
case sink <- event: | |
case err := <-sub.Err(): | |
return err | |
case <-quit: | |
return nil | |
} | |
case err := <-sub.Err(): | |
return err | |
case <-quit: | |
return nil | |
} | |
} | |
}), nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package watcher | |
import ( | |
"context" | |
"math/big" | |
"strings" | |
"time" | |
token "github.com/mycompany/myapp/pkg/erc20" | |
ethereum "github.com/ethereum/go-ethereum" | |
"github.com/ethereum/go-ethereum/accounts/abi" | |
"github.com/ethereum/go-ethereum/common" | |
"github.com/ethereum/go-ethereum/ethclient" | |
"github.com/shopspring/decimal" | |
log "github.com/sirupsen/logrus" | |
) | |
// Do not modify | |
var erc20TransferEventHash = common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") | |
// WatchOnChainTransactionsInput struct | |
type WatchOnChainTransactionsInput struct { | |
FromAddress string | |
ToAddress string | |
OutputChannel chan *WatchOnChainTransactionsOutput | |
} | |
// WatchOnChainTransactionsOutput struct | |
type WatchOnChainTransactionsOutput struct { | |
FromAddress string | |
ToAddress string | |
Amount decimal.Decimal | |
TxHash string | |
} | |
// Service service | |
type Service struct { | |
client *ethclient.Client | |
} | |
// NewInput input for constructor | |
type NewInput struct { | |
ProviderURL string | |
} | |
func init() { | |
log.SetLevel(log.DebugLevel) | |
} | |
// New returns new service | |
func New(input *NewInput) *Service { | |
client, err := ethclient.Dial(input.ProviderURL) | |
if err != nil { | |
log.Fatal(err) | |
} | |
return &Service{ | |
client: client, | |
} | |
} | |
// WatchOnChainTransactions watch for on-chain transactions | |
func (s *Service) WatchOnChainTransactions(input *WatchOnChainTransactionsInput) error { | |
erc20Abi, err := abi.JSON(strings.NewReader(string(token.TokenABI))) | |
if err != nil { | |
return err | |
} | |
go func() { | |
ticker := time.NewTicker(2 * time.Second) | |
currentBlockNumber := big.NewInt(0) | |
lastBlockNumberScanned := big.NewInt(0) | |
for { | |
select { | |
case <-ticker.C: | |
header, err := s.client.HeaderByNumber(context.Background(), nil) | |
if err != nil { | |
log.Errorf("error HeaderByNumber: %s", err) | |
continue | |
} | |
// if block number is the same then just continue | |
if header.Number.Cmp(currentBlockNumber) == 0 { | |
continue | |
} | |
// start a little behind to make sure we didn't miss any txs | |
currentBlockNumber = new(big.Int).Sub(header.Number, big.NewInt(2)) | |
if lastBlockNumberScanned.Cmp(currentBlockNumber) == 0 { | |
continue | |
} | |
log.Debugf("scanning block: %v", currentBlockNumber) | |
lastBlockNumberScanned = currentBlockNumber | |
query := ethereum.FilterQuery{ | |
FromBlock: currentBlockNumber, | |
ToBlock: nil, | |
Addresses: []common.Address{}, // all addresses | |
Topics: [][]common.Hash{ | |
[]common.Hash{erc20TransferEventHash}, // must be transfer event hash | |
[]common.Hash{}, // must be empty | |
[]common.Hash{common.HexToAddress(input.ToAddress).Hash()}, // token receiver | |
}, | |
} | |
logs, err := s.client.FilterLogs(context.Background(), query) | |
if err != nil { | |
log.Errorf("error getting FilterLogs: %s", err) | |
continue | |
} | |
for _, vLog := range logs { | |
output := &WatchOnChainTransactionsOutput{} | |
var event = struct { | |
Value *big.Int // must named "Value", dont' change. | |
}{} | |
err = erc20Abi.Unpack(&event, "Transfer", vLog.Data) | |
if err != nil { | |
log.Errorf("Subscription unpacking error: %s", err) | |
continue | |
} | |
output.Amount = decimal.NewFromBigInt(event.Value, 0) | |
output.FromAddress = common.BytesToAddress(vLog.Topics[1].Bytes()).String() | |
output.ToAddress = common.BytesToAddress(vLog.Topics[2].Bytes()).String() | |
output.TxHash = vLog.TxHash.String() | |
input.OutputChannel <- output | |
} | |
} | |
} | |
}() | |
return nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package watcher | |
import ( | |
"math/big" | |
"testing" | |
token "github.com/mycompany/myapp/pkg/erc20" | |
"github.com/ethereum/go-ethereum/accounts/abi/bind" | |
"github.com/ethereum/go-ethereum/common" | |
"github.com/ethereum/go-ethereum/crypto" | |
"github.com/ethereum/go-ethereum/ethclient" | |
"github.com/shopspring/decimal" | |
log "github.com/sirupsen/logrus" | |
) | |
func decimalsToWei(amount decimal.Decimal, decimals int) *big.Int { | |
mul := decimal.NewFromFloat(float64(10)).Pow(decimal.NewFromFloat(float64(decimals))) | |
result := amount.Mul(mul) | |
wei := new(big.Int) | |
wei.SetString(result.String(), 10) | |
return wei | |
} | |
func sendTokens() { | |
client, err := ethclient.Dial("https://rinkeby.infura.io:443") | |
if err != nil { | |
log.Fatal(err) | |
} | |
// rinkeby | |
amount := decimalsToWei(decimal.NewFromFloat(1), int(18)) // send 1 tokens | |
priv := "a1ea7b205141b739070598cbc7f152cc49f69dfc6ee3cc98363dcd5ae696cbbf" | |
key, err := crypto.HexToECDSA(priv) | |
if err != nil { | |
log.Fatal(err) | |
} | |
auth := *bind.NewKeyedTransactor(key) | |
auth.GasLimit = uint64(350000) // units | |
auth.GasPrice = big.NewInt(40000000000) // wei (40 gwei) | |
auth.Value = big.NewInt(0) | |
auth.Nonce = nil // must be nil | |
tokenAddress := common.HexToAddress("0x265712b02d982dca0ec2488aba707d06c1128baf") | |
toAddress := common.HexToAddress("0x54282fcD78070ff03e20c56786fE46eaF4c48884") | |
instance, err := token.NewToken(tokenAddress, client) | |
if err != nil { | |
log.Fatal(err) | |
} | |
tx, err := instance.Transfer(&auth, toAddress, amount) | |
if err != nil { | |
log.Fatal(err) | |
} | |
if err != nil { | |
log.Fatal(err) | |
} | |
log.Printf("tx: %s", tx.Hash().Hex()) | |
} | |
func TestWatcher(t *testing.T) { | |
t.Parallel() | |
sendTokens() | |
s := New(&NewInput{ | |
ProviderURL: "https://rinkeby.infura.io:443", | |
}) | |
outputChannel := make(chan *WatchOnChainTransactionsOutput) | |
err := s.WatchOnChainTransactions(&WatchOnChainTransactionsInput{ | |
ToAddress: "0x54282fcD78070ff03e20c56786fE46eaF4c48884", | |
OutputChannel: outputChannel, | |
}) | |
if err != nil { | |
t.Fatal(err) | |
} | |
output := <-outputChannel | |
log.Println(output) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment