on e548844 help sign in
bridge/src/lib/wallet.js
123 lines 3.0 kB history raw
1import * as bip32 from 'bip32'
2import * as bip39 from 'bip39'
3import keccak from 'keccak'
4import * as lodash from 'lodash'
5import Maybe from 'folktale/maybe'
6import * as secp256k1 from 'secp256k1'
8const DEFAULT_HD_PATH = "m/44'/60'/0'/0/0"
10const ETH_ZERO_ADDR = '0x0000000000000000000000000000000000000000'
11const CURVE_ZERO_ADDR = "0x0000000000000000000000000000000000000000000000000000000000000000"
13const WALLET_NAMES = {
14 MNEMONIC: Symbol('MNEMONIC'),
15 TICKET: Symbol('TICKET'),
16 SHARDS: Symbol('SHARDS'),
17 LEDGER: Symbol('LEDGER'),
18 TREZOR: Symbol('TREZOR'),
19 PRIVATE_KEY: Symbol('PRIVATE_KEY'),
20 KEYSTORE: Symbol('KEYSTORE')
23function EthereumWallet(privateKey) {
24 this.privateKey = privateKey
25 this.publicKey = secp256k1.publicKeyCreate(this.privateKey)
26 const pub = this.publicKey.toString('hex')
27 this.address = addressFromSecp256k1Public(pub)
30const renderWalletType = (wallet) =>
31 wallet === WALLET_NAMES.MNEMONIC
32 ? 'Mnemonic'
33 : wallet === WALLET_NAMES.TICKET
34 ? 'Ticket'
35 : wallet === WALLET_NAMES.SHARDS
36 ? 'Ticket Shards'
37 : wallet === WALLET_NAMES.LEDGER
38 ? 'Ledger'
39 : wallet === WALLET_NAMES.TREZOR
40 ? 'Trezor'
41 : wallet === WALLET_NAMES.PRIVATE_KEY
42 ? 'Private Key'
43 : wallet === WALLET_NAMES.KEYSTORE
44 ? 'Keystore File'
45 : 'Wallet'
47const addressFromSecp256k1Public = pub => {
48 const compressed = false
49 const uncompressed = secp256k1.publicKeyConvert(
50 Buffer.from(pub, 'hex'),
51 compressed
52 )
53 const chopped = uncompressed.slice(1) // chop parity byte
54 const hashed = keccak256(chopped)
55 const addr = addHexPrefix(hashed.slice(-20).toString('hex'))
56 return toChecksumAddress(addr)
59const addHexPrefix = hex =>
60 hex.slice(0, 2) === '0x'
61 ? hex
62 : '0x' + hex
64const stripHexPrefix = hex =>
65 hex.slice(0, 2) === '0x'
66 ? hex.slice(2)
67 : hex
69const keccak256 = str =>
70 keccak('keccak256').update(str).digest()
72const isValidAddress = (address) =>
73 /^0x[0-9a-fA-F]{40}$/.test(address)
75const toChecksumAddress = (address) => {
76 const addr = stripHexPrefix(address).toLowerCase()
77 const hash = keccak256(addr).toString('hex')
79 return lodash.reduce(addr, (acc, char, idx) =>
80 parseInt(hash[idx], 16) >= 8
81 ? acc + char.toUpperCase()
82 : acc + char,
83 '0x')
86const eqAddr = (addr0, addr1) =>
87 toChecksumAddress(addr0) === toChecksumAddress(addr1)
89const walletFromMnemonic = (mnemonic, hdpath) => {
90 const seed =
91 bip39.validateMnemonic(mnemonic)
92 ? Maybe.Just(bip39.mnemonicToSeed(mnemonic))
93 : Maybe.Nothing()
95 const toWallet = (sd, path) => {
96 let wal
97 try {
98 const hd = bip32.fromSeed(sd)
99 wal = Maybe.Just(hd.derivePath(path))
100 } catch (_) {
101 wal = Maybe.Nothing()
102 }
103 return wal
104 }
106 const wallet = seed.chain(sd => toWallet(sd, hdpath))
107 return wallet
110export {
111 DEFAULT_HD_PATH,
112 WALLET_NAMES,
113 ETH_ZERO_ADDR,
114 CURVE_ZERO_ADDR,
115 renderWalletType,
116 isValidAddress,
117 toChecksumAddress,
118 addressFromSecp256k1Public,
119 eqAddr,
120 walletFromMnemonic,
121 addHexPrefix,
122 EthereumWallet