[feat] added recover to Transaction

@types
neeboo 6 years ago
parent 75a238a425
commit cf7f7be197
  1. 59
      examples/testNode.js
  2. 3
      packages/harmony-account/src/account.ts
  3. 2
      packages/harmony-account/src/index.ts
  4. 85
      packages/harmony-crypto/src/bytes.ts
  5. 66
      packages/harmony-crypto/src/keyTool.ts
  6. 19
      packages/harmony-transaction/src/transaction.ts
  7. 1
      packages/harmony-transaction/src/types.ts
  8. 114
      packages/harmony-transaction/src/utils.ts
  9. 331
      packages/harmony-utils/src/transformers.ts
  10. 5
      typings/elliptic.d.ts

@ -1,8 +1,28 @@
const { Account, Wallet } = require('@harmony/account'); const { Account, Wallet } = require('@harmony/account');
const { isAddress, isPrivateKey, numberToHex } = require('@harmony/utils'); const {
isAddress,
isPrivateKey,
numberToHex,
numToStr,
hexToNumber,
Unit,
strip0x,
} = require('@harmony/utils');
const { HttpProvider, Messenger } = require('@harmony/network'); const { HttpProvider, Messenger } = require('@harmony/network');
const { Transaction } = require('@harmony/transaction'); const { Transaction } = require('@harmony/transaction');
const { hexlify, BN } = require('@harmony/crypto'); const {
arrayify,
hexlify,
BN,
encode,
decode,
getContractAddress,
recoverAddress,
recoverPublicKey,
keccak256,
hexZeroPad,
getAddressFromPublicKey,
} = require('@harmony/crypto');
const msgr = new Messenger(new HttpProvider('https://dev-api.zilliqa.com')); const msgr = new Messenger(new HttpProvider('https://dev-api.zilliqa.com'));
const wallet = new Wallet(msgr); const wallet = new Wallet(msgr);
@ -58,15 +78,44 @@ const acc = wallet.addByPrivateKey(
'0xc3886f791236bf31fe8fd7522a7b12808700deb9c159826fc99236c74614118b', '0xc3886f791236bf31fe8fd7522a7b12808700deb9c159826fc99236c74614118b',
); );
console.log(txn.getRLPUnsigned()[0]); // console.log(txn.getRLPUnsigned()[0]);
const signed = wallet const signed = wallet
.getAccount(acc.address) .getAccount(acc.address)
.signTransaction(txn, false) .signTransaction(txn, false)
.then(console.log); .then((tx) => {
const newTx = tx.recover(tx.unsignedTxnHash);
// console.log(newTx);
acc.signTransaction(newTx, false, 'rlp').then((signed) => {
console.log(signed);
});
});
// recoverAddress();
// console.log(wallet.messenger); // console.log(wallet.messenger);
// console.log(hexlify(0)); // console.log(hexlify(0));
// 0xda8003049401234567890123456789012345678901234567890580; // 0xda8003049401234567890123456789012345678901234567890580;
// 0xda8003049401234567890123456789012345678901234567890580; // 0xda8003049401234567890123456789012345678901234567890580;
/**
* { name: 'nonce', length: 32, fix: false },
{ name: 'gasPrice', length: 32, fix: false, transform: 'hex' },
{ name: 'gasLimit', length: 32, fix: false, transform: 'hex' },
{ name: 'to', length: 20, fix: true },
{ name: 'value', length: 32, fix: false, transform: 'hex' },
{ name: 'data', fix: false },
*/
// const [nonce, gasPrice, gasLimit, to, value, data] = decode(
// txn.getRLPUnsigned()[0],
// );
// console.log({
// nonce: new BN(strip0x(hexToNumber(nonce))).toNumber(),
// gasPrice: hexToNumber(gasPrice !== '0x' ? gasPrice : '0x00'),
// gasLimit: hexToNumber(gasLimit !== '0x' ? gasLimit : '0x00'),
// to: hexToNumber(to !== '0x' ? to : '0x00'),
// value: hexToNumber(value !== '0x' ? value : '0x00'),
// data: hexToNumber(data !== '0x' ? data : '0x00'),
// });
// console.log(getContractAddress(acc.publicKey, 248));

@ -152,6 +152,7 @@ class Account {
const balanceObject: any = await this.getBalance(); const balanceObject: any = await this.getBalance();
transaction.setParams({ transaction.setParams({
...transaction.txParams, ...transaction.txParams,
from: this.address || '0x',
nonce: balanceObject.nonce + 1, nonce: balanceObject.nonce + 1,
}); });
} }
@ -161,7 +162,7 @@ class Account {
this.privateKey, this.privateKey,
); );
return transaction.map((obj: any) => { return transaction.map((obj: any) => {
return { ...obj, signature, txnHash }; return { ...obj, signature, txnHash, from: this.address };
}); });
} else { } else {
// TODO: if we use other encode method, eg. protobuf, we should implement this // TODO: if we use other encode method, eg. protobuf, we should implement this

@ -1,2 +1,4 @@
export * from './account'; export * from './account';
export * from './wallet'; export * from './wallet';
export * from './types';
export * from './utils';

@ -341,54 +341,55 @@ export function isSignature(value: any): value is Signature {
} }
export function splitSignature(signature: Arrayish | Signature): Signature { export function splitSignature(signature: Arrayish | Signature): Signature {
let v: number | undefined = 0; if (signature !== undefined) {
let r = '0x'; let v = 0;
let s = '0x'; let r = '0x';
let s = '0x';
if (isSignature(signature)) {
if (signature.v == null && signature.recoveryParam == null) {
errors.throwError(
'at least on of recoveryParam or v must be specified',
errors.INVALID_ARGUMENT,
{ argument: 'signature', value: signature },
);
}
r = hexZeroPad(signature.r, 32);
s = hexZeroPad(signature.s, 32);
if (isSignature(signature)) { v = signature.v || 0;
if (signature.v == null && signature.recoveryParam == null) { if (typeof v === 'string') {
errors.throwError( v = parseInt(v, 16);
'at least on of recoveryParam or v must be specified', }
errors.INVALID_ARGUMENT,
{ argument: 'signature', value: signature },
);
}
r = hexZeroPad(signature.r, 32);
s = hexZeroPad(signature.s, 32);
v = signature.v; let recoveryParam = signature.recoveryParam || 0;
if (typeof v === 'string') { if (recoveryParam == null && signature.v != null) {
v = parseInt(v, 16); recoveryParam = 1 - (v % 2);
} }
v = 27 + recoveryParam;
} else {
const bytes: Uint8Array = arrayify(signature) || new Uint8Array();
if (bytes.length !== 65) {
throw new Error('invalid signature');
}
r = hexlify(bytes.slice(0, 32));
s = hexlify(bytes.slice(32, 64));
let recoveryParam = signature.recoveryParam || 1; v = bytes[64];
if (recoveryParam == null && signature.v != null) { if (v !== 27 && v !== 28) {
recoveryParam = 1 - (typeof v !== 'number' ? 0 : v % 2); v = 27 + (v % 2);
} }
v = 27 + recoveryParam;
} else {
const bytes: Uint8Array | null = arrayify(signature);
if (bytes === null) {
throw new Error('arrayify failed');
}
if (bytes.length !== 65) {
throw new Error('invalid signature');
} }
r = hexlify(bytes.slice(0, 32));
s = hexlify(bytes.slice(32, 64));
v = bytes[64]; return {
if (v !== 27 && v !== 28) { r,
v = 27 + (v % 2); s,
} recoveryParam: v - 27,
v,
};
} else {
throw new Error('signature is not found');
} }
return {
r,
s,
recoveryParam: v - 27,
v,
};
} }
export function joinSignature(signature: Signature): string { export function joinSignature(signature: Signature): string {

@ -5,6 +5,7 @@ import * as errors from './errors';
import { keccak256 } from './keccak256'; import { keccak256 } from './keccak256';
import { randomBytes } from './random'; import { randomBytes } from './random';
import { isPrivateKey, strip0x } from '@harmony/utils'; import { isPrivateKey, strip0x } from '@harmony/utils';
import { encode } from './rlp';
const secp256k1 = elliptic.ec('secp256k1'); const secp256k1 = elliptic.ec('secp256k1');
@ -63,8 +64,8 @@ export const getPublic = (privateKey: string, compress?: boolean): string => {
*/ */
export const getAddressFromPublicKey = (publicKey: string): string => { export const getAddressFromPublicKey = (publicKey: string): string => {
const ecKey = secp256k1.keyFromPublic(publicKey.slice(2), 'hex'); const ecKey = secp256k1.keyFromPublic(publicKey.slice(2), 'hex');
const publickHash = ecKey.getPublic(false, 'hex'); const publicHash = ecKey.getPublic(false, 'hex');
const address = '0x' + keccak256('0x' + publickHash.slice(2)).slice(-40); const address = '0x' + keccak256('0x' + publicHash.slice(2)).slice(-40);
return address; return address;
}; };
@ -110,12 +111,71 @@ export const sign = (
if (!isPrivateKey(privateKey)) { if (!isPrivateKey(privateKey)) {
throw new Error(`${privateKey} is not PrivateKey`); throw new Error(`${privateKey} is not PrivateKey`);
} }
const keyPair = secp256k1.keyFromPrivate(strip0x(privateKey), 'hex'); const keyPair = secp256k1.keyFromPrivate(strip0x(privateKey), 'hex');
const signature = keyPair.sign(bytes.arrayify(digest), { canonical: true }); const signature = keyPair.sign(bytes.arrayify(digest), { canonical: true });
return { const publicKey = '0x' + keyPair.getPublic(true, 'hex');
const result = {
recoveryParam: signature.recoveryParam, recoveryParam: signature.recoveryParam,
r: bytes.hexZeroPad('0x' + signature.r.toString(16), 32), r: bytes.hexZeroPad('0x' + signature.r.toString(16), 32),
s: bytes.hexZeroPad('0x' + signature.s.toString(16), 32), s: bytes.hexZeroPad('0x' + signature.s.toString(16), 32),
v: 27 + signature.recoveryParam, v: 27 + signature.recoveryParam,
}; };
if (verifySignature(digest, result, publicKey)) {
return result;
} else {
throw new Error('signing process failed');
}
}; };
export function getContractAddress(from: string, nonce: number): string {
if (!from) {
throw new Error('missing from address');
}
const addr = keccak256(
encode([from, bytes.stripZeros(bytes.hexlify(nonce))]),
);
return '0x' + addr.substring(26);
}
export function verifySignature(
digest: bytes.Arrayish,
signature: bytes.Signature,
publicKey: string,
): boolean {
return recoverPublicKey(digest, signature) === publicKey;
}
export function recoverPublicKey(
digest: bytes.Arrayish | string,
signature: bytes.Signature | string,
): string {
const sig = bytes.splitSignature(signature);
const rs = { r: bytes.arrayify(sig.r), s: bytes.arrayify(sig.s) };
////
const recovered = secp256k1.recoverPubKey(
bytes.arrayify(digest),
rs,
sig.recoveryParam,
);
const key = recovered.encode('hex', false);
const ecKey = secp256k1.keyFromPublic(key, 'hex');
const publicKey = '0x' + ecKey.getPublic(true, 'hex');
///
return publicKey;
}
export function recoverAddress(
digest: bytes.Arrayish | string,
signature: bytes.Signature | string,
): string {
return getAddressFromPublicKey(
recoverPublicKey(bytes.arrayify(digest) || new Uint8Array(), signature),
);
}

@ -1,15 +1,19 @@
import { import {
BN, BN,
encode, encode,
// keccak256,
// decode,
// toChecksumAddress, // toChecksumAddress,
arrayify, arrayify,
hexlify, hexlify,
stripZeros, stripZeros,
Signature, Signature,
splitSignature, splitSignature,
// hexZeroPad,
} from '@harmony/crypto'; } from '@harmony/crypto';
import { add0xToString } from '@harmony/utils'; import { add0xToString } from '@harmony/utils';
import { TxParams } from './types'; import { TxParams } from './types';
import { recover } from './utils';
export const transactionFields = [ export const transactionFields = [
{ name: 'nonce', length: 32, fix: false }, { name: 'nonce', length: 32, fix: false },
@ -22,7 +26,7 @@ export const transactionFields = [
class Transaction { class Transaction {
// private hash?: string; // private hash?: string;
// private from?: string; private from: string;
private nonce: number | string; private nonce: number | string;
private to: string; private to: string;
private gasLimit: BN; private gasLimit: BN;
@ -33,11 +37,10 @@ class Transaction {
private txnHash: string; private txnHash: string;
private unsignedTxnHash: string; private unsignedTxnHash: string;
private signature: Signature; private signature: Signature;
// private r?: string;
// private s?: string;
// private v?: number;
// constructor // constructor
constructor(params?: TxParams) { constructor(params?: TxParams) {
this.from = params ? params.from : '0x';
this.nonce = params ? params.nonce : 0; this.nonce = params ? params.nonce : 0;
this.gasPrice = params ? params.gasPrice : new BN(0); this.gasPrice = params ? params.gasPrice : new BN(0);
this.gasLimit = params ? params.gasLimit : new BN(0); this.gasLimit = params ? params.gasLimit : new BN(0);
@ -115,8 +118,15 @@ class Transaction {
return encode(raw); return encode(raw);
} }
recover(txnHash: string): Transaction {
this.setParams(recover(txnHash));
return this;
}
get txParams(): TxParams { get txParams(): TxParams {
return { return {
from: this.from || '',
nonce: this.nonce || 0, nonce: this.nonce || 0,
gasPrice: this.gasPrice || new BN(0), gasPrice: this.gasPrice || new BN(0),
gasLimit: this.gasLimit || new BN(0), gasLimit: this.gasLimit || new BN(0),
@ -130,6 +140,7 @@ class Transaction {
}; };
} }
setParams(params: TxParams) { setParams(params: TxParams) {
this.from = params ? params.from : '0x';
this.nonce = params ? params.nonce : 0; this.nonce = params ? params.nonce : 0;
this.gasPrice = params ? params.gasPrice : new BN(0); this.gasPrice = params ? params.gasPrice : new BN(0);
this.gasLimit = params ? params.gasLimit : new BN(0); this.gasLimit = params ? params.gasLimit : new BN(0);

@ -1,5 +1,6 @@
import { BN, Signature } from '@harmony/crypto'; import { BN, Signature } from '@harmony/crypto';
export interface TxParams { export interface TxParams {
from: string;
to: string; to: string;
nonce: number | string; nonce: number | string;
gasLimit: BN; gasLimit: BN;

@ -0,0 +1,114 @@
import { hexToNumber, isHex, isAddress, strip0x } from '@harmony/utils';
import {
decode,
encode,
keccak256,
hexlify,
BN,
hexZeroPad,
recoverAddress,
} from '@harmony/crypto';
import { TxParams } from './types';
export const handleNumber = (value: string) => {
if (isHex(value) && value === '0x') {
return hexToNumber('0x00');
} else if (isHex(value) && value !== '0x') {
return hexToNumber(value);
} else {
return value;
}
};
export const handleAddress = (value: string): string => {
if (value === '0x') {
return '0x';
} else if (isAddress(value)) {
return value;
} else {
return '0x';
}
};
export const recover = (rawTransaction: string) => {
const transaction = decode(rawTransaction);
if (transaction.length !== 9 && transaction.length !== 6) {
throw new Error('invalid rawTransaction');
}
const tx: TxParams = {
from: '0x',
txnHash: '0x',
unsignedTxnHash: '0x',
nonce: new BN(strip0x(handleNumber(transaction[0]))).toNumber(),
gasPrice: new BN(strip0x(handleNumber(transaction[1]))),
gasLimit: new BN(strip0x(handleNumber(transaction[2]))),
to: handleAddress(transaction[3]),
value: new BN(strip0x(handleNumber(transaction[4]))),
data: transaction[5],
chainId: 0,
signature: {
r: '',
s: '',
recoveryParam: 0,
v: 0,
},
};
// Legacy unsigned transaction
if (transaction.length === 6) {
tx.unsignedTxnHash = rawTransaction;
return tx;
}
try {
tx.signature.v = new BN(strip0x(handleNumber(transaction[6]))).toNumber();
} catch (error) {
throw error;
}
tx.signature.r = hexZeroPad(transaction[7], 32);
tx.signature.s = hexZeroPad(transaction[8], 32);
if (
new BN(strip0x(handleNumber(tx.signature.r))).isZero() &&
new BN(strip0x(handleNumber(tx.signature.s))).isZero()
) {
// EIP-155 unsigned transaction
tx.chainId = tx.signature.v;
tx.signature.v = 0;
} else {
// Signed Tranasaction
tx.chainId = Math.floor((tx.signature.v - 35) / 2);
if (tx.chainId < 0) {
tx.chainId = 0;
}
let recoveryParam = tx.signature.v - 27;
const raw = transaction.slice(0, 6);
if (tx.chainId !== 0) {
raw.push(hexlify(tx.chainId));
raw.push('0x');
raw.push('0x');
recoveryParam -= tx.chainId * 2 + 8;
}
const digest = keccak256(encode(raw));
try {
tx.from = recoverAddress(digest, {
r: hexlify(tx.signature.r),
s: hexlify(tx.signature.s),
recoveryParam,
});
} catch (error) {
throw error;
}
tx.txnHash = keccak256(rawTransaction);
}
return tx;
};

@ -9,8 +9,30 @@ export const enum Units {
szabo = 'szabo', szabo = 'szabo',
finney = 'finney', finney = 'finney',
ether = 'ether', ether = 'ether',
Kether = 'Kether',
Mether = 'Mether',
Gether = 'Gether',
Tether = 'Tether',
} }
export const unitMap = new Map([
[Units.wei, '1'],
[Units.kwei, '1000'], // 1e3 wei
[Units.Mwei, '1000000'], // 1e6 wei
[Units.Gwei, '1000000000'], // 1e9 wei
[Units.szabo, '1000000000000'], // 1e12 wei
[Units.finney, '1000000000000000'], // 1e15 wei
[Units.ether, '1000000000000000000'], // 1e18 wei
[Units.Kether, '1000000000000000000000'], // 1e21 wei
[Units.Mether, '1000000000000000000000000'], // 1e24 wei
[Units.Gether, '1000000000000000000000000000'], // 1e27 wei
[Units.Tether, '1000000000000000000000000000000'], // 1e30 wei
]);
const DEFAULT_OPTIONS = {
pad: false,
};
export const numberToString = ( export const numberToString = (
obj: BN | number | string, obj: BN | number | string,
radix: number = 10, radix: number = 10,
@ -26,6 +48,25 @@ export const numberToString = (
} }
}; };
export const numToStr = (input: any) => {
if (typeof input === 'string') {
if (!input.match(/^-?[0-9.]+$/)) {
throw new Error(
`while converting number to string, invalid number value '${input}', should be a number matching (^-?[0-9.]+).`,
);
}
return input;
} else if (typeof input === 'number') {
return String(input);
} else if (BN.isBN(input)) {
return input.toString(10);
}
throw new Error(
`while converting number to string, invalid number value '${input}' type ${typeof input}.`,
);
};
export const add0xToString = (obj: string): string => { export const add0xToString = (obj: string): string => {
if (isString(obj) && !obj.startsWith('-')) { if (isString(obj) && !obj.startsWith('-')) {
return '0x' + obj.replace('0x', ''); return '0x' + obj.replace('0x', '');
@ -49,19 +90,297 @@ export const numberToHex = (obj: any): string => {
}; };
export const hexToNumber = (hex: string): string => { export const hexToNumber = (hex: string): string => {
if (isHex(hex)) { if (isHex(hex) && hex[0] !== '-') {
return new BN(strip0x(hex), 'hex').toString(); return new BN(strip0x(hex), 'hex').toString();
} else if (isHex(hex) && hex[0] === '-') {
const result: BN = new BN(hex.substring(3), 16);
return result.mul(new BN(-1)).toString();
} else { } else {
throw new Error(`${hex} is not hex number`); throw new Error(`${hex} is not hex number`);
} }
}; };
export const toWei = (obj: any): string => { export const toWei = (input: BN | string, unit: Units): BN => {
return ''; try {
let inputStr = numToStr(input);
const baseStr = unitMap.get(unit);
if (!baseStr) {
throw new Error(`No unit of type ${unit} exists.`);
}
const baseNumDecimals = baseStr.length - 1;
const base = new BN(baseStr, 10);
// Is it negative?
const isNegative = inputStr.substring(0, 1) === '-';
if (isNegative) {
inputStr = inputStr.substring(1);
}
if (inputStr === '.') {
throw new Error(`Cannot convert ${inputStr} to wei.`);
}
// Split it into a whole and fractional part
const comps = inputStr.split('.'); // eslint-disable-line
if (comps.length > 2) {
throw new Error(`Cannot convert ${inputStr} to wei.`);
}
let [whole, fraction] = comps;
if (!whole) {
whole = '0';
}
if (!fraction) {
fraction = '0';
}
if (fraction.length > baseNumDecimals) {
throw new Error(`Cannot convert ${inputStr} to Qa.`);
}
while (fraction.length < baseNumDecimals) {
fraction += '0';
}
const wholeBN = new BN(whole);
const fractionBN = new BN(fraction);
let wei = wholeBN.mul(base).add(fractionBN);
if (isNegative) {
wei = wei.neg();
}
return new BN(wei.toString(10), 10);
} catch (error) {
throw error;
}
}; };
export const fromWei = (obj: any): string => { export const fromWei = (
return ''; wei: BN | string,
unit: Units,
options: any = DEFAULT_OPTIONS,
): string => {
try {
const weiBN: BN = !BN.isBN(wei) ? new BN(wei) : wei;
if (unit === 'wei') {
return weiBN.toString(10);
}
const baseStr = unitMap.get(unit);
if (!baseStr) {
throw new Error(`No unit of type ${unit} exists.`);
}
const base = new BN(baseStr, 10);
const baseNumDecimals = baseStr.length - 1;
let fraction = weiBN
.abs()
.mod(base)
.toString(10);
// prepend 0s to the fraction half
while (fraction.length < baseNumDecimals) {
fraction = `0${fraction}`;
}
if (!options.pad) {
/* eslint-disable prefer-destructuring */
const matchFraction = fraction.match(/^([0-9]*[1-9]|0)(0*)/);
fraction = matchFraction ? matchFraction[1] : '0';
}
const whole = weiBN.div(base).toString(10);
return fraction === '0' ? `${whole}` : `${whole}.${fraction}`;
} catch (error) {
throw error;
}
}; };
export class Unit {} export class Unit {
static from(str: BN | string) {
return new Unit(str);
}
static Wei(str: BN | string) {
return new Unit(str).asWei();
}
static Kwei(str: BN | string) {
return new Unit(str).asKwei();
}
static Mwei(str: BN | string) {
return new Unit(str).asMwei();
}
static Gwei(str: BN | string) {
return new Unit(str).asGwei();
}
static Szabo(str: BN | string) {
return new Unit(str).asSzabo();
}
static Finney(str: BN | string) {
return new Unit(str).asFinney();
}
static Ether(str: BN | string) {
return new Unit(str).asEther();
}
static Kether(str: BN | string) {
return new Unit(str).asKether();
}
static Mether(str: BN | string) {
return new Unit(str).asMether();
}
static Gether(str: BN | string) {
return new Unit(str).asGether();
}
static Tether(str: BN | string) {
return new Unit(str).asTether();
}
wei?: BN;
unit: BN | string;
constructor(str: BN | string) {
this.unit = str;
}
asWei() {
this.wei = new BN(this.unit);
return this;
}
asKwei() {
this.wei = toWei(this.unit, Units.kwei);
return this;
}
asMwei() {
this.wei = toWei(this.unit, Units.Mwei);
return this;
}
asGwei() {
this.wei = toWei(this.unit, Units.Gwei);
return this;
}
asSzabo() {
this.wei = toWei(this.unit, Units.szabo);
return this;
}
asFinney() {
this.wei = toWei(this.unit, Units.finney);
return this;
}
asEther() {
this.wei = toWei(this.unit, Units.ether);
return this;
}
asKether() {
this.wei = toWei(this.unit, Units.Kether);
return this;
}
asMether() {
this.wei = toWei(this.unit, Units.Mether);
return this;
}
asGether() {
this.wei = toWei(this.unit, Units.Gether);
return this;
}
asTether() {
this.wei = toWei(this.unit, Units.Gether);
return this;
}
toWei() {
return this.wei;
}
toKwei() {
if (this.wei) {
return fromWei(this.wei, Units.kwei);
} else {
throw new Error('error transforming');
}
}
toGwei() {
if (this.wei) {
return fromWei(this.wei, Units.Gwei);
} else {
throw new Error('error transforming');
}
}
toMwei() {
if (this.wei) {
return fromWei(this.wei, Units.Mwei);
} else {
throw new Error('error transforming');
}
}
toSzabo() {
if (this.wei) {
return fromWei(this.wei, Units.szabo);
} else {
throw new Error('error transforming');
}
}
tofinney() {
if (this.wei) {
return fromWei(this.wei, Units.finney);
} else {
throw new Error('error transforming');
}
}
toEther() {
if (this.wei) {
return fromWei(this.wei, Units.ether);
} else {
throw new Error('error transforming');
}
}
toKether() {
if (this.wei) {
return fromWei(this.wei, Units.Kether);
} else {
throw new Error('error transforming');
}
}
toMether() {
if (this.wei) {
return fromWei(this.wei, Units.Mether);
} else {
throw new Error('error transforming');
}
}
toGether() {
if (this.wei) {
return fromWei(this.wei, Units.Gether);
} else {
throw new Error('error transforming');
}
}
toTether() {
if (this.wei) {
return fromWei(this.wei, Units.Tether);
} else {
throw new Error('error transforming');
}
}
toWeiString() {
if (this.wei) {
return this.wei.toString();
} else {
throw new Error('error transforming');
}
}
toHex() {
if (this.wei) {
return numberToHex(this.wei);
} else {
throw new Error('error transforming');
}
}
}

@ -31,6 +31,11 @@ declare namespace Elliptic {
} }
interface EC { interface EC {
recoverPubKey(
arg0: Uint8Array | null,
rs: { r: Uint8Array | null; s: Uint8Array | null },
recoveryParam: number | undefined,
): any;
curve: Curve; curve: Curve;
genKeyPair(opt?: GenKeyPairOpt): KeyPair; genKeyPair(opt?: GenKeyPairOpt): KeyPair;
keyFromPrivate(priv: string, enc: string): KeyPair; keyFromPrivate(priv: string, enc: string): KeyPair;

Loading…
Cancel
Save