43

I'm looking to create a raw transaction, sign it, and broadcast it using the eth.sendRawTransaction RPC method.

I would like to do this offline using code or an open-source library OR online but without the need of using an specific wallet or software.

There is neither a RPC method to create/sign the raw transaction, nor can I find any libraries to do this (offline).

Any help or guidance on how this could be achieved would be most thanked. If there is a python implementation that would be awesome.

1

6 Answers 6

29

ethereumjs-tx is a library with this example:

npm install ethereumjs-tx

const Tx = require('ethereumjs-tx').Transaction
var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex')

var rawTx = {
  nonce: '0x00',
  gasPrice: '0x09184e72a000', 
  gasLimit: '0x2710',
  to: '0x0000000000000000000000000000000000000000', 
  value: '0x00', 
  data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057'
}

var tx = new Tx(rawTx)
tx.sign(privateKey)

var serializedTx = tx.serialize()
console.log(serializedTx.toString('hex'))
12
  • 1
    ethereumjs-tx is great indeed. You can also check out this tool I made for a GUI example of using it to sign transactions on an offline machine: github.com/kobigurk/frozeth
    – kobigurk
    Commented Apr 26, 2016 at 22:53
  • @kobigurk FYI, if you are using ethereumjs-utils for private/public key generation, you need to update that library ASAP. There was a nasty padding bug that would result in the wrong public key being derived from the private key occasionally.
    – tayvano
    Commented Apr 27, 2016 at 1:17
  • @eth Do you know of any python libraries to do this?
    – Nico
    Commented Apr 27, 2016 at 13:12
  • 1
    There's github.com/ethereum/pyethereum/blob/develop/ethereum/… but I don't have examples currently; I can edit answer if I find something.
    – eth
    Commented Apr 27, 2016 at 17:52
  • 1
    Correct import in version 2.1.2: const Tx = require('ethereumjs-tx').Transaction Commented Feb 14, 2020 at 10:01
13

In Go creating a signed transaction would look something like this:

transaction := types.NewTransaction(nonce, recipient, value, gasLimit, gasPrice, input)
signature, _ := crypto.Sign(transaction.SigHash().Bytes(), key)
signed, _ := tx.WithSignature(signature)

where key is a plain *ecdsa.PrivateKey. If you want to use Ethereum encrypted accounts, you could take a look at the AccountManager which does all the fancy crypto stuff for you and you can just call a Sign method with an input transaction to sign it.

After having it signed, you'd still need to announce it over RPC to the network. That's already implemented for the Native DApp bindings here: https://github.com/ethereum/go-ethereum/blob/develop/accounts/abi/bind/backends/remote.go#L202 which you can copy paste or alternatively wait a bit until Felix finishes his RPC Go client.

4
  • are you using any library? Can you share the link to that library? Do you know if there is a python implementation?
    – Nico
    Commented Apr 27, 2016 at 13:34
  • 1
    This is the go-ethereum implementation. Essentially Geth's internals. We strive to make Geth (as a whole or in parts) be used as a library in other projects. Regarding Python I can't really help. No idea. Commented Apr 27, 2016 at 13:37
  • Thank you Peter. I was looking to make a simple executable in go to do that. This'll be my starting point.
    – hhh
    Commented Feb 8, 2017 at 19:45
  • What crypto library are you referring to here? Also can you link to your types file? Commented May 21, 2017 at 2:13
11

You can use Web3.

var Accounts = require('web3-eth-accounts');

// Passing in the eth or web3 package is necessary to allow retrieving chainId, gasPrice and nonce automatically
// for accounts.signTransaction().
// var accounts = new Accounts('ws://localhost:8546');
var accounts = new Accounts();
// if nonce, chainId, gas and gasPrice is given it returns synchronous
accounts.signTransaction({
    to: '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
    value: '1000000000',
    gas: 2000000,
    gasPrice: '234567897654321',
    nonce: 0,
    chainId: 1
}, '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318')

Output:

{
    messageHash: '0x6893a6ee8df79b0f5d64a180cd1ef35d030f3e296a5361cf04d02ce720d32ec5',
    r: '0x09ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9c',
    s: '0x440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428',
    v: '0x25',
    rawTransaction: '0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428'
}

Just use rawTransaction.

Source code

1
8

I found a way using the pyethereum lib.

BTW, this lib has little maintenance and doesn't build in most OS's.

Here's the sample code for that:

from libs.pyethereum.ethereum import transactions
from libs.pyethereum.ethereum import utils

# Create the priv keys and addresses. Addresses are returned in bytearray
key = utils.sha3("this is an insecure passphrase")
key2 = utils.sha3("37Dhsg17e92dfghKa Th!s i$ mUcH better r920167dfghjiHFGJsbcm")
addr = utils.privtoaddr(key)
addr2 = utils.privtoaddr(key2)

# Bytearray addresses
addr
'\xb8\xa1\xe7\x0b\x90\xb2\x8c\xde\x1e\xf7@+\xc2\x80\xc5\xb5\xa3W\xb4\x99'
addr2
'R~\xde {\x07"\xde\xfd\x981\x84\xcdA\x81\xbe\x82b\xdf\x01'

# Encoding the addresses in hex
addr_hex = utils.decode_addr(addr)
addr_hex
'b8a1e70b90b28cde1ef7402bc280c5b5a357b499'
addr2_hex = utils.decode_addr(addr2)
addr2_hex
'527ede207b0722defd983184cd4181be8262df01'
# These addresses are better represented with a '0x' prefix


# Create a transaction using key (address 1 priv key) and addr2 in bytearray
tx = transactions.Transaction(0, 1000, 100000, addr2, 56789000, "").sign(key)
tx.to_dict()
{'nonce': 0,
'hash': '648f97b1127bd26e5aa2f9b19d711648cb42509f105fd1ac4c90314c60bb06b1',
'sender': '\xb8\xa1\xe7\x0b\x90\xb2\x8c\xde\x1e\xf7@+\xc2\x80\xc5\xb5\xa3W\xb4\x99',
'startgas': 100000, 'value': 56789000, 'to': 'R~\xde {\x07"\xde\xfd\x981\x84\xcdA\x81\xbe\x82b\xdf\x01',
's': 27174000365690764914673576881913711980121871729925928151256478086834586258233L,
'r': 38109765815193709364550029305417348322702924861956728590268128554533127943524L,
'v': 28L, 'data': '', 'gasprice': 1000
}
1
  • How would the transaction look if I want to compose the transaction to call a state changing function of a contract ? How and where would I specify the arguments to the function of the contract. Commented Aug 29, 2016 at 10:55
5

I wrote an complete Python code. Feel free to use:

def signTransaction(to, value, privkey, nonce=0, gasPrice=20000000000, gas=21000, data=""):
    from ethereum import transactions
    import rlp
    try:
        return { 'error':False, 'sign':rlp.encode(transactions.Transaction(nonce, gasPrice, gas, to, value, data).sign(privkey)).encode('hex') }
    except Exception as msg:
        return { 'error':True, 'message':msg }
3

Here is a command line JavaScript application for creating offline transactions. You can also read the full tutorial blog post.

  • Offline as in your private key never leaves your computer

  • It uses etherscan.io service to get the latest nonce and gas price

  • You can additionally supply a contract function call and arguments

Code:

  /**
   * Sign an Ethereum transaction offline.
   *
   *
   * To run:
   *
   *   nvm use 7.2.1
   *   ./node_modules/babel-cli/bin/babel-node.js --presets es2015 --plugins transform-async-to-generator ./src/offlinetx.js --private-key 0xaaaaaaaaaaaaaaaaaaa --value 0.95 --to 0xAaF2ac6b800398F671b0D24cb8FccC3897B6aE49 --api-key HHHHHHHHHHHHHHHHHHHHHH

   *
   */

  import Web3 from 'web3'; // https://www.npmjs.com/package/web3
  import argv from 'optimist';
  import {buildTx, getAddressFromPrivateKey} from './txbuilder';
  import {API} from './etherscan';

  let web3 = new Web3();

  let _argv = argv.usage("offlinetx $0 --api-key 0x0000000 --private-key 0x00000000000000 --value 1.20 --to 0x1231231231")
    .describe("value", "Transaction amount in ETH")
    .describe("private-key", "32 bytes private key has hexadecimal format")
    .describe("to", "Ethereum 0x address where to send")
    .describe("nonce", "Nonce as hexacimal format, like 0x1")
    .describe("api-key", "etherscan.io API key used to get network status")
    .describe("gas-limt", "Maximum gas limit for the transaction as a hexadecmial")
    .default("gas-limit", web3.toHex(200000))
    .string("private-key")  // Heurestics is number by default which doesn't work for bigints
    .string("to")
    .string("api-key")
    .string("value")
    .string("nonce")
    .string("gas-limit")
    .demand(["private-key", "value", "to"]);

  async function run(argv) {

    // Parse command line
    let apiKey = argv["api-key"];
    let privateKey = argv["private-key"];
    let value = argv["value"];
    let to = argv["to"];
    let nonce = argv["nonce"];
    let gasLimit = argv["gas-limit"];

    if(!privateKey) {
      console.error("No private key given");
      process.exit(1);
    }

    if(!apiKey) {
      console.error("No EtherScan.io API key given");
      process.exit(1);
    }

    // Build EtherScan.io API wrapper object
    const api = new API("https://api.etherscan.io/api", apiKey);

    let fromAddress = getAddressFromPrivateKey(privateKey);

    // If nonce is not given get it usig Etherscan
    if(!nonce) {
      nonce = await api.getTransactionCount(fromAddress);
    }

    let gasPrice = await api.getGasPrice();

    value = web3.toHex(web3.toWei(value, "ether"));

    // What goes into our transaction
    let txData = {
      contractAddress: to,
      privateKey: privateKey,
      nonce: nonce,
      functionSignature: null, // TODO: Add contract call support here
      functionParameters: null,
      value: value,
      gasLimit: gasLimit,
      gasPrice: gasPrice,
    };

    // User readable output
    let info = Object.assign({}, txData);
    info.fromAddress = fromAddress;
    info.gasLimitInt = parseInt(txData.gasLimit, 16);
    info.gasPriceInt = parseInt(txData.gasPrice, 16);
    info.weiValueInt = parseInt(txData.value, 16);
    console.log("Building transaction with parameters\n", info);

    let tx = buildTx(txData);

    console.log("Your raw transaction is: ", tx);
    console.log("Visit at https://etherscan.io/pushTx to broadcast your transaction.");

  }

  run(_argv.argv)
    .catch(function(e) {
      console.error(e);
    });

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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