| 
									
										
										
										
											2016-11-09 02:01:56 +01:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package bind | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-03-22 18:20:33 +01:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum" | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/accounts/abi" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2018-01-05 12:39:24 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SignerFn is a signer function callback when a contract requires a method to | 
					
						
							|  |  |  | // sign the transaction before submission. | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Transaction, error) | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | // CallOpts is the collection of options to fine tune a contract call request. | 
					
						
							|  |  |  | type CallOpts struct { | 
					
						
							| 
									
										
										
										
											2019-01-03 11:54:24 +00:00
										 |  |  | 	Pending     bool            // Whether to operate on the pending state or the last known one | 
					
						
							|  |  |  | 	From        common.Address  // Optional the sender address, otherwise the first account is used | 
					
						
							|  |  |  | 	BlockNumber *big.Int        // Optional the block number on which the call should be performed | 
					
						
							|  |  |  | 	Context     context.Context // Network context to support cancellation and timeouts (nil = no timeout) | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TransactOpts is the collection of authorization data required to create a | 
					
						
							|  |  |  | // valid Ethereum transaction. | 
					
						
							|  |  |  | type TransactOpts struct { | 
					
						
							| 
									
										
										
										
											2016-03-21 14:34:49 +02:00
										 |  |  | 	From   common.Address // Ethereum account to send the transaction from | 
					
						
							|  |  |  | 	Nonce  *big.Int       // Nonce to use for the transaction execution (nil = use pending state) | 
					
						
							|  |  |  | 	Signer SignerFn       // Method to use for signing the transaction (mandatory) | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Value    *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds) | 
					
						
							|  |  |  | 	GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 	GasLimit uint64   // Gas limit to set for the transaction execution (0 = estimate) | 
					
						
							| 
									
										
										
										
											2015-12-16 04:26:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-05 12:39:24 +02:00
										 |  |  | // FilterOpts is the collection of options to fine tune filtering for events | 
					
						
							|  |  |  | // within a bound contract. | 
					
						
							|  |  |  | type FilterOpts struct { | 
					
						
							|  |  |  | 	Start uint64  // Start of the queried range | 
					
						
							|  |  |  | 	End   *uint64 // End of the range (nil = latest) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WatchOpts is the collection of options to fine tune subscribing for events | 
					
						
							|  |  |  | // within a bound contract. | 
					
						
							|  |  |  | type WatchOpts struct { | 
					
						
							|  |  |  | 	Start   *uint64         // Start of the queried range (nil = latest) | 
					
						
							|  |  |  | 	Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | // BoundContract is the base wrapper object that reflects a contract on the | 
					
						
							|  |  |  | // Ethereum network. It contains a collection of methods that are used by the | 
					
						
							|  |  |  | // higher level contract bindings to operate. | 
					
						
							|  |  |  | type BoundContract struct { | 
					
						
							|  |  |  | 	address    common.Address     // Deployment address of the contract on the Ethereum blockchain | 
					
						
							|  |  |  | 	abi        abi.ABI            // Reflect based ABI to access the correct Ethereum methods | 
					
						
							|  |  |  | 	caller     ContractCaller     // Read interface to interact with the blockchain | 
					
						
							|  |  |  | 	transactor ContractTransactor // Write interface to interact with the blockchain | 
					
						
							| 
									
										
										
										
											2018-01-05 12:39:24 +02:00
										 |  |  | 	filterer   ContractFilterer   // Event filtering to interact with the blockchain | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewBoundContract creates a low level contract interface through which calls | 
					
						
							|  |  |  | // and transactions may be made through. | 
					
						
							| 
									
										
										
										
											2018-01-05 12:39:24 +02:00
										 |  |  | func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller, transactor ContractTransactor, filterer ContractFilterer) *BoundContract { | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	return &BoundContract{ | 
					
						
							|  |  |  | 		address:    address, | 
					
						
							|  |  |  | 		abi:        abi, | 
					
						
							|  |  |  | 		caller:     caller, | 
					
						
							|  |  |  | 		transactor: transactor, | 
					
						
							| 
									
										
										
										
											2018-01-05 12:39:24 +02:00
										 |  |  | 		filterer:   filterer, | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | // DeployContract deploys a contract onto the Ethereum blockchain and binds the | 
					
						
							|  |  |  | // deployment address with a Go wrapper. | 
					
						
							|  |  |  | func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) { | 
					
						
							|  |  |  | 	// Otherwise try to deploy the contract | 
					
						
							| 
									
										
										
										
											2018-01-05 12:39:24 +02:00
										 |  |  | 	c := NewBoundContract(common.Address{}, abi, backend, backend, backend) | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	input, err := c.abi.Pack("", params...) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return common.Address{}, nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tx, err := c.transact(opts, nil, append(bytecode, input...)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return common.Address{}, nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-21 14:34:49 +02:00
										 |  |  | 	c.address = crypto.CreateAddress(opts.From, tx.Nonce()) | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | 	return c.address, tx, c, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | // 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. | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, params ...interface{}) error { | 
					
						
							|  |  |  | 	// Don't crash on a lazy user | 
					
						
							|  |  |  | 	if opts == nil { | 
					
						
							|  |  |  | 		opts = new(CallOpts) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Pack the input, call and unpack the results | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	input, err := c.abi.Pack(method, params...) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2017-03-16 12:24:22 +01:00
										 |  |  | 		msg    = ethereum.CallMsg{From: opts.From, To: &c.address, Data: input} | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 		ctx    = ensureContext(opts.Context) | 
					
						
							|  |  |  | 		code   []byte | 
					
						
							|  |  |  | 		output []byte | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if opts.Pending { | 
					
						
							|  |  |  | 		pb, ok := c.caller.(PendingContractCaller) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			return ErrNoPendingState | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		output, err = pb.PendingCallContract(ctx, msg) | 
					
						
							|  |  |  | 		if err == nil && len(output) == 0 { | 
					
						
							|  |  |  | 			// Make sure we have a contract to operate on, and bail out otherwise. | 
					
						
							|  |  |  | 			if code, err = pb.PendingCodeAt(ctx, c.address); err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} else if len(code) == 0 { | 
					
						
							|  |  |  | 				return ErrNoCode | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2019-01-03 11:54:24 +00:00
										 |  |  | 		output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber) | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 		if err == nil && len(output) == 0 { | 
					
						
							|  |  |  | 			// Make sure we have a contract to operate on, and bail out otherwise. | 
					
						
							| 
									
										
										
										
											2019-01-03 11:54:24 +00:00
										 |  |  | 			if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} else if len(code) == 0 { | 
					
						
							|  |  |  | 				return ErrNoCode | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return c.abi.Unpack(result, method, output) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-01 13:02:43 +03:00
										 |  |  | // Transact invokes the (paid) contract method with params as input values. | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { | 
					
						
							|  |  |  | 	// Otherwise pack up the parameters and invoke the contract | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	input, err := c.abi.Pack(method, params...) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | 	return c.transact(opts, &c.address, input) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-01 13:02:43 +03:00
										 |  |  | // Transfer initiates a plain transaction to move funds to the contract, calling | 
					
						
							|  |  |  | // its default method if one is available. | 
					
						
							|  |  |  | func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error) { | 
					
						
							|  |  |  | 	return c.transact(opts, &c.address, nil) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | // transact executes an actual transaction invocation, first deriving any missing | 
					
						
							|  |  |  | // authorization fields, and then scheduling the transaction for execution. | 
					
						
							|  |  |  | func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	// Ensure a valid value field and resolve the account nonce | 
					
						
							|  |  |  | 	value := opts.Value | 
					
						
							|  |  |  | 	if value == nil { | 
					
						
							|  |  |  | 		value = new(big.Int) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-09 11:16:06 +01:00
										 |  |  | 	var nonce uint64 | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	if opts.Nonce == nil { | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 		nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From) | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("failed to retrieve account nonce: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		nonce = opts.Nonce.Uint64() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Figure out the gas allowance and gas price values | 
					
						
							|  |  |  | 	gasPrice := opts.GasPrice | 
					
						
							|  |  |  | 	if gasPrice == nil { | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 		gasPrice, err = c.transactor.SuggestGasPrice(ensureContext(opts.Context)) | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("failed to suggest gas price: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	gasLimit := opts.GasLimit | 
					
						
							| 
									
										
										
										
											2017-11-13 13:47:27 +02:00
										 |  |  | 	if gasLimit == 0 { | 
					
						
							| 
									
										
										
										
											2016-05-20 12:29:28 +03:00
										 |  |  | 		// Gas estimation cannot succeed without code for method invocations | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 		if contract != nil { | 
					
						
							|  |  |  | 			if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil { | 
					
						
							| 
									
										
										
										
											2016-05-20 12:29:28 +03:00
										 |  |  | 				return nil, err | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 			} else if len(code) == 0 { | 
					
						
							| 
									
										
										
										
											2016-05-20 12:29:28 +03:00
										 |  |  | 				return nil, ErrNoCode | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// If the contract surely has code (or code is not needed), estimate the transaction | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 		msg := ethereum.CallMsg{From: opts.From, To: contract, Value: value, Data: input} | 
					
						
							|  |  |  | 		gasLimit, err = c.transactor.EstimateGas(ensureContext(opts.Context), msg) | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 			return nil, fmt.Errorf("failed to estimate gas needed: %v", err) | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Create the transaction, sign it and schedule it for execution | 
					
						
							| 
									
										
										
										
											2016-03-17 19:27:37 +02:00
										 |  |  | 	var rawTx *types.Transaction | 
					
						
							|  |  |  | 	if contract == nil { | 
					
						
							|  |  |  | 		rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	if opts.Signer == nil { | 
					
						
							|  |  |  | 		return nil, errors.New("no signer to authorize the transaction with") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	signedTx, err := opts.Signer(types.HomesteadSigner{}, opts.From, rawTx) | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 	if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil { | 
					
						
							| 
									
										
										
										
											2016-03-16 12:48:33 +02:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return signedTx, nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-05 12:39:24 +02:00
										 |  |  | // FilterLogs filters contract logs for past blocks, returning the necessary | 
					
						
							|  |  |  | // channels to construct a strongly typed bound iterator on top of them. | 
					
						
							|  |  |  | func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { | 
					
						
							|  |  |  | 	// Don't crash on a lazy user | 
					
						
							|  |  |  | 	if opts == nil { | 
					
						
							|  |  |  | 		opts = new(FilterOpts) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Append the event selector to the query parameters and construct the topic set | 
					
						
							|  |  |  | 	query = append([][]interface{}{{c.abi.Events[name].Id()}}, query...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	topics, err := makeTopics(query...) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the background filtering | 
					
						
							|  |  |  | 	logs := make(chan types.Log, 128) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	config := ethereum.FilterQuery{ | 
					
						
							|  |  |  | 		Addresses: []common.Address{c.address}, | 
					
						
							|  |  |  | 		Topics:    topics, | 
					
						
							|  |  |  | 		FromBlock: new(big.Int).SetUint64(opts.Start), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if opts.End != nil { | 
					
						
							|  |  |  | 		config.ToBlock = new(big.Int).SetUint64(*opts.End) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* TODO(karalabe): Replace the rest of the method below with this when supported | 
					
						
							|  |  |  | 	sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs) | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	buff, err := c.filterer.FilterLogs(ensureContext(opts.Context), config) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sub, err := event.NewSubscription(func(quit <-chan struct{}) error { | 
					
						
							|  |  |  | 		for _, log := range buff { | 
					
						
							|  |  |  | 			select { | 
					
						
							|  |  |  | 			case logs <- log: | 
					
						
							|  |  |  | 			case <-quit: | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	}), nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return logs, sub, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WatchLogs filters subscribes to contract logs for future blocks, returning a | 
					
						
							|  |  |  | // subscription object that can be used to tear down the watcher. | 
					
						
							|  |  |  | func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { | 
					
						
							|  |  |  | 	// Don't crash on a lazy user | 
					
						
							|  |  |  | 	if opts == nil { | 
					
						
							|  |  |  | 		opts = new(WatchOpts) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Append the event selector to the query parameters and construct the topic set | 
					
						
							|  |  |  | 	query = append([][]interface{}{{c.abi.Events[name].Id()}}, query...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	topics, err := makeTopics(query...) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the background filtering | 
					
						
							|  |  |  | 	logs := make(chan types.Log, 128) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	config := ethereum.FilterQuery{ | 
					
						
							|  |  |  | 		Addresses: []common.Address{c.address}, | 
					
						
							|  |  |  | 		Topics:    topics, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if opts.Start != nil { | 
					
						
							|  |  |  | 		config.FromBlock = new(big.Int).SetUint64(*opts.Start) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return logs, sub, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UnpackLog unpacks a retrieved log into the provided output structure. | 
					
						
							|  |  |  | func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { | 
					
						
							|  |  |  | 	if len(log.Data) > 0 { | 
					
						
							|  |  |  | 		if err := c.abi.Unpack(out, event, log.Data); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var indexed abi.Arguments | 
					
						
							|  |  |  | 	for _, arg := range c.abi.Events[event].Inputs { | 
					
						
							|  |  |  | 		if arg.Indexed { | 
					
						
							|  |  |  | 			indexed = append(indexed, arg) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return parseTopics(out, indexed, log.Topics[1:]) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ensureContext is a helper method to ensure a context is not nil, even if the | 
					
						
							|  |  |  | // user specified it as such. | 
					
						
							| 
									
										
										
										
											2016-08-22 14:01:28 +02:00
										 |  |  | func ensureContext(ctx context.Context) context.Context { | 
					
						
							|  |  |  | 	if ctx == nil { | 
					
						
							|  |  |  | 		return context.TODO() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ctx | 
					
						
							|  |  |  | } |