28

I have the following simple smart contract...

contract SimpleStorage {
    uint storedData;
    function set(uint x) {
        storedData = x;
    }
    function get() constant returns (uint retVal) {
        return storedData;
    }
}

Which I deploy with the following code in the geth console...

var source = "contract SimpleStorage...[code here]"
var compiled = web3.eth.compile.solidity(source)
var contract = web3.eth.contract(compiled.Coin.info.abiDefinition)
var storage = contract.new({from:web3.eth.accounts[0], data: compiled.SimpleStorage.code, gas: 300000})

After the contract has been mined, I am able to access the contract functions via the storage object. I assumed that I could just call...

storage.set(10)

...to set the storedData variable. However every time I try this I get an "Invalid Address" error.

I'm sure that this is because I am attempting to perform a write operation on the internal state of the contract (read operations work fine).

I need to submit a transaction that mines the new state of the contract, however I can't figure out how to do this.

How can I perform write transactions in smart contracts?

q9f
  • 32,913
  • 47
  • 156
  • 395
billett
  • 1,255
  • 1
  • 12
  • 18

1 Answers1

28

Try setting

web3.eth.defaultAccount = eth.accounts[0]

It sounds like your transaction doesn't know what account to use to sign the call. Any call that changes the state of the contract (write operation) requires a signed transaction.

An alternative approach would be to pass a 'transaction object' as the last argument to contract method:

storage.set(10,{from: accounts[0]});

Edit 1:

When I chose the 'from' account, I got the following error: 'authentication needed: password or unlock'. So I needed to run personal.unlockAccount(eth.accounts[0],"password",15000). You can read about it at 'authentication needed: password or unlock' Error when trying to call smart contract method via web3 .

Luiz Fonseca
  • 123
  • 1
  • 6
dbryson
  • 6,403
  • 2
  • 27
  • 37
  • I knew it would be simple! How would I do this without setting the defaultAccount? For example if I was using multiple accounts on the same geth instance? – billett Mar 16 '16 at 08:04
  • You can call web3.accounts and store the results into an array. Then access the array for the specific account. When you call a method that executes a transaction and needs an account, pass an object that contains a from: storage.set(10,{from: accounts[1]}); – dbryson Mar 16 '16 at 12:15
  • This is exactly what I was looking for. So simple! If the function has multiple parameters, is it just... storage.set(a,b,c,d,{from: eth.accounts[0]})? – billett Mar 16 '16 at 14:31
  • Yes. See the web3.js api docs: https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethsendtransaction Note the transactionObject. This is what you can pass as the last argument to your contract call – dbryson Mar 16 '16 at 15:01
  • and how to obtain the txID of the result? – knocte May 24 '16 at 05:21
  • web3.eth.defaultAccount = accounts[0] should be eth.defaultAccount = eth.accounts[0] – mxk Jun 15 '16 at 14:50
  • This worked for me as well. Just want to share how I changed my call to get a response based upon comments above in web3.js on Mac terminal: Original call: contractInstance.getStep() . New call: contractInstance.getStep({from: web3.eth.accounts[0]}). – Jazzmine Oct 24 '17 at 01:08