[WIP] added Transaction package

@types
neeboo 6 years ago
parent 983d1bffab
commit 1783c54b08
  1. 16
      examples/testNode.js
  2. 1
      gulpfile.js
  3. 18
      packages/harmony-account/src/account.ts
  4. 2
      packages/harmony-account/tsconfig.json
  5. 2
      packages/harmony-crypto/src/bytes.ts
  6. 1
      packages/harmony-crypto/src/index.ts
  7. 23
      packages/harmony-crypto/src/keyTool.ts
  8. 159
      packages/harmony-crypto/src/rlp.ts
  9. 20
      packages/harmony-transaction/package.json
  10. 3
      packages/harmony-transaction/src/factory.ts
  11. 2
      packages/harmony-transaction/src/index.ts
  12. 2
      packages/harmony-transaction/src/transaction.ts
  13. 12
      packages/harmony-transaction/tsconfig.json
  14. 1
      scripts/packages.js
  15. 1
      scripts/packagesList.js
  16. 1
      scripts/packagesTs.ts
  17. 1
      typings/elliptic.d.ts

@ -2,9 +2,9 @@ const { Account, Wallet } = require('@harmony/account');
const { isAddress, isPrivateKey, numberToHex } = require('@harmony/utils');
const { HttpProvider, Messenger } = require('@harmony/network');
async function testEncrypt() {
const wallet = new Wallet();
const wallet = new Wallet();
async function testEncrypt() {
const mne = wallet.generateMnemonic();
console.log('---hint: please write these down');
@ -28,3 +28,15 @@ async function testEncrypt() {
}
testEncrypt();
async function testSign(prvKey, data) {
const newAcc = wallet.addByPrivateKey(prvKey);
const result = await newAcc.sign(data);
console.log(result);
}
testSign(
'0x0123456789012345678901234567890123456789012345678901234567890123',
'0x06',
);

@ -6,6 +6,7 @@ const packages = [
'harmony-account',
'harmony-network',
'harmony-utils',
'harmony-transaction',
];
task('cleanBrowser', async () => {

@ -7,6 +7,9 @@ import {
decrypt,
EncryptOptions,
Keystore,
sign,
isSignature,
Signature,
} from '@harmony/crypto';
import { isPrivateKey, add0xToString } from '@harmony/utils';
@ -118,11 +121,20 @@ class Account {
return '';
}
/**
* @function signTransaction
* @function sign
* @return {Promise<void>} sign transaction
*/
async signTransaction(): Promise<void> {
console.log('sign transaction');
async sign(message: string): Promise<Signature> {
if (this.privateKey && isPrivateKey(this.privateKey)) {
const signature: Signature = await sign(message, this.privateKey);
if (isSignature(signature)) {
return signature;
} else {
throw new Error('Cannot sign');
}
} else {
throw new Error('Privatekey not found or not correct');
}
}
/**
* @function _new private method create Account

@ -1,8 +1,6 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": ".",
"paths": { "*": ["types/*"] },
"outDir": "dist",
"rootDir": "src"
},

@ -336,7 +336,7 @@ export function hexZeroPad(value: string, length: number): string {
return value;
}
function isSignature(value: any): value is Signature {
export function isSignature(value: any): value is Signature {
return value && value.r != null && value.s != null;
}

@ -4,6 +4,7 @@ import bip39 from 'bip39';
export * from './random';
export * from './keyTool';
export * from './keystore';
export * from './bytes';
// export types
export * from './types';

@ -4,6 +4,7 @@ import * as errors from './errors';
import { keccak256 } from './keccak256';
import { randomBytes } from './random';
import { isPrivateKey, strip0x } from '@harmony/utils';
const secp256k1 = elliptic.ec('secp256k1');
@ -48,7 +49,10 @@ export const getAddressFromPrivateKey = (privateKey: string): string => {
};
export const getPublic = (privateKey: string, compress?: boolean): string => {
const ecKey = secp256k1.keyFromPrivate(privateKey.slice(2), 'hex');
if (!isPrivateKey(privateKey)) {
throw new Error(`${privateKey} is not PrivateKey`);
}
const ecKey = secp256k1.keyFromPrivate(strip0x(privateKey), 'hex');
return ecKey.getPublic(compress || false, 'hex');
};
@ -98,3 +102,20 @@ export const toChecksumAddress = (address: string): string => {
return '0x' + chars.join('');
};
export const sign = (
digest: bytes.Arrayish | string,
privateKey: string,
): bytes.Signature => {
if (!isPrivateKey(privateKey)) {
throw new Error(`${privateKey} is not PrivateKey`);
}
const keyPair = secp256k1.keyFromPrivate(strip0x(privateKey), 'hex');
const signature = keyPair.sign(bytes.arrayify(digest), { canonical: true });
return {
recoveryParam: signature.recoveryParam,
r: bytes.hexZeroPad('0x' + signature.r.toString(16), 32),
s: bytes.hexZeroPad('0x' + signature.s.toString(16), 32),
v: 27 + signature.recoveryParam,
};
};

@ -0,0 +1,159 @@
// this file is ported from https://github.com/ethers-io/ethers.js/blob/master/src.ts/utils/rlp.ts
// and done some fixes
import { arrayify, hexlify, Arrayish } from './bytes';
function arrayifyInteger(value: number): number[] {
const result = [];
while (value) {
result.unshift(value & 0xff);
value >>= 8;
}
return result;
}
function unarrayifyInteger(
data: Uint8Array,
offset: number,
length: number,
): number {
let result = 0;
for (let i = 0; i < length; i++) {
result = result * 256 + data[offset + i];
}
return result;
}
function _encode(object: any[] | string): number[] {
if (Array.isArray(object)) {
let payload: number[] = [];
object.forEach((child) => {
payload = payload.concat(_encode(child));
});
if (payload.length <= 55) {
payload.unshift(0xc0 + payload.length);
return payload;
}
// tslint:disable-next-line: no-shadowed-variable
const length = arrayifyInteger(payload.length);
length.unshift(0xf7 + length.length);
return length.concat(payload);
}
const data: number[] = Array.prototype.slice.call(arrayify(object));
if (data.length === 1 && data[0] <= 0x7f) {
return data;
} else if (data.length <= 55) {
data.unshift(0x80 + data.length);
return data;
}
const length = arrayifyInteger(data.length);
length.unshift(0xb7 + length.length);
return length.concat(data);
}
export function encode(object: any): string {
return hexlify(_encode(object));
}
interface Decoded {
result: any;
consumed: number;
}
function _decodeChildren(
data: Uint8Array,
offset: number,
childOffset: number,
length: number,
): Decoded {
const result = [];
while (childOffset < offset + 1 + length) {
const decoded = _decode(data, childOffset);
result.push(decoded.result);
childOffset += decoded.consumed;
if (childOffset > offset + 1 + length) {
throw new Error('invalid rlp');
}
}
return { consumed: 1 + length, result };
}
// returns { consumed: number, result: Object }
function _decode(
data: Uint8Array,
offset: number,
): { consumed: number; result: any } {
if (data.length === 0) {
throw new Error('invalid rlp data');
}
// Array with extra length prefix
if (data[offset] >= 0xf8) {
const lengthLength = data[offset] - 0xf7;
if (offset + 1 + lengthLength > data.length) {
throw new Error('too short');
}
const length = unarrayifyInteger(data, offset + 1, lengthLength);
if (offset + 1 + lengthLength + length > data.length) {
throw new Error('to short');
}
return _decodeChildren(
data,
offset,
offset + 1 + lengthLength,
lengthLength + length,
);
} else if (data[offset] >= 0xc0) {
const length = data[offset] - 0xc0;
if (offset + 1 + length > data.length) {
throw new Error('invalid rlp data');
}
return _decodeChildren(data, offset, offset + 1, length);
} else if (data[offset] >= 0xb8) {
const lengthLength = data[offset] - 0xb7;
if (offset + 1 + lengthLength > data.length) {
throw new Error('invalid rlp data');
}
const length = unarrayifyInteger(data, offset + 1, lengthLength);
if (offset + 1 + lengthLength + length > data.length) {
throw new Error('invalid rlp data');
}
const result = hexlify(
data.slice(offset + 1 + lengthLength, offset + 1 + lengthLength + length),
);
return { consumed: 1 + lengthLength + length, result };
} else if (data[offset] >= 0x80) {
const length = data[offset] - 0x80;
if (offset + 1 + length > data.length) {
throw new Error('invlaid rlp data');
}
const result = hexlify(data.slice(offset + 1, offset + 1 + length));
return { consumed: 1 + length, result };
}
return { consumed: 1, result: hexlify(data[offset]) };
}
export function decode(data: Arrayish): any {
const bytes = arrayify(data) || new Uint8Array();
const decoded = _decode(bytes, 0);
if (decoded.consumed !== bytes.length) {
throw new Error('invalid rlp data');
}
return decoded.result;
}

@ -0,0 +1,20 @@
{
"name": "@harmony/transaction",
"version": "0.0.1",
"description": "transaction package for harmony",
"main": "dist/index.js",
"node": "dist/index.js",
"browser": "dist/index.js",
"module": "dist/index.esm.js",
"jsnext:main": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "neeboo@firestack.one",
"license": "ISC",
"dependencies": {
"@harmony/crypto": "^0.0.1",
"@harmony/utils": "^0.0.1"
}
}

@ -0,0 +1,3 @@
class TransactionFactory {}
export { TransactionFactory };

@ -0,0 +1,2 @@
export * from './factory';
export * from './transaction';

@ -0,0 +1,2 @@
class Transaction {}
export { Transaction };

@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src", "../../typings/**/*.d.ts"],
"references": [
{ "path": "../harmony-utils" },
{ "path": "../harmony-crypto" }
]
}

@ -3,4 +3,5 @@ export default [
'harmony-crypto',
'harmony-account',
'harmony-network',
'harmony-transaction',
];

@ -3,4 +3,5 @@ module.exports = [
{ name: 'HarmonyUtils', dest: 'harmony-utils' },
{ name: 'HarmonyCrypto', dest: 'harmony-crypto' },
{ name: 'HarmonyAccount', dest: 'harmony-account' },
{ name: 'HarmonyTransaction', dest: 'harmony-transaction' },
];

@ -3,6 +3,7 @@ const packages = [
'harmony-crypto',
'harmony-account',
'harmony-network',
'harmony-transaction',
];
export { packages };

@ -45,6 +45,7 @@ declare namespace Elliptic {
}
interface KeyPair {
sign(arg0: Uint8Array | null, arg1: { canonical: boolean }): any;
fromPublic(ec: Curve, pub: BN, enc: string): KeyPair;
fromPrivate(ec: Curve, priv: BN, enc: string): KeyPair;
// this is broken, but we can't fix it without changing the upstream

Loading…
Cancel
Save