on cd91628 help sign in
bridge/src/lib/wallet.js
119 lines 3.3 kB history raw
1import * as bip32 from 'bip32';
2import * as bip39 from 'bip39';
3import keccak from 'keccak';
4import { reduce } from 'lodash';
5import Maybe from 'folktale/maybe';
6import * as secp256k1 from 'secp256k1';
7import * as ob from 'urbit-ob';
8import * as kg from 'urbit-key-generation/dist';
9import { isAddress } from 'web3-utils';
11export const DEFAULT_HD_PATH = "m/44'/60'/0'/0/0";
12export const ETH_ZERO_ADDR = '0x0000000000000000000000000000000000000000';
13export const CURVE_ZERO_ADDR =
14 '0x0000000000000000000000000000000000000000000000000000000000000000';
16export const WALLET_TYPES = {
17 MNEMONIC: Symbol('MNEMONIC'),
18 TICKET: Symbol('TICKET'),
19 SHARDS: Symbol('SHARDS'),
20 LEDGER: Symbol('LEDGER'),
21 TREZOR: Symbol('TREZOR'),
22 PRIVATE_KEY: Symbol('PRIVATE_KEY'),
23 KEYSTORE: Symbol('KEYSTORE'),
24};
26export function EthereumWallet(privateKey) {
27 this.privateKey = privateKey;
28 this.publicKey = secp256k1.publicKeyCreate(this.privateKey);
29 const pub = this.publicKey.toString('hex');
30 this.address = addressFromSecp256k1Public(pub);
33export const addressFromSecp256k1Public = pub => {
34 const compressed = false;
35 const uncompressed = secp256k1.publicKeyConvert(
36 Buffer.from(pub, 'hex'),
37 compressed
38 );
39 const chopped = uncompressed.slice(1); // chop parity byte
40 const hashed = keccak256(chopped);
41 const addr = addHexPrefix(hashed.slice(-20).toString('hex'));
42 return toChecksumAddress(addr);
43};
45export const addHexPrefix = hex =>
46 hex.slice(0, 2) === '0x' ? hex : '0x' + hex;
48export const stripHexPrefix = hex =>
49 hex.slice(0, 2) === '0x' ? hex.slice(2) : hex;
51export const keccak256 = str =>
52 keccak('keccak256')
53 .update(str)
54 .digest();
56export const isValidAddress = a => '0x0' === a || isAddress(a);
58export const toChecksumAddress = address => {
59 const addr = stripHexPrefix(address).toLowerCase();
60 const hash = keccak256(addr).toString('hex');
62 return reduce(
63 addr,
64 (acc, char, idx) =>
65 parseInt(hash[idx], 16) >= 8 ? acc + char.toUpperCase() : acc + char,
66 '0x'
67 );
68};
70export const eqAddr = (addr0, addr1) =>
71 toChecksumAddress(addr0) === toChecksumAddress(addr1);
73export const urbitWalletFromTicket = async (ticket, point, passphrase) => {
74 if (typeof point === 'string') {
75 //TODO why not in kg?
76 point = ob.patp2dec(point);
77 }
79 return await kg.generateWallet({
80 ticket: ticket,
81 ship: point,
82 passphrase: passphrase,
83 });
84};
86export const ownershipWalletFromTicket = async (ticket, point, passphrase) => {
87 if (typeof point === 'string') {
88 //TODO why not in kg?
89 point = ob.patp2dec(point);
90 }
92 return await kg.generateOwnershipWallet({
93 ticket,
94 ship: point,
95 passphrase,
96 });
97};
99export const walletFromMnemonic = (mnemonic, hdpath, passphrase) => {
100 const seed = bip39.validateMnemonic(mnemonic)
101 ? Maybe.Just(bip39.mnemonicToSeed(mnemonic, passphrase))
102 : Maybe.Nothing();
104 const toWallet = (sd, path) => {
105 let wal;
106 try {
107 const hd = bip32.fromSeed(sd);
108 wal = hd.derivePath(path);
109 wal.address = addressFromSecp256k1Public(wal.publicKey);
110 wal = Maybe.Just(wal);
111 } catch (_) {
112 wal = Maybe.Nothing();
113 }
114 return wal;
115 };
117 const wallet = seed.chain(sd => toWallet(sd, hdpath));
118 return wallet;
119};