From 8990ef9cfe36743e975de167036e561347eeb2d9 Mon Sep 17 00:00:00 2001 From: Giancarlo Susin Date: Wed, 4 May 2022 16:11:55 -0300 Subject: [PATCH] Update "Reading ERC-20 Token Event Logs" to Solidity 0.8.13 and Geth 1.10.17 About renaming abi.Unpack to abi.UnpackIntoInterface: https://github.com/ethereum/go-ethereum/pull/21091 --- code/contracts_erc20/erc20.go | 213 ++++++++++++++++++++++----------- code/contracts_erc20/erc20.sol | 18 +-- code/event_read_erc20.go | 6 +- en/event-read-erc20/README.md | 38 ++++-- 4 files changed, 182 insertions(+), 93 deletions(-) diff --git a/code/contracts_erc20/erc20.go b/code/contracts_erc20/erc20.go index f3d2baed..0ac3793a 100644 --- a/code/contracts_erc20/erc20.go +++ b/code/contracts_erc20/erc20.go @@ -4,6 +4,7 @@ package token import ( + "errors" "math/big" "strings" @@ -15,8 +16,26 @@ import ( "github.com/ethereum/go-ethereum/event" ) +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// TokenMetaData contains all meta data concerning the Token contract. +var TokenMetaData = &bind.MetaData{ + ABI: "[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"spender\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenOwner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenOwner\",\"type\":\"address\"},{\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"remaining\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"tokenOwner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"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,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"spender\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"from\",\"type\":\"address\"},{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenOwner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"to\",\"type\":\"address\"},{\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"success\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"tokenOwner\",\"type\":\"address\"},{\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"remaining\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"tokenOwner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"}]" +// Deprecated: Use TokenMetaData.ABI instead. +var TokenABI = TokenMetaData.ABI // Token is an auto generated Go binding around an Ethereum contract. type Token struct { @@ -126,7 +145,7 @@ func bindToken(address common.Address, caller bind.ContractCaller, transactor bi // 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 { +func (_Token *TokenRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { return _Token.Contract.TokenCaller.contract.Call(opts, result, method, params...) } @@ -145,7 +164,7 @@ func (_Token *TokenRaw) Transact(opts *bind.TransactOpts, method string, params // 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 { +func (_Token *TokenCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { return _Token.Contract.contract.Call(opts, result, method, params...) } @@ -162,219 +181,249 @@ func (_Token *TokenTransactorRaw) Transact(opts *bind.TransactOpts, method strin // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. // -// Solidity: function allowance(tokenOwner address, spender address) constant returns(remaining uint256) +// Solidity: function allowance(address tokenOwner, address spender) view returns(uint256 remaining) func (_Token *TokenCaller) Allowance(opts *bind.CallOpts, tokenOwner common.Address, spender common.Address) (*big.Int, error) { - var ( - ret0 = new(*big.Int) - ) - out := ret0 - err := _Token.contract.Call(opts, out, "allowance", tokenOwner, spender) - return *ret0, err + var out []interface{} + err := _Token.contract.Call(opts, &out, "allowance", tokenOwner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + } // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. // -// Solidity: function allowance(tokenOwner address, spender address) constant returns(remaining uint256) +// Solidity: function allowance(address tokenOwner, address spender) view returns(uint256 remaining) func (_Token *TokenSession) Allowance(tokenOwner common.Address, spender common.Address) (*big.Int, error) { return _Token.Contract.Allowance(&_Token.CallOpts, tokenOwner, spender) } // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. // -// Solidity: function allowance(tokenOwner address, spender address) constant returns(remaining uint256) +// Solidity: function allowance(address tokenOwner, address spender) view returns(uint256 remaining) func (_Token *TokenCallerSession) Allowance(tokenOwner common.Address, spender common.Address) (*big.Int, error) { return _Token.Contract.Allowance(&_Token.CallOpts, tokenOwner, spender) } // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(tokenOwner address) constant returns(balance uint256) +// Solidity: function balanceOf(address tokenOwner) view returns(uint256 balance) func (_Token *TokenCaller) BalanceOf(opts *bind.CallOpts, tokenOwner common.Address) (*big.Int, error) { - var ( - ret0 = new(*big.Int) - ) - out := ret0 - err := _Token.contract.Call(opts, out, "balanceOf", tokenOwner) - return *ret0, err + var out []interface{} + err := _Token.contract.Call(opts, &out, "balanceOf", tokenOwner) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + } // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(tokenOwner address) constant returns(balance uint256) +// Solidity: function balanceOf(address tokenOwner) view returns(uint256 balance) func (_Token *TokenSession) BalanceOf(tokenOwner common.Address) (*big.Int, error) { return _Token.Contract.BalanceOf(&_Token.CallOpts, tokenOwner) } // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(tokenOwner address) constant returns(balance uint256) +// Solidity: function balanceOf(address tokenOwner) view returns(uint256 balance) func (_Token *TokenCallerSession) BalanceOf(tokenOwner common.Address) (*big.Int, error) { return _Token.Contract.BalanceOf(&_Token.CallOpts, tokenOwner) } // Decimals is a free data retrieval call binding the contract method 0x313ce567. // -// Solidity: function decimals() constant returns(uint8) +// Solidity: function decimals() view 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 + var out []interface{} + err := _Token.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + } // Decimals is a free data retrieval call binding the contract method 0x313ce567. // -// Solidity: function decimals() constant returns(uint8) +// Solidity: function decimals() view 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) +// Solidity: function decimals() view 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) +// Solidity: function name() view 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 + var out []interface{} + err := _Token.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + } // Name is a free data retrieval call binding the contract method 0x06fdde03. // -// Solidity: function name() constant returns(string) +// Solidity: function name() view 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) +// Solidity: function name() view 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) +// Solidity: function symbol() view 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 + var out []interface{} + err := _Token.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + } // Symbol is a free data retrieval call binding the contract method 0x95d89b41. // -// Solidity: function symbol() constant returns(string) +// Solidity: function symbol() view 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) +// Solidity: function symbol() view 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) +// Solidity: function totalSupply() view 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 + var out []interface{} + err := _Token.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + } // TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. // -// Solidity: function totalSupply() constant returns(uint256) +// Solidity: function totalSupply() view 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) +// Solidity: function totalSupply() view 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, tokens uint256) returns(success bool) +// Solidity: function approve(address spender, uint256 tokens) returns(bool success) func (_Token *TokenTransactor) Approve(opts *bind.TransactOpts, spender common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.contract.Transact(opts, "approve", spender, tokens) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(spender address, tokens uint256) returns(success bool) +// Solidity: function approve(address spender, uint256 tokens) returns(bool success) func (_Token *TokenSession) Approve(spender common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.Contract.Approve(&_Token.TransactOpts, spender, tokens) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(spender address, tokens uint256) returns(success bool) +// Solidity: function approve(address spender, uint256 tokens) returns(bool success) func (_Token *TokenTransactorSession) Approve(spender common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.Contract.Approve(&_Token.TransactOpts, spender, tokens) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(to address, tokens uint256) returns(success bool) +// Solidity: function transfer(address to, uint256 tokens) returns(bool success) func (_Token *TokenTransactor) Transfer(opts *bind.TransactOpts, to common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.contract.Transact(opts, "transfer", to, tokens) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(to address, tokens uint256) returns(success bool) +// Solidity: function transfer(address to, uint256 tokens) returns(bool success) func (_Token *TokenSession) Transfer(to common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.Contract.Transfer(&_Token.TransactOpts, to, tokens) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(to address, tokens uint256) returns(success bool) +// Solidity: function transfer(address to, uint256 tokens) returns(bool success) func (_Token *TokenTransactorSession) Transfer(to common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.Contract.Transfer(&_Token.TransactOpts, to, tokens) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(from address, to address, tokens uint256) returns(success bool) +// Solidity: function transferFrom(address from, address to, uint256 tokens) returns(bool success) func (_Token *TokenTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.contract.Transact(opts, "transferFrom", from, to, tokens) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(from address, to address, tokens uint256) returns(success bool) +// Solidity: function transferFrom(address from, address to, uint256 tokens) returns(bool success) func (_Token *TokenSession) TransferFrom(from common.Address, to common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.Contract.TransferFrom(&_Token.TransactOpts, from, to, tokens) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(from address, to address, tokens uint256) returns(success bool) +// Solidity: function transferFrom(address from, address to, uint256 tokens) returns(bool success) func (_Token *TokenTransactorSession) TransferFrom(from common.Address, to common.Address, tokens *big.Int) (*types.Transaction, error) { return _Token.Contract.TransferFrom(&_Token.TransactOpts, from, to, tokens) } @@ -456,7 +505,7 @@ type TokenApproval struct { // FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. // -// Solidity: e Approval(tokenOwner indexed address, spender indexed address, tokens uint256) +// Solidity: event Approval(address indexed tokenOwner, address indexed spender, uint256 tokens) func (_Token *TokenFilterer) FilterApproval(opts *bind.FilterOpts, tokenOwner []common.Address, spender []common.Address) (*TokenApprovalIterator, error) { var tokenOwnerRule []interface{} @@ -477,7 +526,7 @@ func (_Token *TokenFilterer) FilterApproval(opts *bind.FilterOpts, tokenOwner [] // WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. // -// Solidity: e Approval(tokenOwner indexed address, spender indexed address, tokens uint256) +// Solidity: event Approval(address indexed tokenOwner, address indexed spender, uint256 tokens) func (_Token *TokenFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *TokenApproval, tokenOwner []common.Address, spender []common.Address) (event.Subscription, error) { var tokenOwnerRule []interface{} @@ -521,6 +570,18 @@ func (_Token *TokenFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *To }), nil } +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed tokenOwner, address indexed spender, uint256 tokens) +func (_Token *TokenFilterer) ParseApproval(log types.Log) (*TokenApproval, error) { + event := new(TokenApproval) + if err := _Token.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, 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 @@ -598,7 +659,7 @@ type TokenTransfer struct { // FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. // -// Solidity: e Transfer(from indexed address, to indexed address, tokens uint256) +// Solidity: event Transfer(address indexed from, address indexed to, uint256 tokens) func (_Token *TokenFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenTransferIterator, error) { var fromRule []interface{} @@ -619,7 +680,7 @@ func (_Token *TokenFilterer) FilterTransfer(opts *bind.FilterOpts, from []common // WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. // -// Solidity: e Transfer(from indexed address, to indexed address, tokens uint256) +// Solidity: event Transfer(address indexed from, address indexed to, uint256 tokens) func (_Token *TokenFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *TokenTransfer, from []common.Address, to []common.Address) (event.Subscription, error) { var fromRule []interface{} @@ -662,3 +723,15 @@ func (_Token *TokenFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *To } }), nil } + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 tokens) +func (_Token *TokenFilterer) ParseTransfer(log types.Log) (*TokenTransfer, error) { + event := new(TokenTransfer) + if err := _Token.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/code/contracts_erc20/erc20.sol b/code/contracts_erc20/erc20.sol index da3a5b15..691a9df9 100644 --- a/code/contracts_erc20/erc20.sol +++ b/code/contracts_erc20/erc20.sol @@ -1,16 +1,18 @@ -pragma solidity ^0.4.24; +//SPDX-License-Identifier: MIT -contract ERC20 { +pragma solidity >=0.6.0 <0.9.0; + +abstract contract ERC20 { string public constant name = ""; string public constant symbol = ""; uint8 public constant decimals = 0; - function totalSupply() public constant returns (uint); - function balanceOf(address tokenOwner) public constant returns (uint balance); - function allowance(address tokenOwner, address spender) public constant returns (uint remaining); - function transfer(address to, uint tokens) public returns (bool success); - function approve(address spender, uint tokens) public returns (bool success); - function transferFrom(address from, address to, uint tokens) public returns (bool success); + function totalSupply() public virtual returns (uint); + function balanceOf(address tokenOwner) public virtual returns (uint balance); + function allowance(address tokenOwner, address spender) public virtual returns (uint remaining); + function transfer(address to, uint tokens) public virtual returns (bool success); + function approve(address spender, uint tokens) public virtual returns (bool success); + function transferFrom(address from, address to, uint tokens) public virtual returns (bool success); event Transfer(address indexed from, address indexed to, uint tokens); event Approval(address indexed tokenOwner, address indexed spender, uint tokens); diff --git a/code/event_read_erc20.go b/code/event_read_erc20.go index bd071f54..363239ac 100644 --- a/code/event_read_erc20.go +++ b/code/event_read_erc20.go @@ -7,12 +7,12 @@ import ( "math/big" "strings" - token "./contracts_erc20" // for demo "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" + token "github.com/miguelmota/ethereum-development-with-go-book/code/contracts_erc20" // for demo ) // LogTransfer .. @@ -70,7 +70,7 @@ func main() { var transferEvent LogTransfer - err := contractAbi.Unpack(&transferEvent, "Transfer", vLog.Data) + err := contractAbi.UnpackIntoInterface(&transferEvent, "Transfer", vLog.Data) if err != nil { log.Fatal(err) } @@ -87,7 +87,7 @@ func main() { var approvalEvent LogApproval - err := contractAbi.Unpack(&approvalEvent, "Approval", vLog.Data) + err := contractAbi.UnpackIntoInterface(&approvalEvent, "Approval", vLog.Data) if err != nil { log.Fatal(err) } diff --git a/en/event-read-erc20/README.md b/en/event-read-erc20/README.md index d1959ff7..cdab4e51 100644 --- a/en/event-read-erc20/README.md +++ b/en/event-read-erc20/README.md @@ -7,15 +7,15 @@ description: Tutorial on how to read ERC-20 Token smart contract events with Go. First create the ERC-20 smart contract interface for event logs as `erc20.sol`: ```solidity -pragma solidity ^0.4.24; +pragma solidity >=0.6.0 <0.9.0; -contract ERC20 { +abstract contract ERC20 { event Transfer(address indexed from, address indexed to, uint tokens); event Approval(address indexed tokenOwner, address indexed spender, uint tokens); } ``` -Then use `abigen` to create the Go `exchange` package given the abi: +Then use `abigen` to create the Go `token` package given the abi: ```bash solc --abi erc20.sol @@ -104,14 +104,14 @@ for _, vLog := range logs { } ``` -Now to parse the `Transfer` event log we'll use `abi.Unpack` to parse the raw log data into our log type struct. Unpack will not parse `indexed` event types because those are stored under `topics`, so for those we'll have to parse separately as seen in the example below: +Now to parse the `Transfer` event log we'll use `abi.UnpackIntoInterface` to parse the raw log data into our log type struct. UnpackIntoInterface will not parse `indexed` event types because those are stored under `topics`, so for those we'll have to parse separately as seen in the example below: ```go fmt.Printf("Log Name: Transfer\n") var transferEvent LogTransfer -err := contractAbi.Unpack(&transferEvent, "Transfer", vLog.Data) +err := contractAbi.UnpackIntoInterface(&transferEvent, "Transfer", vLog.Data) if err != nil { log.Fatal(err) } @@ -131,7 +131,7 @@ fmt.Printf("Log Name: Approval\n") var approvalEvent LogApproval -err := contractAbi.Unpack(&approvalEvent, "Approval", vLog.Data) +err := contractAbi.UnpackIntoInterface(&approvalEvent, "Approval", vLog.Data) if err != nil { log.Fatal(err) } @@ -187,9 +187,22 @@ abigen --abi=erc20_sol_ERC20.abi --pkg=token --out=erc20.go [erc20.sol](https://github.com/miguelmota/ethereum-development-with-go-book/blob/master/code/contracts_erc20/erc20.sol) ```solidity -pragma solidity ^0.4.24; +//SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.9.0; + +abstract contract ERC20 { + string public constant name = ""; + string public constant symbol = ""; + uint8 public constant decimals = 0; + + function totalSupply() public virtual returns (uint); + function balanceOf(address tokenOwner) public virtual returns (uint balance); + function allowance(address tokenOwner, address spender) public virtual returns (uint remaining); + function transfer(address to, uint tokens) public virtual returns (bool success); + function approve(address spender, uint tokens) public virtual returns (bool success); + function transferFrom(address from, address to, uint tokens) public virtual returns (bool success); -contract ERC20 { event Transfer(address indexed from, address indexed to, uint tokens); event Approval(address indexed tokenOwner, address indexed spender, uint tokens); } @@ -207,12 +220,12 @@ import ( "math/big" "strings" - token "./contracts_erc20" // for demo "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" + token "github.com/miguelmota/ethereum-development-with-go-book/code/contracts_erc20" // for demo ) // LogTransfer .. @@ -270,7 +283,7 @@ func main() { var transferEvent LogTransfer - err := contractAbi.Unpack(&transferEvent, "Transfer", vLog.Data) + err := contractAbi.UnpackIntoInterface(&transferEvent, "Transfer", vLog.Data) if err != nil { log.Fatal(err) } @@ -287,7 +300,7 @@ func main() { var approvalEvent LogApproval - err := contractAbi.Unpack(&approvalEvent, "Approval", vLog.Data) + err := contractAbi.UnpackIntoInterface(&approvalEvent, "Approval", vLog.Data) if err != nil { log.Fatal(err) } @@ -309,5 +322,6 @@ solc version used for these examples ```bash $ solc --version -0.4.24+commit.e67f0147.Emscripten.clang +solc, the solidity compiler commandline interface +Version: 0.8.13+commit.abaa5c0e.Linux.g++ ```