mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-01-10 19:16:10 +00:00
Add Promises & Signing to Wallet Classes (#105)
* add validation for raw tx * add node module, add signing lib * add tx & message signing, promise everything * remove unnecessary returns * move isValidRawTx to for loop * add & use new type RawTx * implement cleaner promises, reject instead of throw
This commit is contained in:
parent
a66337ac0a
commit
3ef2b51a68
40
common/libs/signing.js
Normal file
40
common/libs/signing.js
Normal file
@ -0,0 +1,40 @@
|
||||
// @flow
|
||||
|
||||
import EthTx from 'ethereumjs-tx';
|
||||
import { sha3, ecsign } from 'ethereumjs-util';
|
||||
import { isValidRawTx } from 'libs/validators';
|
||||
import type { RawTx } from 'libs/validators';
|
||||
|
||||
export function signRawTxWithPrivKey(privKey: Buffer, rawTx: RawTx): string {
|
||||
if (!isValidRawTx(rawTx)) {
|
||||
throw new Error('Invalid raw transaction');
|
||||
}
|
||||
|
||||
let eTx = new EthTx(rawTx);
|
||||
eTx.sign(privKey);
|
||||
return '0x' + eTx.serialize().toString('hex');
|
||||
}
|
||||
|
||||
export function signMessageWithPrivKey(
|
||||
privKey: Buffer,
|
||||
msg: string,
|
||||
address: string,
|
||||
date: string
|
||||
): string {
|
||||
let spacer = msg.length > 0 && date.length > 0 ? ' ' : '';
|
||||
let fullMessage = msg + spacer + date;
|
||||
let hash = sha3(fullMessage);
|
||||
let signed = ecsign(hash, privKey);
|
||||
let combined = Buffer.concat([
|
||||
Buffer.from(signed.r),
|
||||
Buffer.from(signed.s),
|
||||
Buffer.from([signed.v])
|
||||
]);
|
||||
let combinedHex = combined.toString('hex');
|
||||
|
||||
return JSON.stringify({
|
||||
address: address,
|
||||
msg: fullMessage,
|
||||
sig: '0x' + combinedHex
|
||||
});
|
||||
}
|
@ -84,3 +84,53 @@ export function isPositiveIntegerOrZero(number: number): boolean {
|
||||
}
|
||||
return number >= 0 && parseInt(number) === number;
|
||||
}
|
||||
|
||||
export type RawTx = {
|
||||
nonce: string,
|
||||
gasPrice: string,
|
||||
gasLimit: string,
|
||||
to: string,
|
||||
value: string,
|
||||
data: string,
|
||||
chainId: number
|
||||
};
|
||||
|
||||
export function isValidRawTx(rawTx: RawTx): boolean {
|
||||
const propReqs = [
|
||||
{ name: 'nonce', type: 'string', lenReq: true },
|
||||
{ name: 'gasPrice', type: 'string', lenReq: true },
|
||||
{ name: 'gasLimit', type: 'string', lenReq: true },
|
||||
{ name: 'to', type: 'string', lenReq: true },
|
||||
{ name: 'value', type: 'string', lenReq: true },
|
||||
{ name: 'data', type: 'string', lenReq: false },
|
||||
{ name: 'chainId', type: 'number' }
|
||||
];
|
||||
|
||||
//ensure rawTx has above properties
|
||||
//ensure all specified types match
|
||||
//ensure length !0 for strings where length is required
|
||||
//ensure valid hex for strings
|
||||
//ensure all strings begin with '0x'
|
||||
//ensure valid address for 'to' prop
|
||||
//ensure rawTx only has above properties
|
||||
|
||||
for (let i = 0; i < propReqs.length; i++) {
|
||||
const prop = propReqs[i];
|
||||
const value = rawTx[prop.name];
|
||||
|
||||
if (!rawTx.hasOwnProperty(prop.name)) return false;
|
||||
if (typeof value !== prop.type) return false;
|
||||
if (prop.type === 'string') {
|
||||
if (prop.lenReq && value.length === 0) return false;
|
||||
if (value.length && value.substring(0, 2) !== '0x') {
|
||||
return false;
|
||||
}
|
||||
if (!isValidHex(value)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValidETHAddress(rawTx.to)) return false;
|
||||
if (Object.keys(rawTx).length !== propReqs.length) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
// @flow
|
||||
|
||||
export default class BaseWallet {
|
||||
getAddress(): string {
|
||||
throw 'Implement me';
|
||||
getAddress(): Promise<any> {
|
||||
return Promise.reject('Implement me');
|
||||
}
|
||||
|
||||
getNakedAddress(): string {
|
||||
return this.getAddress().replace('0x', '').toLowerCase();
|
||||
getNakedAddress(): Promise<any> {
|
||||
return new Promise(resolve => {
|
||||
this.getAddress.then(address => {
|
||||
resolve(address.replace('0x', '').toLowerCase());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import {
|
||||
} from 'ethereumjs-util';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { pkeyToKeystore } from 'libs/keystore';
|
||||
import { signRawTxWithPrivKey, signMessageWithPrivKey } from 'libs/signing';
|
||||
import type { RawTx } from 'libs/validators';
|
||||
|
||||
export default class PrivKeyWallet extends BaseWallet {
|
||||
privKey: Buffer;
|
||||
@ -19,8 +21,10 @@ export default class PrivKeyWallet extends BaseWallet {
|
||||
this.address = publicToAddress(this.pubKey);
|
||||
}
|
||||
|
||||
getAddress() {
|
||||
return toChecksumAddress(`0x${this.address.toString('hex')}`);
|
||||
getAddress(): Promise<any> {
|
||||
return new Promise(resolve => {
|
||||
resolve(toChecksumAddress(`0x${this.address.toString('hex')}`));
|
||||
});
|
||||
}
|
||||
|
||||
getPrivateKey() {
|
||||
@ -31,7 +35,35 @@ export default class PrivKeyWallet extends BaseWallet {
|
||||
return new PrivKeyWallet(randomBytes(32));
|
||||
}
|
||||
|
||||
toKeystore(password: string): Object {
|
||||
return pkeyToKeystore(this.privKey, this.getNakedAddress(), password);
|
||||
toKeystore(password: string): Promise<any> {
|
||||
return new Promise(resolve => {
|
||||
this.getNakedAddress().then(address => {
|
||||
resolve(pkeyToKeystore(this.privKey, address, password));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
unlock(): Promise<any> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
signRawTransaction(rawTx: RawTx): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
resolve(signRawTxWithPrivKey(this.privKey, rawTx));
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
signMessage(msg: string, address: string, date: string): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
resolve(signMessageWithPrivKey(this.privKey, msg, address, date));
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"big.js": "^3.1.3",
|
||||
"ethereum-blockies": "git+https://github.com/MyEtherWallet/blockies.git",
|
||||
"ethereumjs-tx": "^1.3.3",
|
||||
"ethereumjs-util": "^5.1.2",
|
||||
"ethereumjs-wallet": "^0.6.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user