From af94b98dee89e264d70c736d34a1b5485708bd81 Mon Sep 17 00:00:00 2001 From: Himanshu Nagda <69150921+nagdahimanshu@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:01:48 +0200 Subject: [PATCH] Fix estimate gas logic (#8) * :bug: Fix estimate gas calculation * Add command to generate Go binding in Makefile Update readme * :ok_hand: Applied suggestions * :ok_hand: Applied suggestions from code review --- .env | 6 + Makefile | 33 +- README.md | 25 +- go.mod | 3 + internal/bindings/erc20.go | 1685 ++++++++++++++++++++++++++++ internal/chain/transaction.go | 60 +- internal/chain/transaction_test.go | 105 +- internal/server/server.go | 15 +- 8 files changed, 1850 insertions(+), 82 deletions(-) create mode 100644 .env create mode 100644 internal/bindings/erc20.go diff --git a/.env b/.env new file mode 100644 index 00000000..980f1e63 --- /dev/null +++ b/.env @@ -0,0 +1,6 @@ +WEB3_PROVIDER= +PRIVATE_KEY= +KEYSTORE= +ERC20_TOKEN_ADDRESS= +HCAPTCHA_SITEKEY= +HCAPTCHA_SECRET= \ No newline at end of file diff --git a/Makefile b/Makefile index 519ecdb8..a13f5e2e 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,45 @@ +include .env APP_NAME = lsk-faucet PKGS=$(shell go list ./... | grep -v "/vendor/") BLUE = \033[1;34m GREEN = \033[1;32m COLOR_END = \033[0;39m +BINDING_OUTPUT_DIR=$(realpath ./internal/bindings) + +validate-env: # Validates if the necessary environment variables are set +ifndef ERC20_CONTRACT_FILE_PATH + $(error `ERC20_CONTRACT_FILE_PATH` environment variable is undefined) +endif build: build-frontend build-backend build-backend: # Builds the application and create a binary at ./bin/ @echo "$(BLUE)» Building $(APP_NAME) application binary... $(COLOR_END)" - @go build -a -o bin/$(APP_NAME) . + go build -a -o bin/$(APP_NAME) . @echo "$(GREEN)Binary successfully built$(COLOR_END)" build-frontend: # Builds the frontned application @echo "$(BLUE)» Building frontend... $(COLOR_END)" - @go generate + go generate @echo "$(GREEN)Frontend successfully built$(COLOR_END)" run: # Runs the application, use `make run FLAGS="--help"` - @./bin/${APP_NAME} ${FLAGS} + ./bin/${APP_NAME} ${FLAGS} + +generate-abi: validate-env + @echo "$(BLUE)Generating abi file... $(COLOR_END)" + solc --overwrite --abi $(ERC20_CONTRACT_FILE_PATH) -o $(BINDING_OUTPUT_DIR) + @echo "$(GREEN)ABI file generated successfully$(COLOR_END)" + +generate-binding: generate-abi + @echo "$(BLUE)Generating go binding for the ERC20 token smart contract... $(COLOR_END)" + abigen --abi=$(shell find $(BINDING_OUTPUT_DIR) -type f -name '*.abi') --pkg=bindings --out=$(BINDING_OUTPUT_DIR)/erc20.go + @echo "$(GREEN)Go binding generated successfully$(COLOR_END)" test: # Runs tests @echo "Test packages" - @go test -race -shuffle=on -coverprofile=coverage.out -cover $(PKGS) + go test -race -shuffle=on -coverprofile=coverage.out -cover $(PKGS) lint: # Runs golangci-lint on the repo @go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest @@ -33,19 +50,19 @@ format: # Runs gofmt on the repo build-image: # Builds docker image @echo "$(BLUE)Building docker image...$(COLOR_END)" - @docker build -t $(APP_NAME) . + docker build -t $(APP_NAME) . docker-start: # Runs docker image @echo "$(BLUE)Starting docker container $(APP_NAME)...$(COLOR_END)" ifdef PRIVATE_KEY - @docker run --name $(APP_NAME) -p 8080:8080 -d -e WEB3_PROVIDER=$(WEB3_PROVIDER) -e PRIVATE_KEY=$(PRIVATE_KEY) $(APP_NAME) + docker run --name $(APP_NAME) -p 8080:8080 -d --env-file .env $(APP_NAME) else ifdef KEYSTORE - @docker run --name $(APP_NAME) -p 8080:8080 -d -e WEB3_PROVIDER=$(WEB3_PROVIDER) -e KEYSTORE=$(KEYSTORE) -v $(KEYSTORE)/keystore:/app/keystore -v $(KEYSTORE)/password.txt:/app/password.txt $(APP_NAME) + docker run --name $(APP_NAME) -p 8080:8080 -d --env-file .env -v $(KEYSTORE)/keystore:/app/keystore -v $(KEYSTORE)/password.txt:/app/password.txt $(APP_NAME) endif docker-stop: @echo "$(BLUE)Stopping and removing docker container $(APP_NAME)...$(COLOR_END)" - @docker rm -f $(APP_NAME) + docker rm -f $(APP_NAME) .PHONY: help help: # Show help for each of the Makefile recipes diff --git a/README.md b/README.md index e2ea78d4..b9259d59 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ LSK faucet is a web application that can be configured and deployed to get ETH a * Go (1.22 or later) * Node.js +* Solidity compiler (solc) +* Abigen ### Installation @@ -38,8 +40,14 @@ cd lsk-faucet ```bash make build-frontend ``` +3. Generate Go binding for ERC20 token smart contract +```bash +make generate-binding ERC20_CONTRACT_FILE_PATH= +``` + +**NOTE**: Please make sure to generate the Go binding corresponding to your contract before building the project. -3. Build Go project +4. Build Go project ```bash make build-backend ``` @@ -105,25 +113,16 @@ The following are the available command-line flags(excluding above wallet flags) #### Build docker image Run the following command to build docker image: ```bash -make build +make build-image ``` #### Run faucet -Run the following command to start the application: +Set the appropriate configuration in `.env` file and run the following command to start the application: ```bash -make docker-start WEB3_PROVIDER= PRIVATE_KEY= +make docker-start ``` -**NOTE**: Please replace `` and `` with appropriate values. - -or - -```bash -make docker-start WEB3_PROVIDER= KEYSTORE= -``` - -**NOTE**: Please replace `` and `` with appropriate values. ## License diff --git a/go.mod b/go.mod index f135c8fb..355bd687 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/jellydator/ttlcache/v2 v2.11.1 github.com/kataras/hcaptcha v0.0.2 github.com/sirupsen/logrus v1.9.3 + github.com/stretchr/testify v1.8.4 github.com/urfave/negroni v1.0.0 golang.org/x/crypto v0.22.0 ) @@ -68,6 +69,7 @@ require ( github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.12.0 // indirect github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect github.com/prometheus/common v0.32.1 // indirect @@ -92,5 +94,6 @@ require ( golang.org/x/time v0.5.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/internal/bindings/erc20.go b/internal/bindings/erc20.go new file mode 100644 index 00000000..8903ad1a --- /dev/null +++ b/internal/bindings/erc20.go @@ -0,0 +1,1685 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "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" +) + +// 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 + _ = abi.ConvertType +) + +// TokenMetaData contains all meta data concerning the Token contract. +var TokenMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"remoteTokenAddr\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ECDSAInvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"ECDSAInvalidSignatureLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"ECDSAInvalidSignatureS\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"name\":\"ERC2612ExpiredSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC2612InvalidSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentNonce\",\"type\":\"uint256\"}],\"name\":\"InvalidAccountNonce\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidShortString\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"str\",\"type\":\"string\"}],\"name\":\"StringTooLong\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldBridgeAddr\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newBridgeAddr\",\"type\":\"address\"}],\"name\":\"BridgeAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"EIP712DomainChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BRIDGE\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REMOTE_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"bridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eip712Domain\",\"outputs\":[{\"internalType\":\"bytes1\",\"name\":\"fields\",\"type\":\"bytes1\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"verifyingContract\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"salt\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"extensions\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"bridgeAddr\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"remoteToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// TokenABI is the input ABI used to generate the binding from. +// Deprecated: Use TokenMetaData.ABI instead. +var TokenABI = TokenMetaData.ABI + +// 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 := TokenMetaData.GetAbi() + 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...) +} + +// BRIDGE is a free data retrieval call binding the contract method 0xee9a31a2. +// +// Solidity: function BRIDGE() view returns(address) +func (_Token *TokenCaller) BRIDGE(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "BRIDGE") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// BRIDGE is a free data retrieval call binding the contract method 0xee9a31a2. +// +// Solidity: function BRIDGE() view returns(address) +func (_Token *TokenSession) BRIDGE() (common.Address, error) { + return _Token.Contract.BRIDGE(&_Token.CallOpts) +} + +// BRIDGE is a free data retrieval call binding the contract method 0xee9a31a2. +// +// Solidity: function BRIDGE() view returns(address) +func (_Token *TokenCallerSession) BRIDGE() (common.Address, error) { + return _Token.Contract.BRIDGE(&_Token.CallOpts) +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_Token *TokenCaller) DOMAINSEPARATOR(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "DOMAIN_SEPARATOR") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_Token *TokenSession) DOMAINSEPARATOR() ([32]byte, error) { + return _Token.Contract.DOMAINSEPARATOR(&_Token.CallOpts) +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_Token *TokenCallerSession) DOMAINSEPARATOR() ([32]byte, error) { + return _Token.Contract.DOMAINSEPARATOR(&_Token.CallOpts) +} + +// REMOTETOKEN is a free data retrieval call binding the contract method 0x033964be. +// +// Solidity: function REMOTE_TOKEN() view returns(address) +func (_Token *TokenCaller) REMOTETOKEN(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "REMOTE_TOKEN") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// REMOTETOKEN is a free data retrieval call binding the contract method 0x033964be. +// +// Solidity: function REMOTE_TOKEN() view returns(address) +func (_Token *TokenSession) REMOTETOKEN() (common.Address, error) { + return _Token.Contract.REMOTETOKEN(&_Token.CallOpts) +} + +// REMOTETOKEN is a free data retrieval call binding the contract method 0x033964be. +// +// Solidity: function REMOTE_TOKEN() view returns(address) +func (_Token *TokenCallerSession) REMOTETOKEN() (common.Address, error) { + return _Token.Contract.REMOTETOKEN(&_Token.CallOpts) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Token *TokenCaller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "allowance", owner, 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(address owner, address spender) view 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(address owner, address spender) view 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(address account) view returns(uint256) +func (_Token *TokenCaller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "balanceOf", account) + + 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(address account) view returns(uint256) +func (_Token *TokenSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Token.Contract.BalanceOf(&_Token.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Token *TokenCallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Token.Contract.BalanceOf(&_Token.CallOpts, account) +} + +// Bridge is a free data retrieval call binding the contract method 0xe78cea92. +// +// Solidity: function bridge() view returns(address) +func (_Token *TokenCaller) Bridge(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "bridge") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Bridge is a free data retrieval call binding the contract method 0xe78cea92. +// +// Solidity: function bridge() view returns(address) +func (_Token *TokenSession) Bridge() (common.Address, error) { + return _Token.Contract.Bridge(&_Token.CallOpts) +} + +// Bridge is a free data retrieval call binding the contract method 0xe78cea92. +// +// Solidity: function bridge() view returns(address) +func (_Token *TokenCallerSession) Bridge() (common.Address, error) { + return _Token.Contract.Bridge(&_Token.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Token *TokenCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + 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() 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() view returns(uint8) +func (_Token *TokenCallerSession) Decimals() (uint8, error) { + return _Token.Contract.Decimals(&_Token.CallOpts) +} + +// Eip712Domain is a free data retrieval call binding the contract method 0x84b0196e. +// +// Solidity: function eip712Domain() view returns(bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions) +func (_Token *TokenCaller) Eip712Domain(opts *bind.CallOpts) (struct { + Fields [1]byte + Name string + Version string + ChainId *big.Int + VerifyingContract common.Address + Salt [32]byte + Extensions []*big.Int +}, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "eip712Domain") + + outstruct := new(struct { + Fields [1]byte + Name string + Version string + ChainId *big.Int + VerifyingContract common.Address + Salt [32]byte + Extensions []*big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Fields = *abi.ConvertType(out[0], new([1]byte)).(*[1]byte) + outstruct.Name = *abi.ConvertType(out[1], new(string)).(*string) + outstruct.Version = *abi.ConvertType(out[2], new(string)).(*string) + outstruct.ChainId = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.VerifyingContract = *abi.ConvertType(out[4], new(common.Address)).(*common.Address) + outstruct.Salt = *abi.ConvertType(out[5], new([32]byte)).(*[32]byte) + outstruct.Extensions = *abi.ConvertType(out[6], new([]*big.Int)).(*[]*big.Int) + + return *outstruct, err + +} + +// Eip712Domain is a free data retrieval call binding the contract method 0x84b0196e. +// +// Solidity: function eip712Domain() view returns(bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions) +func (_Token *TokenSession) Eip712Domain() (struct { + Fields [1]byte + Name string + Version string + ChainId *big.Int + VerifyingContract common.Address + Salt [32]byte + Extensions []*big.Int +}, error) { + return _Token.Contract.Eip712Domain(&_Token.CallOpts) +} + +// Eip712Domain is a free data retrieval call binding the contract method 0x84b0196e. +// +// Solidity: function eip712Domain() view returns(bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions) +func (_Token *TokenCallerSession) Eip712Domain() (struct { + Fields [1]byte + Name string + Version string + ChainId *big.Int + VerifyingContract common.Address + Salt [32]byte + Extensions []*big.Int +}, error) { + return _Token.Contract.Eip712Domain(&_Token.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Token *TokenCaller) Name(opts *bind.CallOpts) (string, error) { + 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() 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() view returns(string) +func (_Token *TokenCallerSession) Name() (string, error) { + return _Token.Contract.Name(&_Token.CallOpts) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_Token *TokenCaller) Nonces(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "nonces", owner) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_Token *TokenSession) Nonces(owner common.Address) (*big.Int, error) { + return _Token.Contract.Nonces(&_Token.CallOpts, owner) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_Token *TokenCallerSession) Nonces(owner common.Address) (*big.Int, error) { + return _Token.Contract.Nonces(&_Token.CallOpts, owner) +} + +// RemoteToken is a free data retrieval call binding the contract method 0xd6c0b2c4. +// +// Solidity: function remoteToken() view returns(address) +func (_Token *TokenCaller) RemoteToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "remoteToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// RemoteToken is a free data retrieval call binding the contract method 0xd6c0b2c4. +// +// Solidity: function remoteToken() view returns(address) +func (_Token *TokenSession) RemoteToken() (common.Address, error) { + return _Token.Contract.RemoteToken(&_Token.CallOpts) +} + +// RemoteToken is a free data retrieval call binding the contract method 0xd6c0b2c4. +// +// Solidity: function remoteToken() view returns(address) +func (_Token *TokenCallerSession) RemoteToken() (common.Address, error) { + return _Token.Contract.RemoteToken(&_Token.CallOpts) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) +func (_Token *TokenCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _Token.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) +func (_Token *TokenSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Token.Contract.SupportsInterface(&_Token.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) +func (_Token *TokenCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Token.Contract.SupportsInterface(&_Token.CallOpts, interfaceId) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Token *TokenCaller) Symbol(opts *bind.CallOpts) (string, error) { + 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() 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() 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() view returns(uint256) +func (_Token *TokenCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + 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() 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() 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(address spender, uint256 value) 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(address spender, uint256 value) 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(address spender, uint256 value) returns(bool) +func (_Token *TokenTransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Token.Contract.Approve(&_Token.TransactOpts, spender, value) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address from, uint256 amount) returns() +func (_Token *TokenTransactor) Burn(opts *bind.TransactOpts, from common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "burn", from, amount) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address from, uint256 amount) returns() +func (_Token *TokenSession) Burn(from common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Burn(&_Token.TransactOpts, from, amount) +} + +// Burn is a paid mutator transaction binding the contract method 0x9dc29fac. +// +// Solidity: function burn(address from, uint256 amount) returns() +func (_Token *TokenTransactorSession) Burn(from common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Burn(&_Token.TransactOpts, from, amount) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address bridgeAddr) returns() +func (_Token *TokenTransactor) Initialize(opts *bind.TransactOpts, bridgeAddr common.Address) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "initialize", bridgeAddr) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address bridgeAddr) returns() +func (_Token *TokenSession) Initialize(bridgeAddr common.Address) (*types.Transaction, error) { + return _Token.Contract.Initialize(&_Token.TransactOpts, bridgeAddr) +} + +// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// +// Solidity: function initialize(address bridgeAddr) returns() +func (_Token *TokenTransactorSession) Initialize(bridgeAddr common.Address) (*types.Transaction, error) { + return _Token.Contract.Initialize(&_Token.TransactOpts, bridgeAddr) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 amount) returns() +func (_Token *TokenTransactor) Mint(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "mint", to, amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 amount) returns() +func (_Token *TokenSession) Mint(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Mint(&_Token.TransactOpts, to, amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 amount) returns() +func (_Token *TokenTransactorSession) Mint(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Token.Contract.Mint(&_Token.TransactOpts, to, amount) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Token *TokenTransactor) Permit(opts *bind.TransactOpts, owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Token.contract.Transact(opts, "permit", owner, spender, value, deadline, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Token *TokenSession) Permit(owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Token.Contract.Permit(&_Token.TransactOpts, owner, spender, value, deadline, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Token *TokenTransactorSession) Permit(owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Token.Contract.Permit(&_Token.TransactOpts, owner, spender, value, deadline, v, r, s) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) 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(address to, uint256 value) 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(address to, uint256 value) 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(address from, address to, uint256 value) 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(address from, address to, uint256 value) 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(address from, address to, uint256 value) 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(address indexed owner, address indexed spender, uint256 value) +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(address indexed owner, address indexed spender, uint256 value) +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 +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +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 +} + +// TokenBridgeAddressChangedIterator is returned from FilterBridgeAddressChanged and is used to iterate over the raw logs and unpacked data for BridgeAddressChanged events raised by the Token contract. +type TokenBridgeAddressChangedIterator struct { + Event *TokenBridgeAddressChanged // 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 *TokenBridgeAddressChangedIterator) 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(TokenBridgeAddressChanged) + 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(TokenBridgeAddressChanged) + 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 *TokenBridgeAddressChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenBridgeAddressChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenBridgeAddressChanged represents a BridgeAddressChanged event raised by the Token contract. +type TokenBridgeAddressChanged struct { + OldBridgeAddr common.Address + NewBridgeAddr common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeAddressChanged is a free log retrieval operation binding the contract event 0xecfc86cbcf0a44a77658de7fc62df1f08579e15cc8f872b51231ec8a19bc8507. +// +// Solidity: event BridgeAddressChanged(address indexed oldBridgeAddr, address indexed newBridgeAddr) +func (_Token *TokenFilterer) FilterBridgeAddressChanged(opts *bind.FilterOpts, oldBridgeAddr []common.Address, newBridgeAddr []common.Address) (*TokenBridgeAddressChangedIterator, error) { + + var oldBridgeAddrRule []interface{} + for _, oldBridgeAddrItem := range oldBridgeAddr { + oldBridgeAddrRule = append(oldBridgeAddrRule, oldBridgeAddrItem) + } + var newBridgeAddrRule []interface{} + for _, newBridgeAddrItem := range newBridgeAddr { + newBridgeAddrRule = append(newBridgeAddrRule, newBridgeAddrItem) + } + + logs, sub, err := _Token.contract.FilterLogs(opts, "BridgeAddressChanged", oldBridgeAddrRule, newBridgeAddrRule) + if err != nil { + return nil, err + } + return &TokenBridgeAddressChangedIterator{contract: _Token.contract, event: "BridgeAddressChanged", logs: logs, sub: sub}, nil +} + +// WatchBridgeAddressChanged is a free log subscription operation binding the contract event 0xecfc86cbcf0a44a77658de7fc62df1f08579e15cc8f872b51231ec8a19bc8507. +// +// Solidity: event BridgeAddressChanged(address indexed oldBridgeAddr, address indexed newBridgeAddr) +func (_Token *TokenFilterer) WatchBridgeAddressChanged(opts *bind.WatchOpts, sink chan<- *TokenBridgeAddressChanged, oldBridgeAddr []common.Address, newBridgeAddr []common.Address) (event.Subscription, error) { + + var oldBridgeAddrRule []interface{} + for _, oldBridgeAddrItem := range oldBridgeAddr { + oldBridgeAddrRule = append(oldBridgeAddrRule, oldBridgeAddrItem) + } + var newBridgeAddrRule []interface{} + for _, newBridgeAddrItem := range newBridgeAddr { + newBridgeAddrRule = append(newBridgeAddrRule, newBridgeAddrItem) + } + + logs, sub, err := _Token.contract.WatchLogs(opts, "BridgeAddressChanged", oldBridgeAddrRule, newBridgeAddrRule) + 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(TokenBridgeAddressChanged) + if err := _Token.contract.UnpackLog(event, "BridgeAddressChanged", 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 +} + +// ParseBridgeAddressChanged is a log parse operation binding the contract event 0xecfc86cbcf0a44a77658de7fc62df1f08579e15cc8f872b51231ec8a19bc8507. +// +// Solidity: event BridgeAddressChanged(address indexed oldBridgeAddr, address indexed newBridgeAddr) +func (_Token *TokenFilterer) ParseBridgeAddressChanged(log types.Log) (*TokenBridgeAddressChanged, error) { + event := new(TokenBridgeAddressChanged) + if err := _Token.contract.UnpackLog(event, "BridgeAddressChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TokenBurnIterator is returned from FilterBurn and is used to iterate over the raw logs and unpacked data for Burn events raised by the Token contract. +type TokenBurnIterator struct { + Event *TokenBurn // 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 *TokenBurnIterator) 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(TokenBurn) + 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(TokenBurn) + 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 *TokenBurnIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenBurnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenBurn represents a Burn event raised by the Token contract. +type TokenBurn struct { + Account common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBurn is a free log retrieval operation binding the contract event 0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5. +// +// Solidity: event Burn(address indexed account, uint256 amount) +func (_Token *TokenFilterer) FilterBurn(opts *bind.FilterOpts, account []common.Address) (*TokenBurnIterator, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _Token.contract.FilterLogs(opts, "Burn", accountRule) + if err != nil { + return nil, err + } + return &TokenBurnIterator{contract: _Token.contract, event: "Burn", logs: logs, sub: sub}, nil +} + +// WatchBurn is a free log subscription operation binding the contract event 0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5. +// +// Solidity: event Burn(address indexed account, uint256 amount) +func (_Token *TokenFilterer) WatchBurn(opts *bind.WatchOpts, sink chan<- *TokenBurn, account []common.Address) (event.Subscription, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _Token.contract.WatchLogs(opts, "Burn", accountRule) + 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(TokenBurn) + if err := _Token.contract.UnpackLog(event, "Burn", 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 +} + +// ParseBurn is a log parse operation binding the contract event 0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5. +// +// Solidity: event Burn(address indexed account, uint256 amount) +func (_Token *TokenFilterer) ParseBurn(log types.Log) (*TokenBurn, error) { + event := new(TokenBurn) + if err := _Token.contract.UnpackLog(event, "Burn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TokenEIP712DomainChangedIterator is returned from FilterEIP712DomainChanged and is used to iterate over the raw logs and unpacked data for EIP712DomainChanged events raised by the Token contract. +type TokenEIP712DomainChangedIterator struct { + Event *TokenEIP712DomainChanged // 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 *TokenEIP712DomainChangedIterator) 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(TokenEIP712DomainChanged) + 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(TokenEIP712DomainChanged) + 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 *TokenEIP712DomainChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenEIP712DomainChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenEIP712DomainChanged represents a EIP712DomainChanged event raised by the Token contract. +type TokenEIP712DomainChanged struct { + Raw types.Log // Blockchain specific contextual infos +} + +// FilterEIP712DomainChanged is a free log retrieval operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31. +// +// Solidity: event EIP712DomainChanged() +func (_Token *TokenFilterer) FilterEIP712DomainChanged(opts *bind.FilterOpts) (*TokenEIP712DomainChangedIterator, error) { + + logs, sub, err := _Token.contract.FilterLogs(opts, "EIP712DomainChanged") + if err != nil { + return nil, err + } + return &TokenEIP712DomainChangedIterator{contract: _Token.contract, event: "EIP712DomainChanged", logs: logs, sub: sub}, nil +} + +// WatchEIP712DomainChanged is a free log subscription operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31. +// +// Solidity: event EIP712DomainChanged() +func (_Token *TokenFilterer) WatchEIP712DomainChanged(opts *bind.WatchOpts, sink chan<- *TokenEIP712DomainChanged) (event.Subscription, error) { + + logs, sub, err := _Token.contract.WatchLogs(opts, "EIP712DomainChanged") + 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(TokenEIP712DomainChanged) + if err := _Token.contract.UnpackLog(event, "EIP712DomainChanged", 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 +} + +// ParseEIP712DomainChanged is a log parse operation binding the contract event 0x0a6387c9ea3628b88a633bb4f3b151770f70085117a15f9bf3787cda53f13d31. +// +// Solidity: event EIP712DomainChanged() +func (_Token *TokenFilterer) ParseEIP712DomainChanged(log types.Log) (*TokenEIP712DomainChanged, error) { + event := new(TokenEIP712DomainChanged) + if err := _Token.contract.UnpackLog(event, "EIP712DomainChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// TokenMintIterator is returned from FilterMint and is used to iterate over the raw logs and unpacked data for Mint events raised by the Token contract. +type TokenMintIterator struct { + Event *TokenMint // 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 *TokenMintIterator) 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(TokenMint) + 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(TokenMint) + 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 *TokenMintIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *TokenMintIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// TokenMint represents a Mint event raised by the Token contract. +type TokenMint struct { + Account common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMint is a free log retrieval operation binding the contract event 0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885. +// +// Solidity: event Mint(address indexed account, uint256 amount) +func (_Token *TokenFilterer) FilterMint(opts *bind.FilterOpts, account []common.Address) (*TokenMintIterator, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _Token.contract.FilterLogs(opts, "Mint", accountRule) + if err != nil { + return nil, err + } + return &TokenMintIterator{contract: _Token.contract, event: "Mint", logs: logs, sub: sub}, nil +} + +// WatchMint is a free log subscription operation binding the contract event 0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885. +// +// Solidity: event Mint(address indexed account, uint256 amount) +func (_Token *TokenFilterer) WatchMint(opts *bind.WatchOpts, sink chan<- *TokenMint, account []common.Address) (event.Subscription, error) { + + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + + logs, sub, err := _Token.contract.WatchLogs(opts, "Mint", accountRule) + 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(TokenMint) + if err := _Token.contract.UnpackLog(event, "Mint", 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 +} + +// ParseMint is a log parse operation binding the contract event 0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885. +// +// Solidity: event Mint(address indexed account, uint256 amount) +func (_Token *TokenFilterer) ParseMint(log types.Log) (*TokenMint, error) { + event := new(TokenMint) + if err := _Token.contract.UnpackLog(event, "Mint", 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 + + 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(address indexed from, address indexed to, uint256 value) +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(address indexed from, address indexed to, uint256 value) +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 +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +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/internal/chain/transaction.go b/internal/chain/transaction.go index c8aa04fb..567be7d6 100644 --- a/internal/chain/transaction.go +++ b/internal/chain/transaction.go @@ -8,7 +8,7 @@ import ( "strings" "sync/atomic" - "github.com/ethereum/go-ethereum" + "github.com/LiskHQ/lsk-faucet/internal/bindings" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -18,20 +18,27 @@ import ( "golang.org/x/crypto/sha3" ) +var ( + gasLimitInitializedAccount uint64 = 35000 + gasLimitNonInitializedAccount uint64 = 55000 +) + type TxBuilder interface { Sender() common.Address + GetContractInstance() *bindings.Token TransferETH(ctx context.Context, to string, value *big.Int) (common.Hash, error) - TransferERC20(ctx context.Context, to string, value *big.Int) (common.Hash, error) + TransferERC20(ctx context.Context, to string, value *big.Int, balance *big.Int) (common.Hash, error) } type TxBuild struct { - client bind.ContractTransactor - privateKey *ecdsa.PrivateKey - signer types.Signer - fromAddress common.Address - nonce uint64 - chainID *big.Int - tokenAddress string + client bind.ContractBackend + privateKey *ecdsa.PrivateKey + signer types.Signer + fromAddress common.Address + nonce uint64 + chainID *big.Int + tokenAddress string + contractInstance *bindings.Token } func NewTxBuilder(provider string, privateKey *ecdsa.PrivateKey, tokenAddress string, chainID *big.Int) (TxBuilder, error) { @@ -47,13 +54,19 @@ func NewTxBuilder(provider string, privateKey *ecdsa.PrivateKey, tokenAddress st } } + contractInstance, err := bindings.NewToken(common.HexToAddress(tokenAddress), client) + if err != nil { + return nil, err + } + txBuilder := &TxBuild{ - client: client, - privateKey: privateKey, - signer: types.NewEIP155Signer(chainID), - fromAddress: crypto.PubkeyToAddress(privateKey.PublicKey), - chainID: chainID, - tokenAddress: tokenAddress, + client: client, + privateKey: privateKey, + signer: types.NewEIP155Signer(chainID), + fromAddress: crypto.PubkeyToAddress(privateKey.PublicKey), + chainID: chainID, + tokenAddress: tokenAddress, + contractInstance: contractInstance, } txBuilder.refreshNonce(context.Background()) @@ -64,6 +77,10 @@ func (b *TxBuild) Sender() common.Address { return b.fromAddress } +func (b *TxBuild) GetContractInstance() *bindings.Token { + return b.contractInstance +} + func (b *TxBuild) TransferETH(ctx context.Context, to string, value *big.Int) (common.Hash, error) { gasLimit := uint64(21000) gasPrice, err := b.client.SuggestGasPrice(ctx) @@ -96,7 +113,7 @@ func (b *TxBuild) TransferETH(ctx context.Context, to string, value *big.Int) (c return signedTx.Hash(), nil } -func (b *TxBuild) TransferERC20(ctx context.Context, to string, value *big.Int) (common.Hash, error) { +func (b *TxBuild) TransferERC20(ctx context.Context, to string, value *big.Int, balance *big.Int) (common.Hash, error) { emptyHash := common.Hash{} publicKey := b.privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) @@ -131,12 +148,11 @@ func (b *TxBuild) TransferERC20(ctx context.Context, to string, value *big.Int) data = append(data, paddedAddress...) data = append(data, paddedAmount...) - gasLimit, err := b.client.EstimateGas(ctx, ethereum.CallMsg{ - To: &tokenAddress, - Data: data, - }) - if err != nil { - return emptyHash, err + var gasLimit uint64 + if balance.BitLen() == 0 { + gasLimit = gasLimitNonInitializedAccount + } else { + gasLimit = gasLimitInitializedAccount } tx := types.NewTransaction(nonce, tokenAddress, big.NewInt(0), gasLimit, gasPrice, data) diff --git a/internal/chain/transaction_test.go b/internal/chain/transaction_test.go index 7ae760af..86c33edd 100644 --- a/internal/chain/transaction_test.go +++ b/internal/chain/transaction_test.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient/simulated" + "github.com/stretchr/testify/assert" ) func TestTxBuilder_TransferETH(t *testing.T) { @@ -63,44 +64,76 @@ func TestTxBuilder_TransferETH(t *testing.T) { } func TestTxBuilder_TransferERC20(t *testing.T) { - privateKey, _ := crypto.HexToECDSA("976f9f7772781ff6d1c93941129d417c49a209c674056a3cf5e27e225ee55fa8") - fromAddress := crypto.PubkeyToAddress(privateKey.PublicKey) - simBackend := simulated.NewBackend( - types.GenesisAlloc{ - fromAddress: {Balance: big.NewInt(10000000000000000)}, - }) + testcases := []struct { + name string + accBalance *big.Int + wantGasLimit uint64 + }{ + { + name: "should use appropriate gas limit for transaction when recipient is initialized", + accBalance: big.NewInt(30000), + wantGasLimit: gasLimitInitializedAccount, + }, + { + name: "should use appropriate gas limit for transaction when recipient is not initialized", + accBalance: big.NewInt(0), + wantGasLimit: gasLimitNonInitializedAccount, + }, + } - defer simBackend.Close() - var s *backends.SimulatedBackend - patches := gomonkey.ApplyMethod(reflect.TypeOf(s), "SuggestGasPrice", func(_ *backends.SimulatedBackend, _ context.Context) (*big.Int, error) { - return big.NewInt(875000000), nil - }) - defer patches.Reset() + t.Parallel() + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + privateKey, _ := crypto.HexToECDSA("976f9f7772781ff6d1c93941129d417c49a209c674056a3cf5e27e225ee55fa8") + fromAddress := crypto.PubkeyToAddress(privateKey.PublicKey) + simBackend := simulated.NewBackend( + types.GenesisAlloc{ + fromAddress: {Balance: big.NewInt(10000000000000000)}, + }) - txBuilder := &TxBuild{ - client: simBackend.Client(), - privateKey: privateKey, - signer: types.NewEIP155Signer(big.NewInt(1337)), - fromAddress: crypto.PubkeyToAddress(privateKey.PublicKey), - chainID: big.NewInt(1337), - tokenAddress: "0xbb5801a7D398351b8bE11C439e05C5B3259aeux0", - } - bgCtx := context.Background() - toAddress := common.HexToAddress("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B") - value := big.NewInt(1000) - txHash, err := txBuilder.TransferERC20(bgCtx, toAddress.Hex(), value) - if err != nil { - t.Errorf("could not add tx to pending block: %v", err) - } - simBackend.Commit() + defer simBackend.Close() + var s *backends.SimulatedBackend + patches := gomonkey.ApplyMethod(reflect.TypeOf(s), "SuggestGasPrice", func(_ *backends.SimulatedBackend, _ context.Context) (*big.Int, error) { + return big.NewInt(875000000), nil + }) + defer patches.Reset() - block, err := simBackend.Client().BlockByNumber(bgCtx, big.NewInt(1)) - if err != nil { - t.Errorf("could not get block at height 1: %v", err) - } - if txHash != block.Transactions()[0].Hash() { - t.Errorf("did not commit sent transaction. expected hash %v got hash %v", block.Transactions()[0].Hash(), txHash) - } + txBuilder := &TxBuild{ + client: simBackend.Client(), + privateKey: privateKey, + signer: types.NewEIP155Signer(big.NewInt(1337)), + fromAddress: crypto.PubkeyToAddress(privateKey.PublicKey), + chainID: big.NewInt(1337), + tokenAddress: "0xbb5801a7D398351b8bE11C439e05C5B3259aeux0", + contractInstance: nil, + } + bgCtx := context.Background() + toAddress := common.HexToAddress("0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B") + value := big.NewInt(1000) + + txHashInitAcc, err := txBuilder.TransferERC20(bgCtx, toAddress.Hex(), value, tc.accBalance) + if err != nil { + t.Errorf("could not add tx to pending block: %v", err) + } + simBackend.Commit() - // TODO: Verify ERC20 token balance of recipient if possible in future with the simulator + block, err := simBackend.Client().BlockByNumber(bgCtx, big.NewInt(1)) + if err != nil { + t.Errorf("could not get block at height 1: %v", err) + } + if txHashInitAcc != block.Transactions()[0].Hash() { + t.Errorf("did not commit sent transaction. expected hash %v got hash %v", block.Transactions()[0].Hash(), txHashInitAcc) + } + + txInitAcc, _, err := simBackend.Client().TransactionByHash(bgCtx, txHashInitAcc) + if err != nil { + t.Errorf("could not get transaction by hash: %v", err) + } + + gasLimit := txInitAcc.Gas() + assert.Equal(t, gasLimit, tc.wantGasLimit) + + // TODO: Verify ERC20 token balance of recipient if possible in future with the simulator + }) + } } diff --git a/internal/server/server.go b/internal/server/server.go index 6692ff44..f75f6c37 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -3,10 +3,13 @@ package server import ( "context" "fmt" + "math/big" "net/http" "strconv" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" log "github.com/sirupsen/logrus" "github.com/urfave/negroni" @@ -50,14 +53,20 @@ func (s *Server) handleClaim() http.HandlerFunc { http.NotFound(w, r) return } - // The error always be nil since it has already been handled in limiter address, _ := readAddress(r) ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() - txHash, err := s.TransferERC20(ctx, address, chain.LSKToWei(int64(s.cfg.payout))) + + currBalance, err := s.GetContractInstance().BalanceOf(&bind.CallOpts{}, common.HexToAddress(address)) + if err != nil { + log.WithError(err).Error("failed to fetch recipient balance") + currBalance = big.NewInt(0) + } + + txHash, err := s.TransferERC20(ctx, address, chain.LSKToWei(int64(s.cfg.payout)), currBalance) if err != nil { - log.WithError(err).Error("Failed to send transaction") + log.WithError(err).Error("failed to send transaction") renderJSON(w, claimResponse{Message: err.Error()}, http.StatusInternalServerError) return }