aboutsummaryrefslogtreecommitdiffstats
path: root/ui/lib
diff options
context:
space:
mode:
Diffstat (limited to 'ui/lib')
-rw-r--r--ui/lib/account-link.js26
-rw-r--r--ui/lib/contract-namer.js33
-rw-r--r--ui/lib/etherscan-prefix-for-network.js21
-rw-r--r--ui/lib/explorer-link.js6
-rw-r--r--ui/lib/icon-factory.js65
-rw-r--r--ui/lib/lost-accounts-notice.js23
-rw-r--r--ui/lib/persistent-form.js61
-rw-r--r--ui/lib/tx-helper.js21
8 files changed, 256 insertions, 0 deletions
diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js
new file mode 100644
index 000000000..d061d0ad1
--- /dev/null
+++ b/ui/lib/account-link.js
@@ -0,0 +1,26 @@
+module.exports = function (address, network) {
+ const net = parseInt(network)
+ let link
+ switch (net) {
+ case 1: // main net
+ link = `http://etherscan.io/address/${address}`
+ break
+ case 2: // morden test net
+ link = `http://morden.etherscan.io/address/${address}`
+ break
+ case 3: // ropsten test net
+ link = `http://ropsten.etherscan.io/address/${address}`
+ break
+ case 4: // rinkeby test net
+ link = `http://rinkeby.etherscan.io/address/${address}`
+ break
+ case 42: // kovan test net
+ link = `http://kovan.etherscan.io/address/${address}`
+ break
+ default:
+ link = ''
+ break
+ }
+
+ return link
+}
diff --git a/ui/lib/contract-namer.js b/ui/lib/contract-namer.js
new file mode 100644
index 000000000..f05e770cc
--- /dev/null
+++ b/ui/lib/contract-namer.js
@@ -0,0 +1,33 @@
+/* CONTRACT NAMER
+ *
+ * Takes an address,
+ * Returns a nicname if we have one stored,
+ * otherwise returns null.
+ */
+
+const contractMap = require('eth-contract-metadata')
+const ethUtil = require('ethereumjs-util')
+
+module.exports = function (addr, identities = {}) {
+ const checksummed = ethUtil.toChecksumAddress(addr)
+ if (contractMap[checksummed] && contractMap[checksummed].name) {
+ return contractMap[checksummed].name
+ }
+
+ const address = addr.toLowerCase()
+ const ids = hashFromIdentities(identities)
+ return addrFromHash(address, ids)
+}
+
+function hashFromIdentities (identities) {
+ const result = {}
+ for (const key in identities) {
+ result[key] = identities[key].name
+ }
+ return result
+}
+
+function addrFromHash (addr, hash) {
+ const address = addr.toLowerCase()
+ return hash[address] || null
+}
diff --git a/ui/lib/etherscan-prefix-for-network.js b/ui/lib/etherscan-prefix-for-network.js
new file mode 100644
index 000000000..2c1904f1c
--- /dev/null
+++ b/ui/lib/etherscan-prefix-for-network.js
@@ -0,0 +1,21 @@
+module.exports = function (network) {
+ const net = parseInt(network)
+ let prefix
+ switch (net) {
+ case 1: // main net
+ prefix = ''
+ break
+ case 3: // ropsten test net
+ prefix = 'ropsten.'
+ break
+ case 4: // rinkeby test net
+ prefix = 'rinkeby.'
+ break
+ case 42: // kovan test net
+ prefix = 'kovan.'
+ break
+ default:
+ prefix = ''
+ }
+ return prefix
+}
diff --git a/ui/lib/explorer-link.js b/ui/lib/explorer-link.js
new file mode 100644
index 000000000..3b82ecd5f
--- /dev/null
+++ b/ui/lib/explorer-link.js
@@ -0,0 +1,6 @@
+const prefixForNetwork = require('./etherscan-prefix-for-network')
+
+module.exports = function (hash, network) {
+ const prefix = prefixForNetwork(network)
+ return `http://${prefix}etherscan.io/tx/${hash}`
+}
diff --git a/ui/lib/icon-factory.js b/ui/lib/icon-factory.js
new file mode 100644
index 000000000..27a74de66
--- /dev/null
+++ b/ui/lib/icon-factory.js
@@ -0,0 +1,65 @@
+var iconFactory
+const isValidAddress = require('ethereumjs-util').isValidAddress
+const toChecksumAddress = require('ethereumjs-util').toChecksumAddress
+const contractMap = require('eth-contract-metadata')
+
+module.exports = function (jazzicon) {
+ if (!iconFactory) {
+ iconFactory = new IconFactory(jazzicon)
+ }
+ return iconFactory
+}
+
+function IconFactory (jazzicon) {
+ this.jazzicon = jazzicon
+ this.cache = {}
+}
+
+IconFactory.prototype.iconForAddress = function (address, diameter) {
+ const addr = toChecksumAddress(address)
+ if (iconExistsFor(addr)) {
+ return imageElFor(addr)
+ }
+
+ return this.generateIdenticonSvg(address, diameter)
+}
+
+// returns svg dom element
+IconFactory.prototype.generateIdenticonSvg = function (address, diameter) {
+ var cacheId = `${address}:${diameter}`
+ // check cache, lazily generate and populate cache
+ var identicon = this.cache[cacheId] || (this.cache[cacheId] = this.generateNewIdenticon(address, diameter))
+ // create a clean copy so you can modify it
+ var cleanCopy = identicon.cloneNode(true)
+ return cleanCopy
+}
+
+// creates a new identicon
+IconFactory.prototype.generateNewIdenticon = function (address, diameter) {
+ var numericRepresentation = jsNumberForAddress(address)
+ var identicon = this.jazzicon(diameter, numericRepresentation)
+ return identicon
+}
+
+// util
+
+function iconExistsFor (address) {
+ return contractMap[address] && isValidAddress(address) && contractMap[address].logo
+}
+
+function imageElFor (address) {
+ const contract = contractMap[address]
+ const fileName = contract.logo
+ const path = `images/contract/${fileName}`
+ const img = document.createElement('img')
+ img.src = path
+ img.style.width = '75%'
+ return img
+}
+
+function jsNumberForAddress (address) {
+ var addr = address.slice(2, 10)
+ var seed = parseInt(addr, 16)
+ return seed
+}
+
diff --git a/ui/lib/lost-accounts-notice.js b/ui/lib/lost-accounts-notice.js
new file mode 100644
index 000000000..948b13db6
--- /dev/null
+++ b/ui/lib/lost-accounts-notice.js
@@ -0,0 +1,23 @@
+const summary = require('../app/util').addressSummary
+
+module.exports = function (lostAccounts) {
+ return {
+ date: new Date().toDateString(),
+ title: 'Account Problem Caught',
+ body: `MetaMask has fixed a bug where some accounts were previously mis-generated. This was a rare issue, but you were affected!
+
+We have successfully imported the accounts that were mis-generated, but they will no longer be recovered with your normal seed phrase.
+
+We have marked the affected accounts as "Loose", and recommend you transfer ether and tokens away from those accounts, or export & back them up elsewhere.
+
+Your affected accounts are:
+${lostAccounts.map(acct => ` - ${summary(acct)}`).join('\n')}
+
+These accounts have been marked as "Loose" so they will be easy to recognize in the account list.
+
+For more information, please read [our blog post.][1]
+
+[1]: https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd#.7d8ktj4h3
+ `,
+ }
+}
diff --git a/ui/lib/persistent-form.js b/ui/lib/persistent-form.js
new file mode 100644
index 000000000..d4dc20b03
--- /dev/null
+++ b/ui/lib/persistent-form.js
@@ -0,0 +1,61 @@
+const inherits = require('util').inherits
+const Component = require('react').Component
+const defaultKey = 'persistent-form-default'
+const eventName = 'keyup'
+
+module.exports = PersistentForm
+
+function PersistentForm () {
+ Component.call(this)
+}
+
+inherits(PersistentForm, Component)
+
+PersistentForm.prototype.componentDidMount = function () {
+ const fields = document.querySelectorAll('[data-persistent-formid]')
+ const store = this.getPersistentStore()
+
+ for (var i = 0; i < fields.length; i++) {
+ const field = fields[i]
+ const key = field.getAttribute('data-persistent-formid')
+ const cached = store[key]
+ if (cached !== undefined) {
+ field.value = cached
+ }
+
+ field.addEventListener(eventName, this.persistentFieldDidUpdate.bind(this))
+ }
+}
+
+PersistentForm.prototype.getPersistentStore = function () {
+ let store = window.localStorage[this.persistentFormParentId || defaultKey]
+ if (store && store !== 'null') {
+ store = JSON.parse(store)
+ } else {
+ store = {}
+ }
+ return store
+}
+
+PersistentForm.prototype.setPersistentStore = function (newStore) {
+ window.localStorage[this.persistentFormParentId || defaultKey] = JSON.stringify(newStore)
+}
+
+PersistentForm.prototype.persistentFieldDidUpdate = function (event) {
+ const field = event.target
+ const store = this.getPersistentStore()
+ const key = field.getAttribute('data-persistent-formid')
+ const val = field.value
+ store[key] = val
+ this.setPersistentStore(store)
+}
+
+PersistentForm.prototype.componentWillUnmount = function () {
+ const fields = document.querySelectorAll('[data-persistent-formid]')
+ for (var i = 0; i < fields.length; i++) {
+ const field = fields[i]
+ field.removeEventListener(eventName, this.persistentFieldDidUpdate.bind(this))
+ }
+ this.setPersistentStore({})
+}
+
diff --git a/ui/lib/tx-helper.js b/ui/lib/tx-helper.js
new file mode 100644
index 000000000..afc62e7b6
--- /dev/null
+++ b/ui/lib/tx-helper.js
@@ -0,0 +1,21 @@
+const valuesFor = require('../app/util').valuesFor
+
+module.exports = function (unapprovedTxs, unapprovedMsgs, personalMsgs, network) {
+ log.debug('tx-helper called with params:')
+ log.debug({ unapprovedTxs, unapprovedMsgs, personalMsgs, network })
+
+ const txValues = network ? valuesFor(unapprovedTxs).filter(txMeta => txMeta.metamaskNetworkId === network) : valuesFor(unapprovedTxs)
+ log.debug(`tx helper found ${txValues.length} unapproved txs`)
+ const msgValues = valuesFor(unapprovedMsgs)
+ log.debug(`tx helper found ${msgValues.length} unsigned messages`)
+ let allValues = txValues.concat(msgValues)
+ const personalValues = valuesFor(personalMsgs)
+ log.debug(`tx helper found ${personalValues.length} unsigned personal messages`)
+ allValues = allValues.concat(personalValues)
+ allValues = allValues.sort((a, b) => {
+ return a.time > b.time
+ })
+
+ return allValues
+}
+