Commit 0bdb4f41 authored by SilentCicero's avatar SilentCicero

version 0.1.3 -- added more features, functionality, docs, tests

parent 122dbc5c
# 0.1.3 -- more features
1. Auto nonce, gasPrice filling
2. More test coverage
3. Accounts provider
# 0.1.2 -- remove deps
1. Remove `ethereumjs-tx` and `ethereumjs-util`
......
......@@ -53,6 +53,7 @@ const sign = require('ethjs-signer').sign;
const Eth = require('ethjs-query');
const provider = new SignerProvider('https://ropsten.infura.io', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0x...privateKey...')),
accounts: (cb) => cb(null, ['0x407d73d8a49eeb85d32cf465507dd71d507100c1']),
});
const eth = new Eth(provider);
......@@ -73,6 +74,8 @@ The `signTransaction` method is called everytime a payload must be signed. It pr
`ethjs-provider-signer` works well with `ethjs-signer`, a simple module for signing raw transactions. You may also bring your own signer from packages like `ethereumjs-signer`.
Note, the `nonce` and `gasPrice` get auto-filled by default (by using the `getTransactionCount` and `gasPrice` RPC calls). However, if these properties are specified in the raw tx object, the raw tx object props will override the default `nonce` and `gasPrice` values provided.
## Contributing
Please help better the ecosystem by submitting issues and pull requests to `ethjs-provider-signer`. We need all the help we can get to build the absolute best linting standards and utilities. We follow the AirBNB linting standard and the unix philosophy.
......
......@@ -64,7 +64,7 @@ return /******/ (function(modules) { // webpackBootstrap
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 3);
/******/ return __webpack_require__(__webpack_require__.s = 4);
/******/ })
/************************************************************************/
/******/ ([
......@@ -75,6 +75,7 @@ return /******/ (function(modules) { // webpackBootstrap
'use strict';
var HTTPProvider = __webpack_require__(1);
var EthRPC = __webpack_require__(2);
module.exports = SignerProvider;
......@@ -98,9 +99,12 @@ function SignerProvider(path, options) {
}
var self = this;
self.options = options;
self.options = Object.assign({
provider: HTTPProvider
}, options);
self.timeout = options.timeout || 0;
self.provider = new HTTPProvider(path, self.timeout);
self.provider = new self.options.provider(path, self.timeout); // eslint-disable-line
self.rpc = new EthRPC(self.provider);
}
/**
......@@ -114,23 +118,57 @@ function SignerProvider(path, options) {
SignerProvider.prototype.sendAsync = function (payload, callback) {
// eslint-disable-line
var self = this;
if (payload.method === 'eth_sendTransaction') {
self.options.signTransaction(payload.params[0], function (keyError, signedHexPayload) {
if (payload.method === 'eth_accounts' && self.options.accounts) {
self.options.accounts(function (accountsError, accounts) {
// create new output payload
var inputPayload = Object.assign({}, {
id: payload.id,
jsonrpc: payload.jsonrpc,
result: accounts
});
callback(accountsError, inputPayload);
});
} else if (payload.method === 'eth_sendTransaction') {
// get the nonce, if any
self.rpc.sendAsync({ method: 'eth_getTransactionCount', params: [payload.params[0].from, 'latest'] }, function (nonceError, nonce) {
// eslint-disable-line
if (!keyError) {
// create new output payload
var outputPayload = Object.assign({}, {
id: payload.id,
jsonrpc: payload.jsonrpc,
method: 'eth_sendRawTransaction',
params: [signedHexPayload]
});
// send payload
self.provider.sendAsync(outputPayload, callback);
} else {
return callback(new Error('[ethjs-provider-signer] while signing your sendTransaction payload: ' + JSON.stringify(keyError)), null);
if (nonceError) {
return callback(new Error('[ethjs-provider-signer] while getting nonce: ' + nonceError), null);
}
// get the gas price, if any
self.rpc.sendAsync({ method: 'eth_gasPrice' }, function (gasPriceError, gasPrice) {
// eslint-disable-line
if (gasPriceError) {
return callback(new Error('[ethjs-provider-signer] while getting gasPrice: ' + gasPriceError), null);
}
// build raw tx payload with nonce and gasprice as defaults to be overriden
var rawTxPayload = Object.assign({
nonce: nonce,
gasPrice: gasPrice
}, payload.params[0]);
// sign transaction with raw tx payload
self.options.signTransaction(rawTxPayload, function (keyError, signedHexPayload) {
// eslint-disable-line
if (!keyError) {
// create new output payload
var outputPayload = Object.assign({}, {
id: payload.id,
jsonrpc: payload.jsonrpc,
method: 'eth_sendRawTransaction',
params: [signedHexPayload]
});
// send payload
self.provider.sendAsync(outputPayload, callback);
} else {
callback(new Error('[ethjs-provider-signer] while signing your transaction payload: ' + JSON.stringify(keyError)), null);
}
});
});
});
} else {
self.provider.sendAsync(payload, callback);
......@@ -153,7 +191,7 @@ SignerProvider.prototype.sendAsync = function (payload, callback) {
*/
// workaround to use httpprovider in different envs
var XHR2 = __webpack_require__(2);
var XHR2 = __webpack_require__(3);
/**
* InvalidResponseError helper for invalid errors.
......@@ -227,11 +265,90 @@ module.exports = HttpProvider;
/* 2 */
/***/ function(module, exports) {
module.exports = XMLHttpRequest;
"use strict";
'use strict';
module.exports = EthRPC;
/**
* Constructs the EthRPC instance
*
* @method EthRPC
* @param {Object} cprovider the eth rpc provider web3 standard..
* @param {Object} options the options, if any
* @returns {Object} ethrpc instance
*/
function EthRPC(cprovider, options) {
var self = this;
var optionsObject = options || {};
if (!(this instanceof EthRPC)) {
throw new Error('[ethjs-rpc] the EthRPC object requires the "new" flag in order to function normally (i.e. `const eth = new EthRPC(provider);`).');
}
self.options = Object.assign({
jsonSpace: optionsObject.jsonSpace || 0,
max: optionsObject.max || 9999999999999
});
self.idCounter = Math.floor(Math.random() * self.options.max);
self.setProvider = function (provider) {
if (typeof provider !== 'object') {
throw new Error('[ethjs-rpc] the EthRPC object requires that the first input \'provider\' must be an object, got \'' + typeof provider + '\' (i.e. \'const eth = new EthRPC(provider);\')');
}
self.currentProvider = provider;
};
self.setProvider(cprovider);
}
/**
* The main send async method
*
* @method sendAsync
* @param {Object} payload the rpc payload object
* @param {Function} cb the async standard callback
* @callback {Object|Array|Boolean|String} vary result instance output
*/
EthRPC.prototype.sendAsync = function sendAsync(payload, cb) {
var self = this;
self.idCounter = self.idCounter % self.options.max;
self.currentProvider.sendAsync(createPayload(payload, self.idCounter++), function (err, response) {
var responseObject = response || {};
if (err || responseObject.error) {
var payloadErrorMessage = '[ethjs-rpc] ' + (responseObject.error && 'rpc' || '') + ' error with payload ' + JSON.stringify(payload, null, self.options.jsonSpace) + ' ' + (err || JSON.stringify(responseObject.error, null, self.options.jsonSpace));
return cb(new Error(payloadErrorMessage), null);
}
return cb(null, responseObject.result);
});
};
/**
* A simple create payload method
*
* @method createPayload
* @param {Object} data the rpc payload data
* @param {String} id the rpc data payload ID
* @returns {Object} payload the completed payload object
*/
function createPayload(data, id) {
return Object.assign({
id: id,
jsonrpc: '2.0',
params: []
}, data);
}
/***/ },
/* 3 */
/***/ function(module, exports) {
module.exports = XMLHttpRequest;
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(0);
......
This diff is collapsed.
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("SignerProvider",[],t):"object"==typeof exports?exports.SignerProvider=t():e.SignerProvider=t()}(this,function(){return function(e){function t(o){if(r[o])return r[o].exports;var n=r[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,t),n.l=!0,n.exports}var r={};return t.m=e,t.c=r,t.i=function(e){return e},t.d=function(e,t,r){Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=3)}([function(e,t,r){"use strict";function o(e,t){if(!(this instanceof o))throw Error('[ethjs-provider-signer] the SignerProvider instance requires the "new" flag in order to function normally (e.g. `const eth = new Eth(new SignerProvider(...));`).');if("object"!=typeof t)throw Error("[ethjs-provider-signer] the SignerProvider requires an options object be provided with the 'privateKey' property specified, you provided type "+typeof t+".");if("function"!=typeof t.signTransaction)throw Error("[ethjs-provider-signer] the SignerProvider requires an options object be provided with the 'signTransaction' property specified, you provided type "+typeof t.privateKey+" (e.g. 'const eth = new Eth(new SignerProvider(\"http://ropsten.infura.io\", { privateKey: (account, cb) => cb(null, 'some private key') }));').");var r=this;r.options=t,r.timeout=t.timeout||0,r.provider=new n(e,r.timeout)}var n=r(1);e.exports=o,o.prototype.sendAsync=function(e,t){var r=this;"eth_sendTransaction"===e.method?r.options.signTransaction(e.params[0],function(o,n){if(o)return t(Error("[ethjs-provider-signer] while signing your sendTransaction payload: "+JSON.stringify(o)),null);var i=Object.assign({},{id:e.id,jsonrpc:e.jsonrpc,method:"eth_sendRawTransaction",params:[n]});r.provider.sendAsync(i,t)}):r.provider.sendAsync(e,t)}},function(e,t,r){"use strict";function o(e,t){var r=e&&e.error&&e.error.message?"[ethjs-provider-http] "+e.error.message:"[ethjs-provider-http] Invalid JSON RPC response from host provider "+t+": "+JSON.stringify(e,null,2);return Error(r)}function n(e,t){if(!(this instanceof n))throw Error('[ethjs-provider-http] the HttpProvider instance requires the "new" flag in order to function normally (e.g. `const eth = new Eth(new HttpProvider());`).');if("string"!=typeof e)throw Error('[ethjs-provider-http] the HttpProvider instance requires that the host be specified (e.g. `new HttpProvider("http://localhost:8545")` or via service like infura `new HttpProvider("http://ropsten.infura.io")`)');var r=this;r.host=e,r.timeout=t||0}var i=r(2);n.prototype.sendAsync=function(e,t){var r=this,n=new i;n.timeout=r.timeout,n.open("POST",r.host,!0),n.setRequestHeader("Content-Type","application/json"),n.onreadystatechange=function(){if(4===n.readyState&&1!==n.timeout){var e=n.responseText,i=null;try{e=JSON.parse(e)}catch(s){i=o(n.responseText,r.host)}t(i,e)}},n.ontimeout=function(){t("[ethjs-provider-http] CONNECTION TIMEOUT: http request timeout after "+r.timeout+" ms. (i.e. your connect has timed out for whatever reason, check your provider).",null)};try{n.send(JSON.stringify(e))}catch(s){t("[ethjs-provider-http] CONNECTION ERROR: Couldn't connect to node '"+r.host+"': "+JSON.stringify(s,null,2),null)}},e.exports=n},function(e,t){e.exports=XMLHttpRequest},function(e,t,r){e.exports=r(0)}])});
\ No newline at end of file
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("SignerProvider",[],t):"object"==typeof exports?exports.SignerProvider=t():e.SignerProvider=t()}(this,function(){return function(e){function t(o){if(r[o])return r[o].exports;var n=r[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,t),n.l=!0,n.exports}var r={};return t.m=e,t.c=r,t.i=function(e){return e},t.d=function(e,t,r){Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=4)}([function(e,t,r){"use strict";function o(e,t){if(!(this instanceof o))throw Error('[ethjs-provider-signer] the SignerProvider instance requires the "new" flag in order to function normally (e.g. `const eth = new Eth(new SignerProvider(...));`).');if("object"!=typeof t)throw Error("[ethjs-provider-signer] the SignerProvider requires an options object be provided with the 'privateKey' property specified, you provided type "+typeof t+".");if("function"!=typeof t.signTransaction)throw Error("[ethjs-provider-signer] the SignerProvider requires an options object be provided with the 'signTransaction' property specified, you provided type "+typeof t.privateKey+" (e.g. 'const eth = new Eth(new SignerProvider(\"http://ropsten.infura.io\", { privateKey: (account, cb) => cb(null, 'some private key') }));').");var r=this;r.options=Object.assign({provider:n},t),r.timeout=t.timeout||0,r.provider=new r.options.provider(e,r.timeout),r.rpc=new i(r.provider)}var n=r(1),i=r(2);e.exports=o,o.prototype.sendAsync=function(e,t){var r=this;"eth_accounts"===e.method&&r.options.accounts?r.options.accounts(function(r,o){var n=Object.assign({},{id:e.id,jsonrpc:e.jsonrpc,result:o});t(r,n)}):"eth_sendTransaction"===e.method?r.rpc.sendAsync({method:"eth_getTransactionCount",params:[e.params[0].from,"latest"]},function(o,n){return o?t(Error("[ethjs-provider-signer] while getting nonce: "+o),null):void r.rpc.sendAsync({method:"eth_gasPrice"},function(o,i){if(o)return t(Error("[ethjs-provider-signer] while getting gasPrice: "+o),null);var s=Object.assign({nonce:n,gasPrice:i},e.params[0]);r.options.signTransaction(s,function(o,n){if(o)t(Error("[ethjs-provider-signer] while signing your transaction payload: "+JSON.stringify(o)),null);else{var i=Object.assign({},{id:e.id,jsonrpc:e.jsonrpc,method:"eth_sendRawTransaction",params:[n]});r.provider.sendAsync(i,t)}})})}):r.provider.sendAsync(e,t)}},function(e,t,r){"use strict";function o(e,t){var r=e&&e.error&&e.error.message?"[ethjs-provider-http] "+e.error.message:"[ethjs-provider-http] Invalid JSON RPC response from host provider "+t+": "+JSON.stringify(e,null,2);return Error(r)}function n(e,t){if(!(this instanceof n))throw Error('[ethjs-provider-http] the HttpProvider instance requires the "new" flag in order to function normally (e.g. `const eth = new Eth(new HttpProvider());`).');if("string"!=typeof e)throw Error('[ethjs-provider-http] the HttpProvider instance requires that the host be specified (e.g. `new HttpProvider("http://localhost:8545")` or via service like infura `new HttpProvider("http://ropsten.infura.io")`)');var r=this;r.host=e,r.timeout=t||0}var i=r(3);n.prototype.sendAsync=function(e,t){var r=this,n=new i;n.timeout=r.timeout,n.open("POST",r.host,!0),n.setRequestHeader("Content-Type","application/json"),n.onreadystatechange=function(){if(4===n.readyState&&1!==n.timeout){var e=n.responseText,i=null;try{e=JSON.parse(e)}catch(s){i=o(n.responseText,r.host)}t(i,e)}},n.ontimeout=function(){t("[ethjs-provider-http] CONNECTION TIMEOUT: http request timeout after "+r.timeout+" ms. (i.e. your connect has timed out for whatever reason, check your provider).",null)};try{n.send(JSON.stringify(e))}catch(s){t("[ethjs-provider-http] CONNECTION ERROR: Couldn't connect to node '"+r.host+"': "+JSON.stringify(s,null,2),null)}},e.exports=n},function(e,t){"use strict";function r(e,t){var o=this,n=t||{};if(!(this instanceof r))throw Error('[ethjs-rpc] the EthRPC object requires the "new" flag in order to function normally (i.e. `const eth = new EthRPC(provider);`).');o.options=Object.assign({jsonSpace:n.jsonSpace||0,max:n.max||9999999999999}),o.idCounter=Math.floor(Math.random()*o.options.max),(o.setProvider=function(e){if("object"!=typeof e)throw Error("[ethjs-rpc] the EthRPC object requires that the first input 'provider' must be an object, got '"+typeof e+"' (i.e. 'const eth = new EthRPC(provider);')");o.currentProvider=e})(e)}function o(e,t){return Object.assign({id:t,jsonrpc:"2.0",params:[]},e)}e.exports=r,r.prototype.sendAsync=function(e,t){var r=this;r.idCounter=r.idCounter%r.options.max,r.currentProvider.sendAsync(o(e,r.idCounter++),function(o,n){var i=n||{};if(o||i.error){var s="[ethjs-rpc] "+(i.error&&"rpc"||"")+" error with payload "+JSON.stringify(e,null,r.options.jsonSpace)+" "+(o||JSON.stringify(i.error,null,r.options.jsonSpace));return t(Error(s),null)}return t(null,i.result)})}},function(e,t){e.exports=XMLHttpRequest},function(e,t,r){e.exports=r(0)}])});
\ No newline at end of file
{
"name": "ethjs-provider-signer",
"version": "0.1.2",
"version": "0.1.3",
"description": "A simple web3 standard provider object that signs raw transactions.",
"main": "lib/index.js",
"files": [
......@@ -102,7 +102,8 @@
}
},
"dependencies": {
"ethjs-provider-http": "0.1.3"
"ethjs-provider-http": "0.1.3",
"ethjs-rpc": "0.1.1"
},
"devDependencies": {
"babel-core": "6.18.2",
......@@ -147,7 +148,7 @@
"eslint-plugin-react": "5.1.1",
"ethereumjs-testrpc": "3.0.2",
"ethjs-contract": "0.1.0",
"ethjs-query": "0.0.5",
"ethjs-query": "0.2.1",
"eventsource-polyfill": "0.9.6",
"istanbul": "0.4.5",
"json-loader": "0.5.4",
......
const HTTPProvider = require('ethjs-provider-http');
const EthRPC = require('ethjs-rpc');
module.exports = SignerProvider;
......@@ -16,9 +17,12 @@ function SignerProvider(path, options) {
if (typeof options.signTransaction !== 'function') { throw new Error(`[ethjs-provider-signer] the SignerProvider requires an options object be provided with the 'signTransaction' property specified, you provided type ${typeof options.privateKey} (e.g. 'const eth = new Eth(new SignerProvider("http://ropsten.infura.io", { privateKey: (account, cb) => cb(null, 'some private key') }));').`); }
const self = this;
self.options = options;
self.options = Object.assign({
provider: HTTPProvider,
}, options);
self.timeout = options.timeout || 0;
self.provider = new HTTPProvider(path, self.timeout);
self.provider = new self.options.provider(path, self.timeout); // eslint-disable-line
self.rpc = new EthRPC(self.provider);
}
/**
......@@ -31,22 +35,54 @@ function SignerProvider(path, options) {
*/
SignerProvider.prototype.sendAsync = function (payload, callback) { // eslint-disable-line
const self = this;
if (payload.method === 'eth_sendTransaction') {
self.options.signTransaction(payload.params[0], (keyError, signedHexPayload) => { // eslint-disable-line
if (!keyError) {
// create new output payload
const outputPayload = Object.assign({}, {
id: payload.id,
jsonrpc: payload.jsonrpc,
method: 'eth_sendRawTransaction',
params: [signedHexPayload],
});
if (payload.method === 'eth_accounts' && self.options.accounts) {
self.options.accounts((accountsError, accounts) => {
// create new output payload
const inputPayload = Object.assign({}, {
id: payload.id,
jsonrpc: payload.jsonrpc,
result: accounts,
});
// send payload
self.provider.sendAsync(outputPayload, callback);
} else {
return callback(new Error(`[ethjs-provider-signer] while signing your sendTransaction payload: ${JSON.stringify(keyError)}`), null);
callback(accountsError, inputPayload);
});
} else if (payload.method === 'eth_sendTransaction') {
// get the nonce, if any
self.rpc.sendAsync({ method: 'eth_getTransactionCount', params: [payload.params[0].from, 'latest'] }, (nonceError, nonce) => { // eslint-disable-line
if (nonceError) {
return callback(new Error(`[ethjs-provider-signer] while getting nonce: ${nonceError}`), null);
}
// get the gas price, if any
self.rpc.sendAsync({ method: 'eth_gasPrice' }, (gasPriceError, gasPrice) => { // eslint-disable-line
if (gasPriceError) {
return callback(new Error(`[ethjs-provider-signer] while getting gasPrice: ${gasPriceError}`), null);
}
// build raw tx payload with nonce and gasprice as defaults to be overriden
const rawTxPayload = Object.assign({
nonce,
gasPrice,
}, payload.params[0]);
// sign transaction with raw tx payload
self.options.signTransaction(rawTxPayload, (keyError, signedHexPayload) => { // eslint-disable-line
if (!keyError) {
// create new output payload
const outputPayload = Object.assign({}, {
id: payload.id,
jsonrpc: payload.jsonrpc,
method: 'eth_sendRawTransaction',
params: [signedHexPayload],
});
// send payload
self.provider.sendAsync(outputPayload, callback);
} else {
callback(new Error(`[ethjs-provider-signer] while signing your transaction payload: ${JSON.stringify(keyError)}`), null);
}
});
});
});
} else {
self.provider.sendAsync(payload, callback);
......
......@@ -3,6 +3,7 @@ const HTTPProvider = require('ethjs-provider-http'); // eslint-disable-line
const SignerProvider = require('../index.js'); // eslint-disable-line
const Eth = require('ethjs-query'); // eslint-disable-line
const Web3 = require('web3'); // eslint-disable-line
const HttpProvider = require('ethjs-provider-http');
const TestRPC = require('ethereumjs-testrpc');
const sign = require('ethjs-signer').sign;
const server = TestRPC.server({
......@@ -11,13 +12,17 @@ const server = TestRPC.server({
balance: '0x0000000000000056bc75e2d63100000',
}],
});
server.listen(5001);
server.listen(5012);
describe('SignerProvider', () => {
describe('constructor', () => {
it('should construct properly', (done) => {
const provider = new SignerProvider('http://localhost:5001', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0xc55c58355a32c095c7074837467382924180748768422589f5f75a384e6f3b33')),
const provider = new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => {
const sigpack = sign(rawTx, '0xc55c58355a32c095c7074837467382924180748768422589f5f75a384e6f3b33');
cb(null, sigpack);
},
});
assert.equal(typeof provider, 'object');
......@@ -32,16 +37,16 @@ describe('SignerProvider', () => {
});
it('should throw errors when improperly constructed', () => {
assert.throws(() => SignerProvider('http://localhost:5001', {}), Error); // eslint-disable-line
assert.throws(() => new SignerProvider('http://localhost:5001', 22), Error);
assert.throws(() => new SignerProvider('http://localhost:5001', {}), Error);
assert.throws(() => new SignerProvider('http://localhost:5001'), Error);
assert.throws(() => SignerProvider('http://localhost:5012', {}), Error); // eslint-disable-line
assert.throws(() => new SignerProvider('http://localhost:5012', 22), Error);
assert.throws(() => new SignerProvider('http://localhost:5012', {}), Error);
assert.throws(() => new SignerProvider('http://localhost:5012'), Error);
});
});
describe('functionality', () => {
it('should perform normally for calls', (done) => {
const provider = new SignerProvider('http://localhost:5001', {
const provider = new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0xc55c58355a32c095c7074837467382924180748768422589f5f75a384e6f3b33')),
});
const eth = new Eth(provider);
......@@ -60,8 +65,27 @@ describe('SignerProvider', () => {
});
});
it('should perform normally for calls with tx count and gas price', (done) => {
const eth = new Eth(new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0xc55c58355a32c095c7074837467382924180748768422589f5f75a384e6f3b33')),
}));
eth.accounts((accountsError, accounts) => {
assert.equal(accountsError, null);
assert.equal(typeof accounts, 'object');
assert.equal(Array.isArray(accounts), true);
eth.getBalance(accounts[0], (balanceError, balanceResult) => {
assert.equal(balanceError, null);
assert.equal(typeof balanceResult, 'object');
done();
});
});
});
it('should reconstruct sendTransaction as sendRawTransaction', (done) => {
const provider = new SignerProvider('http://localhost:5001', {
const provider = new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0xc55c58355a32c095c7074837467382924180748768422589f5f75a384e6f3b33')),
});
const eth = new Eth(provider);
......@@ -93,9 +117,93 @@ describe('SignerProvider', () => {
});
});
it('should throw an error when key is invalid', (done) => {
const provider = new SignerProvider('http://localhost:5001', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0xc55c58355a32c095c70748s746738d92d180748768422589f5f75a384e6f3b33')),
it('should handle invalid nonce', (done) => {
const baseProvider = new HttpProvider('http://localhost:5012');
const provider = new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => cb(new Error('account does not have permission')),
provider: function Provider() {
const self = this;
self.sendAsync = (payload, cb) => {
if (payload.method === 'eth_getTransactionCount') {
cb(new Error('invalid nonce'), null);
} else {
baseProvider.sendAsync(payload, cb);
}
};
},
});
const eth = new Eth(provider);
eth.accounts((accountsError, accounts) => {
assert.equal(accountsError, null);
assert.equal(Array.isArray(accounts), true);
done();
});
});
it('should handle valid accounts option', (done1) => {
const provider = new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0xc55c58355a32c095c7074837467382924180748768422589f5f75a384e6f3b33')),
accounts: (cb) => cb(null, ['0xc55c58355a32c095c70748374673829241807487']),
});
const eth = new Eth(provider);
eth.accounts((accountsError, accounts1) => {
assert.equal(accountsError, null);
assert.equal(Array.isArray(accounts1), true);
done1();
});
});
it('should handle invalid gas price', (done) => {
const baseProvider = new HttpProvider('http://localhost:5012');
const provider = new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0xc55c58355a32c095c7074837467382924180748768422589f5f75a384e6f3b33')),
provider: function Provider() {
const self = this;
self.sendAsync = (payload, cb) => {
if (payload.method === 'eth_gasPrice') {
cb(new Error('invalid nonce'), null);
} else {
baseProvider.sendAsync(payload, cb);
}
};
},
});
const eth = new Eth(provider);
eth.accounts((accountsError, accounts) => {
assert.equal(accountsError, null);
assert.equal(Array.isArray(accounts), true);
eth.sendTransaction({
from: accounts[0],
to: '0xc55c58355a32c095c70748374673829241807487',
data: '0x',
gas: 300000,
}).catch((txError) => {
assert.equal(typeof txError, 'object');
done();
});
});
});
it('should handle invalid tx count', (done) => {
const baseProvider = new HttpProvider('http://localhost:5012');
const provider = new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => cb(null, sign(rawTx, '0xc55c58355a32c095c7074837467382924180748768422589f5f75a384e6f3b33')),
provider: function Provider() {
const self = this;
self.sendAsync = (payload, cb) => {
if (payload.method === 'eth_getTransactionCount') {
cb(new Error('invalid nonce'), null);
} else {
baseProvider.sendAsync(payload, cb);
}
};
},
});
const eth = new Eth(provider);
......@@ -107,7 +215,6 @@ describe('SignerProvider', () => {
from: accounts[0],
to: '0xc55c58355a32c095c70748374673829241807487',
data: '0x',
value: 5000,
gas: 300000,
}).catch((txError) => {
assert.equal(typeof txError, 'object');
......@@ -118,7 +225,7 @@ describe('SignerProvider', () => {
});
it('should throw an error when key error is provided', (done) => {
const provider = new SignerProvider('http://localhost:5001', {
const provider = new SignerProvider('http://localhost:5012', {
signTransaction: (rawTx, cb) => cb(new Error('account does not have permission')),
});
const eth = new Eth(provider);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment