Merge remote-tracking branch 'origin/develop' into vb-rsk-dpath-update

This commit is contained in:
Victor Baranov 2020-05-07 18:03:49 +03:00
commit 8f1d7d7121
60 changed files with 2047 additions and 2387 deletions

View File

@ -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

View File

@ -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__",

View File

@ -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) {

View File

@ -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) {

View File

@ -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}).)*$`)

View File

@ -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

View File

@ -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
})

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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,

View File

@ -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)
}

View File

@ -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) => {

View File

@ -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)
},

View File

@ -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'

View File

@ -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', {

View File

@ -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)),
}
}

View File

@ -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 })

View File

@ -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'

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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: {

View File

@ -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)
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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)

View File

@ -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]
}

View File

@ -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
}

View File

@ -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')

22
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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)'),

View File

@ -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)

View File

@ -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 () {

View File

@ -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)

View File

@ -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()
})

View File

@ -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')
})

View File

@ -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

View File

@ -1,5 +1,5 @@
var mockHex = '0xabcdef0123456789'
var mockKey = Buffer.alloc(32)
const mockHex = '0xabcdef0123456789'
const mockKey = Buffer.alloc(32)
let cacheVal
module.exports = {

View File

@ -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)
}
}

View File

@ -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' },
],
}
},

View File

@ -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)
}

View File

@ -345,7 +345,6 @@ describe('Transaction Controller', function () {
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
metamaskNetworkId: currentNetworkId,
}

View File

@ -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)
})
})
})
})

View File

@ -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)
})
})

View File

@ -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')
})
})

View File

@ -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,
})

View File

@ -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'),

View File

@ -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])
}

View File

@ -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}`
}

View File

@ -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,
},
})

View File

@ -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)

View File

@ -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) => {

View File

@ -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}`
}

View File

@ -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,
}))
}

View File

@ -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

View File

@ -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
}