-
Notifications
You must be signed in to change notification settings - Fork 78
/
EthereumJsWalletProvider.js
118 lines (98 loc) · 3.41 KB
/
EthereumJsWalletProvider.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import Provider from '@liquality/provider'
import { Address, addressToString } from '@liquality/utils'
import { ensure0x, remove0x } from '@liquality/ethereum-utils'
import { sha256 } from '@liquality/crypto'
import { mnemonicToSeed } from 'bip39'
import { BigNumber } from 'bignumber.js'
import { fromMasterSeed } from 'hdkey'
import * as ethUtil from 'ethereumjs-util'
import { Transaction } from 'ethereumjs-tx'
import Common from 'ethereumjs-common'
import { version } from '../package.json'
export default class EthereumJsWalletProvider extends Provider {
constructor (network, mnemonic, hardfork = 'istanbul') {
super()
const derivationPath = `m/44'/${network.coinType}'/0'/`
this._derivationPath = derivationPath
this._mnemonic = mnemonic
this._network = network
this._hardfork = hardfork
}
async node () {
const seed = await mnemonicToSeed(this._mnemonic)
return fromMasterSeed(seed)
}
async hdKey (derivationPath) {
const node = await this.node()
return node.derive(derivationPath)
}
async signMessage (message) {
const derivationPath = this._derivationPath + '0/0'
const hdKey = await this.hdKey(derivationPath)
const msgHash = sha256(message)
const hex = Buffer.from(msgHash, 'hex')
const { v, r, s } = ethUtil.ecsign(hex, hdKey._privateKey)
return { v, r: r.toString('hex'), s: s.toString('hex') }
}
async getAddresses () {
const derivationPath = this._derivationPath + '0/0'
const hdKey = await this.hdKey(derivationPath)
const address = ethUtil.privateToAddress(hdKey._privateKey).toString('hex')
const publicKey = ethUtil.privateToPublic(hdKey._privateKey).toString('hex')
return [
new Address({
address,
derivationPath,
publicKey,
index: 0
})
]
}
async getUnusedAddress () {
const addresses = await this.getAddresses()
return addresses[0]
}
async getUsedAddresses () {
return this.getAddresses()
}
async buildTransaction (to, value, data) {
const derivationPath = this._derivationPath + '0/0'
const hdKey = await this.hdKey(derivationPath)
const addresses = await this.getAddresses()
const address = addresses[0]
const from = addressToString(address)
const txData = {
to: to ? ensure0x(to) : null,
from: ensure0x(from),
value: ensure0x(BigNumber(value).toString(16)),
data: data ? ensure0x(data) : undefined
}
const [ nonce, gasPrice, gasLimit ] = await Promise.all([
this.getMethod('getTransactionCount')(remove0x(from)),
this.getMethod('getGasPrice')(),
this.getMethod('estimateGas')(txData)
])
txData.nonce = nonce
txData.gasPrice = gasPrice
txData.gasLimit = gasLimit
let common
if (!(this._network.name === 'local')) {
const baseChain = this._network.name
common = Common.forCustomChain(baseChain, {
name: this._network.name,
chainId: this._network.chainId,
networkId: this._network.networkId
}, this._hardfork)
}
const tx = new Transaction(txData, { common })
tx.sign(hdKey._privateKey)
const serializedTx = tx.serialize().toString('hex')
return serializedTx
}
async sendTransaction (to, value, data) {
const serializedTx = await this.buildTransaction(to, value, data)
const txHash = await this.getMethod('sendRawTransaction')(serializedTx)
return txHash
}
}
EthereumJsWalletProvider.version = version