aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/lib
diff options
context:
space:
mode:
Diffstat (limited to 'app/scripts/lib')
-rw-r--r--app/scripts/lib/local-store.js62
-rw-r--r--app/scripts/lib/seed-phrase-verifier.js48
-rw-r--r--app/scripts/lib/tx-gas-utils.js6
-rw-r--r--app/scripts/lib/tx-state-manager.js42
4 files changed, 146 insertions, 12 deletions
diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js
new file mode 100644
index 000000000..5b47985f6
--- /dev/null
+++ b/app/scripts/lib/local-store.js
@@ -0,0 +1,62 @@
+// We should not rely on local storage in an extension!
+// We should use this instead!
+// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local
+
+const extension = require('extensionizer')
+
+module.exports = class ExtensionStore {
+ constructor() {
+ this.isSupported = !!(extension.storage.local)
+ if (!this.isSupported) {
+ log.error('Storage local API not available.')
+ }
+ }
+
+ async get() {
+ if (!this.isSupported) return undefined
+ const result = await this._get()
+ // extension.storage.local always returns an obj
+ // if the object is empty, treat it as undefined
+ if (isEmpty(result)) {
+ return undefined
+ } else {
+ return result
+ }
+ }
+
+ async set(state) {
+ return this._set(state)
+ }
+
+ _get() {
+ const local = extension.storage.local
+ return new Promise((resolve, reject) => {
+ local.get(null, (result) => {
+ const err = extension.runtime.lastError
+ if (err) {
+ reject(err)
+ } else {
+ resolve(result)
+ }
+ })
+ })
+ }
+
+ _set(obj) {
+ const local = extension.storage.local
+ return new Promise((resolve, reject) => {
+ local.set(obj, () => {
+ const err = extension.runtime.lastError
+ if (err) {
+ reject(err)
+ } else {
+ resolve()
+ }
+ })
+ })
+ }
+}
+
+function isEmpty(obj) {
+ return Object.keys(obj).length === 0
+}
diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js
new file mode 100644
index 000000000..9cea22029
--- /dev/null
+++ b/app/scripts/lib/seed-phrase-verifier.js
@@ -0,0 +1,48 @@
+const KeyringController = require('eth-keyring-controller')
+
+const seedPhraseVerifier = {
+
+ // Verifies if the seed words can restore the accounts.
+ //
+ // The seed words can recreate the primary keyring and the accounts belonging to it.
+ // The created accounts in the primary keyring are always the same.
+ // The keyring always creates the accounts in the same sequence.
+ verifyAccounts (createdAccounts, seedWords) {
+
+ return new Promise((resolve, reject) => {
+
+ if (!createdAccounts || createdAccounts.length < 1) {
+ return reject(new Error('No created accounts defined.'))
+ }
+
+ const keyringController = new KeyringController({})
+ const Keyring = keyringController.getKeyringClassForType('HD Key Tree')
+ const opts = {
+ mnemonic: seedWords,
+ numberOfAccounts: createdAccounts.length,
+ }
+
+ const keyring = new Keyring(opts)
+ keyring.getAccounts()
+ .then((restoredAccounts) => {
+
+ log.debug('Created accounts: ' + JSON.stringify(createdAccounts))
+ log.debug('Restored accounts: ' + JSON.stringify(restoredAccounts))
+
+ if (restoredAccounts.length !== createdAccounts.length) {
+ // this should not happen...
+ return reject(new Error('Wrong number of accounts'))
+ }
+
+ for (let i = 0; i < restoredAccounts.length; i++) {
+ if (restoredAccounts[i].toLowerCase() !== createdAccounts[i].toLowerCase()) {
+ return reject(new Error('Not identical accounts! Original: ' + createdAccounts[i] + ', Restored: ' + restoredAccounts[i]))
+ }
+ }
+ return resolve()
+ })
+ })
+ },
+}
+
+module.exports = seedPhraseVerifier
diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js
index 6f6ff7852..0fa9dd8d4 100644
--- a/app/scripts/lib/tx-gas-utils.js
+++ b/app/scripts/lib/tx-gas-utils.js
@@ -4,7 +4,7 @@ const {
BnMultiplyByFraction,
bnToHex,
} = require('./util')
-const addHexPrefix = require('ethereumjs-util').addHexPrefix
+const { addHexPrefix, isValidAddress } = require('ethereumjs-util')
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
/*
@@ -113,12 +113,14 @@ module.exports = class TxGasUtil {
}
}
validateRecipient (txParams) {
- if (txParams.to === '0x') {
+ if (txParams.to === '0x' || txParams.to === null ) {
if (txParams.data) {
delete txParams.to
} else {
throw new Error('Invalid recipient address')
}
+ } else if ( txParams.to !== undefined && !isValidAddress(txParams.to) ) {
+ throw new Error('Invalid recipient address')
}
return txParams
}
diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js
index 2eb006380..ad07c813f 100644
--- a/app/scripts/lib/tx-state-manager.js
+++ b/app/scripts/lib/tx-state-manager.js
@@ -1,9 +1,21 @@
const extend = require('xtend')
const EventEmitter = require('events')
const ObservableStore = require('obs-store')
+const createId = require('./random-id')
const ethUtil = require('ethereumjs-util')
const txStateHistoryHelper = require('./tx-state-history-helper')
+// STATUS METHODS
+ // statuses:
+ // - `'unapproved'` the user has not responded
+ // - `'rejected'` the user has responded no!
+ // - `'approved'` the user has approved the tx
+ // - `'signed'` the tx is signed
+ // - `'submitted'` the tx is sent to a server
+ // - `'confirmed'` the tx has been included in a block.
+ // - `'failed'` the tx failed for some reason, included on tx data.
+ // - `'dropped'` the tx nonce was already used
+
module.exports = class TransactionStateManager extends EventEmitter {
constructor ({ initState, txHistoryLimit, getNetwork }) {
super()
@@ -16,6 +28,16 @@ module.exports = class TransactionStateManager extends EventEmitter {
this.getNetwork = getNetwork
}
+ generateTxMeta (opts) {
+ return extend({
+ id: createId(),
+ time: (new Date()).getTime(),
+ status: 'unapproved',
+ metamaskNetworkId: this.getNetwork(),
+ loadingDefaults: true,
+ }, opts)
+ }
+
// Returns the number of txs for the current network.
getTxCount () {
return this.getTxList().length
@@ -164,16 +186,6 @@ module.exports = class TransactionStateManager extends EventEmitter {
})
}
- // STATUS METHODS
- // statuses:
- // - `'unapproved'` the user has not responded
- // - `'rejected'` the user has responded no!
- // - `'approved'` the user has approved the tx
- // - `'signed'` the tx is signed
- // - `'submitted'` the tx is sent to a server
- // - `'confirmed'` the tx has been included in a block.
- // - `'failed'` the tx failed for some reason, included on tx data.
-
// get::set status
// should return the status of the tx.
@@ -202,7 +214,11 @@ module.exports = class TransactionStateManager extends EventEmitter {
}
// should update the status of the tx to 'submitted'.
+ // and add a time stamp for when it was called
setTxStatusSubmitted (txId) {
+ const txMeta = this.getTx(txId)
+ txMeta.submittedTime = (new Date()).getTime()
+ this.updateTx(txMeta, 'txStateManager - add submitted time stamp')
this._setTxStatus(txId, 'submitted')
}
@@ -211,6 +227,12 @@ module.exports = class TransactionStateManager extends EventEmitter {
this._setTxStatus(txId, 'confirmed')
}
+ // should update the status dropped
+ setTxStatusDropped (txId) {
+ this._setTxStatus(txId, 'dropped')
+ }
+
+
setTxStatusFailed (txId, err) {
const txMeta = this.getTx(txId)
txMeta.err = {