[Ethereum] How to sign transaction and send it via geth console

go-ethereum

According to https://github.com/ethereum/wiki/wiki/JSON-RPC .There are only two method to sign messages eth_sign and personal_sign . I think they're meant to sign message rather than transaction.However,as there are no any other method to sign transaction I planned to try them out.

I tried:
personal.sign("{'to':'0x177daf75686029aea26afa49d4e771e73bfc379c','value':'1000000000000000000','gas':2000000}",”0xa4916400009dd529d9c647e3088e776faa0a7168","asdf”)

on geth console and have already unlocked account for signing address.Then it showed error message as :

Error: invalid argument 0: json: cannot unmarshal hex string without 0x prefix into Go value of type hexutil.Bytes

Thereafter, I used sha3 to convert the json to hex as:

personal.sign(web3.sha3("{'to':'0x177daf75686029aea26afa49d4e771e73bfc379c','value':'1000000000000000000','gas':2000000}"),”0xa4916400009dd529d9c647e3088e776faa0a7168","asdf”)

This returned 0xf1ed845050ba57e2ca7a233f958f59f28df2fd5bc7d28fa69eb822e56b589e4c01c992cd285e7207361b15acdf73317c9ddeedc383173f6a92a2d3e78aa4f2531c in console.

I tried to confirm if it is valid signed transaction.Hence,I tried to push it on https://etherscan.io/pushTx.The site showed following error:

Unable to broadcast Tx : {"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"rlp: expected input string or byte for uint64, decoding into (types.Transaction)(types.txdata).AccountNonce"}}.

Please can anyone give me solution how to generate signed transaction on geth console?

Best Answer

I don't know if that's a proper way of sending a raw transaction, but it works. Just tested it.

const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
const config = require('./config');

const web3 = new Web3(new Web3.providers.HttpProvider(config.provider)); //link provided by Infura.io
web3.eth.defaultAccount = "0xc929c890f1398d5c1ecdf4f9ecec016906ac9f7f";

const getNonce = () => {
  return new Promise((resolve, reject) => {
    web3.eth.getTransactionCount(web3.eth.defaultAccount, (error, result) => {
      if(error) reject(error);
      resolve(web3.toHex(result));
    })
  })
}
const getGasPrice = () => {
  return new Promise((resolve, reject) => {
    web3.eth.getGasPrice((error, result) => {
      if(error) reject(error);
      resolve(web3.toHex(result.toNumber()));
    })
  })
}

const sendRawTransaction = (rawTx) => {
  const privateKey = "190b820c2627f26fd1b973b72dcba78ff677ca4395c64a4a2d0f4ef8de36883c";
  const tx = new Tx(rawTx);
  const privateKeyBuffer = Buffer.from(privateKey, 'hex');
  tx.sign(privateKeyBuffer);
  const serializedTx = tx.serialize();
  web3.eth.sendRawTransaction('0x' + serializedTx.toString('hex'), function(err, hash) {
      console.log('Error:', err);
      console.log('Hash:', hash);
  });
}

Promise.all([getNonce(), getGasPrice()])
  .then(values => {
    const rawTx = {
      to: '0x203D17B4a1725E001426b7Ab3193E6657b0dBcc6',
      gasLimit: web3.toHex(1000000),
      value: web3.toHex(web3.toWei('0.1', 'ether')),
      nonce: values[0],
      gasPrice: values[1]
    };
    console.log(rawTx);
    return(rawTx);
  })
  .then(sendRawTransaction)
  .catch(e => console.log(e))

console:

{ 
  to: '0x203D17B4a1725E001426b7Ab3193E6657b0dBcc6',
  gasLimit: '0xf4240',
  value: '0x16345785d8a0000',
  nonce: '0x5',
  gasPrice: '0x4a817c800' 
}
Error: null
Hash: 0x2a156efdaa6be587544f32cdf7bac140bbee20dafda2c561a4c9195c6fa6729c

Here's how I generated key pair and address:

const keythereum = require('keythereum');
const utils = require('ethereumjs-util');

const params = {keyBytes: 32, ivBytes: 16};
const dk = keythereum.create(params);
const private = utils.bufferToHex(dk.privateKey);
const public = utils.bufferToHex(utils.privateToPublic(dk.privateKey));
const address = utils.bufferToHex(utils.privateToAddress(dk.privateKey));