From db869ea4007ee92da513746d520bcd0c726a6264 Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Thu, 7 Mar 2019 15:06:05 +0200 Subject: [PATCH] Add unsigned transact function --- accounts/abi/bind/base.go | 59 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 83ad1c8ae7..bf223384fd 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -164,6 +164,63 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, return c.abi.Unpack(result, method, output) } +func (c *BoundContract) UnsignedTransact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + // Otherwise pack up the parameters and invoke the contract + input, err := c.abi.Pack(method, params...) + if err != nil { + return nil, err + } + + // Ensure a valid value field and resolve the account nonce + value := opts.Value + if value == nil { + value = new(big.Int) + } + var nonce uint64 + if opts.Nonce == nil { + nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From) + 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 { + gasPrice, err = c.transactor.SuggestGasPrice(ensureContext(opts.Context)) + if err != nil { + return nil, fmt.Errorf("failed to suggest gas price: %v", err) + } + } + gasLimit := opts.GasLimit + if gasLimit == 0 { + // Gas estimation cannot succeed without code for method invocations + if &c.address != nil { + if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil { + return nil, err + } else if len(code) == 0 { + return nil, ErrNoCode + } + } + // If the contract surely has code (or code is not needed), estimate the transaction + msg := ethereum.CallMsg{From: opts.From, To: &c.address, Value: value, Data: input} + gasLimit, err = c.transactor.EstimateGas(ensureContext(opts.Context), msg) + if err != nil { + return nil, fmt.Errorf("failed to estimate gas needed: %v", err) + } + } + // Create the transaction, sign it and schedule it for execution + var rawTx *types.Transaction + if &c.address == nil { + rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input) + } else { + rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input) + } + + return rawTx, nil +} + // Transact invokes the (paid) contract method with params as input values. func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { // Otherwise pack up the parameters and invoke the contract @@ -232,7 +289,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input) } if opts.Signer == nil { - return nil, errors.New("no signer to authorize the transaction with") + return rawTx, errors.New("no signer to authorize the transaction with") } signedTx, err := opts.Signer(types.HomesteadSigner{}, opts.From, rawTx) if err != nil {