Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eth.accounts.signTransaction method fixed #3141

Merged
merged 15 commits into from
Oct 21, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Released with 1.0.0-beta.37 code base.
- Add `eth.getChainId` method (#3113)
- Minified file added to web3 package (#3131)
- The transaction confirmation workflow can now be configured (#3130)
- Additional parameters for accounts.signTransaction added [(docs)](https://web3js.readthedocs.io/en/v1.2.2/web3-eth-accounts.html#signtransaction) (#3141)
- TypeScript type definitions added for all modules (#3132)
- Bloom filters added to web3.utils (#3137)

Expand Down
26 changes: 26 additions & 0 deletions docs/web3-eth-accounts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ Parameters
----------

1. ``tx`` - ``Object``: The transaction object as follows:
- ``chain`` - ``String``: (optional) Defaults to ``mainnet``.
- ``hardfork`` - ``String``: (optional) Defaults to ``petersburg``.
- ``common`` - ``String``: (optional) The initiated common object of the `ethereumjs-common <https://www.npmjs.com/package/ethereumjs-common>`_ package. `(Example) <https://github.com/ethereumjs/ethereumjs-tx#chain-and-hardfork-support>`_
- ``nonce`` - ``String``: (optional) The nonce to use when signing this transaction. Default will use :ref:`web3.eth.getTransactionCount() <eth-gettransactioncount>`.
- ``chainId`` - ``String``: (optional) The chain id to use when signing this transaction. Default will use :ref:`web3.eth.net.getId() <net-getid>`.
- ``to`` - ``String``: (optional) The recevier of the transaction, can be empty when deploying a contract.
Expand Down Expand Up @@ -206,6 +209,29 @@ Example
transactionHash: '0xd8f64a42b57be0d565f385378db2f6bf324ce14a594afc05de90436e9ce01f60'
}

// or with a common

var Common = require('ethereumjs-common').default;

var customCommon = Common.forCustomChain(
'mainnet',
{
name: 'my-network',
networkId: 1,
chainId: 1337,
},
'petersburg',
);

web3.eth.accounts.signTransaction({
to: '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55',
value: '1000000000',
gas: 2000000
common: customCommon
}, '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318')
.then(console.log);




------------------------------------------------------------------------------
Expand Down
6 changes: 5 additions & 1 deletion docs/web3-eth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1056,9 +1056,13 @@ Parameters
- ``gasPrice`` - ``Number|String|BN|BigNumber``: (optional) The price of gas for this transaction in :ref:`wei <what-is-wei>`, defaults to :ref:`web3.eth.gasPrice <eth-gasprice>`.
- ``data`` - ``String``: (optional) Either a `ABI byte string <http://solidity.readthedocs.io/en/latest/abi-spec.html>`_ containing the data of the function call on a contract, or in the case of a contract-creation transaction the initialisation code.
- ``nonce`` - ``Number``: (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.
- ``chain`` - ``String``: (optional) Defaults to ``mainnet``.
- ``hardfork`` - ``String``: (optional) Defaults to ``petersburg``.
- ``common`` - ``String``: (optional) The initiated common object of the `ethereumjs-common <https://www.npmjs.com/package/ethereumjs-common>`_ package. `(Example) <https://github.com/ethereumjs/ethereumjs-tx#chain-and-hardfork-support>`_

2. ``callback`` - ``Function``: (optional) Optional callback, returns an error object as first parameter and the result as second.

.. note:: The ``from`` property can also be an address or index from the :ref:`web3.eth.accounts.wallet <eth_accounts_wallet>`. It will then sign locally using the private key of that account, and send the transaction via :ref:`web3.eth.sendSignedTransaction() <eth-sendsignedtransaction>`.
.. note:: The ``from`` property can also be an address or index from the :ref:`web3.eth.accounts.wallet <eth_accounts_wallet>`. It will then sign locally using the private key of that account, and send the transaction via :ref:`web3.eth.sendSignedTransaction() <eth-sendsignedtransaction>`. The properties ``chain`` and ``hardfork`` or ``common`` are required if you are not connected to the ``mainnet``.

.. _eth-sendtransaction-return:

Expand Down
3 changes: 3 additions & 0 deletions packages/web3-core/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ export interface TransactionConfig {
data?: string;
nonce?: number;
chainId?: number;
common?: any; // ethereumjs-common
chain?: string;
hardfork?: string;
}

export interface RLPEncodedTransaction {
Expand Down
25 changes: 24 additions & 1 deletion packages/web3-eth-accounts/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(privateKey
Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, callback) {
var _this = this,
error = false,
transactionOptions = {},
result;

callback = callback || function () {};
Expand All @@ -131,6 +132,12 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca

function signed (tx) {

if (tx.common && (tx.chain && tx.hardfork)) {
error = new Error(
'Please provide the ethereumjs-common object or the chain and hardfork property but not all together.'
);
}

if (!tx.gas && !tx.gasLimit) {
error = new Error('"gas" is missing');
}
Expand All @@ -154,11 +161,27 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
transaction.value = transaction.value || '0x';
transaction.chainId = utils.numberToHex(transaction.chainId);

if (transaction.common) {
transactionOptions['common'] = transaction.common;
delete transaction.common;
}

if (transaction.chain) {
transactionOptions['chain'] = transaction.chain;
delete transaction.chain;
}

if (transaction.hardfork) {
transactionOptions['hardfork'] = transaction.hardfork;
delete transaction.hardfork;
}

if (privateKey.startsWith('0x')) {
privateKey = privateKey.substring(2);
}

var ethTx = new Transaction(transaction);
var ethTx = new Transaction(transaction, transactionOptions);

ethTx.sign(Buffer.from(privateKey, 'hex'));

var validationResult = ethTx.validate(true);
Expand Down
2 changes: 1 addition & 1 deletion packages/web3-net/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var Net = function () {
name: 'getId',
call: 'net_version',
params: 0,
outputFormatter: utils.hexToNumber
outputFormatter: parseInt
nivida marked this conversation as resolved.
Show resolved Hide resolved
}),
new Method({
name: 'isListening',
Expand Down
77 changes: 43 additions & 34 deletions test/e2e.method.signing.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
var assert = require('assert');
var EJSCommon = require('ethereumjs-common');
var EJSTx = require('ethereumjs-tx');
var Web3 = require('../packages/web3');
var Basic = require('./sources/Basic');
var utils = require('./helpers/test.utils');
var util = require('util')
let assert = require('assert');
let EJSCommon = require('ethereumjs-common');
let Web3 = require('../packages/web3');

describe('transaction and message signing [ @E2E ]', function() {
var web3;
var accounts;
var wallet;
var Transaction = EJSTx.Transaction;
var Common = EJSCommon.default;
let web3;
let accounts;
let wallet;
let Common = EJSCommon.default;

before(async function(){
web3 = new Web3('http://localhost:8545');
Expand All @@ -25,59 +20,73 @@ describe('transaction and message signing [ @E2E ]', function() {
to: wallet[0].address,
value: web3.utils.toWei('50', 'ether'),
});
})
});

it('sendSignedTransaction (with eth.signTransaction)', async function(){
// ganache does not support eth_signTransaction
if (process.env.GANACHE) return
if (process.env.GANACHE) return;

var destination = wallet[1].address;
var source = accounts[0] // Unlocked geth-dev account
const destination = wallet[1].address;
const source = accounts[0]; // Unlocked geth-dev account

const txCount = await web3.eth.getTransactionCount(source);

var rawTx = {
const rawTx = {
nonce: web3.utils.toHex(txCount),
to: destination,
from: source,
value: web3.utils.toHex(web3.utils.toWei('0.1', 'ether')),
gasLimit: web3.utils.toHex(21000),
gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei'))
}
};

var signed = await web3.eth.signTransaction(rawTx)
var receipt = await web3.eth.sendSignedTransaction(signed.raw);
const signed = await web3.eth.signTransaction(rawTx);
const receipt = await web3.eth.sendSignedTransaction(signed.raw);

assert(receipt.status === true);
});

it.skip('sendSignedTransaction (with eth.accounts.signTransaction)', async function(){
var source = wallet[0].address
var destination = wallet[1].address;
it('sendSignedTransaction (with eth.accounts.signTransaction)', async function(){
const source = wallet[0].address;
const destination = wallet[1].address;

const txCount = await web3.eth.getTransactionCount(source);
const networkId = await web3.eth.net.getId();
const chainId = await web3.eth.getChainId();


const customCommon = Common.forCustomChain(
'mainnet',
{
name: 'my-network',
networkId: networkId,
chainId: chainId,
},
'petersburg',
);

var txObject = {
const txObject = {
nonce: web3.utils.toHex(txCount),
to: destination,
value: web3.utils.toHex(web3.utils.toWei('0.1', 'ether')),
gasLimit: web3.utils.toHex(21000),
gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei'))
}
gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei')),
common: customCommon
};

var signed = await web3.eth.accounts.signTransaction(txObject, wallet[0].privateKey);
var receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
const signed = await web3.eth.accounts.signTransaction(txObject, wallet[0].privateKey);
const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);

assert(receipt.status === true);
});

it('eth.personal.sign', async function(){
// ganache does not support eth_sign
if (process.env.GANACHE) return
if (process.env.GANACHE) return;

var message = 'hello';
const message = 'hello';

var signature = await web3.eth.personal.sign(
const signature = await web3.eth.personal.sign(
message,
accounts[1], // Unlocked geth-dev acct
"left-hand-of-darkness" // Default password at geth-dev
Expand All @@ -89,11 +98,11 @@ describe('transaction and message signing [ @E2E ]', function() {

it('eth.accounts.sign', async function(){
// ganache does not support eth_sign
if (process.env.GANACHE) return
if (process.env.GANACHE) return;

var message = 'hello';
const message = 'hello';

var signed = web3.eth.accounts.sign(message, wallet[0].privateKey);
const signed = web3.eth.accounts.sign(message, wallet[0].privateKey);
const recovered = await web3.eth.personal.ecRecover(message, signed.signature);
assert.equal(wallet[0].address.toLowerCase(), recovered.toLowerCase());
})
Expand Down