Merge remote-tracking branch 'origin/develop' into vb-rsk-dpath-update
This commit is contained in:
commit
8f1d7d7121
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -3,6 +3,18 @@
|
|||
## Current Master
|
||||
|
||||
- [#356](https://github.com/poanetwork/nifty-wallet/pull/356) - (Backwards-compatibility feature) Custom derivation paths and access to funds in accounts derived from ETH dPath
|
||||
- [#379](https://github.com/poanetwork/nifty-wallet/pull/379) - (Feature) Ability to set custom nonce of tx
|
||||
- [#377](https://github.com/poanetwork/nifty-wallet/pull/377) - (Fix) Sign message screen: do not decode message if it is not hex encoded
|
||||
- [#364](https://github.com/poanetwork/nifty-wallet/pull/364) - (Fix) notifications order in batch requests
|
||||
|
||||
## 5.0.3 Fri May 01 2020
|
||||
|
||||
- [#373](https://github.com/poanetwork/nifty-wallet/pull/373) - (Feature) Add STAKE token
|
||||
- [#372](https://github.com/poanetwork/nifty-wallet/pull/372) - (Chore) Update RSK contracts metadata repo
|
||||
- [#369](https://github.com/poanetwork/nifty-wallet/pull/369) - (Fix) RSK: fix GasPrice calculation (changed interface of minimumGasPrice - hex instead of integer)
|
||||
- [#368](https://github.com/poanetwork/nifty-wallet/pull/368) - (Fix) Ability to import Keystore file if it is not secured by password
|
||||
- [#366](https://github.com/poanetwork/nifty-wallet/pull/366) - (Fix) Increase max token symbol length up to 12
|
||||
- [#363](https://github.com/poanetwork/nifty-wallet/pull/363) - (Fix) token decimals display in pending tx screen
|
||||
|
||||
## 5.0.2 Thu Apr 16 2020
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "__MSG_appName__",
|
||||
"short_name": "__MSG_appName__",
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.3",
|
||||
"manifest_version": 2,
|
||||
"author": "POA Network",
|
||||
"description": "__MSG_appDescription__",
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
// this needs to run before anything else
|
||||
require('./lib/setupFetchDebugging')()
|
||||
|
||||
const endOfStream = require('end-of-stream')
|
||||
const pump = require('pump')
|
||||
const debounce = require('debounce-stream')
|
||||
const log = require('loglevel')
|
||||
const extension = require('extensionizer')
|
||||
import endOfStream from 'end-of-stream'
|
||||
import pump from 'pump'
|
||||
import debounce from 'debounce-stream'
|
||||
import log from 'loglevel'
|
||||
import extension from 'extensionizer'
|
||||
const LocalStorageStore = require('obs-store/lib/localStorage')
|
||||
const LocalStore = require('./lib/local-store')
|
||||
const storeTransform = require('obs-store/lib/transform')
|
||||
|
@ -19,13 +19,11 @@ const Migrator = require('./lib/migrator/')
|
|||
const migrations = require('./migrations/')
|
||||
const PortStream = require('extension-port-stream')
|
||||
const createStreamSink = require('./lib/createStreamSink')
|
||||
const NotificationManager = require('./lib/notification-manager.js')
|
||||
import NotificationManager from './lib/notification-manager.js'
|
||||
const MetamaskController = require('./metamask-controller')
|
||||
const rawFirstTimeState = require('./first-time-state')
|
||||
const setupRaven = require('./lib/setupRaven')
|
||||
const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry')
|
||||
const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
|
||||
const EdgeEncryptor = require('./edge-encryptor')
|
||||
const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code')
|
||||
const getObjStructure = require('./lib/getObjStructure')
|
||||
|
||||
|
@ -51,12 +49,6 @@ global.METAMASK_NOTIFIER = notificationManager
|
|||
const release = platform.getVersion()
|
||||
const raven = setupRaven({ release })
|
||||
|
||||
// browser check if it is Edge - https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
|
||||
// Internet Explorer 6-11
|
||||
const isIE = !!document.documentMode
|
||||
// Edge 20+
|
||||
const isEdge = !isIE && !!window.StyleMedia
|
||||
|
||||
let popupIsOpen = false
|
||||
let notificationIsOpen = false
|
||||
const openMetamaskTabsIDs = {}
|
||||
|
@ -70,9 +62,6 @@ let versionedData
|
|||
// initialization flow
|
||||
initialize().catch(log.error)
|
||||
|
||||
// setup metamask mesh testing container
|
||||
setupMetamaskMeshMetrics()
|
||||
|
||||
|
||||
/**
|
||||
* An object representing a transaction, in whatever state it is in.
|
||||
|
@ -177,6 +166,7 @@ async function initialize () {
|
|||
async function loadStateFromPersistence () {
|
||||
// migrations
|
||||
const migrator = new Migrator({ migrations })
|
||||
migrator.on('error', console.warn)
|
||||
|
||||
// read from disk
|
||||
// first from preferred, async API:
|
||||
|
@ -256,7 +246,7 @@ function setupController (initState, initLangCode) {
|
|||
showUnconfirmedMessage: triggerUi,
|
||||
unlockAccountMessage: triggerUi,
|
||||
showUnapprovedTx: triggerUi,
|
||||
showWatchAssetUi: showWatchAssetUi,
|
||||
openPopup: openPopup,
|
||||
// initial state
|
||||
initState,
|
||||
// initial locale code
|
||||
|
@ -269,7 +259,6 @@ function setupController (initState, initLangCode) {
|
|||
getOpenMetamaskTabsIds: () => {
|
||||
return openMetamaskTabsIDs
|
||||
},
|
||||
encryptor: isEdge ? new EdgeEncryptor() : undefined,
|
||||
})
|
||||
global.metamaskController = controller
|
||||
|
||||
|
@ -460,28 +449,27 @@ function setupController (initState, initLangCode) {
|
|||
/**
|
||||
* Opens the browser popup for user confirmation
|
||||
*/
|
||||
function triggerUi () {
|
||||
extension.tabs.query({ active: true }, tabs => {
|
||||
const currentlyActiveMetamaskTab = Boolean(tabs.find(tab => openMetamaskTabsIDs[tab.id]))
|
||||
/**
|
||||
* https://github.com/poanetwork/metamask-extension/issues/19
|
||||
* !notificationIsOpen was removed from the check, because notification can be opened, but it can be behind the DApp
|
||||
* for some reasons. For example, if notification popup was opened, but user moved focus to DApp.
|
||||
* New transaction, in this case, will not appear in front of DApp.
|
||||
*/
|
||||
if (!popupIsOpen && !currentlyActiveMetamaskTab) {
|
||||
notificationManager.showPopup()
|
||||
}
|
||||
})
|
||||
async function triggerUi () {
|
||||
const tabs = await platform.getActiveTabs()
|
||||
const currentlyActiveMetamaskTab = Boolean(tabs.find((tab) => openMetamaskTabsIDs[tab.id]))
|
||||
/**
|
||||
* https://github.com/poanetwork/metamask-extension/issues/19
|
||||
* !notificationIsOpen was removed from the check, because notification can be opened, but it can be behind the DApp
|
||||
* for some reasons. For example, if notification popup was opened, but user moved focus to DApp.
|
||||
* New transaction, in this case, will not appear in front of DApp.
|
||||
*/
|
||||
if (!popupIsOpen && !currentlyActiveMetamaskTab) {
|
||||
await notificationManager.showPopup()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the browser popup for user confirmation of watchAsset
|
||||
* then it waits until user interact with the UI
|
||||
*/
|
||||
function showWatchAssetUi () {
|
||||
triggerUi()
|
||||
return new Promise(
|
||||
async function openPopup () {
|
||||
await triggerUi()
|
||||
await new Promise(
|
||||
(resolve) => {
|
||||
const interval = setInterval(() => {
|
||||
if (!notificationIsOpen) {
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
// // The reload client has a compatibility with livereload.
|
||||
// // WARNING: only supports reload command.
|
||||
|
||||
// var LIVERELOAD_HOST = 'localhost:';
|
||||
// var LIVERELOAD_PORT = 35729;
|
||||
// var connection = new WebSocket('ws://' + LIVERELOAD_HOST + LIVERELOAD_PORT + '/livereload');
|
||||
// const LIVERELOAD_HOST = 'localhost:';
|
||||
// const LIVERELOAD_PORT = 35729;
|
||||
// const connection = new WebSocket('ws://' + LIVERELOAD_HOST + LIVERELOAD_PORT + '/livereload');
|
||||
|
||||
// connection.onopen = function(event) {
|
||||
// var hello = {
|
||||
// const hello = {
|
||||
// command: 'hello',
|
||||
// protocols: ['http://livereload.com/protocols/official-7']
|
||||
// };
|
||||
|
@ -23,7 +23,7 @@
|
|||
|
||||
// connection.onmessage = function (e) {
|
||||
// if (e.data) {
|
||||
// var data = JSON.parse(e.data);
|
||||
// const data = JSON.parse(e.data);
|
||||
// if (data && data.command === 'reload') {
|
||||
// extension.runtime.reload();
|
||||
// }
|
||||
|
@ -32,9 +32,9 @@
|
|||
|
||||
window.LiveReloadOptions = { host: 'localhost' };
|
||||
|
||||
(function e (t, n, r) { function s (o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require === 'function' && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = 'MODULE_NOT_FOUND', f } var l = n[o] = {exports: {}}; t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e) }, l, l.exports, e, t, n, r) } return n[o].exports } var i = typeof require === 'function' && require; for (var o = 0; o < r.length; o++)s(r[o]); return s })({1: [function (require, module, exports) {
|
||||
(function e (t, n, r) { function s (o, u) { if (!n[o]) { if (!t[o]) { let a = typeof require === 'function' && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); let f = new Error("Cannot find module '" + o + "'"); throw f.code = 'MODULE_NOT_FOUND', f } let l = n[o] = {exports: {}}; t[o][0].call(l.exports, function (e) { let n = t[o][1][e]; return s(n ? n : e) }, l, l.exports, e, t, n, r) } return n[o].exports } let i = typeof require === 'function' && require; for (let o = 0; o < r.length; o++)s(r[o]); return s })({1: [function (require, module, exports) {
|
||||
(function () {
|
||||
var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref
|
||||
let Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref
|
||||
|
||||
_ref = require('./protocol'), Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7
|
||||
|
||||
|
@ -166,7 +166,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Connector.prototype._onopen = function (e) {
|
||||
var hello
|
||||
let hello
|
||||
this.handlers.socketConnected()
|
||||
this._disconnectionReason = 'handshake-failed'
|
||||
hello = {
|
||||
|
@ -204,7 +204,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}).call(this)
|
||||
}, {'./protocol': 6}], 2: [function (require, module, exports) {
|
||||
(function () {
|
||||
var CustomEvents
|
||||
let CustomEvents
|
||||
|
||||
CustomEvents = {
|
||||
bind: function (element, eventName, handler) {
|
||||
|
@ -222,7 +222,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
},
|
||||
fire: function (element, eventName) {
|
||||
var event
|
||||
let event
|
||||
if (element.addEventListener) {
|
||||
event = document.createEvent('HTMLEvents')
|
||||
event.initEvent(eventName, true, true)
|
||||
|
@ -243,7 +243,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}).call(this)
|
||||
}, {}], 3: [function (require, module, exports) {
|
||||
(function () {
|
||||
var LessPlugin
|
||||
let LessPlugin
|
||||
|
||||
module.exports = LessPlugin = (function () {
|
||||
LessPlugin.identifier = 'less'
|
||||
|
@ -268,9 +268,9 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
LessPlugin.prototype.reloadLess = function (path) {
|
||||
var link, links, _i, _len
|
||||
let link, links, _i, _len
|
||||
links = (function () {
|
||||
var _i, _len, _ref, _results
|
||||
let _i, _len, _ref, _results
|
||||
_ref = document.getElementsByTagName('link')
|
||||
_results = []
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
|
@ -304,7 +304,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}).call(this)
|
||||
}, {}], 4: [function (require, module, exports) {
|
||||
(function () {
|
||||
var Connector, LiveReload, Options, Reloader, Timer,
|
||||
let Connector, LiveReload, Options, Reloader, Timer,
|
||||
__hasProp = {}.hasOwnProperty
|
||||
|
||||
Connector = require('./connector').Connector
|
||||
|
@ -317,7 +317,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
|
||||
exports.LiveReload = LiveReload = (function () {
|
||||
function LiveReload (window) {
|
||||
var k, v, _ref
|
||||
let k, v, _ref
|
||||
this.window = window
|
||||
this.listeners = {}
|
||||
this.plugins = []
|
||||
|
@ -358,7 +358,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
})(this),
|
||||
connected: (function (_this) {
|
||||
return function (protocol) {
|
||||
var _base
|
||||
let _base
|
||||
if (typeof (_base = _this.listeners).connect === 'function') {
|
||||
_base.connect()
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
})(this),
|
||||
disconnected: (function (_this) {
|
||||
return function (reason, nextDelay) {
|
||||
var _base
|
||||
let _base
|
||||
if (typeof (_base = _this.listeners).disconnect === 'function') {
|
||||
_base.disconnect()
|
||||
}
|
||||
|
@ -426,7 +426,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
LiveReload.prototype.performReload = function (message) {
|
||||
var _ref, _ref1
|
||||
let _ref, _ref1
|
||||
this.log('LiveReload received reload request: ' + (JSON.stringify(message, null, 2)))
|
||||
return this.reloader.reload(message.path, {
|
||||
liveCSS: (_ref = message.liveCSS) != null ? _ref : true,
|
||||
|
@ -442,7 +442,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
LiveReload.prototype.shutDown = function () {
|
||||
var _base
|
||||
let _base
|
||||
if (!this.initialized) {
|
||||
return
|
||||
}
|
||||
|
@ -456,7 +456,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
LiveReload.prototype.addPlugin = function (pluginClass) {
|
||||
var plugin
|
||||
let plugin
|
||||
if (!this.initialized) {
|
||||
return
|
||||
}
|
||||
|
@ -481,7 +481,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
LiveReload.prototype.analyze = function () {
|
||||
var plugin, pluginData, pluginsData, _i, _len, _ref
|
||||
let plugin, pluginData, pluginsData, _i, _len, _ref
|
||||
if (!this.initialized) {
|
||||
return
|
||||
}
|
||||
|
@ -507,7 +507,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}).call(this)
|
||||
}, {'./connector': 1, './options': 5, './reloader': 7, './timer': 9}], 5: [function (require, module, exports) {
|
||||
(function () {
|
||||
var Options
|
||||
let Options
|
||||
|
||||
exports.Options = Options = (function () {
|
||||
function Options () {
|
||||
|
@ -536,7 +536,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
})()
|
||||
|
||||
Options.extract = function (document) {
|
||||
var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len1, _ref, _ref1
|
||||
let element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len1, _ref, _ref1
|
||||
_ref = document.getElementsByTagName('script')
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
element = _ref[_i]
|
||||
|
@ -566,8 +566,8 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}).call(this)
|
||||
}, {}], 6: [function (require, module, exports) {
|
||||
(function () {
|
||||
var PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError,
|
||||
__indexOf = [].indexOf || function (item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i } return -1 }
|
||||
let PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError,
|
||||
__indexOf = [].indexOf || function (item) { for (let i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i } return -1 }
|
||||
|
||||
exports.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6'
|
||||
|
||||
|
@ -592,7 +592,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Parser.prototype.process = function (data) {
|
||||
var command, e, message, options, _ref
|
||||
let command, e, message, options, _ref
|
||||
try {
|
||||
if (this.protocol == null) {
|
||||
if (data.match(/^!!ver:([\d.]+)$/)) {
|
||||
|
@ -638,7 +638,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Parser.prototype._parseMessage = function (data, validCommands) {
|
||||
var e, message, _ref
|
||||
let e, message, _ref
|
||||
try {
|
||||
message = JSON.parse(data)
|
||||
} catch (_error) {
|
||||
|
@ -659,10 +659,10 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}).call(this)
|
||||
}, {}], 7: [function (require, module, exports) {
|
||||
(function () {
|
||||
var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl
|
||||
let IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl
|
||||
|
||||
splitUrl = function (url) {
|
||||
var hash, index, params
|
||||
let hash, index, params
|
||||
if ((index = url.indexOf('#')) >= 0) {
|
||||
hash = url.slice(index)
|
||||
url = url.slice(0, index)
|
||||
|
@ -683,7 +683,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
pathFromUrl = function (url) {
|
||||
var path
|
||||
let path
|
||||
url = splitUrl(url).url
|
||||
if (url.indexOf('file://') === 0) {
|
||||
path = url.replace(/^file:\/\/(localhost)?/, '')
|
||||
|
@ -694,7 +694,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
pickBestMatch = function (path, objects, pathFunc) {
|
||||
var bestMatch, object, score, _i, _len
|
||||
let bestMatch, object, score, _i, _len
|
||||
bestMatch = {
|
||||
score: 0,
|
||||
}
|
||||
|
@ -716,7 +716,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
numberOfMatchingSegments = function (path1, path2) {
|
||||
var comps1, comps2, eqCount, len
|
||||
let comps1, comps2, eqCount, len
|
||||
path1 = path1.replace(/^\/+/, '').toLowerCase()
|
||||
path2 = path2.replace(/^\/+/, '').toLowerCase()
|
||||
if (path1 === path2) {
|
||||
|
@ -765,7 +765,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.reload = function (path, options) {
|
||||
var plugin, _base, _i, _len, _ref
|
||||
let plugin, _base, _i, _len, _ref
|
||||
this.options = options
|
||||
if ((_base = this.options).stylesheetReloadTimeout == null) {
|
||||
_base.stylesheetReloadTimeout = 15000
|
||||
|
@ -798,7 +798,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.reloadImages = function (path) {
|
||||
var expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _results
|
||||
let expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _results
|
||||
expando = this.generateUniqueString()
|
||||
_ref = this.document.images
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
|
@ -829,7 +829,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.reloadStylesheetImages = function (styleSheet, path, expando) {
|
||||
var e, rule, rules, styleNames, _i, _j, _len, _len1
|
||||
let e, rule, rules, styleNames, _i, _j, _len, _len1
|
||||
try {
|
||||
rules = styleSheet != null ? styleSheet.cssRules : void 0
|
||||
} catch (_error) {
|
||||
|
@ -857,7 +857,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.reloadStyleImages = function (style, styleNames, path, expando) {
|
||||
var newValue, styleName, value, _i, _len
|
||||
let newValue, styleName, value, _i, _len
|
||||
for (_i = 0, _len = styleNames.length; _i < _len; _i++) {
|
||||
styleName = styleNames[_i]
|
||||
value = style[styleName]
|
||||
|
@ -879,9 +879,9 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.reloadStylesheet = function (path) {
|
||||
var imported, link, links, match, style, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1
|
||||
let imported, link, links, match, style, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1
|
||||
links = (function () {
|
||||
var _i, _len, _ref, _results
|
||||
let _i, _len, _ref, _results
|
||||
_ref = this.document.getElementsByTagName('link')
|
||||
_results = []
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
|
@ -936,7 +936,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.collectImportedStylesheets = function (link, styleSheet, result) {
|
||||
var e, index, rule, rules, _i, _len
|
||||
let e, index, rule, rules, _i, _len
|
||||
try {
|
||||
rules = styleSheet != null ? styleSheet.cssRules : void 0
|
||||
} catch (_error) {
|
||||
|
@ -965,7 +965,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.waitUntilCssLoads = function (clone, func) {
|
||||
var callbackExecuted, executeCallback, poll
|
||||
let callbackExecuted, executeCallback, poll
|
||||
callbackExecuted = false
|
||||
executeCallback = (function (_this) {
|
||||
return function () {
|
||||
|
@ -1003,7 +1003,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.reattachStylesheetLink = function (link) {
|
||||
var clone, parent
|
||||
let clone, parent
|
||||
if (link.__LiveReload_pendingRemoval) {
|
||||
return
|
||||
}
|
||||
|
@ -1025,14 +1025,14 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
return this.waitUntilCssLoads(clone, (function (_this) {
|
||||
return function () {
|
||||
var additionalWaitingTime
|
||||
let additionalWaitingTime
|
||||
if (/AppleWebKit/.test(navigator.userAgent)) {
|
||||
additionalWaitingTime = 5
|
||||
} else {
|
||||
additionalWaitingTime = 200
|
||||
}
|
||||
return _this.Timer.start(additionalWaitingTime, function () {
|
||||
var _ref
|
||||
let _ref
|
||||
if (!link.parentNode) {
|
||||
return
|
||||
}
|
||||
|
@ -1045,7 +1045,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.reattachImportedRule = function (_arg) {
|
||||
var href, index, link, media, newRule, parent, rule, tempLink
|
||||
let href, index, link, media, newRule, parent, rule, tempLink
|
||||
rule = _arg.rule, index = _arg.index, link = _arg.link
|
||||
parent = rule.parentStyleSheet
|
||||
href = this.generateCacheBustUrl(rule.href)
|
||||
|
@ -1087,7 +1087,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}
|
||||
|
||||
Reloader.prototype.generateCacheBustUrl = function (url, expando) {
|
||||
var hash, oldParams, originalUrl, params, _ref
|
||||
let hash, oldParams, originalUrl, params, _ref
|
||||
if (expando == null) {
|
||||
expando = this.generateUniqueString()
|
||||
}
|
||||
|
@ -1117,7 +1117,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}).call(this)
|
||||
}, {}], 8: [function (require, module, exports) {
|
||||
(function () {
|
||||
var CustomEvents, LiveReload, k
|
||||
let CustomEvents, LiveReload, k
|
||||
|
||||
CustomEvents = require('./customevents')
|
||||
|
||||
|
@ -1149,7 +1149,7 @@ window.LiveReloadOptions = { host: 'localhost' };
|
|||
}).call(this)
|
||||
}, {'./customevents': 2, './less': 3, './livereload': 4}], 9: [function (require, module, exports) {
|
||||
(function () {
|
||||
var Timer
|
||||
let Timer
|
||||
|
||||
exports.Timer = Timer = (function () {
|
||||
function Timer (func) {
|
||||
|
|
|
@ -30,10 +30,10 @@ if (shouldInjectWeb3()) {
|
|||
function setupInjection () {
|
||||
try {
|
||||
// inject in-page script
|
||||
var scriptTag = document.createElement('script')
|
||||
const scriptTag = document.createElement('script')
|
||||
scriptTag.textContent = inpageBundle
|
||||
scriptTag.onload = function () { this.parentNode.removeChild(this) }
|
||||
var container = document.head || document.documentElement
|
||||
const container = document.head || document.documentElement
|
||||
// append as first child
|
||||
container.insertBefore(scriptTag, container.children[0])
|
||||
} catch (e) {
|
||||
|
@ -163,7 +163,7 @@ function suffixCheck () {
|
|||
* @returns {boolean} {@code true} if the documentElement is an html node or if none exists
|
||||
*/
|
||||
function documentElementCheck () {
|
||||
var documentElement = document.documentElement.nodeName
|
||||
const documentElement = document.documentElement.nodeName
|
||||
if (documentElement) {
|
||||
return documentElement.toLowerCase() === 'html'
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ function documentElementCheck () {
|
|||
* @returns {boolean} {@code true} if the current domain is blacklisted
|
||||
*/
|
||||
function blacklistedDomainCheck () {
|
||||
var blacklistedDomains = [
|
||||
const blacklistedDomains = [
|
||||
'uscourts.gov',
|
||||
'dropbox.com',
|
||||
'webbyawards.com',
|
||||
|
@ -187,8 +187,8 @@ function blacklistedDomainCheck () {
|
|||
'ani.gamer.com.tw',
|
||||
'blueskybooking.com',
|
||||
]
|
||||
var currentUrl = window.location.href
|
||||
var currentRegex
|
||||
const currentUrl = window.location.href
|
||||
let currentRegex
|
||||
for (let i = 0; i < blacklistedDomains.length; i++) {
|
||||
const blacklistedDomain = blacklistedDomains[i].replace('.', '\\.')
|
||||
currentRegex = new RegExp(`(?:https?:\\/\\/)(?:(?!${blacklistedDomain}).)*$`)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import Web3 from 'web3'
|
||||
import contractsETH from 'eth-contract-metadata'
|
||||
import contractsPOA from 'poa-contract-metadata'
|
||||
import contractsRSK from 'rsk-contract-metadata'
|
||||
import contractsRSKTest from 'rsk-test-contract-metadata'
|
||||
import contractsRSK from '@rsksmart/rsk-contract-metadata'
|
||||
import contractsRSKTest from '@rsksmart/rsk-testnet-contract-metadata'
|
||||
import { warn } from 'loglevel'
|
||||
const { MAINNET, POA, RSK, RSK_TESTNET } = require('./network/enums')
|
||||
// By default, poll every 3 minutes
|
||||
|
|
|
@ -47,7 +47,7 @@ class PreferencesController {
|
|||
this.diagnostics = opts.diagnostics
|
||||
this.network = opts.network
|
||||
this.store = new ObservableStore(initState)
|
||||
this.showWatchAssetUi = opts.showWatchAssetUi
|
||||
this.openPopup = opts.openPopup
|
||||
this._subscribeProviderType()
|
||||
}
|
||||
// PUBLIC METHODS
|
||||
|
@ -591,7 +591,7 @@ class PreferencesController {
|
|||
}
|
||||
const tokenOpts = { rawAddress, decimals, symbol, image }
|
||||
this.addSuggestedERC20Asset(tokenOpts)
|
||||
return this.showWatchAssetUi().then(() => {
|
||||
return this.openPopup().then(() => {
|
||||
const tokenAddresses = this.getTokens().filter(token => token.address === normalizeAddress(rawAddress))
|
||||
return tokenAddresses.length > 0
|
||||
})
|
||||
|
|
|
@ -290,7 +290,8 @@ class TransactionController extends EventEmitter {
|
|||
*/
|
||||
async updateAndApproveTransaction (txMeta) {
|
||||
this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction')
|
||||
await this.approveTransaction(txMeta.id)
|
||||
const customNonce = txMeta.txParams.nonce
|
||||
await this.approveTransaction(txMeta.id, customNonce)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -301,7 +302,7 @@ class TransactionController extends EventEmitter {
|
|||
if any of these steps fails the tx status will be set to failed
|
||||
@param txId {number} - the tx's Id
|
||||
*/
|
||||
async approveTransaction (txId) {
|
||||
async approveTransaction (txId, customNonce) {
|
||||
let nonceLock
|
||||
try {
|
||||
// approve
|
||||
|
@ -315,7 +316,7 @@ class TransactionController extends EventEmitter {
|
|||
// if txMeta has lastGasPrice then it is a retry at same nonce with higher
|
||||
// gas price transaction and their for the nonce should not be calculated
|
||||
const nonce = txMeta.lastGasPrice ? txMeta.txParams.nonce : nonceLock.nextNonce
|
||||
txMeta.txParams.nonce = ethUtil.addHexPrefix(nonce.toString(16))
|
||||
txMeta.txParams.nonce = customNonce || ethUtil.addHexPrefix(nonce.toString(16))
|
||||
// add nonce debugging information to txMeta
|
||||
txMeta.nonceDetails = nonceLock.nonceDetails
|
||||
this.txStateManager.updateTx(txMeta, 'transactions#approveTransaction')
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
const asmcrypto = require('asmcrypto.js')
|
||||
const Unibabel = require('browserify-unibabel')
|
||||
|
||||
/**
|
||||
* A Microsoft Edge-specific encryption class that exposes
|
||||
* the interface expected by eth-keykeyring-controller
|
||||
*/
|
||||
class EdgeEncryptor {
|
||||
/**
|
||||
* Encrypts an arbitrary object to ciphertext
|
||||
*
|
||||
* @param {string} password Used to generate a key to encrypt the data
|
||||
* @param {Object} dataObject Data to encrypt
|
||||
* @returns {Promise<string>} Promise resolving to an object with ciphertext
|
||||
*/
|
||||
encrypt (password, dataObject) {
|
||||
var salt = this._generateSalt()
|
||||
return this._keyFromPassword(password, salt)
|
||||
.then(function (key) {
|
||||
var data = JSON.stringify(dataObject)
|
||||
var dataBuffer = Unibabel.utf8ToBuffer(data)
|
||||
var vector = global.crypto.getRandomValues(new Uint8Array(16))
|
||||
var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
|
||||
|
||||
var buffer = new Uint8Array(resultbuffer)
|
||||
var vectorStr = Unibabel.bufferToBase64(vector)
|
||||
var vaultStr = Unibabel.bufferToBase64(buffer)
|
||||
return JSON.stringify({
|
||||
data: vaultStr,
|
||||
iv: vectorStr,
|
||||
salt: salt,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts an arbitrary object from ciphertext
|
||||
*
|
||||
* @param {string} password Used to generate a key to decrypt the data
|
||||
* @param {string} text Ciphertext of an encrypted object
|
||||
* @returns {Promise<Object>} Promise resolving to copy of decrypted object
|
||||
*/
|
||||
decrypt (password, text) {
|
||||
const payload = JSON.parse(text)
|
||||
const salt = payload.salt
|
||||
return this._keyFromPassword(password, salt)
|
||||
.then(function (key) {
|
||||
const encryptedData = Unibabel.base64ToBuffer(payload.data)
|
||||
const vector = Unibabel.base64ToBuffer(payload.iv)
|
||||
return new Promise((resolve, reject) => {
|
||||
var result
|
||||
try {
|
||||
result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector)
|
||||
} catch (err) {
|
||||
return reject(new Error('Incorrect password'))
|
||||
}
|
||||
const decryptedData = new Uint8Array(result)
|
||||
const decryptedStr = Unibabel.bufferToUtf8(decryptedData)
|
||||
const decryptedObj = JSON.parse(decryptedStr)
|
||||
resolve(decryptedObj)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a cryptographic key using a password
|
||||
*
|
||||
* @private
|
||||
* @param {string} password Password used to unlock a cryptographic key
|
||||
* @param {string} salt Random base64 data
|
||||
* @returns {Promise<Object>} Promise resolving to a derived key
|
||||
*/
|
||||
_keyFromPassword (password, salt) {
|
||||
|
||||
var passBuffer = Unibabel.utf8ToBuffer(password)
|
||||
var saltBuffer = Unibabel.base64ToBuffer(salt)
|
||||
return new Promise((resolve) => {
|
||||
var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000)
|
||||
resolve(key)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random base64 encoded data
|
||||
*
|
||||
* @private
|
||||
* @returns {string} Randomized base64 encoded data
|
||||
*/
|
||||
_generateSalt (byteCount = 32) {
|
||||
var view = new Uint8Array(byteCount)
|
||||
global.crypto.getRandomValues(view)
|
||||
var b64encoded = btoa(String.fromCharCode.apply(null, view))
|
||||
return b64encoded
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EdgeEncryptor
|
|
@ -1,7 +1,7 @@
|
|||
const extension = require('extensionizer')
|
||||
const height = 620
|
||||
const width = 360
|
||||
import ExtensionPlatform from '../platforms/extension'
|
||||
|
||||
const NOTIFICATION_HEIGHT = 620
|
||||
const NOTIFICATION_WIDTH = 360
|
||||
|
||||
class NotificationManager {
|
||||
|
||||
|
@ -12,47 +12,45 @@ class NotificationManager {
|
|||
*
|
||||
*/
|
||||
|
||||
constructor () {
|
||||
this.platform = new ExtensionPlatform()
|
||||
}
|
||||
|
||||
/**
|
||||
* Either brings an existing MetaMask notification window into focus, or creates a new notification window. New
|
||||
* notification windows are given a 'popup' type.
|
||||
*
|
||||
*/
|
||||
showPopup () {
|
||||
this._getPopup((err, popup) => {
|
||||
if (err) throw err
|
||||
async showPopup () {
|
||||
const popup = await this._getPopup()
|
||||
|
||||
// Bring focus to chrome popup
|
||||
if (popup) {
|
||||
// bring focus to existing chrome popup
|
||||
extension.windows.update(popup.id, { focused: true })
|
||||
} else {
|
||||
const cb = (currentPopup) => {
|
||||
this._popupId = currentPopup.id
|
||||
extension.windows.update(currentPopup.id, { focused: true })
|
||||
}
|
||||
// create new notification popup
|
||||
const creation = extension.windows.create({
|
||||
url: 'notification.html',
|
||||
type: 'popup',
|
||||
width,
|
||||
height,
|
||||
}, cb)
|
||||
creation && creation.then && creation.then(cb)
|
||||
}
|
||||
})
|
||||
// Bring focus to chrome popup
|
||||
if (popup) {
|
||||
// bring focus to existing chrome popup
|
||||
await this.platform.focusWindow(popup.id)
|
||||
} else {
|
||||
|
||||
// create new notification popup
|
||||
const popupWindow = await this.platform.openWindow({
|
||||
url: 'notification.html',
|
||||
type: 'popup',
|
||||
width: NOTIFICATION_WIDTH,
|
||||
height: NOTIFICATION_HEIGHT,
|
||||
})
|
||||
this._popupId = popupWindow.id
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a MetaMask notification if it window exists.
|
||||
*
|
||||
*/
|
||||
closePopup () {
|
||||
// closes notification popup
|
||||
this._getPopup((err, popup) => {
|
||||
if (err) throw err
|
||||
if (!popup) return
|
||||
extension.windows.remove(popup.id, console.error)
|
||||
})
|
||||
async closePopup () {
|
||||
const popup = this._getPopup()
|
||||
if (!popup) {
|
||||
return
|
||||
}
|
||||
await this.platform.removeWindow(popup.id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,39 +58,19 @@ class NotificationManager {
|
|||
* type 'popup')
|
||||
*
|
||||
* @private
|
||||
* @param {Function} cb A node style callback that to whcih the found notification window will be passed.
|
||||
* @param {Function} cb - A node style callback that to whcih the found notification window will be passed.
|
||||
*
|
||||
*/
|
||||
_getPopup (cb) {
|
||||
this._getWindows((err, windows) => {
|
||||
if (err) throw err
|
||||
cb(null, this._getPopupIn(windows))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all open MetaMask windows.
|
||||
*
|
||||
* @private
|
||||
* @param {Function} cb A node style callback that to which the windows will be passed.
|
||||
*
|
||||
*/
|
||||
_getWindows (cb) {
|
||||
// Ignore in test environment
|
||||
if (!extension.windows) {
|
||||
return cb()
|
||||
}
|
||||
|
||||
extension.windows.getAll({}, (windows) => {
|
||||
cb(null, windows)
|
||||
})
|
||||
async _getPopup () {
|
||||
const windows = await this.platform.getAllWindows()
|
||||
return this._getPopupIn(windows)
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of windows, returns the 'popup' that has been opened by MetaMask, or null if no such window exists.
|
||||
*
|
||||
* @private
|
||||
* @param {array} windows An array of objects containing data about the open MetaMask extension windows.
|
||||
* @param {array} windows - An array of objects containing data about the open MetaMask extension windows.
|
||||
*
|
||||
*/
|
||||
_getPopupIn (windows) {
|
||||
|
@ -104,4 +82,4 @@ class NotificationManager {
|
|||
|
||||
}
|
||||
|
||||
module.exports = NotificationManager
|
||||
export default NotificationManager
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
module.exports = setupMetamaskMeshMetrics
|
||||
|
||||
/**
|
||||
* Injects an iframe into the current document for testing
|
||||
*/
|
||||
function setupMetamaskMeshMetrics () {
|
||||
const testingContainer = document.createElement('iframe')
|
||||
testingContainer.src = 'https://metamask.github.io/mesh-testing/'
|
||||
console.log('Injecting Nifty Wallet Mesh testing client')
|
||||
document.head.appendChild(testingContainer)
|
||||
}
|
|
@ -6,6 +6,7 @@ const {
|
|||
ENVIRONMENT_TYPE_POPUP,
|
||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
||||
ENVIRONMENT_TYPE_FULLSCREEN,
|
||||
ENVIRONMENT_TYPE_BACKGROUND,
|
||||
PLATFORM_FIREFOX,
|
||||
PLATFORM_OPERA,
|
||||
PLATFORM_CHROME,
|
||||
|
@ -13,17 +14,6 @@ const {
|
|||
PLATFORM_BRAVE,
|
||||
} = require('./enums')
|
||||
|
||||
/**
|
||||
* Generates an example stack trace
|
||||
*
|
||||
* @returns {string} A stack trace
|
||||
*
|
||||
*/
|
||||
function getStack () {
|
||||
const stack = new Error('Stack trace generator - not an error').stack
|
||||
return stack
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the window type through which the app is being viewed.
|
||||
* - 'popup' refers to the extension opened through the browser app icon (in top right corner in chrome and firefox)
|
||||
|
@ -34,12 +24,15 @@ function getStack () {
|
|||
*
|
||||
*/
|
||||
const getEnvironmentType = (url = window.location.href) => {
|
||||
if (url.match(/popup.html(?:#.*)*$/)) {
|
||||
const parsedUrl = new URL(url)
|
||||
if (parsedUrl.pathname === '/popup.html') {
|
||||
return ENVIRONMENT_TYPE_POPUP
|
||||
} else if (url.match(/home.html(?:\?.+)*$/) || url.match(/home.html(?:#.*)*$/)) {
|
||||
} else if (['/home.html', '/phishing.html'].includes(parsedUrl.pathname)) {
|
||||
return ENVIRONMENT_TYPE_FULLSCREEN
|
||||
} else {
|
||||
} else if (parsedUrl.pathname === '/notification.html') {
|
||||
return ENVIRONMENT_TYPE_NOTIFICATION
|
||||
} else {
|
||||
return ENVIRONMENT_TYPE_BACKGROUND
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +168,6 @@ module.exports = {
|
|||
removeListeners,
|
||||
applyListeners,
|
||||
getPlatform,
|
||||
getStack,
|
||||
getEnvironmentType,
|
||||
sufficientBalance,
|
||||
hexToBn,
|
||||
|
|
|
@ -111,7 +111,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||
this.preferencesController = new PreferencesController({
|
||||
initState: initState.PreferencesController,
|
||||
initLangCode: opts.initLangCode,
|
||||
showWatchAssetUi: opts.showWatchAssetUi,
|
||||
openPopup: opts.openPopup,
|
||||
network: this.networkController,
|
||||
})
|
||||
|
||||
|
@ -1893,7 +1893,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||
resolve(gasPrice)
|
||||
}
|
||||
} else if (isRSK) {
|
||||
gasPrice = this.getGasPriceFromLastBlockRSK(networkId)
|
||||
gasPrice = this.getGasPriceFromLastBlockRSK()
|
||||
resolve(gasPrice)
|
||||
} else {
|
||||
gasPrice = this.getGasPriceFromBlocks(networkId)
|
||||
|
@ -1944,19 +1944,17 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||
* Related issue: https://github.com/poanetwork/nifty-wallet/issues/301
|
||||
* @returns {string} A hex representation of the suggested wei gas price.
|
||||
*/
|
||||
getGasPriceFromLastBlockRSK (networkId) {
|
||||
getGasPriceFromLastBlockRSK () {
|
||||
const { recentBlocksController } = this
|
||||
const { recentBlocks } = recentBlocksController.store.getState()
|
||||
|
||||
const recentBlock = recentBlocks
|
||||
.sort((block1, block2) => block1.number - block2.number)[recentBlocks.length - 1]
|
||||
|
||||
const gasPrice = recentBlock && recentBlock.minimumGasPrice
|
||||
const gasPrice = recentBlock && recentBlock.minimumGasPrice && recentBlock.minimumGasPrice.toString()
|
||||
|
||||
const gasPriceInt = parseInt(gasPrice, 10)
|
||||
|
||||
if (gasPriceInt !== 0) {
|
||||
return '0x' + gasPriceInt.toString(16)
|
||||
if (gasPrice !== '0x' && gasPrice !== '0x0' && gasPrice !== '') {
|
||||
return gasPrice
|
||||
} else {
|
||||
return '0x' + GWEI_BN.toString(16)
|
||||
}
|
||||
|
|
|
@ -12,8 +12,64 @@ class ExtensionPlatform {
|
|||
extension.runtime.reload()
|
||||
}
|
||||
|
||||
openWindow ({ url }) {
|
||||
extension.tabs.create({ url })
|
||||
openTab (options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
extension.tabs.create(options, (newTab) => {
|
||||
const error = checkForError()
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve(newTab)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
openWindow (options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
extension.windows.create(options, (newWindow) => {
|
||||
const error = checkForError()
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve(newWindow)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
closeWindow (windowId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
extension.windows.remove(windowId, () => {
|
||||
const error = checkForError()
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
focusWindow (windowId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
extension.windows.update(windowId, { focused: true }, () => {
|
||||
const error = checkForError()
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getLastFocusedWindow () {
|
||||
return new Promise((resolve, reject) => {
|
||||
extension.windows.getLastFocused((windowObject) => {
|
||||
const error = checkForError()
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve(windowObject)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
closeCurrentWindow () {
|
||||
|
@ -22,27 +78,6 @@ class ExtensionPlatform {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all notifications windows, when action is confirmed in popup
|
||||
* or closes notification window itself, when action is confirmed from it
|
||||
*/
|
||||
closeNotificationWindow () {
|
||||
return extension.windows.getCurrent((curWindowsDetails) => {
|
||||
if (curWindowsDetails.type === 'popup') {
|
||||
return extension.windows.remove(curWindowsDetails.id)
|
||||
} else {
|
||||
extension.windows.getAll((windowsDetails) => {
|
||||
const windowsDetailsFiltered = windowsDetails.filter((windowDetails) => windowDetails.id !== curWindowsDetails.id)
|
||||
return windowsDetailsFiltered.forEach((windowDetails) => {
|
||||
if (windowDetails.type === 'popup') {
|
||||
extension.windows.remove(windowDetails.id)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getVersion () {
|
||||
return extension.runtime.getManifest().version
|
||||
}
|
||||
|
@ -57,7 +92,7 @@ class ExtensionPlatform {
|
|||
if (route) {
|
||||
extensionURL += `#${route}`
|
||||
}
|
||||
this.openWindow({ url: extensionURL })
|
||||
this.openTab({ url: extensionURL })
|
||||
if (getEnvironmentType() !== ENVIRONMENT_TYPE_BACKGROUND) {
|
||||
window.close()
|
||||
}
|
||||
|
@ -86,6 +121,30 @@ class ExtensionPlatform {
|
|||
}
|
||||
}
|
||||
|
||||
getAllWindows () {
|
||||
return new Promise((resolve, reject) => {
|
||||
extension.windows.getAll((windows) => {
|
||||
const error = checkForError()
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve(windows)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getActiveTabs () {
|
||||
return new Promise((resolve, reject) => {
|
||||
extension.tabs.query({ active: true }, (tabs) => {
|
||||
const error = checkForError()
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
return resolve(tabs)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
currentTab () {
|
||||
return new Promise((resolve, reject) => {
|
||||
extension.tabs.getCurrent((tab) => {
|
||||
|
|
|
@ -32,7 +32,7 @@ function initializePopup ({ container, connectionStream }, cb) {
|
|||
function connectToAccountManager (connectionStream, cb) {
|
||||
// setup communication with background
|
||||
// setup multiplexing
|
||||
var mx = setupMultiplex(connectionStream)
|
||||
const mx = setupMultiplex(connectionStream)
|
||||
// connect features
|
||||
setupControllerConnection(mx.createStream('controller'), cb)
|
||||
setupWeb3Connection(mx.createStream('provider'))
|
||||
|
@ -44,7 +44,7 @@ function connectToAccountManager (connectionStream, cb) {
|
|||
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
|
||||
*/
|
||||
function setupWeb3Connection (connectionStream) {
|
||||
var providerStream = new StreamProvider()
|
||||
const providerStream = new StreamProvider()
|
||||
providerStream.pipe(connectionStream).pipe(providerStream)
|
||||
connectionStream.on('error', console.error.bind(console))
|
||||
providerStream.on('error', console.error.bind(console))
|
||||
|
@ -62,8 +62,8 @@ function setupWeb3Connection (connectionStream) {
|
|||
function setupControllerConnection (connectionStream, cb) {
|
||||
// this is a really sneaky way of adding EventEmitter api
|
||||
// to a bi-directional dnode instance
|
||||
var eventEmitter = new EventEmitter()
|
||||
var accountManagerDnode = Dnode({
|
||||
const eventEmitter = new EventEmitter()
|
||||
const accountManagerDnode = Dnode({
|
||||
sendUpdate: function (state) {
|
||||
eventEmitter.emit('update', state)
|
||||
},
|
||||
|
|
|
@ -3,11 +3,8 @@ const OldMetaMaskUiCss = require('../../old-ui/css')
|
|||
const startPopup = require('./popup-core')
|
||||
const PortStream = require('extension-port-stream')
|
||||
const { getEnvironmentType } = require('./lib/util')
|
||||
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('./lib/enums')
|
||||
import extension from 'extensionizer'
|
||||
const ExtensionPlatform = require('./platforms/extension')
|
||||
const NotificationManager = require('./lib/notification-manager')
|
||||
const notificationManager = new NotificationManager()
|
||||
const setupRaven = require('./lib/setupRaven')
|
||||
const log = require('loglevel')
|
||||
|
||||
|
@ -29,7 +26,6 @@ async function start () {
|
|||
// identify window type (popup, notification)
|
||||
const windowType = getEnvironmentType(window.location.href)
|
||||
global.METAMASK_UI_TYPE = windowType
|
||||
closePopupIfOpen(windowType)
|
||||
|
||||
// setup stream to background
|
||||
const extensionPort = extension.runtime.connect({ name: windowType })
|
||||
|
@ -51,13 +47,6 @@ async function start () {
|
|||
})
|
||||
|
||||
|
||||
function closePopupIfOpen (windowType) {
|
||||
if (windowType !== ENVIRONMENT_TYPE_NOTIFICATION) {
|
||||
// should close only chrome popup
|
||||
notificationManager.closePopup()
|
||||
}
|
||||
}
|
||||
|
||||
function displayCriticalError (err) {
|
||||
container.innerHTML = '<div class="critical-error">The Nifty Wallet app failed to load: please open and close Nifty Wallet again to restart.</div>'
|
||||
container.style.height = '80px'
|
||||
|
|
|
@ -73,11 +73,11 @@ createCopyTasks('contractImagesPOA', {
|
|||
destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractPOA`),
|
||||
})
|
||||
createCopyTasks('contractImagesRSK', {
|
||||
source: './node_modules/rsk-contract-metadata/images/',
|
||||
source: './node_modules/@rsksmart/rsk-contract-metadata/images/',
|
||||
destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractRSK`),
|
||||
})
|
||||
createCopyTasks('contractImagesRSKTest', {
|
||||
source: './node_modules/rsk-test-contract-metadata/images/',
|
||||
source: './node_modules/@rsksmart/rsk-testnet-contract-metadata/images/',
|
||||
destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractRSKTest`),
|
||||
})
|
||||
createCopyTasks('fonts', {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const connect = require('react-redux').connect
|
||||
import { connect } from 'react-redux'
|
||||
const actions = require('../../../../ui/app/actions')
|
||||
const FileInput = require('react-simple-file-input').default
|
||||
const PropTypes = require('prop-types')
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
class JsonImportSubview extends Component {
|
||||
constructor (props) {
|
||||
|
@ -75,31 +75,26 @@ class JsonImportSubview extends Component {
|
|||
}
|
||||
|
||||
createNewKeychain () {
|
||||
const { displayWarning, importNewJsonAccount } = this.props
|
||||
const { fileContents } = this.state
|
||||
|
||||
if (!fileContents) {
|
||||
const message = 'You must select a file to import.'
|
||||
return this.props.displayWarning(message)
|
||||
return displayWarning(message)
|
||||
}
|
||||
|
||||
const passwordInput = document.getElementById('json-password-box')
|
||||
const password = passwordInput.value
|
||||
|
||||
if (!password) {
|
||||
const message = 'You must enter a password for the selected file.'
|
||||
return this.props.displayWarning(message)
|
||||
}
|
||||
|
||||
this.props.importNewAccount([ fileContents, password ])
|
||||
// JS runtime requires caught rejections but failures are handled by Redux
|
||||
.catch()
|
||||
importNewJsonAccount([ fileContents, password ])
|
||||
.catch((err) => err && displayWarning(err.message || err))
|
||||
}
|
||||
}
|
||||
|
||||
JsonImportSubview.propTypes = {
|
||||
error: PropTypes.string,
|
||||
displayWarning: PropTypes.func,
|
||||
importNewAccount: PropTypes.func,
|
||||
importNewJsonAccount: PropTypes.func,
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
|
@ -112,7 +107,7 @@ const mapDispatchToProps = dispatch => {
|
|||
return {
|
||||
goHome: () => dispatch(actions.goHome()),
|
||||
displayWarning: warning => dispatch(actions.displayWarning(warning)),
|
||||
importNewAccount: options => dispatch(actions.importNewAccount('JSON File', options)),
|
||||
importNewJsonAccount: options => dispatch(actions.importNewAccount('JSON File', options)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -368,9 +368,9 @@ export default class AddTokenScreen extends Component {
|
|||
}
|
||||
|
||||
const symbolLen = symbol.trim().length
|
||||
const validSymbol = symbolLen > 0 && symbolLen < 10
|
||||
const validSymbol = symbolLen > 0 && symbolLen < 23
|
||||
if (!validSymbol) {
|
||||
msg += 'Symbol must be between 0 and 10 characters.'
|
||||
msg += 'Symbol must be between 0 and 23 characters.'
|
||||
}
|
||||
|
||||
let ownAddress = identitiesList.includes(standardAddress)
|
||||
|
@ -527,8 +527,8 @@ export default class AddTokenScreen extends Component {
|
|||
const symbolLength = customSymbol.length
|
||||
let customSymbolError = null
|
||||
|
||||
if (symbolLength <= 0 || symbolLength >= 10) {
|
||||
customSymbolError = 'Symbol must be between 0 and 10 characters.' /* this.context.t('symbolBetweenZeroTen')*/
|
||||
if (symbolLength <= 0 || symbolLength >= 23) {
|
||||
customSymbolError = 'Symbol must be between 0 and 23 characters.' /* this.context.t('symbolBetweenZeroTen')*/
|
||||
}
|
||||
|
||||
this.setState({ customSymbol, customSymbolError })
|
||||
|
|
|
@ -2,8 +2,8 @@ import React, { Component } from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
import contractMapETH from 'eth-contract-metadata'
|
||||
import contractMapPOA from 'poa-contract-metadata'
|
||||
import contractMapRSK from 'rsk-contract-metadata'
|
||||
import contractMapRSKTest from 'rsk-test-contract-metadata'
|
||||
import contractMapRSK from '@rsksmart/rsk-contract-metadata'
|
||||
import contractMapRSKTest from '@rsksmart/rsk-testnet-contract-metadata'
|
||||
import Fuse from 'fuse.js'
|
||||
import InputAdornment from '@material-ui/core/InputAdornment'
|
||||
import TextField from '../../../../../ui/app/components/text-field'
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const Component = require('react').Component
|
||||
import { Component } from 'react'
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const extend = require('xtend')
|
||||
import ethUtil from 'ethereumjs-util'
|
||||
import extend from 'xtend'
|
||||
|
||||
module.exports = BinaryRenderer
|
||||
|
||||
|
@ -14,7 +14,7 @@ function BinaryRenderer () {
|
|||
BinaryRenderer.prototype.render = function () {
|
||||
const props = this.props
|
||||
const { value, style } = props
|
||||
const text = this.hexToText(value)
|
||||
const message = this.msgHexToText(value)
|
||||
|
||||
const defaultStyle = extend({
|
||||
width: '100%',
|
||||
|
@ -30,16 +30,16 @@ BinaryRenderer.prototype.render = function () {
|
|||
h('textarea.font-small', {
|
||||
readOnly: true,
|
||||
style: defaultStyle,
|
||||
defaultValue: text,
|
||||
defaultValue: message,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
BinaryRenderer.prototype.hexToText = function (hex) {
|
||||
BinaryRenderer.prototype.msgHexToText = (hex) => {
|
||||
try {
|
||||
const stripped = ethUtil.stripHexPrefix(hex)
|
||||
const buff = Buffer.from(stripped, 'hex')
|
||||
return buff.toString('utf8')
|
||||
return buff.length === 32 ? hex : buff.toString('utf8')
|
||||
} catch (e) {
|
||||
return hex
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ class ConnectScreen extends Component {
|
|||
<Button
|
||||
type="primary"
|
||||
large={true}
|
||||
onClick={() => global.platform.openWindow({
|
||||
onClick={() => global.platform.openTab({
|
||||
url: 'https://google.com/chrome',
|
||||
})}
|
||||
>Download Google Chrome</Button>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,23 +1,220 @@
|
|||
const inherits = require('util').inherits
|
||||
const PersistentForm = require('../../../lib/persistent-form')
|
||||
const h = require('react-hyperscript')
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('../../../../ui/app/actions')
|
||||
const {
|
||||
import React from 'react'
|
||||
import PersistentForm from '../../../lib/persistent-form'
|
||||
import { connect } from 'react-redux'
|
||||
import actions from '../../../../ui/app/actions'
|
||||
import {
|
||||
numericBalance,
|
||||
isHex,
|
||||
normalizeEthStringToWei,
|
||||
isInvalidChecksumAddress,
|
||||
isValidAddress,
|
||||
} = require('../../util')
|
||||
const EnsInput = require('../ens-input')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
} from '../../util'
|
||||
import EnsInput from '../ens-input'
|
||||
import ethUtil from 'ethereumjs-util'
|
||||
import SendProfile from './send-profile'
|
||||
import SendHeader from './send-header'
|
||||
import ErrorComponent from '../error'
|
||||
import { getMetaMaskAccounts } from '../../../../ui/app/selectors'
|
||||
import * as Toast from '../toast'
|
||||
module.exports = connect(mapStateToProps)(SendTransactionScreen)
|
||||
|
||||
const optionalDataLabelStyle = {
|
||||
background: '#ffffff',
|
||||
color: '#333333',
|
||||
marginTop: '16px',
|
||||
marginBottom: '16px',
|
||||
}
|
||||
const optionalDataValueStyle = {
|
||||
width: '100%',
|
||||
resize: 'none',
|
||||
}
|
||||
|
||||
class SendTransactionScreen extends PersistentForm {
|
||||
render () {
|
||||
this.persistentFormParentId = 'send-tx-form'
|
||||
|
||||
const props = this.props
|
||||
const {
|
||||
network,
|
||||
identities,
|
||||
addressBook,
|
||||
error,
|
||||
} = props
|
||||
|
||||
return (
|
||||
<div className="send-screen flex-column flex-grow">
|
||||
<Toast.ToastComponent type={Toast.TOAST_TYPE_ERROR} />
|
||||
<SendProfile/>
|
||||
|
||||
<SendHeader
|
||||
title= "Send Transaction"
|
||||
/>
|
||||
|
||||
<ErrorComponent
|
||||
error={error}
|
||||
/>
|
||||
|
||||
<section className="flex-row flex-center">
|
||||
<EnsInput
|
||||
name="address"
|
||||
placeholder="Recipient Address"
|
||||
onChange={this.recipientDidChange.bind(this)}
|
||||
network={network}
|
||||
identities={identities}
|
||||
addressBook={addressBook}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className="flex-row flex-center">
|
||||
|
||||
<input className="large-input"
|
||||
name= "amount"
|
||||
placeholder= "Amount"
|
||||
type= "number"
|
||||
style= {{
|
||||
marginRight: '6px',
|
||||
}}
|
||||
dataset={{
|
||||
persistentFormid: 'tx-amount',
|
||||
}}
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={this.onSubmit.bind(this)}>
|
||||
Next
|
||||
</button>
|
||||
|
||||
</section>
|
||||
|
||||
<h3 className="flex-center"
|
||||
style={optionalDataLabelStyle}
|
||||
>
|
||||
Transaction Data (optional)
|
||||
</h3>
|
||||
|
||||
<section className="flex-column flex-center">
|
||||
<input className="large-input"
|
||||
name= "txData"
|
||||
placeholder= "e.g. 0x01234"
|
||||
style={optionalDataValueStyle}
|
||||
dataset={{
|
||||
persistentFormid: 'tx-data',
|
||||
}}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<h3 className="flex-center"
|
||||
style={optionalDataLabelStyle}
|
||||
>
|
||||
Custom nonce (optional)
|
||||
</h3>
|
||||
|
||||
<section className="flex-column flex-center">
|
||||
<input className="large-input"
|
||||
name= "txCustomNonce"
|
||||
type= "number"
|
||||
placeholder= "e.g. 42"
|
||||
style={optionalDataValueStyle}
|
||||
dataset={{
|
||||
persistentFormid: 'tx-custom-nonce',
|
||||
}}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.props.dispatch(actions.displayWarning(''))
|
||||
}
|
||||
|
||||
navigateToAccounts (event) {
|
||||
event.stopPropagation()
|
||||
this.props.dispatch(actions.showAccountsPage())
|
||||
}
|
||||
|
||||
recipientDidChange (recipient, nickname) {
|
||||
this.setState({
|
||||
recipient: recipient,
|
||||
nickname: nickname,
|
||||
})
|
||||
}
|
||||
|
||||
onSubmit () {
|
||||
const state = this.state || {}
|
||||
let recipient = state.recipient || document.querySelector('input[name="address"]').value.replace(/^[.\s]+|[.\s]+$/g, '')
|
||||
let nickname = state.nickname || ' '
|
||||
if (typeof recipient === 'object') {
|
||||
if (recipient.toAddress) {
|
||||
recipient = recipient.toAddress
|
||||
}
|
||||
if (recipient.nickname) {
|
||||
nickname = recipient.nickname
|
||||
}
|
||||
}
|
||||
const input = document.querySelector('input[name="amount"]').value
|
||||
const parts = input.split('.')
|
||||
|
||||
let message
|
||||
|
||||
if (isNaN(input) || input === '') {
|
||||
message = 'Invalid ether value.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if (parts[1]) {
|
||||
const decimal = parts[1]
|
||||
if (decimal.length > 18) {
|
||||
message = 'Ether amount is too precise.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
}
|
||||
|
||||
const value = normalizeEthStringToWei(input)
|
||||
const txData = document.querySelector('input[name="txData"]').value
|
||||
const txCustomNonce = document.querySelector('input[name="txCustomNonce"]').value
|
||||
const balance = this.props.balance
|
||||
|
||||
if (value.gt(balance)) {
|
||||
message = 'Insufficient funds.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if (input < 0) {
|
||||
message = 'Can not send negative amounts of ETH.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if ((isInvalidChecksumAddress(recipient, this.props.network))) {
|
||||
message = 'Recipient address checksum is invalid.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if ((!isValidAddress(recipient, this.props.network) && !txData) || (!recipient && !txData)) {
|
||||
message = 'Recipient address is invalid.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if (!isHex(ethUtil.stripHexPrefix(txData)) && txData) {
|
||||
message = 'Transaction data must be hex string.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
this.props.dispatch(actions.hideWarning())
|
||||
|
||||
this.props.dispatch(actions.addToAddressBook(recipient, nickname))
|
||||
|
||||
const txParams = {
|
||||
from: this.props.address,
|
||||
value: '0x' + value.toString(16),
|
||||
}
|
||||
|
||||
if (recipient) txParams.to = ethUtil.addHexPrefix(recipient)
|
||||
if (txData) txParams.data = txData
|
||||
if (txCustomNonce) txParams.nonce = '0x' + parseInt(txCustomNonce, 10).toString(16)
|
||||
|
||||
this.props.dispatch(actions.signTx(txParams))
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const accounts = getMetaMaskAccounts(state)
|
||||
|
@ -37,200 +234,4 @@ function mapStateToProps (state) {
|
|||
return result
|
||||
}
|
||||
|
||||
inherits(SendTransactionScreen, PersistentForm)
|
||||
function SendTransactionScreen () {
|
||||
PersistentForm.call(this)
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.render = function () {
|
||||
this.persistentFormParentId = 'send-tx-form'
|
||||
|
||||
const props = this.props
|
||||
const {
|
||||
network,
|
||||
identities,
|
||||
addressBook,
|
||||
error,
|
||||
} = props
|
||||
|
||||
return (
|
||||
|
||||
h('.send-screen.flex-column.flex-grow', [
|
||||
|
||||
h(Toast.ToastComponent, {
|
||||
type: Toast.TOAST_TYPE_ERROR,
|
||||
}),
|
||||
|
||||
//
|
||||
// Sender Profile
|
||||
//
|
||||
|
||||
h(SendProfile),
|
||||
|
||||
//
|
||||
// Send Header
|
||||
//
|
||||
|
||||
h(SendHeader, {
|
||||
title: 'Send Transaction',
|
||||
}),
|
||||
|
||||
// error message
|
||||
h(ErrorComponent, {
|
||||
error,
|
||||
}),
|
||||
|
||||
// 'to' field
|
||||
h('section.flex-row.flex-center', [
|
||||
h(EnsInput, {
|
||||
name: 'address',
|
||||
placeholder: 'Recipient Address',
|
||||
onChange: this.recipientDidChange.bind(this),
|
||||
network,
|
||||
identities,
|
||||
addressBook,
|
||||
}),
|
||||
]),
|
||||
|
||||
// 'amount' and send button
|
||||
h('section.flex-row.flex-center', [
|
||||
|
||||
h('input.large-input', {
|
||||
name: 'amount',
|
||||
placeholder: 'Amount',
|
||||
type: 'number',
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
dataset: {
|
||||
persistentFormid: 'tx-amount',
|
||||
},
|
||||
}),
|
||||
|
||||
h('button', {
|
||||
onClick: this.onSubmit.bind(this),
|
||||
}, 'Next'),
|
||||
|
||||
]),
|
||||
|
||||
//
|
||||
// Optional Fields
|
||||
//
|
||||
h('h3.flex-center', {
|
||||
style: {
|
||||
background: '#ffffff',
|
||||
color: '#333333',
|
||||
marginTop: '16px',
|
||||
marginBottom: '16px',
|
||||
},
|
||||
}, [
|
||||
'Transaction Data (optional)',
|
||||
]),
|
||||
|
||||
// 'data' field
|
||||
h('section.flex-column.flex-center', [
|
||||
h('input.large-input', {
|
||||
name: 'txData',
|
||||
placeholder: '0x01234',
|
||||
style: {
|
||||
width: '100%',
|
||||
resize: 'none',
|
||||
},
|
||||
dataset: {
|
||||
persistentFormid: 'tx-data',
|
||||
},
|
||||
}),
|
||||
]),
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.componentWillUnmount = function () {
|
||||
this.props.dispatch(actions.displayWarning(''))
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.navigateToAccounts = function (event) {
|
||||
event.stopPropagation()
|
||||
this.props.dispatch(actions.showAccountsPage())
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.recipientDidChange = function (recipient, nickname) {
|
||||
this.setState({
|
||||
recipient: recipient,
|
||||
nickname: nickname,
|
||||
})
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.onSubmit = function () {
|
||||
const state = this.state || {}
|
||||
let recipient = state.recipient || document.querySelector('input[name="address"]').value.replace(/^[.\s]+|[.\s]+$/g, '')
|
||||
let nickname = state.nickname || ' '
|
||||
if (typeof recipient === 'object') {
|
||||
if (recipient.toAddress) {
|
||||
recipient = recipient.toAddress
|
||||
}
|
||||
if (recipient.nickname) {
|
||||
nickname = recipient.nickname
|
||||
}
|
||||
}
|
||||
const input = document.querySelector('input[name="amount"]').value
|
||||
const parts = input.split('.')
|
||||
|
||||
let message
|
||||
|
||||
if (isNaN(input) || input === '') {
|
||||
message = 'Invalid ether value.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if (parts[1]) {
|
||||
const decimal = parts[1]
|
||||
if (decimal.length > 18) {
|
||||
message = 'Ether amount is too precise.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
}
|
||||
|
||||
const value = normalizeEthStringToWei(input)
|
||||
const txData = document.querySelector('input[name="txData"]').value
|
||||
const balance = this.props.balance
|
||||
|
||||
if (value.gt(balance)) {
|
||||
message = 'Insufficient funds.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if (input < 0) {
|
||||
message = 'Can not send negative amounts of ETH.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if ((isInvalidChecksumAddress(recipient, this.props.network))) {
|
||||
message = 'Recipient address checksum is invalid.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if ((!isValidAddress(recipient, this.props.network) && !txData) || (!recipient && !txData)) {
|
||||
message = 'Recipient address is invalid.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
if (!isHex(ethUtil.stripHexPrefix(txData)) && txData) {
|
||||
message = 'Transaction data must be hex string.'
|
||||
return this.props.dispatch(actions.displayWarning(message))
|
||||
}
|
||||
|
||||
this.props.dispatch(actions.hideWarning())
|
||||
|
||||
this.props.dispatch(actions.addToAddressBook(recipient, nickname))
|
||||
|
||||
const txParams = {
|
||||
from: this.props.address,
|
||||
value: '0x' + value.toString(16),
|
||||
}
|
||||
|
||||
if (recipient) txParams.to = ethUtil.addHexPrefix(recipient)
|
||||
if (txData) txParams.data = txData
|
||||
|
||||
this.props.dispatch(actions.signTx(txParams))
|
||||
}
|
||||
module.exports = connect(mapStateToProps)(SendTransactionScreen)
|
||||
|
|
|
@ -212,7 +212,7 @@ ShiftListItem.prototype.renderInfo = function () {
|
|||
paddingLeft: '29px',
|
||||
textAlign: 'left',
|
||||
},
|
||||
onClick: () => global.platform.openWindow({ url }),
|
||||
onClick: () => global.platform.openTab({ url }),
|
||||
}, [
|
||||
h('div', {
|
||||
style: {
|
||||
|
|
|
@ -1,10 +1,146 @@
|
|||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const TokenTracker = require('eth-token-watcher')
|
||||
const connect = require('react-redux').connect
|
||||
import PropTypes from 'prop-types'
|
||||
import TokenTracker from 'eth-token-watcher'
|
||||
import { connect } from 'react-redux'
|
||||
const selectors = require('../../../ui/app/selectors')
|
||||
const log = require('loglevel')
|
||||
import log from 'loglevel'
|
||||
|
||||
class TokenBalance extends Component {
|
||||
static propTypes = {
|
||||
dimStyle: PropTypes.object,
|
||||
valueStyle: PropTypes.object,
|
||||
fontSize: PropTypes.string,
|
||||
token: PropTypes.object,
|
||||
userAddress: PropTypes.string,
|
||||
}
|
||||
|
||||
constructor () {
|
||||
super()
|
||||
this.state = {
|
||||
string: '',
|
||||
symbol: '',
|
||||
isLoading: true,
|
||||
error: null,
|
||||
}
|
||||
Component.call(this)
|
||||
}
|
||||
|
||||
render () {
|
||||
const state = this.state
|
||||
const props = this.props
|
||||
const { string, isLoading } = state
|
||||
|
||||
const valueStyle = props.valueStyle ? props.valueStyle : {
|
||||
color: '#ffffff',
|
||||
width: '100%',
|
||||
fontSize: props.fontSize || '14px',
|
||||
textAlign: 'right',
|
||||
}
|
||||
const dimStyle = props.dimStyle ? props.dimStyle : {
|
||||
color: ' #60db97',
|
||||
fontSize: props.fontSize || '14px',
|
||||
marginLeft: '5px',
|
||||
}
|
||||
|
||||
return isLoading
|
||||
? h('div', '')
|
||||
: h('.flex-row', {
|
||||
style: {
|
||||
alignItems: 'flex-end',
|
||||
lineHeight: '20px',
|
||||
textRendering: 'geometricPrecision',
|
||||
},
|
||||
}, [
|
||||
h('div.hide-text-overflow.token-balance__amount', {
|
||||
style: valueStyle,
|
||||
}, string),
|
||||
h('span.token-balance__symbol', {
|
||||
style: dimStyle,
|
||||
}, this.state.symbol),
|
||||
])
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.createFreshTokenTracker()
|
||||
}
|
||||
|
||||
createFreshTokenTracker () {
|
||||
if (this.tracker) {
|
||||
// Clean up old trackers when refreshing:
|
||||
this.tracker.stop()
|
||||
this.tracker.removeListener('update', this.balanceUpdater)
|
||||
this.tracker.removeListener('error', this.showError)
|
||||
}
|
||||
|
||||
if (!global.ethereumProvider) return
|
||||
const { userAddress, token } = this.props
|
||||
|
||||
this.tracker = new TokenTracker({
|
||||
userAddress,
|
||||
provider: global.ethereumProvider,
|
||||
tokens: [token],
|
||||
pollingInterval: 8000,
|
||||
})
|
||||
|
||||
|
||||
// Set up listener instances for cleaning up
|
||||
this.balanceUpdater = this.updateBalance.bind(this)
|
||||
this.showError = error => {
|
||||
this.setState({ error, isLoading: false })
|
||||
}
|
||||
this.tracker.on('update', this.balanceUpdater)
|
||||
this.tracker.on('error', this.showError)
|
||||
|
||||
this.tracker.updateBalances()
|
||||
.then(() => {
|
||||
this.updateBalance(this.tracker.serialize())
|
||||
})
|
||||
.catch((reason) => {
|
||||
log.error(`Problem updating balances`, reason)
|
||||
this.setState({ isLoading: false })
|
||||
})
|
||||
}
|
||||
|
||||
componentDidUpdate (nextProps) {
|
||||
const {
|
||||
userAddress: oldAddress,
|
||||
token: { address: oldTokenAddress },
|
||||
} = this.props
|
||||
const {
|
||||
userAddress: newAddress,
|
||||
token: { address: newTokenAddress },
|
||||
} = nextProps
|
||||
|
||||
if ((!oldAddress || !newAddress) && (!oldTokenAddress || !newTokenAddress)) return
|
||||
if ((oldAddress === newAddress) && (oldTokenAddress === newTokenAddress)) return
|
||||
|
||||
this.setState({ isLoading: true })
|
||||
this.createFreshTokenTracker()
|
||||
}
|
||||
|
||||
updateBalance (tokens = []) {
|
||||
if (!this.tracker.running) {
|
||||
return
|
||||
}
|
||||
|
||||
const [{ string, symbol }] = tokens
|
||||
|
||||
this.setState({
|
||||
string,
|
||||
symbol,
|
||||
isLoading: false,
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (!this.tracker) return
|
||||
this.tracker.stop()
|
||||
this.tracker.removeListener('update', this.balanceUpdater)
|
||||
this.tracker.removeListener('error', this.showError)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
|
@ -13,131 +149,3 @@ function mapStateToProps (state) {
|
|||
}
|
||||
|
||||
module.exports = connect(mapStateToProps)(TokenBalance)
|
||||
|
||||
|
||||
inherits(TokenBalance, Component)
|
||||
function TokenBalance () {
|
||||
this.state = {
|
||||
string: '',
|
||||
symbol: '',
|
||||
isLoading: true,
|
||||
error: null,
|
||||
}
|
||||
Component.call(this)
|
||||
}
|
||||
|
||||
TokenBalance.prototype.render = function () {
|
||||
const state = this.state
|
||||
const props = this.props
|
||||
const { symbol, string, isLoading } = state
|
||||
const { balanceOnly } = this.props
|
||||
|
||||
const valueStyle = props.valueStyle ? props.valueStyle : {
|
||||
color: '#ffffff',
|
||||
width: '100%',
|
||||
fontSize: props.fontSize || '14px',
|
||||
textAlign: 'right',
|
||||
}
|
||||
const dimStyle = props.dimStyle ? props.dimStyle : {
|
||||
color: ' #60db97',
|
||||
fontSize: props.fontSize || '14px',
|
||||
marginLeft: '5px',
|
||||
}
|
||||
|
||||
return isLoading
|
||||
? h('div', '')
|
||||
: h('.flex-row', {
|
||||
style: {
|
||||
alignItems: 'flex-end',
|
||||
lineHeight: '20px',
|
||||
textRendering: 'geometricPrecision',
|
||||
},
|
||||
}, [
|
||||
h('div.hide-text-overflow.token-balance__amount', {
|
||||
style: valueStyle,
|
||||
}, string),
|
||||
!balanceOnly && h('span.token-balance__symbol', {
|
||||
style: dimStyle,
|
||||
}, symbol),
|
||||
])
|
||||
}
|
||||
|
||||
TokenBalance.prototype.componentDidMount = function () {
|
||||
this.createFreshTokenTracker()
|
||||
}
|
||||
|
||||
TokenBalance.prototype.createFreshTokenTracker = function () {
|
||||
if (this.tracker) {
|
||||
// Clean up old trackers when refreshing:
|
||||
this.tracker.stop()
|
||||
this.tracker.removeListener('update', this.balanceUpdater)
|
||||
this.tracker.removeListener('error', this.showError)
|
||||
}
|
||||
|
||||
if (!global.ethereumProvider) return
|
||||
const { userAddress, token } = this.props
|
||||
|
||||
this.tracker = new TokenTracker({
|
||||
userAddress,
|
||||
provider: global.ethereumProvider,
|
||||
tokens: [token],
|
||||
pollingInterval: 8000,
|
||||
})
|
||||
|
||||
|
||||
// Set up listener instances for cleaning up
|
||||
this.balanceUpdater = this.updateBalance.bind(this)
|
||||
this.showError = error => {
|
||||
this.setState({ error, isLoading: false })
|
||||
}
|
||||
this.tracker.on('update', this.balanceUpdater)
|
||||
this.tracker.on('error', this.showError)
|
||||
|
||||
this.tracker.updateBalances()
|
||||
.then(() => {
|
||||
this.updateBalance(this.tracker.serialize())
|
||||
})
|
||||
.catch((reason) => {
|
||||
log.error(`Problem updating balances`, reason)
|
||||
this.setState({ isLoading: false })
|
||||
})
|
||||
}
|
||||
|
||||
TokenBalance.prototype.componentDidUpdate = function (nextProps) {
|
||||
const {
|
||||
userAddress: oldAddress,
|
||||
token: { address: oldTokenAddress },
|
||||
} = this.props
|
||||
const {
|
||||
userAddress: newAddress,
|
||||
token: { address: newTokenAddress },
|
||||
} = nextProps
|
||||
|
||||
if ((!oldAddress || !newAddress) && (!oldTokenAddress || !newTokenAddress)) return
|
||||
if ((oldAddress === newAddress) && (oldTokenAddress === newTokenAddress)) return
|
||||
|
||||
this.setState({ isLoading: true })
|
||||
this.createFreshTokenTracker()
|
||||
}
|
||||
|
||||
TokenBalance.prototype.updateBalance = function (tokens = []) {
|
||||
if (!this.tracker.running) {
|
||||
return
|
||||
}
|
||||
|
||||
const [{ string, symbol }] = tokens
|
||||
|
||||
this.setState({
|
||||
string,
|
||||
symbol,
|
||||
isLoading: false,
|
||||
})
|
||||
}
|
||||
|
||||
TokenBalance.prototype.componentWillUnmount = function () {
|
||||
if (!this.tracker) return
|
||||
this.tracker.stop()
|
||||
this.tracker.removeListener('update', this.balanceUpdater)
|
||||
this.tracker.removeListener('error', this.showError)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,168 +1,170 @@
|
|||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const Identicon = require('./identicon')
|
||||
const ethNetProps = require('eth-net-props')
|
||||
const Dropdown = require('./dropdown').Dropdown
|
||||
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
||||
const copyToClipboard = require('copy-to-clipboard')
|
||||
const actions = require('../../../ui/app/actions')
|
||||
const connect = require('react-redux').connect
|
||||
const { MAINNET_CODE } = require('../../../app/scripts/controllers/network/enums')
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Identicon from './identicon'
|
||||
import ethNetProps from 'eth-net-props'
|
||||
import { Dropdown, DropdownMenuItem } from './dropdown'
|
||||
import copyToClipboard from 'copy-to-clipboard'
|
||||
import { connect } from 'react-redux'
|
||||
import { countSignificantDecimals, toChecksumAddress } from '../util'
|
||||
import actions from '../../../ui/app/actions'
|
||||
const { MAINNET_CODE } = require('../../../app/scripts/controllers/network/enums')
|
||||
|
||||
const tokenCellDropDownPrefix = 'token-cell_dropdown_'
|
||||
|
||||
inherits(TokenCell, Component)
|
||||
function TokenCell () {
|
||||
Component.call(this)
|
||||
|
||||
this.state = {
|
||||
optionsMenuActive: false,
|
||||
class TokenCell extends Component {
|
||||
static propTypes = {
|
||||
address: PropTypes.string,
|
||||
symbol: PropTypes.string,
|
||||
string: PropTypes.string,
|
||||
network: PropTypes.string,
|
||||
ind: PropTypes.number,
|
||||
showSendTokenPage: PropTypes.func,
|
||||
isLastTokenCell: PropTypes.bool,
|
||||
userAddress: PropTypes.string,
|
||||
menuToTop: PropTypes.bool,
|
||||
removeToken: PropTypes.func,
|
||||
}
|
||||
this.optionsMenuToggleClassName = 'token-dropdown'
|
||||
}
|
||||
|
||||
TokenCell.prototype.render = function () {
|
||||
const { address, symbol, string, network, userAddress, isLastTokenCell, menuToTop, ind } = this.props
|
||||
const { optionsMenuActive } = this.state
|
||||
constructor () {
|
||||
super()
|
||||
|
||||
const tokenBalanceRaw = Number.parseFloat(string)
|
||||
const tokenBalance = tokenBalanceRaw.toFixed(countSignificantDecimals(tokenBalanceRaw, 2))
|
||||
this.state = {
|
||||
optionsMenuActive: false,
|
||||
}
|
||||
this.optionsMenuToggleClassName = 'token-dropdown'
|
||||
}
|
||||
|
||||
return (
|
||||
h(`li#token-cell_${ind}.token-cell`, {
|
||||
style: {
|
||||
cursor: Number(network) === MAINNET_CODE ? 'pointer' : 'default',
|
||||
borderBottom: isLastTokenCell ? 'none' : '1px solid #e2e2e2',
|
||||
padding: '20px 0',
|
||||
margin: '0 30px',
|
||||
},
|
||||
onClick: this.view.bind(this, address, userAddress, network),
|
||||
}, [
|
||||
render () {
|
||||
const { address, symbol, string, network, userAddress, isLastTokenCell, menuToTop, ind } = this.props
|
||||
const { optionsMenuActive } = this.state
|
||||
|
||||
h(Identicon, {
|
||||
diameter: 50,
|
||||
address,
|
||||
network,
|
||||
}),
|
||||
const tokenBalanceRaw = Number.parseFloat(string)
|
||||
const tokenBalance = tokenBalanceRaw.toFixed(countSignificantDecimals(tokenBalanceRaw, 2))
|
||||
|
||||
h('h3', {
|
||||
style: {
|
||||
fontFamily: 'Nunito Bold',
|
||||
fontSize: '14px',
|
||||
},
|
||||
}, `${tokenBalance || 0} ${symbol}`),
|
||||
return (
|
||||
<span
|
||||
id={`token-cell_${ind}`}
|
||||
className="token-cell"
|
||||
style= {{
|
||||
cursor: Number(network) === MAINNET_CODE ? 'pointer' : 'default',
|
||||
borderBottom: isLastTokenCell ? 'none' : '1px solid #e2e2e2',
|
||||
padding: '20px 0',
|
||||
margin: '0 30px',
|
||||
}}
|
||||
key={`token-cell_${ind}`}
|
||||
onClick= {this.view.bind(this, address, userAddress, network)}
|
||||
>
|
||||
<Identicon
|
||||
diameter= {50}
|
||||
address={address}
|
||||
network={network}
|
||||
/>
|
||||
|
||||
h('span', { style: { flex: '1 0 auto' } }),
|
||||
<h3
|
||||
style= {{
|
||||
fontFamily: 'Nunito Bold',
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
{`${tokenBalance || 0} ${symbol}`}
|
||||
</h3>
|
||||
|
||||
h(`div#${tokenCellDropDownPrefix}${ind}.address-dropdown.token-dropdown`,
|
||||
{
|
||||
style: { cursor: 'pointer' },
|
||||
onClick: (event) => {
|
||||
event.stopPropagation()
|
||||
this.setState({
|
||||
optionsMenuActive: !optionsMenuActive,
|
||||
})
|
||||
},
|
||||
},
|
||||
this.renderTokenOptions(menuToTop, ind),
|
||||
),
|
||||
<span
|
||||
style= {{ flex: '1 0 auto' }}
|
||||
/>
|
||||
|
||||
/*
|
||||
h('button', {
|
||||
onClick: this.send.bind(this, address),
|
||||
}, 'SEND'),
|
||||
*/
|
||||
<div
|
||||
id={`${tokenCellDropDownPrefix}${ind}`}
|
||||
className="address-dropdown token-dropdown"
|
||||
style= {{ cursor: 'pointer' }}
|
||||
onClick= {(event) => {
|
||||
event.stopPropagation()
|
||||
this.setState({
|
||||
optionsMenuActive: !optionsMenuActive,
|
||||
})
|
||||
}}
|
||||
>
|
||||
{this.renderTokenOptions(menuToTop, ind)}
|
||||
</div>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
])
|
||||
)
|
||||
}
|
||||
renderTokenOptions (menuToTop, ind) {
|
||||
const { address, symbol, string, network, userAddress, showSendTokenPage } = this.props
|
||||
const { optionsMenuActive } = this.state
|
||||
|
||||
TokenCell.prototype.renderTokenOptions = function (menuToTop, ind) {
|
||||
const { address, symbol, string, network, userAddress, showSendTokenPage } = this.props
|
||||
const { optionsMenuActive } = this.state
|
||||
|
||||
return h(
|
||||
Dropdown,
|
||||
{
|
||||
style: {
|
||||
return (
|
||||
<Dropdown
|
||||
style= {{
|
||||
position: 'relative',
|
||||
marginLeft: menuToTop ? '-273px' : '-263px',
|
||||
minWidth: '180px',
|
||||
marginTop: menuToTop ? '-214px' : '30px',
|
||||
width: '280px',
|
||||
},
|
||||
isOpen: optionsMenuActive,
|
||||
onClickOutside: (event) => {
|
||||
}}
|
||||
isOpen={optionsMenuActive}
|
||||
onClickOutside={(event) => {
|
||||
const { classList, id: targetID } = event.target
|
||||
const isNotToggleCell = !classList.contains(this.optionsMenuToggleClassName)
|
||||
const isAnotherCell = targetID !== `${tokenCellDropDownPrefix}${ind}`
|
||||
if (optionsMenuActive && (isNotToggleCell || (!isNotToggleCell && isAnotherCell))) {
|
||||
this.setState({ optionsMenuActive: false })
|
||||
}
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
DropdownMenuItem,
|
||||
{
|
||||
closeMenu: () => {},
|
||||
onClick: () => {
|
||||
showSendTokenPage(address)
|
||||
},
|
||||
},
|
||||
`Send`,
|
||||
),
|
||||
h(
|
||||
DropdownMenuItem,
|
||||
{
|
||||
closeMenu: () => {},
|
||||
onClick: () => {
|
||||
const { network } = this.props
|
||||
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
|
||||
global.platform.openWindow({ url })
|
||||
},
|
||||
},
|
||||
`View token on block explorer`,
|
||||
),
|
||||
h(
|
||||
DropdownMenuItem,
|
||||
{
|
||||
closeMenu: () => {},
|
||||
onClick: () => {
|
||||
const checkSumAddress = address && toChecksumAddress(network, address)
|
||||
copyToClipboard(checkSumAddress)
|
||||
},
|
||||
},
|
||||
'Copy address to clipboard',
|
||||
),
|
||||
h(
|
||||
DropdownMenuItem,
|
||||
{
|
||||
closeMenu: () => {},
|
||||
onClick: () => {
|
||||
this.props.removeToken({ address, symbol, string, network, userAddress })
|
||||
},
|
||||
},
|
||||
'Remove',
|
||||
),
|
||||
],
|
||||
)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
closeMenu={() => {}}
|
||||
onClick={() => {
|
||||
showSendTokenPage(address)
|
||||
}}
|
||||
>
|
||||
Send
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
closeMenu={() => {}}
|
||||
onClick={() => {
|
||||
const { network } = this.props
|
||||
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
|
||||
global.platform.openWindow({ url })
|
||||
}}
|
||||
>
|
||||
View token on block explorer
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
closeMenu={() => {}}
|
||||
onClick={() => {
|
||||
const checkSumAddress = address && toChecksumAddress(network, address)
|
||||
copyToClipboard(checkSumAddress)
|
||||
}}
|
||||
>
|
||||
Copy address to clipboard
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
closeMenu={() => {}}
|
||||
onClick={() => {
|
||||
this.props.removeToken({ address, symbol, string, network, userAddress })
|
||||
}}
|
||||
>
|
||||
Remove
|
||||
</DropdownMenuItem>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
|
||||
TokenCell.prototype.send = function (address, event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
const url = tokenFactoryFor(address)
|
||||
navigateTo(url)
|
||||
}
|
||||
|
||||
TokenCell.prototype.view = function (address, userAddress, network, event) {
|
||||
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
|
||||
if (url) {
|
||||
send (address, event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
const url = tokenFactoryFor(address)
|
||||
navigateTo(url)
|
||||
}
|
||||
|
||||
view (address, userAddress, network, _event) {
|
||||
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
|
||||
if (url) {
|
||||
navigateTo(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function navigateTo (url) {
|
||||
|
|
|
@ -19,8 +19,8 @@ const defaultTokens = []
|
|||
|
||||
const contractsETH = require('eth-contract-metadata')
|
||||
const contractsPOA = require('poa-contract-metadata')
|
||||
const contractsRSK = require('rsk-contract-metadata')
|
||||
const contractsRSKTest = require('rsk-test-contract-metadata')
|
||||
const contractsRSK = require('@rsksmart/rsk-contract-metadata')
|
||||
const contractsRSKTest = require('@rsksmart/rsk-testnet-contract-metadata')
|
||||
for (const address in contractsETH) {
|
||||
const contract = contractsETH[address]
|
||||
if (contract.erc20) {
|
||||
|
@ -120,7 +120,7 @@ TokenList.prototype.render = function () {
|
|||
}, [
|
||||
h('style', `
|
||||
|
||||
li.token-cell {
|
||||
span.token-cell {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
@ -128,11 +128,11 @@ TokenList.prototype.render = function () {
|
|||
min-height: 50px;
|
||||
}
|
||||
|
||||
li.token-cell > h3 {
|
||||
span.token-cell > h3 {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
li.token-cell:hover {
|
||||
span.token-cell:hover {
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
const inherits = require('util').inherits
|
||||
const Component = require('react').Component
|
||||
import PropTypes from 'prop-types'
|
||||
import { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
const h = require('react-hyperscript')
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('../../ui/app/actions')
|
||||
const LoadingIndicator = require('./components/loading')
|
||||
const txHelper = require('../lib/tx-helper')
|
||||
const log = require('loglevel')
|
||||
import log from 'loglevel'
|
||||
const { getCurrentKeyring, ifContractAcc } = require('./util')
|
||||
|
||||
const PendingTx = require('./components/pending-tx')
|
||||
|
@ -15,118 +15,224 @@ import PendingTypedMsg from './components/pending-typed-msg'
|
|||
const Loading = require('./components/loading')
|
||||
const { DAI_CODE, POA_SOKOL_CODE, RSK_TESTNET_CODE, GOERLI_TESTNET_CODE } = require('../../app/scripts/controllers/network/enums')
|
||||
const { getMetaMaskAccounts } = require('../../ui/app/selectors')
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
module.exports = connect(mapStateToProps)(ConfirmTxScreen)
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { metamask, appState } = state
|
||||
const { screenParams, pendingTxIndex } = appState.currentView
|
||||
return {
|
||||
identities: metamask.identities,
|
||||
accounts: getMetaMaskAccounts(state),
|
||||
keyrings: metamask.keyrings,
|
||||
selectedAddress: metamask.selectedAddress,
|
||||
unapprovedTxs: metamask.unapprovedTxs,
|
||||
unapprovedMsgs: metamask.unapprovedMsgs,
|
||||
unapprovedPersonalMsgs: metamask.unapprovedPersonalMsgs,
|
||||
unapprovedTypedMessages: metamask.unapprovedTypedMessages,
|
||||
index: pendingTxIndex || 0,
|
||||
warning: appState.warning,
|
||||
network: metamask.network,
|
||||
provider: metamask.provider,
|
||||
conversionRate: metamask.conversionRate,
|
||||
currentCurrency: metamask.currentCurrency,
|
||||
blockGasLimit: metamask.currentBlockGasLimit,
|
||||
computedBalances: metamask.computedBalances,
|
||||
isToken: (screenParams && screenParams.isToken),
|
||||
tokenSymbol: (screenParams && screenParams.tokenSymbol),
|
||||
tokensToSend: (screenParams && screenParams.tokensToSend),
|
||||
tokensTransferTo: (screenParams && screenParams.tokensTransferTo),
|
||||
isContractExecutionByUser: (screenParams && screenParams.isContractExecutionByUser),
|
||||
}
|
||||
}
|
||||
|
||||
inherits(ConfirmTxScreen, Component)
|
||||
function ConfirmTxScreen () {
|
||||
Component.call(this)
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.render = function () {
|
||||
const props = this.props
|
||||
const { network, unapprovedTxs, currentCurrency, computedBalances,
|
||||
unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, blockGasLimit } = props
|
||||
let { conversionRate } = props
|
||||
|
||||
const isTestnet = parseInt(network) === POA_SOKOL_CODE || parseInt(network) === RSK_TESTNET_CODE || parseInt(network) === GOERLI_TESTNET_CODE
|
||||
const isDai = parseInt(network) === DAI_CODE
|
||||
if (isTestnet) {
|
||||
conversionRate = 0
|
||||
} else if (isDai) {
|
||||
conversionRate = 1
|
||||
class ConfirmTxScreen extends Component {
|
||||
static propTypes = {
|
||||
network: PropTypes.string,
|
||||
identities: PropTypes.objectOf(PropTypes.object),
|
||||
keyrings: PropTypes.array,
|
||||
actions: PropTypes.objectOf(PropTypes.func),
|
||||
isToken: PropTypes.bool,
|
||||
isContractExecutionByUser: PropTypes.bool,
|
||||
selectedAddress: PropTypes.string,
|
||||
warning: PropTypes.string,
|
||||
unapprovedTxs: PropTypes.object,
|
||||
unapprovedMsgs: PropTypes.object,
|
||||
unapprovedPersonalMsgs: PropTypes.object,
|
||||
unapprovedTypedMessages: PropTypes.object,
|
||||
pendingTxIndex: PropTypes.number,
|
||||
blockGasLimit: PropTypes.string,
|
||||
accounts: PropTypes.object,
|
||||
currentCurrency: PropTypes.string,
|
||||
computedBalances: PropTypes.object,
|
||||
conversionRate: PropTypes.number,
|
||||
tokenSymbol: PropTypes.string,
|
||||
tokensToSend: PropTypes.objectOf(BigNumber),
|
||||
tokensTransferTo: PropTypes.string,
|
||||
}
|
||||
|
||||
const unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network)
|
||||
const ind = props.index || 0
|
||||
const txData = unconfTxList[ind] || {}
|
||||
const txParams = txData.params || {}
|
||||
render () {
|
||||
const props = this.props
|
||||
const { network, unapprovedTxs, currentCurrency, computedBalances,
|
||||
unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, blockGasLimit } = props
|
||||
let { conversionRate } = props
|
||||
|
||||
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
|
||||
if (unconfTxList.length === 0) return h(Loading, { isLoading: true })
|
||||
const isTestnet = parseInt(network) === POA_SOKOL_CODE || parseInt(network) === RSK_TESTNET_CODE || parseInt(network) === GOERLI_TESTNET_CODE
|
||||
const isDai = parseInt(network) === DAI_CODE
|
||||
if (isTestnet) {
|
||||
conversionRate = 0
|
||||
} else if (isDai) {
|
||||
conversionRate = 1
|
||||
}
|
||||
|
||||
const unconfTxListLength = unconfTxList.length
|
||||
const unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network)
|
||||
const ind = props.pendingTxIndex || 0
|
||||
const txData = unconfTxList[ind] || {}
|
||||
const txParams = txData.params || {}
|
||||
|
||||
return (
|
||||
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
|
||||
if (unconfTxList.length === 0) return h(Loading, { isLoading: true })
|
||||
|
||||
h('.flex-column.flex-grow', {
|
||||
style: {
|
||||
width: '100%',
|
||||
},
|
||||
}, [
|
||||
const unconfTxListLength = unconfTxList.length
|
||||
|
||||
h(LoadingIndicator, {
|
||||
isLoading: this.state ? !this.state.bypassLoadingScreen : txData.loadingDefaults,
|
||||
loadingMessage: 'Estimating transaction cost…',
|
||||
canBypass: true,
|
||||
bypass: () => {
|
||||
this.setState({bypassLoadingScreen: true})
|
||||
return (
|
||||
|
||||
h('.flex-column.flex-grow', {
|
||||
style: {
|
||||
width: '100%',
|
||||
},
|
||||
}),
|
||||
}, [
|
||||
|
||||
// subtitle and nav
|
||||
h(LoadingIndicator, {
|
||||
isLoading: this.state ? !this.state.bypassLoadingScreen : txData.loadingDefaults,
|
||||
loadingMessage: 'Estimating transaction cost…',
|
||||
canBypass: true,
|
||||
bypass: () => {
|
||||
this.setState({bypassLoadingScreen: true})
|
||||
},
|
||||
}),
|
||||
|
||||
warningIfExists(props.warning),
|
||||
// subtitle and nav
|
||||
|
||||
currentTxView({
|
||||
// Properties
|
||||
txData: txData,
|
||||
key: txData.id,
|
||||
selectedAddress: props.selectedAddress,
|
||||
accounts: props.accounts,
|
||||
identities: props.identities,
|
||||
conversionRate,
|
||||
currentCurrency,
|
||||
blockGasLimit,
|
||||
unconfTxListLength,
|
||||
computedBalances,
|
||||
network,
|
||||
isToken: props.isToken,
|
||||
tokenSymbol: props.tokenSymbol,
|
||||
tokensToSend: props.tokensToSend,
|
||||
tokensTransferTo: props.tokensTransferTo,
|
||||
// Actions
|
||||
buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress, props.isContractExecutionByUser),
|
||||
sendTransaction: this.sendTransaction.bind(this),
|
||||
cancelTransaction: this.cancelTransaction.bind(this, txData),
|
||||
cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList),
|
||||
signMessage: this.signMessage.bind(this, txData),
|
||||
signPersonalMessage: this.signPersonalMessage.bind(this, txData),
|
||||
signTypedMessage: this.signTypedMessage.bind(this, txData),
|
||||
cancelMessage: this.cancelMessage.bind(this, txData),
|
||||
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
|
||||
cancelTypedMessage: this.cancelTypedMessage.bind(this, txData),
|
||||
}),
|
||||
])
|
||||
)
|
||||
warningIfExists(props.warning),
|
||||
|
||||
currentTxView({
|
||||
// Properties
|
||||
txData: txData,
|
||||
key: txData.id,
|
||||
selectedAddress: props.selectedAddress,
|
||||
accounts: props.accounts,
|
||||
identities: props.identities,
|
||||
conversionRate,
|
||||
currentCurrency,
|
||||
blockGasLimit,
|
||||
unconfTxListLength,
|
||||
computedBalances,
|
||||
network,
|
||||
isToken: props.isToken,
|
||||
tokenSymbol: props.tokenSymbol,
|
||||
tokensToSend: props.tokensToSend,
|
||||
tokensTransferTo: props.tokensTransferTo,
|
||||
// Actions
|
||||
buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress, props.isContractExecutionByUser),
|
||||
sendTransaction: this.sendTransaction.bind(this),
|
||||
cancelTransaction: this.cancelTransaction.bind(this, txData),
|
||||
cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList),
|
||||
signMessage: this.signMessage.bind(this, txData),
|
||||
signPersonalMessage: this.signPersonalMessage.bind(this, txData),
|
||||
signTypedMessage: this.signTypedMessage.bind(this, txData),
|
||||
cancelMessage: this.cancelMessage.bind(this, txData),
|
||||
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
|
||||
cancelTypedMessage: this.cancelTypedMessage.bind(this, txData),
|
||||
}),
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
buyEth (address, isContractExecutionByUser, event) {
|
||||
event.preventDefault()
|
||||
this.props.actions.buyEthView(address, isContractExecutionByUser)
|
||||
}
|
||||
|
||||
sendTransaction (txData, event) {
|
||||
this.stopPropagation(event)
|
||||
this.props.actions.updateAndApproveTx(txData)
|
||||
this._checkIfContractExecutionAndUnlockContract(txData)
|
||||
}
|
||||
|
||||
cancelTransaction (txData, event) {
|
||||
this.stopPropagation(event)
|
||||
event.preventDefault()
|
||||
this.props.actions.cancelTx(txData)
|
||||
this._checkIfContractExecutionAndUnlockContract(txData)
|
||||
}
|
||||
|
||||
cancelAllTransactions (unconfTxList, event) {
|
||||
this.stopPropagation(event)
|
||||
event.preventDefault()
|
||||
this.props.actions.cancelTxs(unconfTxList)
|
||||
this._checkIfMultipleContractExecutionAndUnlockContract(unconfTxList)
|
||||
}
|
||||
|
||||
signMessage (msgData, event) {
|
||||
log.info('conf-tx.js: signing message')
|
||||
const params = msgData.msgParams
|
||||
params.metamaskId = msgData.id
|
||||
this.stopPropagation(event)
|
||||
this.props.actions.signMsg(params)
|
||||
}
|
||||
|
||||
stopPropagation (event) {
|
||||
if (event.stopPropagation) {
|
||||
event.stopPropagation()
|
||||
}
|
||||
}
|
||||
|
||||
signPersonalMessage (msgData, event) {
|
||||
log.info('conf-tx.js: signing personal message')
|
||||
const params = msgData.msgParams
|
||||
params.metamaskId = msgData.id
|
||||
this.stopPropagation(event)
|
||||
this.props.actions.signPersonalMsg(params)
|
||||
}
|
||||
|
||||
signTypedMessage (msgData, event) {
|
||||
log.info('conf-tx.js: signing typed message')
|
||||
const params = msgData.msgParams
|
||||
params.metamaskId = msgData.id
|
||||
this.stopPropagation(event)
|
||||
this.props.actions.signTypedMsg(params)
|
||||
}
|
||||
|
||||
cancelMessage (msgData, event) {
|
||||
log.info('canceling message')
|
||||
this.stopPropagation(event)
|
||||
this.props.actions.cancelMsg(msgData)
|
||||
}
|
||||
|
||||
cancelPersonalMessage (msgData, event) {
|
||||
log.info('canceling personal message')
|
||||
this.stopPropagation(event)
|
||||
this.props.actions.cancelPersonalMsg(msgData)
|
||||
}
|
||||
|
||||
cancelTypedMessage (msgData, event) {
|
||||
log.info('canceling typed message')
|
||||
this.stopPropagation(event)
|
||||
this.props.actions.cancelTypedMsg(msgData)
|
||||
}
|
||||
|
||||
_checkIfMultipleContractExecutionAndUnlockContract (unconfTxList) {
|
||||
const areTxsToOneContractFromTheList = unconfTxList.slice(0).reduce((res, txData, ind, unconfTxList) => {
|
||||
if (txData.txParams.data && this.props.isContractExecutionByUser) {
|
||||
const to = txData && txData.txParams && txData.txParams.to
|
||||
const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to)
|
||||
if (targetContractIsInTheList && Object.keys(res).length === 0) {
|
||||
res = { status: true, to }
|
||||
} else if (res.status && res.to !== to) {
|
||||
res = { status: false }
|
||||
unconfTxList.splice(1)
|
||||
}
|
||||
} else {
|
||||
res = { status: false }
|
||||
unconfTxList.splice(1)
|
||||
}
|
||||
return res
|
||||
}, {})
|
||||
|
||||
if (areTxsToOneContractFromTheList.status) {
|
||||
this._unlockContract(areTxsToOneContractFromTheList.to)
|
||||
}
|
||||
}
|
||||
|
||||
_checkIfContractExecutionAndUnlockContract (txData) {
|
||||
if (txData.txParams.data && this.props.isContractExecutionByUser) {
|
||||
const to = txData && txData.txParams && txData.txParams.to
|
||||
const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to)
|
||||
if (targetContractIsInTheList) {
|
||||
this._unlockContract(to)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_unlockContract (to) {
|
||||
const currentKeyring = getCurrentKeyring(to, this.props.network, this.props.keyrings, this.props.identities)
|
||||
if (ifContractAcc(currentKeyring)) {
|
||||
this.props.actions.showAccountDetail(to)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function currentTxView (opts) {
|
||||
|
@ -153,119 +259,6 @@ function currentTxView (opts) {
|
|||
}
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.buyEth = function (address, isContractExecutionByUser, event) {
|
||||
event.preventDefault()
|
||||
this.props.dispatch(actions.buyEthView(address, isContractExecutionByUser))
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.sendTransaction = function (txData, event) {
|
||||
this.stopPropagation(event)
|
||||
this.props.dispatch(actions.updateAndApproveTx(txData))
|
||||
this._checkIfContractExecutionAndUnlockContract(txData)
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.cancelTransaction = function (txData, event) {
|
||||
this.stopPropagation(event)
|
||||
event.preventDefault()
|
||||
this.props.dispatch(actions.cancelTx(txData))
|
||||
this._checkIfContractExecutionAndUnlockContract(txData)
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.cancelAllTransactions = function (unconfTxList, event) {
|
||||
this.stopPropagation(event)
|
||||
event.preventDefault()
|
||||
this.props.dispatch(actions.cancelAllTx(unconfTxList))
|
||||
this._checkIfMultipleContractExecutionAndUnlockContract(unconfTxList)
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.signMessage = function (msgData, event) {
|
||||
log.info('conf-tx.js: signing message')
|
||||
const params = msgData.msgParams
|
||||
params.metamaskId = msgData.id
|
||||
this.stopPropagation(event)
|
||||
this.props.dispatch(actions.signMsg(params))
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.stopPropagation = function (event) {
|
||||
if (event.stopPropagation) {
|
||||
event.stopPropagation()
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) {
|
||||
log.info('conf-tx.js: signing personal message')
|
||||
const params = msgData.msgParams
|
||||
params.metamaskId = msgData.id
|
||||
this.stopPropagation(event)
|
||||
this.props.dispatch(actions.signPersonalMsg(params))
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) {
|
||||
log.info('conf-tx.js: signing typed message')
|
||||
const params = msgData.msgParams
|
||||
params.metamaskId = msgData.id
|
||||
this.stopPropagation(event)
|
||||
this.props.dispatch(actions.signTypedMsg(params))
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) {
|
||||
log.info('canceling message')
|
||||
this.stopPropagation(event)
|
||||
this.props.dispatch(actions.cancelMsg(msgData))
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) {
|
||||
log.info('canceling personal message')
|
||||
this.stopPropagation(event)
|
||||
this.props.dispatch(actions.cancelPersonalMsg(msgData))
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) {
|
||||
log.info('canceling typed message')
|
||||
this.stopPropagation(event)
|
||||
this.props.dispatch(actions.cancelTypedMsg(msgData))
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype._checkIfMultipleContractExecutionAndUnlockContract = function (unconfTxList) {
|
||||
const areTxsToOneContractFromTheList = unconfTxList.slice(0).reduce((res, txData, ind, unconfTxList) => {
|
||||
if (txData.txParams.data && this.props.isContractExecutionByUser) {
|
||||
const to = txData && txData.txParams && txData.txParams.to
|
||||
const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to)
|
||||
if (targetContractIsInTheList && Object.keys(res).length === 0) {
|
||||
res = { status: true, to }
|
||||
} else if (res.status && res.to !== to) {
|
||||
res = { status: false }
|
||||
unconfTxList.splice(1)
|
||||
}
|
||||
} else {
|
||||
res = { status: false }
|
||||
unconfTxList.splice(1)
|
||||
}
|
||||
return res
|
||||
}, {})
|
||||
|
||||
if (areTxsToOneContractFromTheList.status) {
|
||||
this._unlockContract(areTxsToOneContractFromTheList.to)
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype._checkIfContractExecutionAndUnlockContract = function (txData) {
|
||||
if (txData.txParams.data && this.props.isContractExecutionByUser) {
|
||||
const to = txData && txData.txParams && txData.txParams.to
|
||||
const targetContractIsInTheList = Object.keys(this.props.accounts).some((acc) => acc === to)
|
||||
if (targetContractIsInTheList) {
|
||||
this._unlockContract(to)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfirmTxScreen.prototype._unlockContract = function (to) {
|
||||
const currentKeyring = getCurrentKeyring(to, this.props.network, this.props.keyrings, this.props.identities)
|
||||
if (ifContractAcc(currentKeyring)) {
|
||||
this.props.dispatch(actions.showAccountDetail(to))
|
||||
}
|
||||
}
|
||||
|
||||
function warningIfExists (warning) {
|
||||
if (warning &&
|
||||
// Do not display user rejections on this screen:
|
||||
|
@ -277,3 +270,51 @@ function warningIfExists (warning) {
|
|||
}, warning)
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const { metamask, appState } = state
|
||||
const { screenParams, pendingTxIndex } = appState.currentView
|
||||
return {
|
||||
identities: metamask.identities,
|
||||
accounts: getMetaMaskAccounts(state),
|
||||
keyrings: metamask.keyrings,
|
||||
selectedAddress: metamask.selectedAddress,
|
||||
unapprovedTxs: metamask.unapprovedTxs,
|
||||
unapprovedMsgs: metamask.unapprovedMsgs,
|
||||
unapprovedPersonalMsgs: metamask.unapprovedPersonalMsgs,
|
||||
unapprovedTypedMessages: metamask.unapprovedTypedMessages,
|
||||
pendingTxIndex: pendingTxIndex || 0,
|
||||
warning: appState.warning,
|
||||
network: metamask.network,
|
||||
provider: metamask.provider,
|
||||
conversionRate: metamask.conversionRate,
|
||||
currentCurrency: metamask.currentCurrency,
|
||||
blockGasLimit: metamask.currentBlockGasLimit,
|
||||
computedBalances: metamask.computedBalances,
|
||||
isToken: (screenParams && screenParams.isToken),
|
||||
tokenSymbol: (screenParams && screenParams.tokenSymbol),
|
||||
tokensToSend: (screenParams && screenParams.tokensToSend),
|
||||
tokensTransferTo: (screenParams && screenParams.tokensTransferTo),
|
||||
isContractExecutionByUser: (screenParams && screenParams.isContractExecutionByUser),
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
actions: {
|
||||
buyEthView: (address, isContractExecutionByUser) => dispatch(actions.buyEthView(address, isContractExecutionByUser)),
|
||||
updateAndApproveTx: (txData) => dispatch(actions.updateAndApproveTx(txData)),
|
||||
cancelTx: (txData) => dispatch(actions.cancelTx(txData)),
|
||||
cancelTxs: (unconfTxList) => dispatch(actions.cancelTxs(unconfTxList)),
|
||||
signMsg: (params) => dispatch(actions.signMsg(params)),
|
||||
signPersonalMsg: (params) => dispatch(actions.signPersonalMsg(params)),
|
||||
signTypedMsg: (params) => dispatch(actions.signTypedMsg(params)),
|
||||
cancelMsg: (msgData) => dispatch(actions.cancelMsg(msgData)),
|
||||
cancelPersonalMsg: (msgData) => dispatch(actions.cancelPersonalMsg(msgData)),
|
||||
cancelTypedMsg: (msgData) => dispatch(actions.cancelTypedMsg(msgData)),
|
||||
showAccountDetail: (to) => dispatch(actions.showAccountDetail(to)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmTxScreen)
|
||||
|
|
|
@ -161,12 +161,13 @@ function numericBalance (balance) {
|
|||
|
||||
// Takes hex, returns [beforeDecimal, afterDecimal]
|
||||
function parseBalance (balance) {
|
||||
let afterDecimal
|
||||
const wei = numericBalance(balance)
|
||||
const weiString = wei.toString()
|
||||
const trailingZeros = /0+$/
|
||||
|
||||
const beforeDecimal = weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0'
|
||||
let afterDecimal = ('000000000000000000' + wei).slice(-18).replace(trailingZeros, '')
|
||||
afterDecimal = ('000000000000000000' + wei).slice(-18).replace(trailingZeros, '')
|
||||
if (afterDecimal === '') { afterDecimal = '0' }
|
||||
return [beforeDecimal, afterDecimal]
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ const EventEmitter = require('events').EventEmitter
|
|||
|
||||
// account management
|
||||
|
||||
var identities = {
|
||||
const identities = {
|
||||
'0x1113462427bcc9133bb46e88bcbe39cd7ef0e111': {
|
||||
name: 'Walrus',
|
||||
img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
|
||||
|
@ -29,7 +29,7 @@ var identities = {
|
|||
},
|
||||
}
|
||||
|
||||
var unapprovedTxs = {}
|
||||
const unapprovedTxs = {}
|
||||
addUnconfTx({
|
||||
from: '0x222462427bcc9133bb46e88bcbe39cd7ef0e7222',
|
||||
to: '0x1113462427bcc9133bb46e88bcbe39cd7ef0e111',
|
||||
|
@ -43,8 +43,8 @@ addUnconfTx({
|
|||
})
|
||||
|
||||
function addUnconfTx (txParams) {
|
||||
var time = (new Date()).getTime()
|
||||
var id = createRandomId()
|
||||
const time = (new Date()).getTime()
|
||||
const id = createRandomId()
|
||||
unapprovedTxs[id] = {
|
||||
id: id,
|
||||
txParams: txParams,
|
||||
|
@ -52,8 +52,8 @@ function addUnconfTx (txParams) {
|
|||
}
|
||||
}
|
||||
|
||||
var isUnlocked = false
|
||||
var selectedAccount = null
|
||||
let isUnlocked = false
|
||||
let selectedAccount = null
|
||||
|
||||
function getState () {
|
||||
return {
|
||||
|
@ -64,7 +64,7 @@ function getState () {
|
|||
}
|
||||
}
|
||||
|
||||
var accountManager = new EventEmitter()
|
||||
const accountManager = new EventEmitter()
|
||||
|
||||
accountManager.getState = function (cb) {
|
||||
cb(null, getState())
|
||||
|
@ -101,9 +101,9 @@ accountManager._didUpdate = function () {
|
|||
|
||||
// start app
|
||||
|
||||
var container = document.getElementById('app-content')
|
||||
const container = document.getElementById('app-content')
|
||||
|
||||
var css = MetaMaskUiCss()
|
||||
const css = MetaMaskUiCss()
|
||||
injectCss(css)
|
||||
|
||||
MetaMaskUi({
|
||||
|
@ -115,9 +115,9 @@ MetaMaskUi({
|
|||
|
||||
function createRandomId () {
|
||||
// 13 time digits
|
||||
var datePart = new Date().getTime() * Math.pow(10, 3)
|
||||
const datePart = new Date().getTime() * Math.pow(10, 3)
|
||||
// 3 random digits
|
||||
var extraPart = Math.floor(Math.random() * Math.pow(10, 3))
|
||||
const extraPart = Math.floor(Math.random() * Math.pow(10, 3))
|
||||
// 16 digits
|
||||
return datePart + extraPart
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { isValidAddress } from 'ethereumjs-util'
|
||||
import contractMapETH from 'eth-contract-metadata'
|
||||
import contractMapPOA from 'poa-contract-metadata'
|
||||
import contractMapRSK from 'rsk-contract-metadata'
|
||||
import contractMapRSKTest from 'rsk-test-contract-metadata'
|
||||
import contractMapRSK from '@rsksmart/rsk-contract-metadata'
|
||||
import contractMapRSKTest from '@rsksmart/rsk-testnet-contract-metadata'
|
||||
import { MAINNET_CODE, POA_CODE, RSK_CODE, RSK_TESTNET_CODE } from '../../app/scripts/controllers/network/enums'
|
||||
const colors = require('../../colors')
|
||||
const { toChecksumAddress, getTokenImageFolder } = require('../app/util')
|
||||
|
|
|
@ -1966,6 +1966,14 @@
|
|||
"react-lifecycles-compat": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"@rsksmart/rsk-contract-metadata": {
|
||||
"version": "github:rsksmart/rsk-contract-metadata#d7913739e5ee93dac8667043e2c17b0ef339c206",
|
||||
"from": "github:rsksmart/rsk-contract-metadata#master"
|
||||
},
|
||||
"@rsksmart/rsk-testnet-contract-metadata": {
|
||||
"version": "github:rsksmart/rsk-testnet-contract-metadata#2b89e70d36d2aa58cae68ac817debbf3c451690a",
|
||||
"from": "github:rsksmart/rsk-testnet-contract-metadata#master"
|
||||
},
|
||||
"@sentry/cli": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.52.0.tgz",
|
||||
|
@ -11355,9 +11363,9 @@
|
|||
}
|
||||
},
|
||||
"eth-contract-metadata": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/eth-contract-metadata/-/eth-contract-metadata-1.12.1.tgz",
|
||||
"integrity": "sha512-9u2jUcdxaKIv4RvA9RtjyD4+M2yWt4yCulR5bpdQTiG3HUFnN9lHtNL5NIRDpvQVJKerFhexrgEM2WdGP3a6VA=="
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/eth-contract-metadata/-/eth-contract-metadata-1.13.0.tgz",
|
||||
"integrity": "sha512-9CjXHX8IdXysUEvOHdbCsjdAwM1E98jaeK2HeOqm/9S/vOZ8YryaBBt/YSiBq3MkpCwf+d1pEQ53p96rsdy52w=="
|
||||
},
|
||||
"eth-ens-namehash": {
|
||||
"version": "2.0.8",
|
||||
|
@ -49791,14 +49799,6 @@
|
|||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"rsk-contract-metadata": {
|
||||
"version": "github:rsksmart/rsk-contract-metadata#262495abfa6ff83fb9cd46c7fb9f85690e4e5d4b",
|
||||
"from": "github:rsksmart/rsk-contract-metadata#master"
|
||||
},
|
||||
"rsk-test-contract-metadata": {
|
||||
"version": "github:rsksmart/rsk-testnet-contract-metadata#69ff2d652b286648e9264e2689009e940ec7ccad",
|
||||
"from": "github:rsksmart/rsk-testnet-contract-metadata#master"
|
||||
},
|
||||
"rst-selector-parser": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz",
|
||||
|
|
|
@ -85,6 +85,8 @@
|
|||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"@material-ui/core": "^4.1.1",
|
||||
"@rsksmart/rsk-contract-metadata": "github:rsksmart/rsk-contract-metadata#master",
|
||||
"@rsksmart/rsk-testnet-contract-metadata": "github:rsksmart/rsk-testnet-contract-metadata#master",
|
||||
"@zxing/library": "^0.8.0",
|
||||
"abi-decoder": "^1.2.0",
|
||||
"asmcrypto.js": "0.22.0",
|
||||
|
@ -109,7 +111,7 @@
|
|||
"dnode": "^1.2.2",
|
||||
"end-of-stream": "^1.4.4",
|
||||
"eth-block-tracker": "^4.4.2",
|
||||
"eth-contract-metadata": "^1.12.1",
|
||||
"eth-contract-metadata": "^1.13.0",
|
||||
"eth-ens-namehash": "^2.0.8",
|
||||
"eth-json-rpc-errors": "^2.0.2",
|
||||
"eth-json-rpc-filters": "github:poanetwork/eth-json-rpc-filters#3.0.2",
|
||||
|
@ -198,8 +200,6 @@
|
|||
"reselect": "^3.0.1",
|
||||
"rockicon": "^1.0.0",
|
||||
"rpc-cap": "^2.0.0",
|
||||
"rsk-contract-metadata": "github:rsksmart/rsk-contract-metadata#master",
|
||||
"rsk-test-contract-metadata": "github:rsksmart/rsk-testnet-contract-metadata#master",
|
||||
"sandwich-expando": "^1.1.3",
|
||||
"semaphore": "^1.0.5",
|
||||
"semver": "^5.4.1",
|
||||
|
|
|
@ -244,6 +244,7 @@ module.exports = {
|
|||
titleText: 'Delete Imported Account',
|
||||
buttons: {
|
||||
no: By.css('#app-content > div > div.app-primary.from-left > div > div.flex-row.flex-right > button.btn-violet'),
|
||||
no2: By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-right > button.btn-violet'),
|
||||
yes: By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-right > button:nth-child(2)'),
|
||||
arrow: By.className('fa fa-arrow-left fa-lg cursor-pointer'),
|
||||
},
|
||||
|
@ -255,6 +256,7 @@ module.exports = {
|
|||
selectArrow: By.className('Select-arrow-zone'),
|
||||
selectType: By.name('import-type-select'),
|
||||
itemContract: By.id('react-select-4--option-2'),
|
||||
itemContract1: By.id('react-select-3--option-2'),
|
||||
// itemContract2: By.id('react-select-3--option-2'),
|
||||
itemProxyContract: By.id('react-select-3--option-3'),
|
||||
// itemProxyContract2: By.id('react-select-2--option-3'),
|
||||
|
@ -296,7 +298,7 @@ module.exports = {
|
|||
accountName: By.className('font-medium color-forest'),
|
||||
edit: By.className('edit-text'),
|
||||
iconCopy: By.className('clipboard cursor-pointer white'),
|
||||
transactionList: By.css('#app-content > div > div.app-primary.from-left > div > section > section > div > div > div > div.ether-balance.ether-balance-amount > div > div > div > div:nth-child(1)'),
|
||||
transactionList: By.css('#app-content > div > div.app-primary.from-left > div > section > section > div > div > div > div.ether-balance.ether-balance-amount > div > div.flex-column > div > div:nth-child(1)'),
|
||||
buttons: {
|
||||
send: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(4)'),
|
||||
buy: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(3)'),
|
||||
|
@ -307,7 +309,7 @@ module.exports = {
|
|||
},
|
||||
network: By.className('network-name'),
|
||||
sent: {
|
||||
menu: By.className('wallet-view__tab-history'),
|
||||
menu: By.css('#wallet-view__tab-history'),
|
||||
tokens: By.className('activeForm right'),
|
||||
},
|
||||
// balance: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > div.ether-balance.ether-balance-amount > div > div > div:nth-child(1) > div:nth-child(1)'),
|
||||
|
|
|
@ -6,10 +6,10 @@ const account2 = '0xd7b7AFeCa35e32594e29504771aC847E2a803742'
|
|||
const testsFolder = './test-cases'
|
||||
const setup = require(`${testsFolder}/setup.spec`)
|
||||
const login = require(`${testsFolder}/login.spec`)
|
||||
const { accountCreation } = require(`${testsFolder}/account-creation.spec`)
|
||||
const { accountCreation, getCreatedAccounts } = require(`${testsFolder}/account-creation.spec`)
|
||||
const connectHDWallet = require(`${testsFolder}/connect-hd-wallet.spec`)
|
||||
const importAccount = require(`${testsFolder}/import-account.spec`)
|
||||
// const importContractAccount = require(`${testsFolder}/import-contract-account.spec`)
|
||||
const importContractAccount = require(`${testsFolder}/import-contract-account.spec`)
|
||||
const deleteImportedAccount = require(`${testsFolder}/delete-imported-account.spec`)
|
||||
const signData = require(`${testsFolder}/sign-data.spec`)
|
||||
const exportPrivateKey = require(`${testsFolder}/export-private-key.spec`)
|
||||
|
@ -18,7 +18,7 @@ const RSKNetworkTests = require(`${testsFolder}/RSK-network-tests.js`)
|
|||
const checkEmittedEvents = require(`${testsFolder}/check-emitted-events.spec`)
|
||||
// const addCustomToken = require(`${testsFolder}/add-token-custom.spec`)
|
||||
const changePassword = require(`${testsFolder}/change-password.spec`)
|
||||
// const addTokenFromSearch = require(`${testsFolder}/add-token-search.spec`)
|
||||
const addTokenFromSearch = require(`${testsFolder}/add-token-search.spec`)
|
||||
const customRPC = require(`${testsFolder}/custom-rpc.spec`)
|
||||
const { buildWebDriver } = require(`./webdriver`)
|
||||
|
||||
|
@ -98,9 +98,9 @@ describe('Metamask popup page', async function () {
|
|||
await importAccount(f)
|
||||
})
|
||||
|
||||
// describe('Import Contract account', async () => {
|
||||
// await importContractAccount(f, account1, getCreatedAccounts)
|
||||
// })
|
||||
describe('Import Contract account', async () => {
|
||||
await importContractAccount(f, account1, getCreatedAccounts)
|
||||
})
|
||||
|
||||
describe('Delete Imported Account', async () => {
|
||||
await deleteImportedAccount(f)
|
||||
|
@ -136,9 +136,9 @@ describe('Metamask popup page', async function () {
|
|||
})
|
||||
|
||||
// todo
|
||||
// describe('Add Token:Search', async () => {
|
||||
// await addTokenFromSearch(f)
|
||||
// })
|
||||
describe('Add Token:Search', async () => {
|
||||
await addTokenFromSearch(f)
|
||||
})
|
||||
|
||||
describe('Custom RPC', async () => {
|
||||
await customRPC(f)
|
||||
|
|
|
@ -254,15 +254,15 @@ const addTokeFromSearch = async (f) => {
|
|||
assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
|
||||
})
|
||||
|
||||
it('token should not be displayed in RSK', async () => {
|
||||
await f.setProvider(NETWORKS.RSK)
|
||||
assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
|
||||
})
|
||||
// it('token should not be displayed in RSK', async () => {
|
||||
// await f.setProvider(NETWORKS.RSK)
|
||||
// assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
|
||||
// })
|
||||
|
||||
it('token should not be displayed in RSK testnet', async () => {
|
||||
await f.setProvider(NETWORKS.RSK_TESTNET)
|
||||
assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
|
||||
})
|
||||
// it('token should not be displayed in RSK testnet', async () => {
|
||||
// await f.setProvider(NETWORKS.RSK_TESTNET)
|
||||
// assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
|
||||
// })
|
||||
})
|
||||
describe('remove Mainnet\'s tokens', function () {
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const deleteImportedAccount = async (f) => {
|
|||
})
|
||||
|
||||
it("Can't remove imported account with 'No' button", async function () {
|
||||
const button = await f.waitUntilShowUp(deleteImportedAccountScr.buttons.no)
|
||||
const button = await f.waitUntilShowUp(deleteImportedAccountScr.buttons.no2)
|
||||
assert.equal(await button.getText(), 'No', 'button has incorrect name')
|
||||
await f.click(button)
|
||||
await f.driver.findElements(main.container)
|
||||
|
|
|
@ -5,105 +5,105 @@ const { main } = screens
|
|||
let abiClipboard
|
||||
|
||||
const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
||||
describe('Proxy contract', async () => {
|
||||
const proxyContract = '0x0518ac3db78eb326f42dbcfb4b2978e8059989a5'
|
||||
const proxyABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}] // eslint-disable-line no-unused-vars
|
||||
const joinedABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}, {'constant': true, 'inputs': [], 'name': 'desc', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'methodFromImplementation', 'outputs': [{'name': 'yep', 'type': 'bool'}], 'payable': false, 'stateMutability': 'pure', 'type': 'function'}]
|
||||
// describe('Proxy contract', async () => {
|
||||
// const proxyContract = '0x0518ac3db78eb326f42dbcfb4b2978e8059989a5'
|
||||
// const proxyABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}] // eslint-disable-line no-unused-vars
|
||||
// const joinedABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}, {'constant': true, 'inputs': [], 'name': 'desc', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'methodFromImplementation', 'outputs': [{'name': 'yep', 'type': 'bool'}], 'payable': false, 'stateMutability': 'pure', 'type': 'function'}]
|
||||
|
||||
describe('imports ABI of proxy and implementation together', async () => {
|
||||
it('opens import account menu', async () => {
|
||||
await f.setProvider(NETWORKS.SOKOL)
|
||||
const menu = await f.waitUntilShowUp(menus.account.menu)
|
||||
await menu.click()
|
||||
const item = await f.waitUntilShowUp(menus.account.import2)
|
||||
await item.click()
|
||||
const importAccountTitle = await f.waitUntilShowUp(screens.importAccounts.title)
|
||||
assert.equal(await importAccountTitle.getText(), screens.importAccounts.textTitle)
|
||||
})
|
||||
// describe('imports ABI of proxy and implementation together', async () => {
|
||||
// it('opens import account menu', async () => {
|
||||
// await f.setProvider(NETWORKS.SOKOL)
|
||||
// const menu = await f.waitUntilShowUp(menus.account.menu)
|
||||
// await menu.click()
|
||||
// const item = await f.waitUntilShowUp(menus.account.import2)
|
||||
// await item.click()
|
||||
// const importAccountTitle = await f.waitUntilShowUp(screens.importAccounts.title)
|
||||
// assert.equal(await importAccountTitle.getText(), screens.importAccounts.textTitle)
|
||||
// })
|
||||
|
||||
it("Select type 'Proxy'", async () => {
|
||||
await f.delay(1000)
|
||||
const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
|
||||
await field.click()
|
||||
await f.delay(1000)
|
||||
const item = await f.waitUntilShowUp(screens.importAccounts.itemProxyContract)
|
||||
await item.click()
|
||||
})
|
||||
// it("Select type 'Proxy'", async () => {
|
||||
// await f.delay(1000)
|
||||
// const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
|
||||
// await field.click()
|
||||
// await f.delay(1000)
|
||||
// const item = await f.waitUntilShowUp(screens.importAccounts.itemProxyContract)
|
||||
// await item.click()
|
||||
// })
|
||||
|
||||
it("Fill 'Address' with valid proxy contract , SOKOL", async () => {
|
||||
const field = await f.waitUntilShowUp(screens.importAccounts.contractAddress)
|
||||
await f.clearField(field, 100)
|
||||
await field.sendKeys(proxyContract)
|
||||
})
|
||||
// it("Fill 'Address' with valid proxy contract , SOKOL", async () => {
|
||||
// const field = await f.waitUntilShowUp(screens.importAccounts.contractAddress)
|
||||
// await f.clearField(field, 100)
|
||||
// await field.sendKeys(proxyContract)
|
||||
// })
|
||||
|
||||
it('ABI of Proxy + Implementation is fetched and matches the pattern', async () => {
|
||||
await f.delay(10000)
|
||||
const field = await f.waitUntilShowUp(screens.importAccounts.contractABI)
|
||||
abiClipboard = await field.getText()
|
||||
assert.deepEqual(JSON.parse(abiClipboard), joinedABI, "ABI isn't fetched")
|
||||
})
|
||||
// it('ABI of Proxy + Implementation is fetched and matches the pattern', async () => {
|
||||
// await f.delay(10000)
|
||||
// const field = await f.waitUntilShowUp(screens.importAccounts.contractABI)
|
||||
// abiClipboard = await field.getText()
|
||||
// assert.deepEqual(JSON.parse(abiClipboard), joinedABI, "ABI isn't fetched")
|
||||
// })
|
||||
|
||||
it("Click button 'Import', main screen opens", async () => {
|
||||
const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
|
||||
await f.click(button)
|
||||
await f.delay(7000)
|
||||
const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
|
||||
assert.notEqual(ident, false, "main screen isn't opened")
|
||||
})
|
||||
})
|
||||
// it("Click button 'Import', main screen opens", async () => {
|
||||
// const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
|
||||
// await f.click(button)
|
||||
// await f.delay(7000)
|
||||
// const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
|
||||
// assert.notEqual(ident, false, "main screen isn't opened")
|
||||
// })
|
||||
// })
|
||||
|
||||
describe("Check 3dots menu for 'Proxy' account", () => {
|
||||
// describe("Check 3dots menu for 'Proxy' account", () => {
|
||||
|
||||
it('open 3dots menu', async () => {
|
||||
const menu = await f.waitUntilShowUp(menus.dot.menu)
|
||||
await menu.click()
|
||||
await f.waitUntilShowUp(menus.dot.item)
|
||||
const items = await f.driver.findElements(menus.dot.item)
|
||||
assert.equal(items.length, 5, '3dot menu has incorrect number of items')
|
||||
})
|
||||
// it('open 3dots menu', async () => {
|
||||
// const menu = await f.waitUntilShowUp(menus.dot.menu)
|
||||
// await menu.click()
|
||||
// await f.waitUntilShowUp(menus.dot.item)
|
||||
// const items = await f.driver.findElements(menus.dot.item)
|
||||
// assert.equal(items.length, 5, '3dot menu has incorrect number of items')
|
||||
// })
|
||||
|
||||
it('Check text of items', async () => {
|
||||
const items = await f.driver.findElements(menus.dot.item)
|
||||
assert.equal(await items[0].getText(), 'View on block explorer', '1st item has incorrect text')
|
||||
assert.equal(await items[1].getText(), 'Show QR Code', '2nd item has incorrect text')
|
||||
assert.equal(await items[2].getText(), 'Copy address to clipboard', '3d item has incorrect text')
|
||||
assert.equal(await items[3].getText(), 'Copy ABI to clipboard', '4th item has incorrect text')
|
||||
assert.equal(await items[4].getText(), 'Update implementation ABI', '5th item has incorrect text')
|
||||
})
|
||||
// it('Check text of items', async () => {
|
||||
// const items = await f.driver.findElements(menus.dot.item)
|
||||
// assert.equal(await items[0].getText(), 'View on block explorer', '1st item has incorrect text')
|
||||
// assert.equal(await items[1].getText(), 'Show QR Code', '2nd item has incorrect text')
|
||||
// assert.equal(await items[2].getText(), 'Copy address to clipboard', '3d item has incorrect text')
|
||||
// assert.equal(await items[3].getText(), 'Copy ABI to clipboard', '4th item has incorrect text')
|
||||
// assert.equal(await items[4].getText(), 'Update implementation ABI', '5th item has incorrect text')
|
||||
// })
|
||||
|
||||
it("Click 'Update implementation ABI'", async () => {
|
||||
const items = await f.driver.findElements(menus.dot.item)
|
||||
await items[4].click()
|
||||
const menu = await f.waitUntilShowUp(menus.dot.item, 20)
|
||||
assert.equal(menu, false, "3dot menu wasn't closed")
|
||||
})
|
||||
})
|
||||
// it("Click 'Update implementation ABI'", async () => {
|
||||
// const items = await f.driver.findElements(menus.dot.item)
|
||||
// await items[4].click()
|
||||
// const menu = await f.waitUntilShowUp(menus.dot.item, 20)
|
||||
// assert.equal(menu, false, "3dot menu wasn't closed")
|
||||
// })
|
||||
// })
|
||||
|
||||
const accountPosition = 1
|
||||
// const accountPosition = 1
|
||||
|
||||
describe("Remove imported 'Proxy' account", async () => {
|
||||
it("Label 'PROXY' present", async () => {
|
||||
const menu = await f.waitUntilShowUp(menus.account.menu)
|
||||
await menu.click()
|
||||
await f.delay(2000)
|
||||
await f.waitUntilShowUp(menus.account.label)
|
||||
const labels = await f.driver.findElements(menus.account.label)
|
||||
const label = labels[accountPosition]
|
||||
const text1 = await label.getText()
|
||||
console.log(text1)
|
||||
assert.equal(text1, 'PROXY', 'label incorrect')
|
||||
})
|
||||
it('Delete imported account', async () => {
|
||||
const deleteButton = await f.waitUntilShowUp(menus.account.delete)
|
||||
await deleteButton.click()
|
||||
const yesButton = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
|
||||
await yesButton.click()
|
||||
await f.driver.findElements(main.container)
|
||||
const identicon = await f.waitUntilShowUp(screens.main.identicon)
|
||||
assert.notEqual(identicon, false, 'main screen didn\'t opened')
|
||||
})
|
||||
})
|
||||
})
|
||||
// describe("Remove imported 'Proxy' account", async () => {
|
||||
// it("Label 'PROXY' present", async () => {
|
||||
// const menu = await f.waitUntilShowUp(menus.account.menu)
|
||||
// await menu.click()
|
||||
// await f.delay(2000)
|
||||
// await f.waitUntilShowUp(menus.account.label)
|
||||
// const labels = await f.driver.findElements(menus.account.label)
|
||||
// const label = labels[accountPosition]
|
||||
// const text1 = await label.getText()
|
||||
// console.log(text1)
|
||||
// assert.equal(text1, 'PROXY', 'label incorrect')
|
||||
// })
|
||||
// it('Delete imported account', async () => {
|
||||
// const deleteButton = await f.waitUntilShowUp(menus.account.delete)
|
||||
// await deleteButton.click()
|
||||
// const yesButton = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
|
||||
// await yesButton.click()
|
||||
// await f.driver.findElements(main.container)
|
||||
// const identicon = await f.waitUntilShowUp(screens.main.identicon)
|
||||
// assert.notEqual(identicon, false, 'main screen didn\'t opened')
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
|
||||
describe('Simple contract', async () => {
|
||||
const contractSokol = '0x215b2ab35749e5a9f3efe890de602fb9844e842f'
|
||||
|
@ -127,7 +127,7 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
|
|||
const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
|
||||
await field.click()
|
||||
await f.delay(2000)
|
||||
const item = await f.waitUntilShowUp(screens.importAccounts.itemContract)
|
||||
const item = await f.waitUntilShowUp(screens.importAccounts.itemContract1)
|
||||
await item.click()
|
||||
})
|
||||
|
||||
|
|
|
@ -60,6 +60,8 @@ const importGanacheSeedPhrase = async (f, account2, password) => {
|
|||
})
|
||||
|
||||
it('finds the transaction in the transactions list', async () => {
|
||||
const sentTab = await f.waitUntilShowUp(screens.main.sent.menu)
|
||||
await sentTab.click()
|
||||
const transactionAmount = await f.waitUntilShowUp(screens.main.transactionList)
|
||||
assert.equal(await transactionAmount.getText(), '10.0')
|
||||
})
|
||||
|
|
|
@ -17,7 +17,7 @@ server.listen(8545, () => {
|
|||
})
|
||||
|
||||
// logging util
|
||||
var log = require('loglevel')
|
||||
const log = require('loglevel')
|
||||
log.setDefaultLevel(5)
|
||||
global.log = log
|
||||
|
||||
|
@ -57,7 +57,7 @@ function enableFailureOnUnhandledPromiseRejection () {
|
|||
throw evt.detail.reason
|
||||
})
|
||||
} else {
|
||||
var oldOHR = window.onunhandledrejection
|
||||
const oldOHR = window.onunhandledrejection
|
||||
window.onunhandledrejection = function (evt) {
|
||||
if (typeof oldOHR === 'function') oldOHR.apply(this, arguments)
|
||||
throw evt.detail.reason
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
var mockHex = '0xabcdef0123456789'
|
||||
var mockKey = Buffer.alloc(32)
|
||||
const mockHex = '0xabcdef0123456789'
|
||||
const mockKey = Buffer.alloc(32)
|
||||
let cacheVal
|
||||
|
||||
module.exports = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var fakeWallet = {
|
||||
const fakeWallet = {
|
||||
privKey: '0x123456788890abcdef',
|
||||
address: '0xfedcba0987654321',
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ module.exports = class MockSimpleKeychain {
|
|||
}
|
||||
|
||||
addAccounts (n = 1) {
|
||||
for (var i = 0; i < n; i++) {
|
||||
for (let i = 0; i < n; i++) {
|
||||
this.wallets.push(fakeWallet)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,9 +161,9 @@ describe('MetaMaskController', function () {
|
|||
getState: () => {
|
||||
return {
|
||||
recentBlocks: [
|
||||
{ number: '0x1', minimumGasPrice: '59240010' },
|
||||
{ number: '0x2', minimumGasPrice: '59240005' },
|
||||
{ number: '0x3', minimumGasPrice: '59240000' },
|
||||
{ number: '0x1', minimumGasPrice: '0x387ee48' },
|
||||
{ number: '0x2', minimumGasPrice: '0x387ee42' },
|
||||
{ number: '0x3', minimumGasPrice: '0x387ee40' },
|
||||
],
|
||||
}
|
||||
},
|
||||
|
@ -175,7 +175,7 @@ describe('MetaMaskController', function () {
|
|||
getState: () => {
|
||||
return {
|
||||
recentBlocks: [
|
||||
{ number: '0x4', minimumGasPrice: '0' },
|
||||
{ number: '0x4', minimumGasPrice: '0x' },
|
||||
],
|
||||
}
|
||||
},
|
||||
|
|
|
@ -443,7 +443,7 @@ describe('preferences controller', function () {
|
|||
req.params.options = { address, symbol, decimals, image }
|
||||
|
||||
sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true)
|
||||
preferencesController.showWatchAssetUi = async () => {}
|
||||
preferencesController.openPopup = async () => {}
|
||||
|
||||
await preferencesController._handleWatchAssetERC20(req.params.options)
|
||||
const suggested = preferencesController.getSuggestedTokens()
|
||||
|
@ -463,7 +463,7 @@ describe('preferences controller', function () {
|
|||
req.params.options = { address, symbol, decimals, image }
|
||||
|
||||
sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true)
|
||||
preferencesController.showWatchAssetUi = async () => {
|
||||
preferencesController.openPopup = async () => {
|
||||
await preferencesController.addToken(address, symbol, decimals, image)
|
||||
}
|
||||
|
||||
|
|
|
@ -345,7 +345,6 @@ describe('Transaction Controller', function () {
|
|||
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||
gasPrice: '0x77359400',
|
||||
gas: '0x7b0d',
|
||||
nonce: '0x4b',
|
||||
},
|
||||
metamaskNetworkId: currentNetworkId,
|
||||
}
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
const assert = require('assert')
|
||||
|
||||
const EdgeEncryptor = require('../../../app/scripts/edge-encryptor')
|
||||
|
||||
var password = 'passw0rd1'
|
||||
var data = 'some random data'
|
||||
|
||||
global.crypto = global.crypto || {
|
||||
getRandomValues: function (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
array[i] = Math.random() * 100
|
||||
}
|
||||
return array
|
||||
},
|
||||
}
|
||||
|
||||
describe('EdgeEncryptor', function () {
|
||||
|
||||
const edgeEncryptor = new EdgeEncryptor()
|
||||
describe('encrypt', function () {
|
||||
|
||||
it('should encrypt the data.', function (done) {
|
||||
edgeEncryptor.encrypt(password, data)
|
||||
.then(function (encryptedData) {
|
||||
assert.notEqual(data, encryptedData)
|
||||
assert.notEqual(encryptedData.length, 0)
|
||||
done()
|
||||
}).catch(function (err) {
|
||||
done(err)
|
||||
})
|
||||
})
|
||||
|
||||
it('should return proper format.', function (done) {
|
||||
edgeEncryptor.encrypt(password, data)
|
||||
.then(function (encryptedData) {
|
||||
const encryptedObject = JSON.parse(encryptedData)
|
||||
assert.ok(encryptedObject.data, 'there is no data')
|
||||
assert.ok(encryptedObject.iv && encryptedObject.iv.length !== 0, 'there is no iv')
|
||||
assert.ok(encryptedObject.salt && encryptedObject.salt.length !== 0, 'there is no salt')
|
||||
done()
|
||||
}).catch(function (err) {
|
||||
done(err)
|
||||
})
|
||||
})
|
||||
|
||||
it('should not return the same twice.', function (done) {
|
||||
|
||||
const encryptPromises = []
|
||||
encryptPromises.push(edgeEncryptor.encrypt(password, data))
|
||||
encryptPromises.push(edgeEncryptor.encrypt(password, data))
|
||||
|
||||
Promise.all(encryptPromises).then((encryptedData) => {
|
||||
assert.equal(encryptedData.length, 2)
|
||||
assert.notEqual(encryptedData[0], encryptedData[1])
|
||||
assert.notEqual(encryptedData[0].length, 0)
|
||||
assert.notEqual(encryptedData[1].length, 0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('decrypt', function () {
|
||||
it('should be able to decrypt the encrypted data.', function (done) {
|
||||
|
||||
edgeEncryptor.encrypt(password, data)
|
||||
.then(function (encryptedData) {
|
||||
edgeEncryptor.decrypt(password, encryptedData)
|
||||
.then(function (decryptedData) {
|
||||
assert.equal(decryptedData, data)
|
||||
done()
|
||||
})
|
||||
.catch(function (err) {
|
||||
done(err)
|
||||
})
|
||||
})
|
||||
.catch(function (err) {
|
||||
done(err)
|
||||
})
|
||||
})
|
||||
|
||||
it('cannot decrypt the encrypted data with wrong password.', function (done) {
|
||||
|
||||
edgeEncryptor.encrypt(password, data)
|
||||
.then(function (encryptedData) {
|
||||
edgeEncryptor.decrypt('wrong password', encryptedData)
|
||||
.then(function (decryptedData) {
|
||||
assert.fail('could decrypt with wrong password')
|
||||
done()
|
||||
})
|
||||
.catch(function (err) {
|
||||
assert.ok(err instanceof Error)
|
||||
assert.equal(err.message, 'Incorrect password')
|
||||
done()
|
||||
})
|
||||
})
|
||||
.catch(function (err) {
|
||||
done(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -12,12 +12,12 @@ describe('BinaryRenderer', function () {
|
|||
})
|
||||
|
||||
it('recovers message', function () {
|
||||
const result = binaryRenderer.hexToText(hex)
|
||||
const result = binaryRenderer.msgHexToText(hex)
|
||||
assert.equal(result, message)
|
||||
})
|
||||
|
||||
it('recovers message with hex prefix', function () {
|
||||
const result = binaryRenderer.hexToText('0x' + hex)
|
||||
const result = binaryRenderer.msgHexToText('0x' + hex)
|
||||
assert.equal(result, message)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
import React from 'react'
|
||||
import assert from 'assert'
|
||||
import thunk from 'redux-thunk'
|
||||
import { Provider } from 'react-redux'
|
||||
import configureMockStore from 'redux-mock-store'
|
||||
import { mount } from 'enzyme'
|
||||
|
||||
import TokenCell from '../../../../../ui/app/components/token-cell'
|
||||
import Identicon from '../../../../../ui/app/components/identicon'
|
||||
|
||||
describe('Token Cell', () => {
|
||||
let wrapper
|
||||
|
||||
const state = {
|
||||
metamask: {
|
||||
network: 'test',
|
||||
currentCurrency: 'usd',
|
||||
selectedTokenAddress: '0xToken',
|
||||
selectedAddress: '0xAddress',
|
||||
contractExchangeRates: {
|
||||
'0xAnotherToken': 0.015,
|
||||
},
|
||||
conversionRate: 7.00,
|
||||
},
|
||||
appState: {
|
||||
sidebar: {
|
||||
isOpen: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const middlewares = [thunk]
|
||||
const mockStore = configureMockStore(middlewares)
|
||||
const store = mockStore(state)
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<Provider store={store}>
|
||||
<TokenCell
|
||||
address={'0xAnotherToken'}
|
||||
symbol={'TEST'}
|
||||
string={'5.000'}
|
||||
network={22}
|
||||
currentCurrency={'usd'}
|
||||
image={'./test-image'}
|
||||
/>
|
||||
</Provider>,
|
||||
)
|
||||
})
|
||||
|
||||
it('renders Identicon with props from token cell', () => {
|
||||
assert.equal(wrapper.find(Identicon).prop('address'), '0xAnotherToken')
|
||||
assert.equal(wrapper.find(Identicon).prop('network'), 'test')
|
||||
assert.equal(wrapper.find(Identicon).prop('image'), './test-image')
|
||||
})
|
||||
|
||||
it('renders token balance', () => {
|
||||
assert.equal(wrapper.find('.token-list-item__token-balance').text(), '5.000')
|
||||
})
|
||||
|
||||
it('renders token symbol', () => {
|
||||
assert.equal(wrapper.find('.token-list-item__token-symbol').text(), 'TEST')
|
||||
})
|
||||
|
||||
it('renders converted fiat amount', () => {
|
||||
assert.equal(wrapper.find('.token-list-item__fiat-amount').text(), '0.52 USD')
|
||||
})
|
||||
|
||||
})
|
|
@ -19,6 +19,7 @@ const { POA,
|
|||
CLASSIC } = require('../../app/scripts/controllers/network/enums')
|
||||
const { hasUnconfirmedTransactions } = require('./helpers/confirm-transaction/util')
|
||||
const WebcamUtils = require('../lib/webcam-utils')
|
||||
import { getEnvironmentType } from '../../app/scripts/lib/util'
|
||||
|
||||
const actions = {
|
||||
_setBackgroundConnection: _setBackgroundConnection,
|
||||
|
@ -30,6 +31,9 @@ const actions = {
|
|||
MODAL_CLOSE: 'UI_MODAL_CLOSE',
|
||||
showModal: showModal,
|
||||
hideModal: hideModal,
|
||||
|
||||
CLOSE_NOTIFICATION_WINDOW: 'CLOSE_NOTIFICATION_WINDOW',
|
||||
|
||||
// sidebar state
|
||||
SIDEBAR_OPEN: 'UI_SIDEBAR_OPEN',
|
||||
SIDEBAR_CLOSE: 'UI_SIDEBAR_CLOSE',
|
||||
|
@ -173,7 +177,6 @@ const actions = {
|
|||
COMPLETED_TX: 'COMPLETED_TX',
|
||||
TRANSACTION_ERROR: 'TRANSACTION_ERROR',
|
||||
NEXT_TX: 'NEXT_TX',
|
||||
PREVIOUS_TX: 'PREV_TX',
|
||||
EDIT_TX: 'EDIT_TX',
|
||||
signMsg: signMsg,
|
||||
cancelMsg: cancelMsg,
|
||||
|
@ -181,19 +184,16 @@ const actions = {
|
|||
cancelPersonalMsg,
|
||||
signTypedMsg,
|
||||
cancelTypedMsg,
|
||||
sendTx: sendTx,
|
||||
signTx: signTx,
|
||||
signTokenTx: signTokenTx,
|
||||
updateTransaction,
|
||||
updateAndApproveTx,
|
||||
cancelTx: cancelTx,
|
||||
cancelTx,
|
||||
cancelTxs,
|
||||
completedTx: completedTx,
|
||||
txError: txError,
|
||||
nextTx: nextTx,
|
||||
editTx,
|
||||
previousTx: previousTx,
|
||||
cancelAllTx: cancelAllTx,
|
||||
viewPendingTx: viewPendingTx,
|
||||
VIEW_PENDING_TX: 'VIEW_PENDING_TX',
|
||||
updateTransactionParams,
|
||||
|
@ -370,8 +370,9 @@ const actions = {
|
|||
getRequestAccountTabIds,
|
||||
setOpenMetamaskTabsIDs,
|
||||
getOpenMetamaskTabsIds,
|
||||
|
||||
isCreatedWithCorrectDPath,
|
||||
closeCurrentNotificationWindow,
|
||||
closeNotificationWindow,
|
||||
}
|
||||
|
||||
module.exports = actions
|
||||
|
@ -945,9 +946,8 @@ function setCurrentCurrency (currencyCode) {
|
|||
|
||||
function signMsg (msgData) {
|
||||
log.debug('action - signMsg')
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
log.debug(`actions calling background.signMessage`)
|
||||
background.signMessage(msgData, (err, newState) => {
|
||||
|
@ -962,10 +962,7 @@ function signMsg (msgData) {
|
|||
}
|
||||
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
dispatch(closeCurrentNotificationWindow())
|
||||
|
||||
return resolve(msgData)
|
||||
})
|
||||
|
@ -975,7 +972,7 @@ function signMsg (msgData) {
|
|||
|
||||
function signPersonalMsg (msgData) {
|
||||
log.debug('action - signPersonalMsg')
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -993,9 +990,7 @@ function signPersonalMsg (msgData) {
|
|||
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
dispatch(actions.closeCurrentNotificationWindow())
|
||||
|
||||
return resolve(msgData)
|
||||
})
|
||||
|
@ -1005,7 +1000,7 @@ function signPersonalMsg (msgData) {
|
|||
|
||||
function signTypedMsg (msgData) {
|
||||
log.debug('action - signTypedMsg')
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -1023,9 +1018,7 @@ function signTypedMsg (msgData) {
|
|||
|
||||
dispatch(actions.completedTx(msgData.metamaskId))
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
dispatch(actions.closeCurrentNotificationWindow())
|
||||
|
||||
return resolve(msgData)
|
||||
})
|
||||
|
@ -1230,25 +1223,6 @@ function clearSend () {
|
|||
}
|
||||
|
||||
|
||||
function sendTx (txData) {
|
||||
log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`)
|
||||
return (dispatch, getState) => {
|
||||
log.debug(`actions calling background.approveTransaction`)
|
||||
background.approveTransaction(txData.id, (err) => {
|
||||
if (err) {
|
||||
err = err.message || err.error || err
|
||||
dispatch(actions.txError(err))
|
||||
return log.error(err)
|
||||
}
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function signTokenTx (tokenAddress, toAddress, amount, txData, confTxScreenParams) {
|
||||
return dispatch => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
@ -1294,10 +1268,9 @@ function updateTransaction (txData) {
|
|||
|
||||
function updateAndApproveTx (txData) {
|
||||
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
log.debug(`actions calling background.updateAndApproveTx`)
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
background.updateAndApproveTransaction(txData, err => {
|
||||
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
|
||||
|
@ -1320,11 +1293,7 @@ function updateAndApproveTx (txData) {
|
|||
dispatch(actions.clearSend())
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
dispatch(actions.setCurrentAccountTab('history'))
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
dispatch(actions.closeCurrentNotificationWindow())
|
||||
|
||||
return txData
|
||||
})
|
||||
|
@ -1358,7 +1327,7 @@ function txError (err) {
|
|||
}
|
||||
|
||||
function cancelMsg (msgData) {
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -1373,9 +1342,7 @@ function cancelMsg (msgData) {
|
|||
|
||||
dispatch(actions.completedTx(msgData.id))
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
dispatch(actions.closeCurrentNotificationWindow())
|
||||
|
||||
return resolve(msgData)
|
||||
})
|
||||
|
@ -1384,7 +1351,7 @@ function cancelMsg (msgData) {
|
|||
}
|
||||
|
||||
function cancelPersonalMsg (msgData) {
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -1399,9 +1366,7 @@ function cancelPersonalMsg (msgData) {
|
|||
|
||||
dispatch(actions.completedTx(id))
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
dispatch(actions.closeCurrentNotificationWindow())
|
||||
|
||||
return resolve(msgData)
|
||||
})
|
||||
|
@ -1410,7 +1375,7 @@ function cancelPersonalMsg (msgData) {
|
|||
}
|
||||
|
||||
function cancelTypedMsg (msgData) {
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -1425,9 +1390,7 @@ function cancelTypedMsg (msgData) {
|
|||
|
||||
dispatch(actions.completedTx(id))
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
dispatch(actions.closeCurrentNotificationWindow())
|
||||
|
||||
return resolve(msgData)
|
||||
})
|
||||
|
@ -1436,12 +1399,11 @@ function cancelTypedMsg (msgData) {
|
|||
}
|
||||
|
||||
function cancelTx (txData) {
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
log.debug(`background.cancelTransaction`)
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
background.cancelTransaction(txData.id, err => {
|
||||
background.cancelTransaction(txData.id, (err) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
|
@ -1450,15 +1412,12 @@ function cancelTx (txData) {
|
|||
})
|
||||
})
|
||||
.then(() => updateMetamaskStateFromBackground())
|
||||
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
||||
.then((newState) => dispatch(actions.updateMetamaskState(newState)))
|
||||
.then(() => {
|
||||
dispatch(actions.clearSend())
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
|
||||
if (!hasUnconfirmedTransactions(getState())) {
|
||||
return global.platform.closeNotificationWindow()
|
||||
}
|
||||
dispatch(actions.closeCurrentNotificationWindow())
|
||||
|
||||
return txData
|
||||
})
|
||||
|
@ -1471,9 +1430,9 @@ function cancelTx (txData) {
|
|||
* @return {function(*): Promise<void>}
|
||||
*/
|
||||
function cancelTxs (txDataList) {
|
||||
return async (dispatch, getState) => {
|
||||
return async (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
const txIds = txDataList.map(({id}) => id)
|
||||
const txIds = txDataList.map(({ id }) => id)
|
||||
const cancellations = txIds.map((id) => new Promise((resolve, reject) => {
|
||||
background.cancelTransaction(id, (err) => {
|
||||
if (err) {
|
||||
|
@ -1495,30 +1454,12 @@ function cancelTxs (txDataList) {
|
|||
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
|
||||
if (global.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION) {
|
||||
if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) {
|
||||
return global.platform.closeCurrentWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param {Array<object>} txsData
|
||||
* @return {Function}
|
||||
*/
|
||||
function cancelAllTx (txsData) {
|
||||
return (dispatch) => {
|
||||
txsData.forEach((txData, i) => {
|
||||
background.cancelTransaction(txData.id, () => {
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
if (i === txsData.length - 1) {
|
||||
dispatch(actions.goHome())
|
||||
global.platform.closeNotificationWindow()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
//
|
||||
// initialize screen
|
||||
//
|
||||
|
@ -1789,9 +1730,10 @@ function showConfTxPage (screenParams) {
|
|||
}
|
||||
}
|
||||
|
||||
function nextTx () {
|
||||
function nextTx (txId) {
|
||||
return {
|
||||
type: actions.NEXT_TX,
|
||||
value: txId,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1802,12 +1744,6 @@ function viewPendingTx (txId) {
|
|||
}
|
||||
}
|
||||
|
||||
function previousTx () {
|
||||
return {
|
||||
type: actions.PREVIOUS_TX,
|
||||
}
|
||||
}
|
||||
|
||||
function editTx (txId) {
|
||||
return {
|
||||
type: actions.EDIT_TX,
|
||||
|
@ -2158,6 +2094,23 @@ function hideModal (payload) {
|
|||
}
|
||||
}
|
||||
|
||||
function closeCurrentNotificationWindow () {
|
||||
return (dispatch, getState) => {
|
||||
if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION &&
|
||||
!hasUnconfirmedTransactions(getState())) {
|
||||
global.platform.closeCurrentWindow()
|
||||
|
||||
dispatch(actions.closeNotificationWindow())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeNotificationWindow () {
|
||||
return {
|
||||
type: actions.CLOSE_NOTIFICATION_WINDOW,
|
||||
}
|
||||
}
|
||||
|
||||
function showSidebar ({ transitionName, type }) {
|
||||
return {
|
||||
type: actions.SIDEBAR_OPEN,
|
||||
|
@ -2362,7 +2315,7 @@ function showSendContractPage ({methodSelected, methodABI, inputValues}) {
|
|||
function buyEth (opts) {
|
||||
return (dispatch) => {
|
||||
const url = getBuyEthUrl(opts)
|
||||
global.platform.openWindow({ url })
|
||||
global.platform.openTab({ url })
|
||||
dispatch({
|
||||
type: actions.BUY_ETH,
|
||||
})
|
||||
|
|
|
@ -68,7 +68,7 @@ TokenMenuDropdown.prototype.render = function () {
|
|||
onClick: (e) => {
|
||||
e.stopPropagation()
|
||||
const url = ethNetProps.explorerLinks.getExplorerAccountLinkFor(this.props.token.address, this.props.network)
|
||||
global.platform.openWindow({ url })
|
||||
global.platform.openTab({ url })
|
||||
this.props.onClose()
|
||||
},
|
||||
text: this.context.t('viewOnEtherscan'),
|
||||
|
|
|
@ -25,9 +25,9 @@ function mapStateToProps (state) {
|
|||
}
|
||||
|
||||
IdenticonComponent.prototype.render = function () {
|
||||
var props = this.props
|
||||
const props = this.props
|
||||
const { className = '', address, image } = props
|
||||
var diameter = props.diameter || this.defaultDiameter
|
||||
const diameter = props.diameter || this.defaultDiameter
|
||||
const style = {
|
||||
height: diameter,
|
||||
width: diameter,
|
||||
|
@ -66,14 +66,14 @@ IdenticonComponent.prototype.render = function () {
|
|||
}
|
||||
|
||||
IdenticonComponent.prototype.componentDidMount = function () {
|
||||
var props = this.props
|
||||
const props = this.props
|
||||
const { address, useBlockie } = props
|
||||
|
||||
if (!address) return
|
||||
|
||||
if (!isNode) {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
var container = findDOMNode(this)
|
||||
const container = findDOMNode(this)
|
||||
|
||||
const diameter = props.diameter || this.defaultDiameter
|
||||
|
||||
|
@ -86,17 +86,17 @@ IdenticonComponent.prototype.componentDidMount = function () {
|
|||
}
|
||||
|
||||
IdenticonComponent.prototype.componentDidUpdate = function () {
|
||||
var props = this.props
|
||||
const props = this.props
|
||||
const { address, useBlockie } = props
|
||||
|
||||
if (!address) return
|
||||
|
||||
if (!isNode) {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
var container = findDOMNode(this)
|
||||
const container = findDOMNode(this)
|
||||
|
||||
var children = container.children
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
const children = container.children
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
container.removeChild(children[i])
|
||||
}
|
||||
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const connect = require('react-redux').connect
|
||||
const Identicon = require('./identicon')
|
||||
const ethNetProps = require('eth-net-props')
|
||||
const selectors = require('../selectors')
|
||||
const actions = require('../actions')
|
||||
const { conversionUtil, multiplyCurrencies } = require('../conversion-util')
|
||||
|
||||
const TokenMenuDropdown = require('./dropdowns/token-menu-dropdown.js')
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
network: state.metamask.network,
|
||||
currentCurrency: state.metamask.currentCurrency,
|
||||
selectedTokenAddress: state.metamask.selectedTokenAddress,
|
||||
userAddress: selectors.getSelectedAddress(state),
|
||||
contractExchangeRates: state.metamask.contractExchangeRates,
|
||||
conversionRate: state.metamask.conversionRate,
|
||||
sidebarOpen: state.appState.sidebar.isOpen,
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
setSelectedToken: address => dispatch(actions.setSelectedToken(address)),
|
||||
hideSidebar: () => dispatch(actions.hideSidebar()),
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(TokenCell)
|
||||
|
||||
inherits(TokenCell, Component)
|
||||
function TokenCell () {
|
||||
Component.call(this)
|
||||
|
||||
this.state = {
|
||||
tokenMenuOpen: false,
|
||||
}
|
||||
}
|
||||
|
||||
TokenCell.prototype.render = function () {
|
||||
const { tokenMenuOpen } = this.state
|
||||
const props = this.props
|
||||
const {
|
||||
address,
|
||||
symbol,
|
||||
string,
|
||||
network,
|
||||
setSelectedToken,
|
||||
selectedTokenAddress,
|
||||
contractExchangeRates,
|
||||
conversionRate,
|
||||
hideSidebar,
|
||||
sidebarOpen,
|
||||
currentCurrency,
|
||||
// userAddress,
|
||||
image,
|
||||
} = props
|
||||
let currentTokenToFiatRate
|
||||
let currentTokenInFiat
|
||||
let formattedFiat = ''
|
||||
|
||||
if (contractExchangeRates[address]) {
|
||||
currentTokenToFiatRate = multiplyCurrencies(
|
||||
contractExchangeRates[address],
|
||||
conversionRate,
|
||||
)
|
||||
currentTokenInFiat = conversionUtil(string, {
|
||||
fromNumericBase: 'dec',
|
||||
fromCurrency: symbol,
|
||||
toCurrency: currentCurrency.toUpperCase(),
|
||||
numberOfDecimals: 2,
|
||||
conversionRate: currentTokenToFiatRate,
|
||||
})
|
||||
formattedFiat = currentTokenInFiat.toString() === '0'
|
||||
? ''
|
||||
: `${currentTokenInFiat} ${currentCurrency.toUpperCase()}`
|
||||
}
|
||||
|
||||
const showFiat = Boolean(currentTokenInFiat) && currentCurrency.toUpperCase() !== symbol
|
||||
|
||||
return (
|
||||
h('div.token-list-item', {
|
||||
className: `token-list-item ${selectedTokenAddress === address ? 'token-list-item--active' : ''}`,
|
||||
// style: { cursor: network === '1' ? 'pointer' : 'default' },
|
||||
// onClick: this.view.bind(this, address, userAddress, network),
|
||||
onClick: () => {
|
||||
setSelectedToken(address)
|
||||
selectedTokenAddress !== address && sidebarOpen && hideSidebar()
|
||||
},
|
||||
}, [
|
||||
|
||||
h(Identicon, {
|
||||
className: 'token-list-item__identicon',
|
||||
diameter: 50,
|
||||
address,
|
||||
network,
|
||||
image,
|
||||
}),
|
||||
|
||||
h('div.token-list-item__balance-ellipsis', null, [
|
||||
h('div.token-list-item__balance-wrapper', null, [
|
||||
h('div.token-list-item__token-balance', `${string || 0}`),
|
||||
h('div.token-list-item__token-symbol', symbol),
|
||||
showFiat && h('div.token-list-item__fiat-amount', {
|
||||
style: {},
|
||||
}, formattedFiat),
|
||||
]),
|
||||
|
||||
h('i.fa.fa-ellipsis-h.fa-lg.token-list-item__ellipsis.cursor-pointer', {
|
||||
onClick: (e) => {
|
||||
e.stopPropagation()
|
||||
this.setState({ tokenMenuOpen: true })
|
||||
},
|
||||
}),
|
||||
|
||||
]),
|
||||
|
||||
|
||||
tokenMenuOpen && h(TokenMenuDropdown, {
|
||||
onClose: () => this.setState({ tokenMenuOpen: false }),
|
||||
token: { symbol, address },
|
||||
}),
|
||||
|
||||
/*
|
||||
h('button', {
|
||||
onClick: this.send.bind(this, address),
|
||||
}, 'SEND'),
|
||||
*/
|
||||
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
TokenCell.prototype.send = function (address, event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
const url = tokenFactoryFor(address)
|
||||
if (url) {
|
||||
navigateTo(url)
|
||||
}
|
||||
}
|
||||
|
||||
TokenCell.prototype.view = function (address, userAddress, network, event) {
|
||||
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
|
||||
if (url) {
|
||||
navigateTo(url)
|
||||
}
|
||||
}
|
||||
|
||||
function navigateTo (url) {
|
||||
global.platform.openWindow({ url })
|
||||
}
|
||||
|
||||
function tokenFactoryFor (tokenAddress) {
|
||||
return `https://tokenfactory.surge.sh/#/token/${tokenAddress}`
|
||||
}
|
||||
|
|
@ -79,7 +79,8 @@ function reduceApp (state, action) {
|
|||
customHdPaths: customHdPaths,
|
||||
}, state.appState)
|
||||
|
||||
let curPendingTxIndex = appState.currentView.pendingTxIndex || 0
|
||||
const curPendingTxIndex = appState.currentView.pendingTxIndex || 0
|
||||
const curPendingTxId = appState.currentView.pendingTxId || 0
|
||||
|
||||
switch (action.type) {
|
||||
// dropdown methods
|
||||
|
@ -507,6 +508,7 @@ function reduceApp (state, action) {
|
|||
currentView: {
|
||||
name: 'confTx',
|
||||
pendingTxIndex: action.id ? indexForPending(state, action.id) : 0,
|
||||
pendingTxId: action.id,
|
||||
screenParams: action.value,
|
||||
},
|
||||
transForward: action.transForward,
|
||||
|
@ -559,11 +561,14 @@ function reduceApp (state, action) {
|
|||
}
|
||||
|
||||
case actions.NEXT_TX:
|
||||
const increment = (action.value - curPendingTxId)
|
||||
return extend(appState, {
|
||||
transForward: true,
|
||||
currentView: {
|
||||
name: 'confTx',
|
||||
pendingTxIndex: ++curPendingTxIndex,
|
||||
pendingTxIndex: curPendingTxIndex + increment,
|
||||
pendingTxId: action.value,
|
||||
index: curPendingTxIndex + increment,
|
||||
warning: null,
|
||||
},
|
||||
})
|
||||
|
@ -575,16 +580,7 @@ function reduceApp (state, action) {
|
|||
currentView: {
|
||||
name: 'confTx',
|
||||
pendingTxIndex,
|
||||
warning: null,
|
||||
},
|
||||
})
|
||||
|
||||
case actions.PREVIOUS_TX:
|
||||
return extend(appState, {
|
||||
transForward: false,
|
||||
currentView: {
|
||||
name: 'confTx',
|
||||
pendingTxIndex: --curPendingTxIndex,
|
||||
pendingTxId: action.value,
|
||||
warning: null,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -6,6 +6,8 @@ import { roundExponential } from '../helpers/confirm-transaction/util'
|
|||
const unapprovedTxsSelector = state => state.metamask.unapprovedTxs
|
||||
const unapprovedMsgsSelector = state => state.metamask.unapprovedMsgs
|
||||
const unapprovedPersonalMsgsSelector = state => state.metamask.unapprovedPersonalMsgs
|
||||
const unapprovedDecryptMsgsSelector = (state) => state.metamask.unapprovedDecryptMsgs
|
||||
const unapprovedEncryptionPublicKeyMsgsSelector = (state) => state.metamask.unapprovedEncryptionPublicKeyMsgs
|
||||
const unapprovedTypedMessagesSelector = state => state.metamask.unapprovedTypedMessages
|
||||
const networkSelector = state => state.metamask.network
|
||||
|
||||
|
@ -13,18 +15,24 @@ export const unconfirmedTransactionsListSelector = createSelector(
|
|||
unapprovedTxsSelector,
|
||||
unapprovedMsgsSelector,
|
||||
unapprovedPersonalMsgsSelector,
|
||||
unapprovedDecryptMsgsSelector,
|
||||
unapprovedEncryptionPublicKeyMsgsSelector,
|
||||
unapprovedTypedMessagesSelector,
|
||||
networkSelector,
|
||||
(
|
||||
unapprovedTxs = {},
|
||||
unapprovedMsgs = {},
|
||||
unapprovedPersonalMsgs = {},
|
||||
unapprovedDecryptMsgs = {},
|
||||
unapprovedEncryptionPublicKeyMsgs = {},
|
||||
unapprovedTypedMessages = {},
|
||||
network,
|
||||
) => txHelper(
|
||||
unapprovedTxs,
|
||||
unapprovedMsgs,
|
||||
unapprovedPersonalMsgs,
|
||||
unapprovedDecryptMsgs,
|
||||
unapprovedEncryptionPublicKeyMsgs,
|
||||
unapprovedTypedMessages,
|
||||
network,
|
||||
) || [],
|
||||
|
@ -34,12 +42,16 @@ export const unconfirmedTransactionsHashSelector = createSelector(
|
|||
unapprovedTxsSelector,
|
||||
unapprovedMsgsSelector,
|
||||
unapprovedPersonalMsgsSelector,
|
||||
unapprovedDecryptMsgsSelector,
|
||||
unapprovedEncryptionPublicKeyMsgsSelector,
|
||||
unapprovedTypedMessagesSelector,
|
||||
networkSelector,
|
||||
(
|
||||
unapprovedTxs = {},
|
||||
unapprovedMsgs = {},
|
||||
unapprovedPersonalMsgs = {},
|
||||
unapprovedDecryptMsgs = {},
|
||||
unapprovedEncryptionPublicKeyMsgs = {},
|
||||
unapprovedTypedMessages = {},
|
||||
network,
|
||||
) => {
|
||||
|
@ -58,6 +70,8 @@ export const unconfirmedTransactionsHashSelector = createSelector(
|
|||
...filteredUnapprovedTxs,
|
||||
...unapprovedMsgs,
|
||||
...unapprovedPersonalMsgs,
|
||||
...unapprovedDecryptMsgs,
|
||||
...unapprovedEncryptionPublicKeyMsgs,
|
||||
...unapprovedTypedMessages,
|
||||
}
|
||||
},
|
||||
|
@ -65,18 +79,24 @@ export const unconfirmedTransactionsHashSelector = createSelector(
|
|||
|
||||
const unapprovedMsgCountSelector = state => state.metamask.unapprovedMsgCount
|
||||
const unapprovedPersonalMsgCountSelector = state => state.metamask.unapprovedPersonalMsgCount
|
||||
const unapprovedDecryptMsgCountSelector = (state) => state.metamask.unapprovedDecryptMsgCount
|
||||
const unapprovedEncryptionPublicKeyMsgCountSelector = (state) => state.metamask.unapprovedEncryptionPublicKeyMsgCount
|
||||
const unapprovedTypedMessagesCountSelector = state => state.metamask.unapprovedTypedMessagesCount
|
||||
|
||||
export const unconfirmedTransactionsCountSelector = createSelector(
|
||||
unapprovedTxsSelector,
|
||||
unapprovedMsgCountSelector,
|
||||
unapprovedPersonalMsgCountSelector,
|
||||
unapprovedDecryptMsgCountSelector,
|
||||
unapprovedEncryptionPublicKeyMsgCountSelector,
|
||||
unapprovedTypedMessagesCountSelector,
|
||||
networkSelector,
|
||||
(
|
||||
unapprovedTxs = {},
|
||||
unapprovedMsgCount = 0,
|
||||
unapprovedPersonalMsgCount = 0,
|
||||
unapprovedDecryptMsgCount = 0,
|
||||
unapprovedEncryptionPublicKeyMsgCount = 0,
|
||||
unapprovedTypedMessagesCount = 0,
|
||||
network,
|
||||
) => {
|
||||
|
@ -86,7 +106,7 @@ export const unconfirmedTransactionsCountSelector = createSelector(
|
|||
})
|
||||
|
||||
return filteredUnapprovedTxIds.length + unapprovedTypedMessagesCount + unapprovedMsgCount +
|
||||
unapprovedPersonalMsgCount
|
||||
unapprovedPersonalMsgCount + unapprovedDecryptMsgCount + unapprovedEncryptionPublicKeyMsgCount
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -132,15 +152,16 @@ export const tokenAmountAndToAddressSelector = createSelector(
|
|||
let tokenAmount = 0
|
||||
|
||||
if (params && params.length) {
|
||||
const toParam = params.find(param => param.name === TOKEN_PARAM_TO)
|
||||
const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE)
|
||||
const toParam = params.find((param) => param.name === TOKEN_PARAM_TO)
|
||||
const valueParam = params.find((param) => param.name === TOKEN_PARAM_VALUE)
|
||||
toAddress = toParam ? toParam.value : params[0].value
|
||||
const value = valueParam ? Number(valueParam.value) : Number(params[1].value)
|
||||
tokenAmount = roundExponential(value)
|
||||
|
||||
if (tokenDecimals) {
|
||||
tokenAmount = calcTokenAmount(value, tokenDecimals)
|
||||
tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber()
|
||||
}
|
||||
|
||||
tokenAmount = roundExponential(tokenAmount)
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -158,11 +179,11 @@ export const approveTokenAmountAndToAddressSelector = createSelector(
|
|||
let tokenAmount = 0
|
||||
|
||||
if (params && params.length) {
|
||||
toAddress = params.find(param => param.name === TOKEN_PARAM_SPENDER).value
|
||||
const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
|
||||
toAddress = params.find((param) => param.name === TOKEN_PARAM_SPENDER).value
|
||||
const value = Number(params.find((param) => param.name === TOKEN_PARAM_VALUE).value)
|
||||
|
||||
if (tokenDecimals) {
|
||||
tokenAmount = calcTokenAmount(value, tokenDecimals)
|
||||
tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber()
|
||||
}
|
||||
|
||||
tokenAmount = roundExponential(tokenAmount)
|
||||
|
@ -183,11 +204,11 @@ export const sendTokenTokenAmountAndToAddressSelector = createSelector(
|
|||
let tokenAmount = 0
|
||||
|
||||
if (params && params.length) {
|
||||
toAddress = params.find(param => param.name === TOKEN_PARAM_TO).value
|
||||
let value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
|
||||
toAddress = params.find((param) => param.name === TOKEN_PARAM_TO).value
|
||||
let value = Number(params.find((param) => param.name === TOKEN_PARAM_VALUE).value)
|
||||
|
||||
if (tokenDecimals) {
|
||||
value = calcTokenAmount(value, tokenDecimals)
|
||||
value = calcTokenAmount(value, tokenDecimals).toNumber()
|
||||
}
|
||||
|
||||
tokenAmount = roundExponential(value)
|
||||
|
|
|
@ -2,8 +2,8 @@ import log from 'loglevel'
|
|||
import BigNumber from 'bignumber.js'
|
||||
import contractMapETH from 'eth-contract-metadata'
|
||||
import contractMapPOA from 'poa-contract-metadata'
|
||||
import contractMapRSK from 'rsk-contract-metadata'
|
||||
import contractMapRSKTest from 'rsk-test-contract-metadata'
|
||||
import contractMapRSK from '@rsksmart/rsk-contract-metadata'
|
||||
import contractMapRSKTest from '@rsksmart/rsk-testnet-contract-metadata'
|
||||
const util = require('./util')
|
||||
|
||||
const casedContractMapETH = Object.keys(contractMapETH).reduce((acc, base) => {
|
||||
|
|
|
@ -12,7 +12,7 @@ function formatDate (date) {
|
|||
return vreme.format(new Date(date), '3/16/2014 at 14:30')
|
||||
}
|
||||
|
||||
var valueTable = {
|
||||
const valueTable = {
|
||||
wei: '1000000000000000000',
|
||||
kwei: '1000000000000000',
|
||||
mwei: '1000000000000',
|
||||
|
@ -25,8 +25,8 @@ var valueTable = {
|
|||
gether: '0.000000001',
|
||||
tether: '0.000000000001',
|
||||
}
|
||||
var bnTable = {}
|
||||
for (var currency in valueTable) {
|
||||
const bnTable = {}
|
||||
for (const currency in valueTable) {
|
||||
bnTable[currency] = new ethUtil.BN(valueTable[currency], 10)
|
||||
}
|
||||
|
||||
|
@ -79,12 +79,12 @@ function addressSummary (address, firstSegLength = 10, lastSegLength = 4, includ
|
|||
|
||||
function miniAddressSummary (address) {
|
||||
if (!address) return ''
|
||||
var checked = checksumAddress(address)
|
||||
const checked = checksumAddress(address)
|
||||
return checked ? checked.slice(0, 4) + '...' + checked.slice(-4) : '...'
|
||||
}
|
||||
|
||||
function isValidAddress (address) {
|
||||
var prefixed = ethUtil.addHexPrefix(address)
|
||||
const prefixed = ethUtil.addHexPrefix(address)
|
||||
if (address === '0x0000000000000000000000000000000000000000') return false
|
||||
return (isAllOneCase(prefixed) && ethUtil.isValidAddress(prefixed)) || ethUtil.isValidChecksumAddress(prefixed)
|
||||
}
|
||||
|
@ -94,33 +94,33 @@ function isValidENSAddress (address) {
|
|||
}
|
||||
|
||||
function isInvalidChecksumAddress (address) {
|
||||
var prefixed = ethUtil.addHexPrefix(address)
|
||||
const prefixed = ethUtil.addHexPrefix(address)
|
||||
if (address === '0x0000000000000000000000000000000000000000') return false
|
||||
return !isAllOneCase(prefixed) && !ethUtil.isValidChecksumAddress(prefixed) && ethUtil.isValidAddress(prefixed)
|
||||
}
|
||||
|
||||
function isAllOneCase (address) {
|
||||
if (!address) return true
|
||||
var lower = address.toLowerCase()
|
||||
var upper = address.toUpperCase()
|
||||
const lower = address.toLowerCase()
|
||||
const upper = address.toUpperCase()
|
||||
return address === lower || address === upper
|
||||
}
|
||||
|
||||
// Takes wei Hex, returns wei BN, even if input is null
|
||||
function numericBalance (balance) {
|
||||
if (!balance) return new ethUtil.BN(0, 16)
|
||||
var stripped = ethUtil.stripHexPrefix(balance)
|
||||
const stripped = ethUtil.stripHexPrefix(balance)
|
||||
return new ethUtil.BN(stripped, 16)
|
||||
}
|
||||
|
||||
// Takes hex, returns [beforeDecimal, afterDecimal]
|
||||
function parseBalance (balance) {
|
||||
var beforeDecimal, afterDecimal
|
||||
let afterDecimal
|
||||
const wei = numericBalance(balance)
|
||||
var weiString = wei.toString()
|
||||
const weiString = wei.toString()
|
||||
const trailingZeros = /0+$/
|
||||
|
||||
beforeDecimal = weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0'
|
||||
const beforeDecimal = weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0'
|
||||
afterDecimal = ('000000000000000000' + wei).slice(-18).replace(trailingZeros, '')
|
||||
if (afterDecimal === '') { afterDecimal = '0' }
|
||||
return [beforeDecimal, afterDecimal]
|
||||
|
@ -129,14 +129,14 @@ function parseBalance (balance) {
|
|||
// Takes wei hex, returns an object with three properties.
|
||||
// Its "formatted" property is what we generally use to render values.
|
||||
function formatBalance (balance, decimalsToKeep, needsParse = true) {
|
||||
var parsed = needsParse ? parseBalance(balance) : balance.split('.')
|
||||
var beforeDecimal = parsed[0]
|
||||
var afterDecimal = parsed[1]
|
||||
var formatted = 'None'
|
||||
const parsed = needsParse ? parseBalance(balance) : balance.split('.')
|
||||
const beforeDecimal = parsed[0]
|
||||
let afterDecimal = parsed[1]
|
||||
let formatted = 'None'
|
||||
if (decimalsToKeep === undefined) {
|
||||
if (beforeDecimal === '0') {
|
||||
if (afterDecimal !== '0') {
|
||||
var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits
|
||||
const sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits
|
||||
if (sigFigs) { afterDecimal = sigFigs[0] }
|
||||
formatted = '0.' + afterDecimal + ' ETH'
|
||||
}
|
||||
|
@ -152,11 +152,11 @@ function formatBalance (balance, decimalsToKeep, needsParse = true) {
|
|||
|
||||
|
||||
function generateBalanceObject (formattedBalance, decimalsToKeep = 1) {
|
||||
var balance = formattedBalance.split(' ')[0]
|
||||
var label = formattedBalance.split(' ')[1]
|
||||
var beforeDecimal = balance.split('.')[0]
|
||||
var afterDecimal = balance.split('.')[1]
|
||||
var shortBalance = shortenBalance(balance, decimalsToKeep)
|
||||
let balance = formattedBalance.split(' ')[0]
|
||||
const label = formattedBalance.split(' ')[1]
|
||||
const beforeDecimal = balance.split('.')[0]
|
||||
const afterDecimal = balance.split('.')[1]
|
||||
const shortBalance = shortenBalance(balance, decimalsToKeep)
|
||||
|
||||
if (beforeDecimal === '0' && afterDecimal.substr(0, 5) === '00000') {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
|
@ -173,8 +173,8 @@ function generateBalanceObject (formattedBalance, decimalsToKeep = 1) {
|
|||
}
|
||||
|
||||
function shortenBalance (balance, decimalsToKeep = 1) {
|
||||
var truncatedValue
|
||||
var convertedBalance = parseFloat(balance)
|
||||
let truncatedValue
|
||||
const convertedBalance = parseFloat(balance)
|
||||
if (convertedBalance > 1000000) {
|
||||
truncatedValue = (balance / 1000000).toFixed(decimalsToKeep)
|
||||
return `${truncatedValue}m`
|
||||
|
@ -186,7 +186,7 @@ function shortenBalance (balance, decimalsToKeep = 1) {
|
|||
} else if (convertedBalance < 0.001) {
|
||||
return '<0.001'
|
||||
} else if (convertedBalance < 1) {
|
||||
var stringBalance = convertedBalance.toString()
|
||||
const stringBalance = convertedBalance.toString()
|
||||
if (stringBalance.split('.')[1].length > 3) {
|
||||
return convertedBalance.toFixed(3)
|
||||
} else {
|
||||
|
@ -198,7 +198,7 @@ function shortenBalance (balance, decimalsToKeep = 1) {
|
|||
}
|
||||
|
||||
function dataSize (data) {
|
||||
var size = data ? ethUtil.stripHexPrefix(data).length : 0
|
||||
const size = data ? ethUtil.stripHexPrefix(data).length : 0
|
||||
return size + ' bytes'
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ function normalizeEthStringToWei (str) {
|
|||
const parts = str.split('.')
|
||||
let eth = new ethUtil.BN(parts[0], 10).mul(bnTable.wei)
|
||||
if (parts[1]) {
|
||||
var decimal = parts[1]
|
||||
let decimal = parts[1]
|
||||
while (decimal.length < 18) {
|
||||
decimal += '0'
|
||||
}
|
||||
|
@ -228,24 +228,24 @@ function normalizeEthStringToWei (str) {
|
|||
return eth
|
||||
}
|
||||
|
||||
var multiple = new ethUtil.BN('10000', 10)
|
||||
const multiple = new ethUtil.BN('10000', 10)
|
||||
function normalizeNumberToWei (n, currency) {
|
||||
var enlarged = n * 10000
|
||||
var amount = new ethUtil.BN(String(enlarged), 10)
|
||||
const enlarged = n * 10000
|
||||
const amount = new ethUtil.BN(String(enlarged), 10)
|
||||
return normalizeToWei(amount, currency).div(multiple)
|
||||
}
|
||||
|
||||
function readableDate (ms) {
|
||||
var date = new Date(ms)
|
||||
var month = date.getMonth()
|
||||
var day = date.getDate()
|
||||
var year = date.getFullYear()
|
||||
var hours = date.getHours()
|
||||
var minutes = '0' + date.getMinutes()
|
||||
var seconds = '0' + date.getSeconds()
|
||||
const date = new Date(ms)
|
||||
const month = date.getMonth()
|
||||
const day = date.getDate()
|
||||
const year = date.getFullYear()
|
||||
const hours = date.getHours()
|
||||
const minutes = '0' + date.getMinutes()
|
||||
const seconds = '0' + date.getSeconds()
|
||||
|
||||
var dateStr = `${month}/${day}/${year}`
|
||||
var time = `${hours}:${minutes.substr(-2)}:${seconds.substr(-2)}`
|
||||
const dateStr = `${month}/${day}/${year}`
|
||||
const time = `${hours}:${minutes.substr(-2)}:${seconds.substr(-2)}`
|
||||
return `${dateStr} ${time}`
|
||||
}
|
||||
|
||||
|
|
|
@ -54,9 +54,8 @@ async function startApp (metamaskState, accountManager, opts) {
|
|||
const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network)
|
||||
const numberOfUnapprivedTx = unapprovedTxsAll.length
|
||||
if (numberOfUnapprivedTx > 0) {
|
||||
|
||||
store.dispatch(actions.showConfTxPage({
|
||||
id: unapprovedTxsAll[numberOfUnapprivedTx - 1].id,
|
||||
id: unapprovedTxsAll[0].id,
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
// helper functions for that ctx
|
||||
function write(buffer, offs) {
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
for (var j = 0; j < arguments[i].length; j++) {
|
||||
for (let i = 2; i < arguments.length; i++) {
|
||||
for (let j = 0; j < arguments[i].length; j++) {
|
||||
buffer[offs++] = arguments[i].charAt(j);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
|||
return String.fromCharCode(w & 255, (w >> 8) & 255);
|
||||
}
|
||||
|
||||
var PNG = function(width,height,depth) {
|
||||
const PNG = function(width,height,depth) {
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
@ -66,10 +66,10 @@
|
|||
this.palette = new Object();
|
||||
this.pindex = 0;
|
||||
|
||||
var _crc32 = new Array();
|
||||
const _crc32 = new Array();
|
||||
|
||||
// initialize buffer with zero bytes
|
||||
for (var i = 0; i < this.buffer_size; i++) {
|
||||
for (let i = 0; i < this.buffer_size; i++) {
|
||||
this.buffer[i] = "\x00";
|
||||
}
|
||||
|
||||
|
@ -81,14 +81,14 @@
|
|||
write(this.buffer, this.iend_offs, byte4(this.iend_size - 12), 'IEND');
|
||||
|
||||
// initialize deflate header
|
||||
var header = ((8 + (7 << 4)) << 8) | (3 << 6);
|
||||
const header = ((8 + (7 << 4)) << 8) | (3 << 6);
|
||||
header+= 31 - (header % 31);
|
||||
|
||||
write(this.buffer, this.idat_offs + 8, byte2(header));
|
||||
|
||||
// initialize deflate block headers
|
||||
for (var i = 0; (i << 16) - 1 < this.pix_size; i++) {
|
||||
var size, bits;
|
||||
for (let i = 0; (i << 16) - 1 < this.pix_size; i++) {
|
||||
let size, bits;
|
||||
if (i + 0xffff < this.pix_size) {
|
||||
size = 0xffff;
|
||||
bits = "\x00";
|
||||
|
@ -100,9 +100,9 @@
|
|||
}
|
||||
|
||||
/* Create crc32 lookup table */
|
||||
for (var i = 0; i < 256; i++) {
|
||||
var c = i;
|
||||
for (var j = 0; j < 8; j++) {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
const c = i;
|
||||
for (let j = 0; j < 8; j++) {
|
||||
if (c & 1) {
|
||||
c = -306674912 ^ ((c >> 1) & 0x7fffffff);
|
||||
} else {
|
||||
|
@ -114,8 +114,8 @@
|
|||
|
||||
// compute the index into a png for a given pixel
|
||||
this.index = function(x,y) {
|
||||
var i = y * (this.width + 1) + x + 1;
|
||||
var j = this.idat_offs + 8 + 2 + 5 * Math.floor((i / 0xffff) + 1) + i;
|
||||
const i = y * (this.width + 1) + x + 1;
|
||||
const j = this.idat_offs + 8 + 2 + 5 * Math.floor((i / 0xffff) + 1) + i;
|
||||
return j;
|
||||
};
|
||||
|
||||
|
@ -123,12 +123,12 @@
|
|||
this.color = function(red, green, blue, alpha) {
|
||||
|
||||
alpha = alpha >= 0 ? alpha : 255;
|
||||
var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue;
|
||||
const color = (((((alpha << 8) | red) << 8) | green) << 8) | blue;
|
||||
|
||||
if (typeof this.palette[color] == "undefined") {
|
||||
if (this.pindex == this.depth) return "\x00";
|
||||
|
||||
var ndx = this.plte_offs + 8 + 3 * this.pindex;
|
||||
const ndx = this.plte_offs + 8 + 3 * this.pindex;
|
||||
|
||||
this.buffer[ndx + 0] = String.fromCharCode(red);
|
||||
this.buffer[ndx + 1] = String.fromCharCode(green);
|
||||
|
@ -143,13 +143,13 @@
|
|||
// output a PNG string, Base64 encoded
|
||||
this.getBase64 = function() {
|
||||
|
||||
var s = this.getDump();
|
||||
const s = this.getDump();
|
||||
|
||||
var ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
var c1, c2, c3, e1, e2, e3, e4;
|
||||
var l = s.length;
|
||||
var i = 0;
|
||||
var r = "";
|
||||
const ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
let c1, c2, c3, e1, e2, e3, e4;
|
||||
const l = s.length;
|
||||
const i = 0;
|
||||
const r = "";
|
||||
|
||||
do {
|
||||
c1 = s.charCodeAt(i);
|
||||
|
@ -168,14 +168,14 @@
|
|||
this.getDump = function() {
|
||||
|
||||
// compute adler32 of output pixels + row filter bytes
|
||||
var BASE = 65521; /* largest prime smaller than 65536 */
|
||||
var NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
||||
var s1 = 1;
|
||||
var s2 = 0;
|
||||
var n = NMAX;
|
||||
const BASE = 65521; /* largest prime smaller than 65536 */
|
||||
const NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
||||
const s1 = 1;
|
||||
const s2 = 0;
|
||||
const n = NMAX;
|
||||
|
||||
for (var y = 0; y < this.height; y++) {
|
||||
for (var x = -1; x < this.width; x++) {
|
||||
for (let y = 0; y < this.height; y++) {
|
||||
for (let x = -1; x < this.width; x++) {
|
||||
s1+= this.buffer[this.index(x, y)].charCodeAt(0);
|
||||
s2+= s1;
|
||||
if ((n-= 1) == 0) {
|
||||
|
@ -191,8 +191,8 @@
|
|||
|
||||
// compute crc32 of the PNG chunks
|
||||
function crc32(png, offs, size) {
|
||||
var crc = -1;
|
||||
for (var i = 4; i < size-4; i += 1) {
|
||||
const crc = -1;
|
||||
for (let i = 4; i < size-4; i += 1) {
|
||||
crc = _crc32[(crc ^ png[offs+i].charCodeAt(0)) & 0xff] ^ ((crc >> 8) & 0x00ffffff);
|
||||
}
|
||||
write(png, offs+size-4, byte4(crc ^ -1));
|
||||
|
@ -209,8 +209,8 @@
|
|||
};
|
||||
|
||||
this.fillRect = function (x, y, w, h, color) {
|
||||
for(var i = 0; i < w; i++) {
|
||||
for (var j = 0; j < h; j++) {
|
||||
for(let i = 0; i < w; i++) {
|
||||
for (let j = 0; j < h; j++) {
|
||||
this.buffer[this.index(x+i, y+j)] = color;
|
||||
}
|
||||
}
|
||||
|
@ -240,13 +240,13 @@
|
|||
}
|
||||
|
||||
function hsl2rgb(h, s, l){
|
||||
var r, g, b;
|
||||
let r, g, b;
|
||||
|
||||
if(s == 0){
|
||||
r = g = b = l; // achromatic
|
||||
}else{
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
const p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3);
|
||||
|
@ -256,20 +256,20 @@
|
|||
}
|
||||
|
||||
// The random number is a js implementation of the Xorshift PRNG
|
||||
var randseed = new Array(4); // Xorshift: [x, y, z, w] 32 bit values
|
||||
const randseed = new Array(4); // Xorshift: [x, y, z, w] 32 bit values
|
||||
|
||||
function seedrand(seed) {
|
||||
for (var i = 0; i < randseed.length; i++) {
|
||||
for (let i = 0; i < randseed.length; i++) {
|
||||
randseed[i] = 0;
|
||||
}
|
||||
for (var i = 0; i < seed.length; i++) {
|
||||
for (let i = 0; i < seed.length; i++) {
|
||||
randseed[i % 4] = (randseed[i % 4] << 5) - randseed[i % 4] + seed.charCodeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
function rand() {
|
||||
// based on Java's String.hashCode(), expanded to 4 32bit values
|
||||
var t = randseed[0] ^ (randseed[0] << 11);
|
||||
const t = randseed[0] ^ (randseed[0] << 11);
|
||||
|
||||
randseed[0] = randseed[1];
|
||||
randseed[1] = randseed[2];
|
||||
|
@ -281,35 +281,35 @@
|
|||
|
||||
function createColor() {
|
||||
//saturation is the whole color spectrum
|
||||
var h = Math.floor(rand() * 360);
|
||||
const h = Math.floor(rand() * 360);
|
||||
//saturation goes from 40 to 100, it avoids greyish colors
|
||||
var s = rand() * 60 + 40;
|
||||
const s = rand() * 60 + 40;
|
||||
//lightness can be anything from 0 to 100, but probabilities are a bell curve around 50%
|
||||
var l = (rand() + rand() + rand() + rand()) * 25;
|
||||
const l = (rand() + rand() + rand() + rand()) * 25;
|
||||
|
||||
return [h / 360,s / 100,l / 100];
|
||||
}
|
||||
|
||||
function createImageData(size) {
|
||||
var width = size; // Only support square icons for now
|
||||
var height = size;
|
||||
const width = size; // Only support square icons for now
|
||||
const height = size;
|
||||
|
||||
var dataWidth = Math.ceil(width / 2);
|
||||
var mirrorWidth = width - dataWidth;
|
||||
const dataWidth = Math.ceil(width / 2);
|
||||
const mirrorWidth = width - dataWidth;
|
||||
|
||||
var data = [];
|
||||
for (var y = 0; y < height; y++) {
|
||||
var row = [];
|
||||
for (var x = 0; x < dataWidth; x++) {
|
||||
const data = [];
|
||||
for (let y = 0; y < height; y++) {
|
||||
const row = [];
|
||||
for (let x = 0; x < dataWidth; x++) {
|
||||
// this makes foreground and background color to have a 43% (1/2.3) probability
|
||||
// spot color has 13% chance
|
||||
row[x] = Math.floor(rand() * 2.3);
|
||||
}
|
||||
var r = row.slice(0, mirrorWidth);
|
||||
const r = row.slice(0, mirrorWidth);
|
||||
r.reverse();
|
||||
row = row.concat(r);
|
||||
|
||||
for (var i = 0; i < row.length; i++) {
|
||||
for (let i = 0; i < row.length; i++) {
|
||||
data.push(row[i]);
|
||||
}
|
||||
}
|
||||
|
@ -344,9 +344,9 @@
|
|||
const color = p.color(...hsl2rgb(...opts.color));
|
||||
const spotcolor = p.color(...hsl2rgb(...opts.spotcolor));
|
||||
|
||||
for (var i = 0; i < imageData.length; i++) {
|
||||
var row = Math.floor(i / width);
|
||||
var col = i % width;
|
||||
for (let i = 0; i < imageData.length; i++) {
|
||||
const row = Math.floor(i / width);
|
||||
const col = i % width;
|
||||
// if data is 0, leave the background
|
||||
if (imageData[i]) {
|
||||
// if data is 2, choose spot color, if 1 choose foreground
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var iconFactory
|
||||
let iconFactory
|
||||
const isValidAddress = require('ethereumjs-util').isValidAddress
|
||||
const { checksumAddress } = require('../app/util')
|
||||
const contractMap = require('eth-contract-metadata')
|
||||
|
@ -28,18 +28,18 @@ IconFactory.prototype.iconForAddress = function (address, diameter) {
|
|||
|
||||
// returns svg dom element
|
||||
IconFactory.prototype.generateIdenticonSvg = function (address, diameter) {
|
||||
var cacheId = `${address}:${diameter}`
|
||||
const cacheId = `${address}:${diameter}`
|
||||
// check cache, lazily generate and populate cache
|
||||
var identicon = this.cache[cacheId] || (this.cache[cacheId] = this.generateNewIdenticon(address, diameter))
|
||||
const 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)
|
||||
const cleanCopy = identicon.cloneNode(true)
|
||||
return cleanCopy
|
||||
}
|
||||
|
||||
// creates a new identicon
|
||||
IconFactory.prototype.generateNewIdenticon = function (address, diameter) {
|
||||
var numericRepresentation = jsNumberForAddress(address)
|
||||
var identicon = this.jazzicon.generateIdenticon(diameter, numericRepresentation)
|
||||
const numericRepresentation = jsNumberForAddress(address)
|
||||
const identicon = this.jazzicon.generateIdenticon(diameter, numericRepresentation)
|
||||
return identicon
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ function imageElFor (address) {
|
|||
}
|
||||
|
||||
function jsNumberForAddress (address) {
|
||||
var addr = address.slice(2, 10)
|
||||
var seed = parseInt(addr, 16)
|
||||
const addr = address.slice(2, 10)
|
||||
const seed = parseInt(addr, 16)
|
||||
return seed
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue