10

I want to create and sign a transaction in browser using web3. In order to create a raw transaction, I think I have to do something like this (hopefully you can fill the gaps of my knowledge)

var pk = '0x6ba33b3f7997c2bf63d82f3baa1a8069014a59fa1f554af3266aa85afee9d0a9';

pk = new Buffer(pk,'hex');

var address = '0xFb4d271F3056aAF8Bcf8aeB00b5cb4B6C02c7368';

var myContractsAddress = '0x0cb4edc28d17c43a75797bf5effc141fd5da8715';

var rawTx = {

nonce: web3.toHex(web3.eth.getTransactionCount(acct1)),

to: myContractsAddress,

gasPrice: web3.toHex(20000000000),

gasLimit: web3.toHex(200000),

value: ***Here I am not sure, am I supposed to encode my list of variables? and do I encode everything to hex, or just integers? And how would that list look like?***

data: *This field is irrelevant for now, and just for documentationpurpose, right?*
}

This should give me my raw transaction (the part about the datafield I unfortunately don't know and would love to get help with!

Lets say my raw transaction is valid and correct at this point, I would have to sign it with the private key now. The solution I've seen used a node.js library called ethereumjs-tx. Is there a solution with web3 only, or do I have to port this library somehow into my browser?

  • 1
    ethereumjs-tx doesn't need to be "ported" to the browser, since it already works fine there. Do you have the ABI for your contract? value is the amount of ether you're sending (perhaps 0 if you're just calling a contract function). data is what tells the contract what function you're calling (via a hash called a "function selector") and with what parameters (ABI-encoded). If you have the ABI, web3.js can compute the data field for you. – smarx Jan 15 '18 at 17:14
  • Thanks for your reply! I do have the contracts abi. So for value I'd use web3.toHex(0) If you don't mind, please share with me an example of how to fill the data-field. lets assume the abi is stored under var abi = ...; – S1r_Mar71n Jan 15 '18 at 19:15
  • Then the two answers here should work for you. – smarx Jan 15 '18 at 19:16
  • I've updated my reply again, misstyped it a little – S1r_Mar71n Jan 15 '18 at 19:19
  • I think my answer already shows how to fill in the data field. – smarx Jan 15 '18 at 19:22
13

Below is working code that calls "increment" on https://programtheblockchain.com/dapps/counter. (More info about that sample here: https://programtheblockchain.com/posts/2017/12/13/building-decentralized-apps-with-ethereum-and-javascript/.)

It uses web3.js and ethereumjs-tx:

<!-- from https://github.com/ethereumjs/browser-builds/raw/master/dist/ethereumjs-tx/ethereumjs-tx-1.3.3.min.js -->
<script src="ethereumjs-tx-1.3.3.min.js"></script>
<script>
  var address = "0xf15090c01bec877a122b567e5552504e5fd22b79";
  var abi = [{"constant":true,"inputs":[],"name":"getCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"increment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_count","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}];

  var account = "<REDACTED ACCOUNT ADDRESS>";
  var privateKey = "<REDACTED PRIVATE KEY WITHOUT 0x PREFIX>";

  var web3 = new Web3(new Web3.providers.HttpProvider(
    "https://ropsten.infura.io/<REDACTED API KEY"));

  web3.eth.getTransactionCount(account, function (err, nonce) {
    var data = web3.eth.contract(abi).at(address).increment.getData();

    var tx = new ethereumjs.Tx({
      nonce: nonce,
      gasPrice: web3.toHex(web3.toWei('20', 'gwei')),
      gasLimit: 100000,
      to: address,
      value: 0,
      data: data,
    });
    tx.sign(ethereumjs.Buffer.Buffer.from(privateKey, 'hex'));

    var raw = '0x' + tx.serialize().toString('hex');
    web3.eth.sendRawTransaction(raw, function (err, transactionHash) {
      console.log(transactionHash);
    });
  });
</script>
  • 2
    okay, I unfortunately do have to bother you again... The increment function doesn't expect any params. What if it would want (string, uint256) i.E. Because I can't just change var data = web3.eth.contract(abi).at(address).increment(string,uint256).getData(); – S1r_Mar71n Jan 16 '18 at 0:18
  • 1
    The parameters get passed to getData: ...increment.getData("foo", 32); – smarx Jan 16 '18 at 0:20
  • Okay, fully figured it out now, you're my hero. Can I thank you somehow? – S1r_Mar71n Jan 16 '18 at 0:31
  • 1
    Happy to help! Promote programtheblockchain.com to your Ethereum developer friends. :-) – smarx Jan 16 '18 at 0:32
  • I wish I had any developerfriends haha. link me your steamid, I can gift you something there if you want (if you even use steam) – S1r_Mar71n Jan 16 '18 at 0:36
12

Using Web3.js 1.0.0

encoded = contractInstance.methods.myMethod(params).encodeABI()

var tx = {
    to : myContractAddress,
    data : encoded
}

web3.eth.accounts.signTransaction(tx, privateKey).then(signed => {
    web3.eth.sendSignedTransaction(signed.rawTransaction).on('receipt', console.log)
});
  • How can I access return values from myMethod ? – Channa Sep 28 '18 at 6:12
  • Seems like the raw transaction is missing some pieces, not sure if they're necessary -- does this actually work? Does it just infer the nonce, gasPrice, gasLimit, etc? – ohsully Oct 18 '18 at 20:30
  • @ohsully Mostly you can infer those params when using web3 and built in accounts/wallet. Occasionally operational params are atypical, which is when you need to manually set them. – robertdavid Nov 27 '18 at 13:34
  • In case anyone comes across this, my specific scenario is that I was trying to build a raw transaction and then sign it with an account that isn't stored in web3. If you aren't using web3 to sign, then your tx object also needs to include nonce, gasPrice, gasLimit, value, and chainId. These would normally be inferred by web3, but if you want to keep keys elsewhere and sign using something like eth-lightwallet, that's what your tx object needs to have set. – ohsully Nov 29 '18 at 17:12
  • where do you get your privateKey when you only have a keystore file – Barney Chambers Sep 2 at 12:44
0

I was lost in this mystery for some time and end up writing a package to solve this. It is web3js-raw which is a simple wrapper around web3.js. Fully functioning sample using this could found here.

You could use browserify to package everything into a single .js file and run on browser. Sample above explains how to use browserify as well.

  • Take a look at my answer. I'm curious what's different/better about your library or whether it just does the same sort of thing under the hood as the code in my answer. – smarx Jan 15 '18 at 17:51
  • @smarx Surely I'm not doing anything fundamentally different. All I have done is wrapping web3.js in a manner which is easy to use. There are so many moving parts/permutations of use (for instance having variables or not, sending ether with function call or not, involvement of MetaMast under the hood, etc) when you are trying to send a transaction. So my approach is to use sendRawTransaction (which seems to be one of the underlying helper function in web3.js) for all possible cases from deploying a contract to invoke a function. – Chim Jan 16 '18 at 2:48
  • Thanks for the explanation! I hope, though, that cases where a user has to turn over their private keys to JavaScript in the browser are rare. :-) – smarx Jan 16 '18 at 2:51
  • I could see the convenience of not dealing with private keys for both average users and even for developers. But if DApps ever need to take off, and get into main stream, average users should have easy ways to manage their private keys. Do you think MetaMask would be the best way forward for handling private keys? Personally I feel like it is too much to ask from an average user to install MetaMask. Any thoughts? – Chim Jan 16 '18 at 2:57
  • 1
    I think MetaMask (or something like it) is definitely the way to go. If users are pasting their private keys into web pages, I think cryptocurrency will surely die a quick death when everyone gets their money stolen. :-) But it's early days. – smarx Jan 16 '18 at 2:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.