|
|
|
@ -1,9 +1,13 @@ |
|
|
|
|
const async = require('async') |
|
|
|
|
const EventEmitter = require('events').EventEmitter |
|
|
|
|
const encryptor = require('./lib/encryptor') |
|
|
|
|
const messageManager = require('./lib/message-manager') |
|
|
|
|
const ethUtil = require('ethereumjs-util') |
|
|
|
|
const ethBinToOps = require('eth-bin-to-ops') |
|
|
|
|
const EthQuery = require('eth-query') |
|
|
|
|
const BN = ethUtil.BN |
|
|
|
|
const Transaction = require('ethereumjs-tx') |
|
|
|
|
const createId = require('web3-provider-engine/util/random-id') |
|
|
|
|
|
|
|
|
|
// Keyrings:
|
|
|
|
|
const SimpleKeyring = require('./keyrings/simple') |
|
|
|
@ -15,6 +19,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
|
|
|
|
|
|
constructor (opts) { |
|
|
|
|
super() |
|
|
|
|
this.web3 = opts.web3 |
|
|
|
|
this.configManager = opts.configManager |
|
|
|
|
this.ethStore = opts.ethStore |
|
|
|
|
this.encryptor = encryptor |
|
|
|
@ -22,6 +27,11 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
|
|
|
|
|
|
this.keyrings = [] |
|
|
|
|
this.identities = {} // Essentially a name hash
|
|
|
|
|
|
|
|
|
|
this._unconfTxCbs = {} |
|
|
|
|
this._unconfMsgCbs = {} |
|
|
|
|
|
|
|
|
|
this.network = 'loading' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getState() { |
|
|
|
@ -41,6 +51,7 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
|
conversionDate: this.configManager.getConversionDate(), |
|
|
|
|
keyringTypes: this.keyringTypes.map((krt) => krt.type()), |
|
|
|
|
identities: this.identities, |
|
|
|
|
network: this.network, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -193,11 +204,121 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
|
cb(null, address) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addUnconfirmedTransaction(txParams, onTxDoneCb, cb) { |
|
|
|
|
var self = this |
|
|
|
|
const configManager = this.configManager |
|
|
|
|
|
|
|
|
|
// create txData obj with parameters and meta data
|
|
|
|
|
var time = (new Date()).getTime() |
|
|
|
|
var txId = createId() |
|
|
|
|
txParams.metamaskId = txId |
|
|
|
|
txParams.metamaskNetworkId = this.network |
|
|
|
|
var txData = { |
|
|
|
|
id: txId, |
|
|
|
|
txParams: txParams, |
|
|
|
|
time: time, |
|
|
|
|
status: 'unconfirmed', |
|
|
|
|
gasMultiplier: configManager.getGasMultiplier() || 1, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
console.log('addUnconfirmedTransaction:', txData) |
|
|
|
|
|
|
|
|
|
// keep the onTxDoneCb around for after approval/denial (requires user interaction)
|
|
|
|
|
// This onTxDoneCb fires completion to the Dapp's write operation.
|
|
|
|
|
this._unconfTxCbs[txId] = onTxDoneCb |
|
|
|
|
|
|
|
|
|
var provider = this.ethStore._query.currentProvider |
|
|
|
|
var query = new EthQuery(provider) |
|
|
|
|
|
|
|
|
|
// calculate metadata for tx
|
|
|
|
|
async.parallel([ |
|
|
|
|
analyzeForDelegateCall, |
|
|
|
|
estimateGas, |
|
|
|
|
], didComplete) |
|
|
|
|
|
|
|
|
|
// perform static analyis on the target contract code
|
|
|
|
|
function analyzeForDelegateCall(cb){ |
|
|
|
|
if (txParams.to) { |
|
|
|
|
query.getCode(txParams.to, function (err, result) { |
|
|
|
|
if (err) return cb(err) |
|
|
|
|
var code = ethUtil.toBuffer(result) |
|
|
|
|
if (code !== '0x') { |
|
|
|
|
var ops = ethBinToOps(code) |
|
|
|
|
var containsDelegateCall = ops.some((op) => op.name === 'DELEGATECALL') |
|
|
|
|
txData.containsDelegateCall = containsDelegateCall |
|
|
|
|
cb() |
|
|
|
|
} else { |
|
|
|
|
cb() |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} else { |
|
|
|
|
cb() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function estimateGas(cb){ |
|
|
|
|
query.estimateGas(txParams, function(err, result){ |
|
|
|
|
if (err) return cb(err) |
|
|
|
|
txData.estimatedGas = self.addGasBuffer(result) |
|
|
|
|
cb() |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function didComplete (err) { |
|
|
|
|
if (err) return cb(err) |
|
|
|
|
configManager.addTx(txData) |
|
|
|
|
// signal update
|
|
|
|
|
self.emit('update') |
|
|
|
|
// signal completion of add tx
|
|
|
|
|
cb(null, txData) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addUnconfirmedMessage(msgParams, cb) { |
|
|
|
|
// create txData obj with parameters and meta data
|
|
|
|
|
var time = (new Date()).getTime() |
|
|
|
|
var msgId = createId() |
|
|
|
|
var msgData = { |
|
|
|
|
id: msgId, |
|
|
|
|
msgParams: msgParams, |
|
|
|
|
time: time, |
|
|
|
|
status: 'unconfirmed', |
|
|
|
|
} |
|
|
|
|
messageManager.addMsg(msgData) |
|
|
|
|
console.log('addUnconfirmedMessage:', msgData) |
|
|
|
|
|
|
|
|
|
// keep the cb around for after approval (requires user interaction)
|
|
|
|
|
// This cb fires completion to the Dapp's write operation.
|
|
|
|
|
this._unconfMsgCbs[msgId] = cb |
|
|
|
|
|
|
|
|
|
// signal update
|
|
|
|
|
this.emit('update') |
|
|
|
|
return msgId |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
approveTransaction(txId, cb) { |
|
|
|
|
const configManager = this.configManager |
|
|
|
|
var approvalCb = this._unconfTxCbs[txId] || noop |
|
|
|
|
|
|
|
|
|
// accept tx
|
|
|
|
|
cb() |
|
|
|
|
approvalCb(null, true) |
|
|
|
|
// clean up
|
|
|
|
|
configManager.confirmTx(txId) |
|
|
|
|
delete this._unconfTxCbs[txId] |
|
|
|
|
this.emit('update') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cancelTransaction(txId, cb) { |
|
|
|
|
const configManager = this.configManager |
|
|
|
|
var approvalCb = this._unconfTxCbs[txId] || noop |
|
|
|
|
|
|
|
|
|
// reject tx
|
|
|
|
|
approvalCb(null, false) |
|
|
|
|
// clean up
|
|
|
|
|
configManager.rejectTx(txId) |
|
|
|
|
delete this._unconfTxCbs[txId] |
|
|
|
|
|
|
|
|
|
if (cb && typeof cb === 'function') { |
|
|
|
|
cb() |
|
|
|
|
} |
|
|
|
@ -279,5 +400,32 @@ module.exports = class KeyringController extends EventEmitter { |
|
|
|
|
cb() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getNetwork(err) { |
|
|
|
|
if (err) { |
|
|
|
|
this.network = 'loading' |
|
|
|
|
this.emit('update') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.web3.version.getNetwork((err, network) => { |
|
|
|
|
if (err) { |
|
|
|
|
this.network = 'loading' |
|
|
|
|
return this.emit('update') |
|
|
|
|
} |
|
|
|
|
if (global.METAMASK_DEBUG) { |
|
|
|
|
console.log('web3.getNetwork returned ' + network) |
|
|
|
|
} |
|
|
|
|
this.network = network |
|
|
|
|
this.emit('update') |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addGasBuffer(gasHex) { |
|
|
|
|
var gas = new BN(gasHex, 16) |
|
|
|
|
var buffer = new BN('100000', 10) |
|
|
|
|
var result = gas.add(buffer) |
|
|
|
|
return ethUtil.addHexPrefix(result.toString(16)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function noop () {} |
|
|
|
|