mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
idmgmt - refactor
This commit is contained in:
parent
31c9bf3c26
commit
f8c5b90320
@ -1,27 +1,18 @@
|
||||
const Dnode = require('dnode')
|
||||
const eos = require('end-of-stream')
|
||||
const extend = require('xtend')
|
||||
const EthStore = require('eth-store')
|
||||
const PortStream = require('./lib/port-stream.js')
|
||||
const MetaMaskProvider = require('./lib/metamask-provider')
|
||||
const IdentityManager = require('./lib/idmgmt')
|
||||
const eos = require('end-of-stream')
|
||||
// const IdentityManager = require('./lib/idmgmt')
|
||||
const IdentityStore = require('./lib/idStore')
|
||||
|
||||
console.log('ready to roll')
|
||||
|
||||
var wallet = new IdentityManager()
|
||||
//
|
||||
// connect to other contexts
|
||||
//
|
||||
|
||||
// setup provider
|
||||
var zeroClient = MetaMaskProvider({
|
||||
rpcUrl: 'https://rawtestrpc.metamask.io/',
|
||||
getAccounts: wallet.getAccounts.bind(wallet),
|
||||
signTransaction: wallet.addUnconfirmedTransaction.bind(wallet),
|
||||
})
|
||||
|
||||
wallet.setProvider(zeroClient)
|
||||
zeroClient.on('block', function(block){
|
||||
wallet.newBlock(block)
|
||||
})
|
||||
|
||||
|
||||
// setup messaging
|
||||
chrome.runtime.onConnect.addListener(connectRemote)
|
||||
function connectRemote(remotePort){
|
||||
var isMetaMaskInternalProcess = (remotePort.name === 'popup')
|
||||
@ -34,42 +25,33 @@ function connectRemote(remotePort){
|
||||
}
|
||||
}
|
||||
|
||||
function handleInternalCommunication(remotePort){
|
||||
var duplex = new PortStream(remotePort)
|
||||
var connection = Dnode({
|
||||
// this is annoying, have to decompose wallet
|
||||
getState: wallet.getState.bind(wallet),
|
||||
submitPassword: wallet.submitPassword.bind(wallet),
|
||||
setSelectedAddress: wallet.setSelectedAddress.bind(wallet),
|
||||
signTransaction: wallet.signTransaction.bind(wallet),
|
||||
setLocked: wallet.setLocked.bind(wallet),
|
||||
getAccounts: wallet.getAccounts.bind(wallet),
|
||||
newBlock: wallet.newBlock.bind(wallet),
|
||||
setProvider: wallet.setProvider.bind(wallet),
|
||||
})
|
||||
duplex.pipe(connection).pipe(duplex)
|
||||
connection.on('remote', function(remote){
|
||||
|
||||
// push updates to popup
|
||||
wallet.on('update', sendUpdate)
|
||||
eos(duplex, function unsubscribe(){
|
||||
wallet.removeListener('update', sendUpdate)
|
||||
})
|
||||
function sendUpdate(state){
|
||||
remote.sendUpdate(state)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
// sub to metamask store
|
||||
}
|
||||
|
||||
function handleExternalCommunication(remotePort){
|
||||
remotePort.onMessage.addListener(onRpcRequest.bind(null, remotePort))
|
||||
}
|
||||
|
||||
//
|
||||
// state and network
|
||||
//
|
||||
|
||||
var idStore = new IdentityStore()
|
||||
var zeroClient = MetaMaskProvider({
|
||||
rpcUrl: 'https://rawtestrpc.metamask.io/',
|
||||
getAccounts: function(cb){
|
||||
var selectedAddress = idStore.getSelectedAddress()
|
||||
var result = selectedAddress ? [selectedAddress] : []
|
||||
cb(null, result)
|
||||
},
|
||||
signTransaction: idStore.addUnconfirmedTransaction.bind(idStore),
|
||||
})
|
||||
var ethStore = new EthStore(zeroClient)
|
||||
idStore.setStore(ethStore)
|
||||
|
||||
function getState(){
|
||||
var state = extend(ethStore.getState(), idStore.getState())
|
||||
console.log(state)
|
||||
return state
|
||||
}
|
||||
|
||||
// handle rpc requests
|
||||
function onRpcRequest(remotePort, payload){
|
||||
// console.log('MetaMaskPlugin - incoming payload:', payload)
|
||||
@ -84,8 +66,44 @@ function onRpcRequest(remotePort, payload){
|
||||
})
|
||||
}
|
||||
|
||||
// setup badge text
|
||||
wallet.on('update', updateBadge)
|
||||
|
||||
//
|
||||
// popup integration
|
||||
//
|
||||
|
||||
function handleInternalCommunication(remotePort){
|
||||
var duplex = new PortStream(remotePort)
|
||||
var connection = Dnode({
|
||||
getState: function(cb){ cb(null, getState()) },
|
||||
// forward directly to idStore
|
||||
submitPassword: idStore.submitPassword.bind(idStore),
|
||||
setSelectedAddress: idStore.setSelectedAddress.bind(idStore),
|
||||
signTransaction: idStore.signTransaction.bind(idStore),
|
||||
setLocked: idStore.setLocked.bind(idStore),
|
||||
})
|
||||
duplex.pipe(connection).pipe(duplex)
|
||||
connection.on('remote', function(remote){
|
||||
|
||||
// push updates to popup
|
||||
ethStore.on('update', sendUpdate)
|
||||
idStore.on('update', sendUpdate)
|
||||
// teardown on disconnect
|
||||
eos(duplex, function unsubscribe(){
|
||||
ethStore.removeListener('update', sendUpdate)
|
||||
})
|
||||
function sendUpdate(){
|
||||
var state = getState()
|
||||
remote.sendUpdate(state)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
// plugin badge text
|
||||
//
|
||||
|
||||
idStore.on('update', updateBadge)
|
||||
|
||||
function updateBadge(state){
|
||||
var label = ''
|
||||
@ -97,17 +115,3 @@ function updateBadge(state){
|
||||
chrome.browserAction.setBadgeBackgroundColor({color: '#506F8B'})
|
||||
}
|
||||
|
||||
// function handleMessage(msg){
|
||||
// console.log('got message!', msg.type)
|
||||
// switch(msg.type){
|
||||
|
||||
// case 'addUnsignedTx':
|
||||
// addTransaction(msg.payload)
|
||||
// return
|
||||
|
||||
// case 'removeUnsignedTx':
|
||||
// removeTransaction(msg.payload)
|
||||
// return
|
||||
|
||||
// }
|
||||
// }
|
||||
|
263
app/scripts/lib/idStore.js
Normal file
263
app/scripts/lib/idStore.js
Normal file
@ -0,0 +1,263 @@
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const inherits = require('util').inherits
|
||||
const Transaction = require('ethereumjs-tx')
|
||||
const KeyStore = require('eth-lightwallet').keystore
|
||||
const async = require('async')
|
||||
const clone = require('clone')
|
||||
const extend = require('xtend')
|
||||
const createId = require('web3-provider-engine/util/random-id')
|
||||
|
||||
|
||||
module.exports = IdentityStore
|
||||
|
||||
|
||||
inherits(IdentityStore, EventEmitter)
|
||||
function IdentityStore(ethStore) {
|
||||
const self = this
|
||||
EventEmitter.call(self)
|
||||
|
||||
// we just use the ethStore to auto-add accounts
|
||||
self._ethStore = ethStore
|
||||
|
||||
self._currentState = {
|
||||
selectedAddress: null,
|
||||
identities: {},
|
||||
unconfTxs: {},
|
||||
}
|
||||
// not part of serilized metamask state - only kept in memory
|
||||
self._unconfTxCbs = {}
|
||||
}
|
||||
|
||||
//
|
||||
// public
|
||||
//
|
||||
|
||||
IdentityStore.prototype.setStore = function(store){
|
||||
const self = this
|
||||
self._ethStore = store
|
||||
}
|
||||
|
||||
IdentityStore.prototype.getState = function(){
|
||||
const self = this
|
||||
return clone(extend(self._currentState, {
|
||||
isUnlocked: self._isUnlocked(),
|
||||
}))
|
||||
}
|
||||
|
||||
IdentityStore.prototype.getSelectedAddress = function(){
|
||||
const self = this
|
||||
return self._currentState.selectedAddress
|
||||
}
|
||||
|
||||
IdentityStore.prototype.setSelectedAddress = function(address){
|
||||
const self = this
|
||||
self._currentState.selectedAddress = address
|
||||
self._didUpdate()
|
||||
}
|
||||
|
||||
IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){
|
||||
var self = this
|
||||
|
||||
var time = (new Date()).getTime()
|
||||
var txId = createId()
|
||||
self._currentState.unconfTxs[txId] = {
|
||||
id: txId,
|
||||
txParams: txParams,
|
||||
time: time,
|
||||
status: 'unconfirmed',
|
||||
}
|
||||
console.log('addUnconfirmedTransaction:', txParams)
|
||||
|
||||
// temp - just sign the tx
|
||||
// otherwise we need to keep the cb around
|
||||
// signTransaction(txId, cb)
|
||||
self._unconfTxCbs[txId] = cb
|
||||
|
||||
// signal update
|
||||
self._didUpdate()
|
||||
}
|
||||
|
||||
|
||||
|
||||
IdentityStore.prototype.setLocked = function(){
|
||||
const self = this
|
||||
delete self._keyStore
|
||||
delete window.sessionStorage['password']
|
||||
}
|
||||
|
||||
IdentityStore.prototype.submitPassword = function(password, cb){
|
||||
const self = this
|
||||
console.log('submitPassword:', password)
|
||||
self._tryPassword(password, function(err){
|
||||
if (err) console.log('bad password:', password, err)
|
||||
if (err) return cb(err)
|
||||
console.log('good password:', password)
|
||||
window.sessionStorage['password'] = password
|
||||
// load identities before returning...
|
||||
self._loadIdentities()
|
||||
cb()
|
||||
})
|
||||
}
|
||||
|
||||
IdentityStore.prototype.signTransaction = function(password, txId, cb){
|
||||
const self = this
|
||||
|
||||
var txData = self._currentState.unconfTxs[txId]
|
||||
var txParams = txData.txParams
|
||||
|
||||
self._signTransaction(txParams, function(err, rawTx, txHash){
|
||||
if (err) {
|
||||
throw err
|
||||
txData.status = 'error'
|
||||
txData.error = err
|
||||
self._didUpdate()
|
||||
return
|
||||
}
|
||||
|
||||
txData.hash = txHash
|
||||
txData.status = 'pending'
|
||||
|
||||
// for now just remove it
|
||||
delete self._currentState.unconfTxs[txData.id]
|
||||
|
||||
// rpc callback
|
||||
var txSigCb = self._unconfTxCbs[txId] || noop
|
||||
txSigCb(null, rawTx)
|
||||
|
||||
// confirm tx callback
|
||||
cb()
|
||||
|
||||
self._didUpdate()
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
// private
|
||||
//
|
||||
|
||||
// internal - actually signs the tx
|
||||
IdentityStore.prototype._signTransaction = function(txParams, cb){
|
||||
const self = this
|
||||
try {
|
||||
// console.log('signing tx:', txParams)
|
||||
var tx = new Transaction({
|
||||
nonce: txParams.nonce,
|
||||
to: txParams.to,
|
||||
value: txParams.value,
|
||||
data: txParams.input,
|
||||
gasPrice: txParams.gasPrice,
|
||||
gasLimit: txParams.gas,
|
||||
})
|
||||
|
||||
var password = self._getPassword()
|
||||
var serializedTx = self._keyStore.signTx(tx.serialize(), password, self._currentState.selectedAddress)
|
||||
|
||||
// // deserialize and dump values to confirm configuration
|
||||
// var verifyTx = new Transaction(tx.serialize())
|
||||
// console.log('signed transaction:', {
|
||||
// to: '0x'+verifyTx.to.toString('hex'),
|
||||
// from: '0x'+verifyTx.from.toString('hex'),
|
||||
// nonce: '0x'+verifyTx.nonce.toString('hex'),
|
||||
// value: (ethUtil.bufferToInt(verifyTx.value)/1e18)+' ether',
|
||||
// data: '0x'+verifyTx.data.toString('hex'),
|
||||
// gasPrice: '0x'+verifyTx.gasPrice.toString('hex'),
|
||||
// gasLimit: '0x'+verifyTx.gasLimit.toString('hex'),
|
||||
// })
|
||||
cb(null, serializedTx, tx.hash())
|
||||
} catch (err) {
|
||||
cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
IdentityStore.prototype._didUpdate = function(){
|
||||
const self = this
|
||||
self.emit('update', self.getState())
|
||||
}
|
||||
|
||||
IdentityStore.prototype._isUnlocked = function(){
|
||||
const self = this
|
||||
// var password = window.sessionStorage['password']
|
||||
// var result = Boolean(password)
|
||||
var result = Boolean(self._keyStore)
|
||||
return result
|
||||
}
|
||||
|
||||
// load identities from keyStore
|
||||
IdentityStore.prototype._loadIdentities = function(){
|
||||
const self = this
|
||||
if (!self._isUnlocked()) throw new Error('not unlocked')
|
||||
// get addresses and normalize address hexString
|
||||
var addresses = self._keyStore.getAddresses().map(function(address){ return '0x'+address })
|
||||
addresses.forEach(function(address){
|
||||
// add to ethStore
|
||||
self._ethStore.addAccount(address)
|
||||
// add to identities
|
||||
var identity = {
|
||||
name: 'Wally',
|
||||
img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
|
||||
address: address,
|
||||
}
|
||||
self._currentState.identities[address] = identity
|
||||
})
|
||||
self._didUpdate()
|
||||
}
|
||||
|
||||
//
|
||||
// keyStore managment - unlocking + deserialization
|
||||
//
|
||||
|
||||
IdentityStore.prototype._tryPassword = function(password, cb){
|
||||
const self = this
|
||||
var keyStore = self._getKeyStore(password)
|
||||
var address = keyStore.getAddresses()[0]
|
||||
if (!address) return cb(new Error('KeyStore - No address to check.'))
|
||||
var hdPathString = keyStore.defaultHdPathString
|
||||
try {
|
||||
var encKey = keyStore.generateEncKey(password)
|
||||
var encPrivKey = keyStore.ksData[hdPathString].encPrivKeys[address]
|
||||
var privKey = KeyStore._decryptKey(encPrivKey, encKey)
|
||||
var addrFromPrivKey = KeyStore._computeAddressFromPrivKey(privKey)
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
if (addrFromPrivKey !== address) return cb(new Error('KeyStore - Decrypting private key failed!'))
|
||||
cb()
|
||||
}
|
||||
|
||||
IdentityStore.prototype._getKeyStore = function(password){
|
||||
const self = this
|
||||
var keyStore = null
|
||||
var serializedKeystore = window.localStorage['lightwallet']
|
||||
// returning user
|
||||
if (serializedKeystore) {
|
||||
keyStore = KeyStore.deserialize(serializedKeystore)
|
||||
// first time here
|
||||
} else {
|
||||
console.log('creating new keystore with password:', password)
|
||||
var secretSeed = KeyStore.generateRandomSeed()
|
||||
keyStore = new KeyStore(secretSeed, password)
|
||||
keyStore.generateNewAddress(password, 3)
|
||||
self._saveKeystore(keyStore)
|
||||
}
|
||||
keyStore.passwordProvider = function getPassword(cb){
|
||||
cb(null, self._getPassword())
|
||||
}
|
||||
self._keyStore = keyStore
|
||||
return keyStore
|
||||
}
|
||||
|
||||
IdentityStore.prototype._saveKeystore = function(keyStore){
|
||||
const self = this
|
||||
window.localStorage['lightwallet'] = keyStore.serialize()
|
||||
}
|
||||
|
||||
IdentityStore.prototype._getPassword = function(){
|
||||
const self = this
|
||||
var password = window.sessionStorage['password']
|
||||
console.warn('using password from memory:', password)
|
||||
return password
|
||||
}
|
||||
|
||||
// util
|
||||
|
||||
function noop(){}
|
@ -1,318 +0,0 @@
|
||||
const inherits = require('util').inherits
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const async = require('async')
|
||||
const KeyStore = require('eth-lightwallet').keystore
|
||||
const createPayload = require('web3-provider-engine/util/create-payload')
|
||||
const createId = require('web3-provider-engine/util/random-id')
|
||||
const Transaction = require('ethereumjs-tx')
|
||||
|
||||
module.exports = IdentityManager
|
||||
|
||||
|
||||
var selectedAddress = null
|
||||
var identities = {}
|
||||
var unconfTxs = {}
|
||||
|
||||
// not part of serilized metamask state - only keep in memory
|
||||
var unconfTxCbs = {}
|
||||
|
||||
var provider = null
|
||||
var defaultPassword = 'test'
|
||||
|
||||
|
||||
|
||||
inherits(IdentityManager, EventEmitter)
|
||||
function IdentityManager(opts){
|
||||
const self = this
|
||||
self.on('block', function(){
|
||||
self.updateIdentities()
|
||||
})
|
||||
}
|
||||
|
||||
// plugin popup
|
||||
IdentityManager.prototype.getState = getState
|
||||
IdentityManager.prototype.submitPassword = submitPassword
|
||||
IdentityManager.prototype.setSelectedAddress = setSelectedAddress
|
||||
IdentityManager.prototype.signTransaction = signTransaction
|
||||
IdentityManager.prototype.setLocked = setLocked
|
||||
// eth rpc
|
||||
IdentityManager.prototype.getAccounts = getAccounts
|
||||
IdentityManager.prototype.addUnconfirmedTransaction = addUnconfirmedTransaction
|
||||
// etc
|
||||
IdentityManager.prototype.newBlock = newBlock
|
||||
IdentityManager.prototype.setProvider = setProvider
|
||||
|
||||
|
||||
|
||||
function setProvider(_provider){
|
||||
provider = _provider
|
||||
}
|
||||
|
||||
function newBlock(block){
|
||||
var self = this
|
||||
self.emit('block', block)
|
||||
}
|
||||
|
||||
function getState(cb){
|
||||
var result = _getState()
|
||||
cb(null, result)
|
||||
}
|
||||
|
||||
function _getState(cb){
|
||||
var unlocked = isUnlocked()
|
||||
var result = {
|
||||
isUnlocked: unlocked,
|
||||
identities: unlocked ? getIdentities() : {},
|
||||
unconfTxs: unlocked ? unconfTxs : {},
|
||||
selectedAddress: selectedAddress,
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function isUnlocked(){
|
||||
var password = window.sessionStorage['password']
|
||||
var result = Boolean(password)
|
||||
return result
|
||||
}
|
||||
|
||||
function setLocked(){
|
||||
delete window.sessionStorage['password']
|
||||
}
|
||||
|
||||
function setSelectedAddress(address, cb){
|
||||
selectedAddress = address
|
||||
cb(null, _getState())
|
||||
}
|
||||
|
||||
function submitPassword(password, cb){
|
||||
const self = this
|
||||
console.log('submitPassword:', password)
|
||||
tryPassword(password, function(err){
|
||||
if (err) console.log('bad password:', password, err)
|
||||
if (err) return cb(err)
|
||||
console.log('good password:', password)
|
||||
window.sessionStorage['password'] = password
|
||||
// load identities before returning...
|
||||
self.loadIdentities()
|
||||
var state = _getState()
|
||||
cb(null, state)
|
||||
// trigger an update but dont wait for it
|
||||
self.updateIdentities()
|
||||
})
|
||||
}
|
||||
|
||||
// get the current selected address
|
||||
function getAccounts(cb){
|
||||
var result = selectedAddress ? [selectedAddress] : []
|
||||
cb(null, result)
|
||||
}
|
||||
|
||||
function getIdentities(){
|
||||
return identities
|
||||
}
|
||||
|
||||
// load identities from keyStore
|
||||
IdentityManager.prototype.loadIdentities = function(){
|
||||
const self = this
|
||||
if (!isUnlocked()) throw new Error('not unlocked')
|
||||
var keyStore = getKeyStore()
|
||||
var addresses = keyStore.getAddresses().map(function(address){ return '0x'+address })
|
||||
addresses.forEach(function(address){
|
||||
var identity = {
|
||||
name: 'Wally',
|
||||
img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
|
||||
address: address,
|
||||
balance: null,
|
||||
txCount: null,
|
||||
}
|
||||
identities[address] = identity
|
||||
})
|
||||
self._didUpdate()
|
||||
}
|
||||
|
||||
IdentityManager.prototype._didUpdate = function(){
|
||||
const self = this
|
||||
self.emit('update', _getState())
|
||||
}
|
||||
|
||||
// foreach in identities, update balance + nonce
|
||||
IdentityManager.prototype.updateIdentities = function(cb){
|
||||
var self = this
|
||||
cb = cb || function(){}
|
||||
if (!isUnlocked()) return cb(new Error('Not unlocked.'))
|
||||
var addresses = Object.keys(identities)
|
||||
async.map(addresses, self.updateIdentity.bind(self), cb)
|
||||
}
|
||||
|
||||
// gets latest info from the network for the identity
|
||||
IdentityManager.prototype.updateIdentity = function(address, cb){
|
||||
var self = this
|
||||
async.parallel([
|
||||
getAccountBalance.bind(null, address),
|
||||
getTxCount.bind(null, address),
|
||||
], function(err, result){
|
||||
if (err) return cb(err)
|
||||
var identity = identities[address]
|
||||
identity.balance = result[0]
|
||||
identity.txCount = result[1]
|
||||
self._didUpdate()
|
||||
cb()
|
||||
})
|
||||
}
|
||||
|
||||
function getTxCount(address, cb){
|
||||
provider.sendAsync(createPayload({
|
||||
method: 'eth_getTransactionCount',
|
||||
params: [address, 'pending'],
|
||||
}), function(err, res){
|
||||
if (err) return cb(err)
|
||||
if (res.error) return cb(res.error)
|
||||
cb(null, res.result)
|
||||
})
|
||||
}
|
||||
|
||||
function getAccountBalance(address, cb){
|
||||
provider.sendAsync(createPayload({
|
||||
method: 'eth_getBalance',
|
||||
params: [address, 'latest'],
|
||||
}), function(err, res){
|
||||
if (err) return cb(err)
|
||||
if (res.error) return cb(res.error)
|
||||
cb(null, res.result)
|
||||
})
|
||||
}
|
||||
|
||||
function tryPassword(password, cb){
|
||||
var keyStore = getKeyStore(password)
|
||||
var address = keyStore.getAddresses()[0]
|
||||
if (!address) return cb(new Error('KeyStore - No address to check.'))
|
||||
var hdPathString = keyStore.defaultHdPathString
|
||||
try {
|
||||
var encKey = keyStore.generateEncKey(password)
|
||||
var encPrivKey = keyStore.ksData[hdPathString].encPrivKeys[address]
|
||||
var privKey = KeyStore._decryptKey(encPrivKey, encKey)
|
||||
var addrFromPrivKey = KeyStore._computeAddressFromPrivKey(privKey)
|
||||
} catch (err) {
|
||||
return cb(err)
|
||||
}
|
||||
if (addrFromPrivKey !== address) return cb(new Error('KeyStore - Decrypting private key failed!'))
|
||||
cb()
|
||||
}
|
||||
|
||||
function addUnconfirmedTransaction(txParams, cb){
|
||||
var self = this
|
||||
|
||||
var time = (new Date()).getTime()
|
||||
var txId = createId()
|
||||
unconfTxs[txId] = {
|
||||
id: txId,
|
||||
txParams: txParams,
|
||||
time: time,
|
||||
status: 'unconfirmed',
|
||||
}
|
||||
console.log('addUnconfirmedTransaction:', txParams)
|
||||
|
||||
// temp - just sign the tx
|
||||
// otherwise we need to keep the cb around
|
||||
// signTransaction(txId, cb)
|
||||
unconfTxCbs[txId] = cb
|
||||
|
||||
// signal update
|
||||
self._didUpdate()
|
||||
}
|
||||
|
||||
// called from
|
||||
function signTransaction(password, txId, cb){
|
||||
const self = this
|
||||
|
||||
var txData = unconfTxs[txId]
|
||||
var txParams = txData.txParams
|
||||
console.log('signTransaction:', txData)
|
||||
|
||||
self._signTransaction(txParams, function(err, rawTx, txHash){
|
||||
if (err) {
|
||||
txData.status = 'error'
|
||||
txData.error = err
|
||||
self._didUpdate()
|
||||
return
|
||||
}
|
||||
txData.hash = txHash
|
||||
txData.status = 'pending'
|
||||
// for now just kill it
|
||||
delete unconfTxs[txData.id]
|
||||
|
||||
var txSigCb = unconfTxCbs[txId] || function(){}
|
||||
txSigCb(null, rawTx)
|
||||
|
||||
cb(null, _getState())
|
||||
self._didUpdate()
|
||||
})
|
||||
}
|
||||
|
||||
// internal - actually signs the tx
|
||||
IdentityManager.prototype._signTransaction = function(txParams, cb){
|
||||
try {
|
||||
// console.log('signing tx:', txParams)
|
||||
var tx = new Transaction({
|
||||
nonce: txParams.nonce,
|
||||
to: txParams.to,
|
||||
value: txParams.value,
|
||||
data: txParams.input,
|
||||
gasPrice: txParams.gasPrice,
|
||||
gasLimit: txParams.gas,
|
||||
})
|
||||
|
||||
var keyStore = getKeyStore()
|
||||
var serializedTx = keyStore.signTx(tx.serialize(), defaultPassword, selectedAddress)
|
||||
|
||||
// // deserialize and dump values to confirm configuration
|
||||
// var verifyTx = new Transaction(tx.serialize())
|
||||
// console.log('signed transaction:', {
|
||||
// to: '0x'+verifyTx.to.toString('hex'),
|
||||
// from: '0x'+verifyTx.from.toString('hex'),
|
||||
// nonce: '0x'+verifyTx.nonce.toString('hex'),
|
||||
// value: (ethUtil.bufferToInt(verifyTx.value)/1e18)+' ether',
|
||||
// data: '0x'+verifyTx.data.toString('hex'),
|
||||
// gasPrice: '0x'+verifyTx.gasPrice.toString('hex'),
|
||||
// gasLimit: '0x'+verifyTx.gasLimit.toString('hex'),
|
||||
// })
|
||||
cb(null, serializedTx, tx.hash())
|
||||
} catch (err) {
|
||||
cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
var keyStore = null
|
||||
function getKeyStore(password){
|
||||
if (keyStore) return keyStore
|
||||
password = password || getPassword()
|
||||
var serializedKeystore = window.localStorage['lightwallet']
|
||||
// returning user
|
||||
if (serializedKeystore) {
|
||||
keyStore = KeyStore.deserialize(serializedKeystore)
|
||||
// first time here
|
||||
} else {
|
||||
console.log('creating new keystore with default password:', defaultPassword)
|
||||
var secretSeed = KeyStore.generateRandomSeed()
|
||||
keyStore = new KeyStore(secretSeed, defaultPassword)
|
||||
keyStore.generateNewAddress(defaultPassword, 3)
|
||||
saveKeystore()
|
||||
}
|
||||
keyStore.passwordProvider = unlockKeystore
|
||||
return keyStore
|
||||
}
|
||||
|
||||
function saveKeystore(){
|
||||
window.localStorage['lightwallet'] = keyStore.serialize()
|
||||
}
|
||||
|
||||
function getPassword(){
|
||||
var password = window.sessionStorage['password']
|
||||
if (!password) throw new Error('No password found...')
|
||||
}
|
||||
|
||||
function unlockKeystore(cb){
|
||||
var password = getPassword()
|
||||
console.warn('unlocking keystore...')
|
||||
cb(null, password)
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "^1.5.2",
|
||||
"clone": "^1.0.2",
|
||||
"dnode": "^1.2.2",
|
||||
"end-of-stream": "^1.1.0",
|
||||
"eth-lightwallet": "^1.0.1",
|
||||
|
Loading…
Reference in New Issue
Block a user