Merge branch 'develop' into vb-rsk-dpath-update

This commit is contained in:
Victor Baranov 2020-05-04 14:53:43 +03:00 committed by GitHub
commit fa96fd072e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 598 additions and 754 deletions

View File

@ -2,6 +2,15 @@
## Current Master ## Current Master
- [#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 - [#363](https://github.com/poanetwork/nifty-wallet/pull/363) - (Fix) token decimals display in pending tx screen
- [#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 - [#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

View File

@ -1,7 +1,7 @@
{ {
"name": "__MSG_appName__", "name": "__MSG_appName__",
"short_name": "__MSG_appName__", "short_name": "__MSG_appName__",
"version": "5.0.2", "version": "5.0.3",
"manifest_version": 2, "manifest_version": 2,
"author": "POA Network", "author": "POA Network",
"description": "__MSG_appDescription__", "description": "__MSG_appDescription__",

View File

@ -5,11 +5,11 @@
// this needs to run before anything else // this needs to run before anything else
require('./lib/setupFetchDebugging')() require('./lib/setupFetchDebugging')()
const endOfStream = require('end-of-stream') import endOfStream from 'end-of-stream'
const pump = require('pump') import pump from 'pump'
const debounce = require('debounce-stream') import debounce from 'debounce-stream'
const log = require('loglevel') import log from 'loglevel'
const extension = require('extensionizer') import extension from 'extensionizer'
const LocalStorageStore = require('obs-store/lib/localStorage') const LocalStorageStore = require('obs-store/lib/localStorage')
const LocalStore = require('./lib/local-store') const LocalStore = require('./lib/local-store')
const storeTransform = require('obs-store/lib/transform') const storeTransform = require('obs-store/lib/transform')
@ -19,13 +19,11 @@ const Migrator = require('./lib/migrator/')
const migrations = require('./migrations/') const migrations = require('./migrations/')
const PortStream = require('extension-port-stream') const PortStream = require('extension-port-stream')
const createStreamSink = require('./lib/createStreamSink') 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 MetamaskController = require('./metamask-controller')
const rawFirstTimeState = require('./first-time-state') const rawFirstTimeState = require('./first-time-state')
const setupRaven = require('./lib/setupRaven') const setupRaven = require('./lib/setupRaven')
const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') 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 getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code')
const getObjStructure = require('./lib/getObjStructure') const getObjStructure = require('./lib/getObjStructure')
@ -51,12 +49,6 @@ global.METAMASK_NOTIFIER = notificationManager
const release = platform.getVersion() const release = platform.getVersion()
const raven = setupRaven({ release }) 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 popupIsOpen = false
let notificationIsOpen = false let notificationIsOpen = false
const openMetamaskTabsIDs = {} const openMetamaskTabsIDs = {}
@ -70,9 +62,6 @@ let versionedData
// initialization flow // initialization flow
initialize().catch(log.error) initialize().catch(log.error)
// setup metamask mesh testing container
setupMetamaskMeshMetrics()
/** /**
* An object representing a transaction, in whatever state it is in. * An object representing a transaction, in whatever state it is in.
@ -177,6 +166,7 @@ async function initialize () {
async function loadStateFromPersistence () { async function loadStateFromPersistence () {
// migrations // migrations
const migrator = new Migrator({ migrations }) const migrator = new Migrator({ migrations })
migrator.on('error', console.warn)
// read from disk // read from disk
// first from preferred, async API: // first from preferred, async API:
@ -256,7 +246,7 @@ function setupController (initState, initLangCode) {
showUnconfirmedMessage: triggerUi, showUnconfirmedMessage: triggerUi,
unlockAccountMessage: triggerUi, unlockAccountMessage: triggerUi,
showUnapprovedTx: triggerUi, showUnapprovedTx: triggerUi,
showWatchAssetUi: showWatchAssetUi, openPopup: openPopup,
// initial state // initial state
initState, initState,
// initial locale code // initial locale code
@ -269,7 +259,6 @@ function setupController (initState, initLangCode) {
getOpenMetamaskTabsIds: () => { getOpenMetamaskTabsIds: () => {
return openMetamaskTabsIDs return openMetamaskTabsIDs
}, },
encryptor: isEdge ? new EdgeEncryptor() : undefined,
}) })
global.metamaskController = controller global.metamaskController = controller
@ -460,28 +449,27 @@ function setupController (initState, initLangCode) {
/** /**
* Opens the browser popup for user confirmation * Opens the browser popup for user confirmation
*/ */
function triggerUi () { async function triggerUi () {
extension.tabs.query({ active: true }, tabs => { const tabs = await platform.getActiveTabs()
const currentlyActiveMetamaskTab = Boolean(tabs.find(tab => openMetamaskTabsIDs[tab.id])) const currentlyActiveMetamaskTab = Boolean(tabs.find((tab) => openMetamaskTabsIDs[tab.id]))
/** /**
* https://github.com/poanetwork/metamask-extension/issues/19 * 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 * !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. * 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. * New transaction, in this case, will not appear in front of DApp.
*/ */
if (!popupIsOpen && !currentlyActiveMetamaskTab) { if (!popupIsOpen && !currentlyActiveMetamaskTab) {
notificationManager.showPopup() await notificationManager.showPopup()
} }
})
} }
/** /**
* Opens the browser popup for user confirmation of watchAsset * Opens the browser popup for user confirmation of watchAsset
* then it waits until user interact with the UI * then it waits until user interact with the UI
*/ */
function showWatchAssetUi () { async function openPopup () {
triggerUi() await triggerUi()
return new Promise( await new Promise(
(resolve) => { (resolve) => {
const interval = setInterval(() => { const interval = setInterval(() => {
if (!notificationIsOpen) { if (!notificationIsOpen) {

View File

@ -1,8 +1,8 @@
import Web3 from 'web3' import Web3 from 'web3'
import contractsETH from 'eth-contract-metadata' import contractsETH from 'eth-contract-metadata'
import contractsPOA from 'poa-contract-metadata' import contractsPOA from 'poa-contract-metadata'
import contractsRSK from 'rsk-contract-metadata' import contractsRSK from '@rsksmart/rsk-contract-metadata'
import contractsRSKTest from 'rsk-test-contract-metadata' import contractsRSKTest from '@rsksmart/rsk-testnet-contract-metadata'
import { warn } from 'loglevel' import { warn } from 'loglevel'
const { MAINNET, POA, RSK, RSK_TESTNET } = require('./network/enums') const { MAINNET, POA, RSK, RSK_TESTNET } = require('./network/enums')
// By default, poll every 3 minutes // By default, poll every 3 minutes

View File

@ -47,7 +47,7 @@ class PreferencesController {
this.diagnostics = opts.diagnostics this.diagnostics = opts.diagnostics
this.network = opts.network this.network = opts.network
this.store = new ObservableStore(initState) this.store = new ObservableStore(initState)
this.showWatchAssetUi = opts.showWatchAssetUi this.openPopup = opts.openPopup
this._subscribeProviderType() this._subscribeProviderType()
} }
// PUBLIC METHODS // PUBLIC METHODS
@ -591,7 +591,7 @@ class PreferencesController {
} }
const tokenOpts = { rawAddress, decimals, symbol, image } const tokenOpts = { rawAddress, decimals, symbol, image }
this.addSuggestedERC20Asset(tokenOpts) this.addSuggestedERC20Asset(tokenOpts)
return this.showWatchAssetUi().then(() => { return this.openPopup().then(() => {
const tokenAddresses = this.getTokens().filter(token => token.address === normalizeAddress(rawAddress)) const tokenAddresses = this.getTokens().filter(token => token.address === normalizeAddress(rawAddress))
return tokenAddresses.length > 0 return tokenAddresses.length > 0
}) })

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) {
const salt = this._generateSalt()
return this._keyFromPassword(password, salt)
.then(function (key) {
const data = JSON.stringify(dataObject)
const dataBuffer = Unibabel.utf8ToBuffer(data)
const vector = global.crypto.getRandomValues(new Uint8Array(16))
const resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
const buffer = new Uint8Array(resultbuffer)
const vectorStr = Unibabel.bufferToBase64(vector)
const 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) => {
let 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) {
const passBuffer = Unibabel.utf8ToBuffer(password)
const saltBuffer = Unibabel.base64ToBuffer(salt)
return new Promise((resolve) => {
const 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) {
const view = new Uint8Array(byteCount)
global.crypto.getRandomValues(view)
const b64encoded = btoa(String.fromCharCode.apply(null, view))
return b64encoded
}
}
module.exports = EdgeEncryptor

View File

@ -1,7 +1,7 @@
const extension = require('extensionizer') import ExtensionPlatform from '../platforms/extension'
const height = 620
const width = 360
const NOTIFICATION_HEIGHT = 620
const NOTIFICATION_WIDTH = 360
class NotificationManager { 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 * Either brings an existing MetaMask notification window into focus, or creates a new notification window. New
* notification windows are given a 'popup' type. * notification windows are given a 'popup' type.
* *
*/ */
showPopup () { async showPopup () {
this._getPopup((err, popup) => { const popup = await this._getPopup()
if (err) throw err
// Bring focus to chrome popup // Bring focus to chrome popup
if (popup) { if (popup) {
// bring focus to existing chrome popup // bring focus to existing chrome popup
extension.windows.update(popup.id, { focused: true }) await this.platform.focusWindow(popup.id)
} else { } else {
const cb = (currentPopup) => {
this._popupId = currentPopup.id // create new notification popup
extension.windows.update(currentPopup.id, { focused: true }) const popupWindow = await this.platform.openWindow({
} url: 'notification.html',
// create new notification popup type: 'popup',
const creation = extension.windows.create({ width: NOTIFICATION_WIDTH,
url: 'notification.html', height: NOTIFICATION_HEIGHT,
type: 'popup', })
width, this._popupId = popupWindow.id
height, }
}, cb)
creation && creation.then && creation.then(cb)
}
})
} }
/** /**
* Closes a MetaMask notification if it window exists. * Closes a MetaMask notification if it window exists.
* *
*/ */
closePopup () { async closePopup () {
// closes notification popup const popup = this._getPopup()
this._getPopup((err, popup) => { if (!popup) {
if (err) throw err return
if (!popup) return }
extension.windows.remove(popup.id, console.error) await this.platform.removeWindow(popup.id)
})
} }
/** /**
@ -60,39 +58,19 @@ class NotificationManager {
* type 'popup') * type 'popup')
* *
* @private * @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) { async _getPopup () {
this._getWindows((err, windows) => { const windows = await this.platform.getAllWindows()
if (err) throw err return this._getPopupIn(windows)
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)
})
} }
/** /**
* Given an array of windows, returns the 'popup' that has been opened by MetaMask, or null if no such window exists. * Given an array of windows, returns the 'popup' that has been opened by MetaMask, or null if no such window exists.
* *
* @private * @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) { _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_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN, ENVIRONMENT_TYPE_FULLSCREEN,
ENVIRONMENT_TYPE_BACKGROUND,
PLATFORM_FIREFOX, PLATFORM_FIREFOX,
PLATFORM_OPERA, PLATFORM_OPERA,
PLATFORM_CHROME, PLATFORM_CHROME,
@ -13,17 +14,6 @@ const {
PLATFORM_BRAVE, PLATFORM_BRAVE,
} = require('./enums') } = 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. * 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) * - '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) => { 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 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 return ENVIRONMENT_TYPE_FULLSCREEN
} else { } else if (parsedUrl.pathname === '/notification.html') {
return ENVIRONMENT_TYPE_NOTIFICATION return ENVIRONMENT_TYPE_NOTIFICATION
} else {
return ENVIRONMENT_TYPE_BACKGROUND
} }
} }
@ -175,7 +168,6 @@ module.exports = {
removeListeners, removeListeners,
applyListeners, applyListeners,
getPlatform, getPlatform,
getStack,
getEnvironmentType, getEnvironmentType,
sufficientBalance, sufficientBalance,
hexToBn, hexToBn,

View File

@ -111,7 +111,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.preferencesController = new PreferencesController({ this.preferencesController = new PreferencesController({
initState: initState.PreferencesController, initState: initState.PreferencesController,
initLangCode: opts.initLangCode, initLangCode: opts.initLangCode,
showWatchAssetUi: opts.showWatchAssetUi, openPopup: opts.openPopup,
network: this.networkController, network: this.networkController,
}) })
@ -1893,7 +1893,7 @@ module.exports = class MetamaskController extends EventEmitter {
resolve(gasPrice) resolve(gasPrice)
} }
} else if (isRSK) { } else if (isRSK) {
gasPrice = this.getGasPriceFromLastBlockRSK(networkId) gasPrice = this.getGasPriceFromLastBlockRSK()
resolve(gasPrice) resolve(gasPrice)
} else { } else {
gasPrice = this.getGasPriceFromBlocks(networkId) gasPrice = this.getGasPriceFromBlocks(networkId)
@ -1944,19 +1944,17 @@ module.exports = class MetamaskController extends EventEmitter {
* Related issue: https://github.com/poanetwork/nifty-wallet/issues/301 * Related issue: https://github.com/poanetwork/nifty-wallet/issues/301
* @returns {string} A hex representation of the suggested wei gas price. * @returns {string} A hex representation of the suggested wei gas price.
*/ */
getGasPriceFromLastBlockRSK (networkId) { getGasPriceFromLastBlockRSK () {
const { recentBlocksController } = this const { recentBlocksController } = this
const { recentBlocks } = recentBlocksController.store.getState() const { recentBlocks } = recentBlocksController.store.getState()
const recentBlock = recentBlocks const recentBlock = recentBlocks
.sort((block1, block2) => block1.number - block2.number)[recentBlocks.length - 1] .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 (gasPrice !== '0x' && gasPrice !== '0x0' && gasPrice !== '') {
return gasPrice
if (gasPriceInt !== 0) {
return '0x' + gasPriceInt.toString(16)
} else { } else {
return '0x' + GWEI_BN.toString(16) return '0x' + GWEI_BN.toString(16)
} }

View File

@ -12,8 +12,64 @@ class ExtensionPlatform {
extension.runtime.reload() extension.runtime.reload()
} }
openWindow ({ url }) { openTab (options) {
extension.tabs.create({ url }) 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 () { 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 () { getVersion () {
return extension.runtime.getManifest().version return extension.runtime.getManifest().version
} }
@ -57,7 +92,7 @@ class ExtensionPlatform {
if (route) { if (route) {
extensionURL += `#${route}` extensionURL += `#${route}`
} }
this.openWindow({ url: extensionURL }) this.openTab({ url: extensionURL })
if (getEnvironmentType() !== ENVIRONMENT_TYPE_BACKGROUND) { if (getEnvironmentType() !== ENVIRONMENT_TYPE_BACKGROUND) {
window.close() 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 () { currentTab () {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
extension.tabs.getCurrent((tab) => { extension.tabs.getCurrent((tab) => {

View File

@ -3,11 +3,8 @@ const OldMetaMaskUiCss = require('../../old-ui/css')
const startPopup = require('./popup-core') const startPopup = require('./popup-core')
const PortStream = require('extension-port-stream') const PortStream = require('extension-port-stream')
const { getEnvironmentType } = require('./lib/util') const { getEnvironmentType } = require('./lib/util')
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('./lib/enums')
import extension from 'extensionizer' import extension from 'extensionizer'
const ExtensionPlatform = require('./platforms/extension') const ExtensionPlatform = require('./platforms/extension')
const NotificationManager = require('./lib/notification-manager')
const notificationManager = new NotificationManager()
const setupRaven = require('./lib/setupRaven') const setupRaven = require('./lib/setupRaven')
const log = require('loglevel') const log = require('loglevel')
@ -29,7 +26,6 @@ async function start () {
// identify window type (popup, notification) // identify window type (popup, notification)
const windowType = getEnvironmentType(window.location.href) const windowType = getEnvironmentType(window.location.href)
global.METAMASK_UI_TYPE = windowType global.METAMASK_UI_TYPE = windowType
closePopupIfOpen(windowType)
// setup stream to background // setup stream to background
const extensionPort = extension.runtime.connect({ name: windowType }) 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) { 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.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' container.style.height = '80px'

View File

@ -73,11 +73,11 @@ createCopyTasks('contractImagesPOA', {
destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractPOA`), destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractPOA`),
}) })
createCopyTasks('contractImagesRSK', { 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`), destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractRSK`),
}) })
createCopyTasks('contractImagesRSKTest', { 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`), destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractRSKTest`),
}) })
createCopyTasks('fonts', { createCopyTasks('fonts', {

View File

@ -1,9 +1,9 @@
const Component = require('react').Component const Component = require('react').Component
const h = require('react-hyperscript') const h = require('react-hyperscript')
const connect = require('react-redux').connect import { connect } from 'react-redux'
const actions = require('../../../../ui/app/actions') const actions = require('../../../../ui/app/actions')
const FileInput = require('react-simple-file-input').default const FileInput = require('react-simple-file-input').default
const PropTypes = require('prop-types') import PropTypes from 'prop-types'
class JsonImportSubview extends Component { class JsonImportSubview extends Component {
constructor (props) { constructor (props) {
@ -75,31 +75,26 @@ class JsonImportSubview extends Component {
} }
createNewKeychain () { createNewKeychain () {
const { displayWarning, importNewJsonAccount } = this.props
const { fileContents } = this.state const { fileContents } = this.state
if (!fileContents) { if (!fileContents) {
const message = 'You must select a file to import.' 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 passwordInput = document.getElementById('json-password-box')
const password = passwordInput.value const password = passwordInput.value
if (!password) { importNewJsonAccount([ fileContents, password ])
const message = 'You must enter a password for the selected file.' .catch((err) => err && displayWarning(err.message || err))
return this.props.displayWarning(message)
}
this.props.importNewAccount([ fileContents, password ])
// JS runtime requires caught rejections but failures are handled by Redux
.catch()
} }
} }
JsonImportSubview.propTypes = { JsonImportSubview.propTypes = {
error: PropTypes.string, error: PropTypes.string,
displayWarning: PropTypes.func, displayWarning: PropTypes.func,
importNewAccount: PropTypes.func, importNewJsonAccount: PropTypes.func,
} }
const mapStateToProps = state => { const mapStateToProps = state => {
@ -112,7 +107,7 @@ const mapDispatchToProps = dispatch => {
return { return {
goHome: () => dispatch(actions.goHome()), goHome: () => dispatch(actions.goHome()),
displayWarning: warning => dispatch(actions.displayWarning(warning)), 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 symbolLen = symbol.trim().length
const validSymbol = symbolLen > 0 && symbolLen < 10 const validSymbol = symbolLen > 0 && symbolLen < 23
if (!validSymbol) { 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) let ownAddress = identitiesList.includes(standardAddress)
@ -527,8 +527,8 @@ export default class AddTokenScreen extends Component {
const symbolLength = customSymbol.length const symbolLength = customSymbol.length
let customSymbolError = null let customSymbolError = null
if (symbolLength <= 0 || symbolLength >= 10) { if (symbolLength <= 0 || symbolLength >= 23) {
customSymbolError = 'Symbol must be between 0 and 10 characters.' /* this.context.t('symbolBetweenZeroTen')*/ customSymbolError = 'Symbol must be between 0 and 23 characters.' /* this.context.t('symbolBetweenZeroTen')*/
} }
this.setState({ customSymbol, customSymbolError }) this.setState({ customSymbol, customSymbolError })

View File

@ -2,8 +2,8 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import contractMapETH from 'eth-contract-metadata' import contractMapETH from 'eth-contract-metadata'
import contractMapPOA from 'poa-contract-metadata' import contractMapPOA from 'poa-contract-metadata'
import contractMapRSK from 'rsk-contract-metadata' import contractMapRSK from '@rsksmart/rsk-contract-metadata'
import contractMapRSKTest from 'rsk-test-contract-metadata' import contractMapRSKTest from '@rsksmart/rsk-testnet-contract-metadata'
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import InputAdornment from '@material-ui/core/InputAdornment' import InputAdornment from '@material-ui/core/InputAdornment'
import TextField from '../../../../../ui/app/components/text-field' import TextField from '../../../../../ui/app/components/text-field'

View File

@ -74,7 +74,7 @@ class ConnectScreen extends Component {
<Button <Button
type="primary" type="primary"
large={true} large={true}
onClick={() => global.platform.openWindow({ onClick={() => global.platform.openTab({
url: 'https://google.com/chrome', url: 'https://google.com/chrome',
})} })}
>Download Google Chrome</Button> >Download Google Chrome</Button>

View File

@ -5,7 +5,7 @@ import PropTypes from 'prop-types'
import clone from 'clone' import clone from 'clone'
import log from 'loglevel' import log from 'loglevel'
const ethUtil = require('ethereumjs-util') import ethUtil from 'ethereumjs-util'
const BN = ethUtil.BN const BN = ethUtil.BN
const hexToBn = require('../../../app/scripts/lib/hex-to-bn') const hexToBn = require('../../../app/scripts/lib/hex-to-bn')
const util = require('../util') const util = require('../util')
@ -47,12 +47,12 @@ class PendingTx extends Component {
isUnlocked: PropTypes.bool, isUnlocked: PropTypes.bool,
currentCurrency: PropTypes.string, currentCurrency: PropTypes.string,
conversionRate: PropTypes.number, conversionRate: PropTypes.number,
unconfTxListLength: PropTypes.number,
provider: PropTypes.object, provider: PropTypes.object,
index: PropTypes.number, index: PropTypes.number,
blockGasLimit: PropTypes.string, blockGasLimit: PropTypes.string,
tokensToSend: PropTypes.objectOf(BigNumber), tokensToSend: PropTypes.objectOf(BigNumber),
tokensTransferTo: PropTypes.string, tokensTransferTo: PropTypes.string,
unapprovedTxs: PropTypes.object,
} }
constructor (opts = {}) { constructor (opts = {}) {
@ -132,12 +132,13 @@ class PendingTx extends Component {
const dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0 const dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0
const { totalTx, positionOfCurrentTx, nextTxId, prevTxId, showNavigation } = this.getNavigateTxData()
const balanceBn = hexToBn(balance) const balanceBn = hexToBn(balance)
const insufficientBalance = balanceBn.lt(maxCost) const insufficientBalance = balanceBn.lt(maxCost)
const dangerousGasLimit = gasBn.gte(saferGasLimitBN) const dangerousGasLimit = gasBn.gte(saferGasLimitBN)
const gasLimitSpecified = txMeta.gasLimitSpecified const gasLimitSpecified = txMeta.gasLimitSpecified
const buyDisabled = insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting const buyDisabled = insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting
const showRejectAll = props.unconfTxListLength > 1
const isNotification = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION const isNotification = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION
@ -159,7 +160,6 @@ class PendingTx extends Component {
const isError = txMeta.simulationFails || !isValidAddress || insufficientBalance || (dangerousGasLimit && !gasLimitSpecified) const isError = txMeta.simulationFails || !isValidAddress || insufficientBalance || (dangerousGasLimit && !gasLimitSpecified)
return ( return (
h('div', { h('div', {
@ -180,7 +180,7 @@ class PendingTx extends Component {
h('.flex-row.flex-center', { h('.flex-row.flex-center', {
style: { style: {
maxWidth: '100%', maxWidth: '100%',
padding: showRejectAll ? '20px 20px 50px 20px' : '20px 20px 20px 20px', padding: showNavigation ? '20px 20px 50px 20px' : '20px 20px 20px 20px',
background: 'linear-gradient(rgb(84, 36, 147), rgb(104, 45, 182))', background: 'linear-gradient(rgb(84, 36, 147), rgb(104, 45, 182))',
position: 'relative', position: 'relative',
}, },
@ -198,22 +198,22 @@ class PendingTx extends Component {
h('h3', { h('h3', {
style: { style: {
alignSelf: 'center', alignSelf: 'center',
display: props.unconfTxListLength > 1 ? 'block' : 'none', display: showNavigation ? 'block' : 'none',
fontSize: '14px', fontSize: '14px',
}, },
}, [ }, [
h('i.fa.white-arrow-left.fa-lg.cursor-pointer', { h('i.fa.white-arrow-left.fa-lg.cursor-pointer', {
style: { style: {
display: props.index === 0 ? 'none' : 'inline-block', display: positionOfCurrentTx === 1 ? 'none' : 'inline-block',
}, },
onClick: () => props.actions.previousTx(), onClick: () => props.actions.nextTx(prevTxId),
}), }),
` ${props.index + 1} of ${props.unconfTxListLength} `, ` ${positionOfCurrentTx} of ${totalTx} `,
h('i.fa.white-arrow-right.fa-lg.cursor-pointer', { h('i.fa.white-arrow-right.fa-lg.cursor-pointer', {
style: { style: {
display: props.index + 1 === props.unconfTxListLength ? 'none' : 'inline-block', display: positionOfCurrentTx === totalTx ? 'none' : 'inline-block',
}, },
onClick: () => props.actions.nextTx(), onClick: () => props.actions.nextTx(nextTxId),
}), }),
])], ])],
), ),
@ -520,7 +520,7 @@ class PendingTx extends Component {
onClick: props.cancelTransaction, onClick: props.cancelTransaction,
}, 'Reject'), }, 'Reject'),
]), ]),
showRejectAll ? h('.flex-row.flex-space-around.conf-buttons', { showNavigation ? h('.flex-row.flex-space-around.conf-buttons', {
style: { style: {
display: 'flex', display: 'flex',
justifyContent: 'flex-end', justifyContent: 'flex-end',
@ -732,6 +732,23 @@ class PendingTx extends Component {
} }
} }
getNavigateTxData () {
const { unapprovedTxs, network, txData: { id } = {} } = this.props
const currentNetworkUnapprovedTxs = Object.keys(unapprovedTxs)
.filter((key) => unapprovedTxs[key].metamaskNetworkId === network)
.reduce((acc, key) => ({ ...acc, [key]: unapprovedTxs[key] }), {})
const enumUnapprovedTxs = Object.keys(currentNetworkUnapprovedTxs)
const currentPosition = enumUnapprovedTxs.indexOf(id ? id.toString() : '')
return {
totalTx: enumUnapprovedTxs.length,
positionOfCurrentTx: currentPosition + 1,
nextTxId: enumUnapprovedTxs[currentPosition + 1],
prevTxId: enumUnapprovedTxs[currentPosition - 1],
showNavigation: enumUnapprovedTxs.length > 1,
}
}
} }
function forwardCarrat () { function forwardCarrat () {
@ -756,7 +773,7 @@ function mapStateToProps (state) {
unapprovedMsgs: state.metamask.unapprovedMsgs, unapprovedMsgs: state.metamask.unapprovedMsgs,
unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs, unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs,
unapprovedTypedMessages: state.metamask.unapprovedTypedMessages, unapprovedTypedMessages: state.metamask.unapprovedTypedMessages,
index: state.appState.currentView.pendingTxIndex || 0, index: state.appState.currentView.key || 0,
warning: state.appState.warning, warning: state.appState.warning,
network: state.metamask.network, network: state.metamask.network,
provider: state.metamask.provider, provider: state.metamask.provider,
@ -765,14 +782,14 @@ function mapStateToProps (state) {
currentCurrency: state.metamask.currentCurrency, currentCurrency: state.metamask.currentCurrency,
blockGasLimit: state.metamask.currentBlockGasLimit, blockGasLimit: state.metamask.currentBlockGasLimit,
computedBalances: state.metamask.computedBalances, computedBalances: state.metamask.computedBalances,
pendingTxIndex: state.appState.currentView.pendingTxIndex || 0,
} }
} }
const mapDispatchToProps = (dispatch) => { const mapDispatchToProps = (dispatch) => {
return { return {
actions: { actions: {
previousTx: () => dispatch(actions.previousTx()), nextTx: (txId) => dispatch(actions.nextTx(txId)),
nextTx: () => dispatch(actions.nextTx()),
displayWarning: (msg) => dispatch(actions.displayWarning(msg)), displayWarning: (msg) => dispatch(actions.displayWarning(msg)),
goHome: () => dispatch(actions.goHome()), goHome: () => dispatch(actions.goHome()),
}, },

View File

@ -212,7 +212,7 @@ ShiftListItem.prototype.renderInfo = function () {
paddingLeft: '29px', paddingLeft: '29px',
textAlign: 'left', textAlign: 'left',
}, },
onClick: () => global.platform.openWindow({ url }), onClick: () => global.platform.openTab({ url }),
}, [ }, [
h('div', { h('div', {
style: { style: {

View File

@ -19,8 +19,8 @@ const defaultTokens = []
const contractsETH = require('eth-contract-metadata') const contractsETH = require('eth-contract-metadata')
const contractsPOA = require('poa-contract-metadata') const contractsPOA = require('poa-contract-metadata')
const contractsRSK = require('rsk-contract-metadata') const contractsRSK = require('@rsksmart/rsk-contract-metadata')
const contractsRSKTest = require('rsk-test-contract-metadata') const contractsRSKTest = require('@rsksmart/rsk-testnet-contract-metadata')
for (const address in contractsETH) { for (const address in contractsETH) {
const contract = contractsETH[address] const contract = contractsETH[address]
if (contract.erc20) { if (contract.erc20) {

View File

@ -1,11 +1,11 @@
const inherits = require('util').inherits import PropTypes from 'prop-types'
const Component = require('react').Component import { Component } from 'react'
import { connect } from 'react-redux'
const h = require('react-hyperscript') const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('../../ui/app/actions') const actions = require('../../ui/app/actions')
const LoadingIndicator = require('./components/loading') const LoadingIndicator = require('./components/loading')
const txHelper = require('../lib/tx-helper') const txHelper = require('../lib/tx-helper')
const log = require('loglevel') import log from 'loglevel'
const { getCurrentKeyring, ifContractAcc } = require('./util') const { getCurrentKeyring, ifContractAcc } = require('./util')
const PendingTx = require('./components/pending-tx') const PendingTx = require('./components/pending-tx')
@ -15,118 +15,224 @@ import PendingTypedMsg from './components/pending-typed-msg'
const Loading = require('./components/loading') const Loading = require('./components/loading')
const { DAI_CODE, POA_SOKOL_CODE, RSK_TESTNET_CODE, GOERLI_TESTNET_CODE } = require('../../app/scripts/controllers/network/enums') const { DAI_CODE, POA_SOKOL_CODE, RSK_TESTNET_CODE, GOERLI_TESTNET_CODE } = require('../../app/scripts/controllers/network/enums')
const { getMetaMaskAccounts } = require('../../ui/app/selectors') const { getMetaMaskAccounts } = require('../../ui/app/selectors')
import BigNumber from 'bignumber.js'
module.exports = connect(mapStateToProps)(ConfirmTxScreen)
function mapStateToProps (state) { class ConfirmTxScreen extends Component {
const { metamask, appState } = state static propTypes = {
const { screenParams, pendingTxIndex } = appState.currentView network: PropTypes.string,
return { identities: PropTypes.objectOf(PropTypes.object),
identities: metamask.identities, keyrings: PropTypes.array,
accounts: getMetaMaskAccounts(state), actions: PropTypes.objectOf(PropTypes.func),
keyrings: metamask.keyrings, isToken: PropTypes.bool,
selectedAddress: metamask.selectedAddress, isContractExecutionByUser: PropTypes.bool,
unapprovedTxs: metamask.unapprovedTxs, selectedAddress: PropTypes.string,
unapprovedMsgs: metamask.unapprovedMsgs, warning: PropTypes.string,
unapprovedPersonalMsgs: metamask.unapprovedPersonalMsgs, unapprovedTxs: PropTypes.object,
unapprovedTypedMessages: metamask.unapprovedTypedMessages, unapprovedMsgs: PropTypes.object,
index: pendingTxIndex || 0, unapprovedPersonalMsgs: PropTypes.object,
warning: appState.warning, unapprovedTypedMessages: PropTypes.object,
network: metamask.network, pendingTxIndex: PropTypes.number,
provider: metamask.provider, blockGasLimit: PropTypes.string,
conversionRate: metamask.conversionRate, accounts: PropTypes.object,
currentCurrency: metamask.currentCurrency, currentCurrency: PropTypes.string,
blockGasLimit: metamask.currentBlockGasLimit, computedBalances: PropTypes.object,
computedBalances: metamask.computedBalances, conversionRate: PropTypes.number,
isToken: (screenParams && screenParams.isToken), tokenSymbol: PropTypes.string,
tokenSymbol: (screenParams && screenParams.tokenSymbol), tokensToSend: PropTypes.objectOf(BigNumber),
tokensToSend: (screenParams && screenParams.tokensToSend), tokensTransferTo: PropTypes.string,
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
} }
const unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network) render () {
const ind = props.index || 0 const props = this.props
const txData = unconfTxList[ind] || {} const { network, unapprovedTxs, currentCurrency, computedBalances,
const txParams = txData.params || {} unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, blockGasLimit } = props
let { conversionRate } = props
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`) const isTestnet = parseInt(network) === POA_SOKOL_CODE || parseInt(network) === RSK_TESTNET_CODE || parseInt(network) === GOERLI_TESTNET_CODE
if (unconfTxList.length === 0) return h(Loading, { isLoading: true }) 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', { const unconfTxListLength = unconfTxList.length
style: {
width: '100%',
},
}, [
h(LoadingIndicator, { return (
isLoading: this.state ? !this.state.bypassLoadingScreen : txData.loadingDefaults,
loadingMessage: 'Estimating transaction cost…', h('.flex-column.flex-grow', {
canBypass: true, style: {
bypass: () => { width: '100%',
this.setState({bypassLoadingScreen: true})
}, },
}), }, [
// 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({ warningIfExists(props.warning),
// Properties
txData: txData, currentTxView({
key: txData.id, // Properties
selectedAddress: props.selectedAddress, txData: txData,
accounts: props.accounts, key: txData.id,
identities: props.identities, selectedAddress: props.selectedAddress,
conversionRate, accounts: props.accounts,
currentCurrency, identities: props.identities,
blockGasLimit, conversionRate,
unconfTxListLength, currentCurrency,
computedBalances, blockGasLimit,
network, unconfTxListLength,
isToken: props.isToken, computedBalances,
tokenSymbol: props.tokenSymbol, network,
tokensToSend: props.tokensToSend, isToken: props.isToken,
tokensTransferTo: props.tokensTransferTo, tokenSymbol: props.tokenSymbol,
// Actions tokensToSend: props.tokensToSend,
buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress, props.isContractExecutionByUser), tokensTransferTo: props.tokensTransferTo,
sendTransaction: this.sendTransaction.bind(this), // Actions
cancelTransaction: this.cancelTransaction.bind(this, txData), buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress, props.isContractExecutionByUser),
cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList), sendTransaction: this.sendTransaction.bind(this),
signMessage: this.signMessage.bind(this, txData), cancelTransaction: this.cancelTransaction.bind(this, txData),
signPersonalMessage: this.signPersonalMessage.bind(this, txData), cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList),
signTypedMessage: this.signTypedMessage.bind(this, txData), signMessage: this.signMessage.bind(this, txData),
cancelMessage: this.cancelMessage.bind(this, txData), signPersonalMessage: this.signPersonalMessage.bind(this, txData),
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData), signTypedMessage: this.signTypedMessage.bind(this, txData),
cancelTypedMessage: this.cancelTypedMessage.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) { 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) { function warningIfExists (warning) {
if (warning && if (warning &&
// Do not display user rejections on this screen: // Do not display user rejections on this screen:
@ -277,3 +270,51 @@ function warningIfExists (warning) {
}, 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

@ -1,8 +1,8 @@
import { isValidAddress } from 'ethereumjs-util' import { isValidAddress } from 'ethereumjs-util'
import contractMapETH from 'eth-contract-metadata' import contractMapETH from 'eth-contract-metadata'
import contractMapPOA from 'poa-contract-metadata' import contractMapPOA from 'poa-contract-metadata'
import contractMapRSK from 'rsk-contract-metadata' import contractMapRSK from '@rsksmart/rsk-contract-metadata'
import contractMapRSKTest from 'rsk-test-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' import { MAINNET_CODE, POA_CODE, RSK_CODE, RSK_TESTNET_CODE } from '../../app/scripts/controllers/network/enums'
const colors = require('../../colors') const colors = require('../../colors')
const { toChecksumAddress, getTokenImageFolder } = require('../app/util') const { toChecksumAddress, getTokenImageFolder } = require('../app/util')

22
package-lock.json generated
View File

@ -1966,6 +1966,14 @@
"react-lifecycles-compat": "^3.0.4" "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": { "@sentry/cli": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.52.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.52.0.tgz",
@ -11355,9 +11363,9 @@
} }
}, },
"eth-contract-metadata": { "eth-contract-metadata": {
"version": "1.12.1", "version": "1.13.0",
"resolved": "https://registry.npmjs.org/eth-contract-metadata/-/eth-contract-metadata-1.12.1.tgz", "resolved": "https://registry.npmjs.org/eth-contract-metadata/-/eth-contract-metadata-1.13.0.tgz",
"integrity": "sha512-9u2jUcdxaKIv4RvA9RtjyD4+M2yWt4yCulR5bpdQTiG3HUFnN9lHtNL5NIRDpvQVJKerFhexrgEM2WdGP3a6VA==" "integrity": "sha512-9CjXHX8IdXysUEvOHdbCsjdAwM1E98jaeK2HeOqm/9S/vOZ8YryaBBt/YSiBq3MkpCwf+d1pEQ53p96rsdy52w=="
}, },
"eth-ens-namehash": { "eth-ens-namehash": {
"version": "2.0.8", "version": "2.0.8",
@ -49791,14 +49799,6 @@
"uuid": "^3.3.2" "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": { "rst-selector-parser": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz",

View File

@ -85,6 +85,8 @@
"dependencies": { "dependencies": {
"@babel/runtime": "^7.5.5", "@babel/runtime": "^7.5.5",
"@material-ui/core": "^4.1.1", "@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", "@zxing/library": "^0.8.0",
"abi-decoder": "^1.2.0", "abi-decoder": "^1.2.0",
"asmcrypto.js": "0.22.0", "asmcrypto.js": "0.22.0",
@ -109,7 +111,7 @@
"dnode": "^1.2.2", "dnode": "^1.2.2",
"end-of-stream": "^1.4.4", "end-of-stream": "^1.4.4",
"eth-block-tracker": "^4.4.2", "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-ens-namehash": "^2.0.8",
"eth-json-rpc-errors": "^2.0.2", "eth-json-rpc-errors": "^2.0.2",
"eth-json-rpc-filters": "github:poanetwork/eth-json-rpc-filters#3.0.2", "eth-json-rpc-filters": "github:poanetwork/eth-json-rpc-filters#3.0.2",
@ -198,8 +200,6 @@
"reselect": "^3.0.1", "reselect": "^3.0.1",
"rockicon": "^1.0.0", "rockicon": "^1.0.0",
"rpc-cap": "^2.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", "sandwich-expando": "^1.1.3",
"semaphore": "^1.0.5", "semaphore": "^1.0.5",
"semver": "^5.4.1", "semver": "^5.4.1",

View File

@ -298,7 +298,7 @@ module.exports = {
accountName: By.className('font-medium color-forest'), accountName: By.className('font-medium color-forest'),
edit: By.className('edit-text'), edit: By.className('edit-text'),
iconCopy: By.className('clipboard cursor-pointer white'), 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: { buttons: {
send: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(4)'), 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)'), buy: By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(3)'),
@ -309,7 +309,7 @@ module.exports = {
}, },
network: By.className('network-name'), network: By.className('network-name'),
sent: { sent: {
menu: By.className('wallet-view__tab-history'), menu: By.css('#wallet-view__tab-history'),
tokens: By.className('activeForm right'), 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)'), // 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

@ -60,6 +60,8 @@ const importGanacheSeedPhrase = async (f, account2, password) => {
}) })
it('finds the transaction in the transactions list', async () => { 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) const transactionAmount = await f.waitUntilShowUp(screens.main.transactionList)
assert.equal(await transactionAmount.getText(), '10.0') assert.equal(await transactionAmount.getText(), '10.0')
}) })

View File

@ -161,9 +161,9 @@ describe('MetaMaskController', function () {
getState: () => { getState: () => {
return { return {
recentBlocks: [ recentBlocks: [
{ number: '0x1', minimumGasPrice: '59240010' }, { number: '0x1', minimumGasPrice: '0x387ee48' },
{ number: '0x2', minimumGasPrice: '59240005' }, { number: '0x2', minimumGasPrice: '0x387ee42' },
{ number: '0x3', minimumGasPrice: '59240000' }, { number: '0x3', minimumGasPrice: '0x387ee40' },
], ],
} }
}, },
@ -175,7 +175,7 @@ describe('MetaMaskController', function () {
getState: () => { getState: () => {
return { return {
recentBlocks: [ 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 } req.params.options = { address, symbol, decimals, image }
sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true)
preferencesController.showWatchAssetUi = async () => {} preferencesController.openPopup = async () => {}
await preferencesController._handleWatchAssetERC20(req.params.options) await preferencesController._handleWatchAssetERC20(req.params.options)
const suggested = preferencesController.getSuggestedTokens() const suggested = preferencesController.getSuggestedTokens()
@ -463,7 +463,7 @@ describe('preferences controller', function () {
req.params.options = { address, symbol, decimals, image } req.params.options = { address, symbol, decimals, image }
sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true)
preferencesController.showWatchAssetUi = async () => { preferencesController.openPopup = async () => {
await preferencesController.addToken(address, symbol, decimals, image) await preferencesController.addToken(address, symbol, decimals, image)
} }

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

@ -19,6 +19,7 @@ const { POA,
CLASSIC } = require('../../app/scripts/controllers/network/enums') CLASSIC } = require('../../app/scripts/controllers/network/enums')
const { hasUnconfirmedTransactions } = require('./helpers/confirm-transaction/util') const { hasUnconfirmedTransactions } = require('./helpers/confirm-transaction/util')
const WebcamUtils = require('../lib/webcam-utils') const WebcamUtils = require('../lib/webcam-utils')
import { getEnvironmentType } from '../../app/scripts/lib/util'
const actions = { const actions = {
_setBackgroundConnection: _setBackgroundConnection, _setBackgroundConnection: _setBackgroundConnection,
@ -30,6 +31,9 @@ const actions = {
MODAL_CLOSE: 'UI_MODAL_CLOSE', MODAL_CLOSE: 'UI_MODAL_CLOSE',
showModal: showModal, showModal: showModal,
hideModal: hideModal, hideModal: hideModal,
CLOSE_NOTIFICATION_WINDOW: 'CLOSE_NOTIFICATION_WINDOW',
// sidebar state // sidebar state
SIDEBAR_OPEN: 'UI_SIDEBAR_OPEN', SIDEBAR_OPEN: 'UI_SIDEBAR_OPEN',
SIDEBAR_CLOSE: 'UI_SIDEBAR_CLOSE', SIDEBAR_CLOSE: 'UI_SIDEBAR_CLOSE',
@ -173,7 +177,6 @@ const actions = {
COMPLETED_TX: 'COMPLETED_TX', COMPLETED_TX: 'COMPLETED_TX',
TRANSACTION_ERROR: 'TRANSACTION_ERROR', TRANSACTION_ERROR: 'TRANSACTION_ERROR',
NEXT_TX: 'NEXT_TX', NEXT_TX: 'NEXT_TX',
PREVIOUS_TX: 'PREV_TX',
EDIT_TX: 'EDIT_TX', EDIT_TX: 'EDIT_TX',
signMsg: signMsg, signMsg: signMsg,
cancelMsg: cancelMsg, cancelMsg: cancelMsg,
@ -186,14 +189,12 @@ const actions = {
signTokenTx: signTokenTx, signTokenTx: signTokenTx,
updateTransaction, updateTransaction,
updateAndApproveTx, updateAndApproveTx,
cancelTx: cancelTx, cancelTx,
cancelTxs, cancelTxs,
completedTx: completedTx, completedTx: completedTx,
txError: txError, txError: txError,
nextTx: nextTx, nextTx: nextTx,
editTx, editTx,
previousTx: previousTx,
cancelAllTx: cancelAllTx,
viewPendingTx: viewPendingTx, viewPendingTx: viewPendingTx,
VIEW_PENDING_TX: 'VIEW_PENDING_TX', VIEW_PENDING_TX: 'VIEW_PENDING_TX',
updateTransactionParams, updateTransactionParams,
@ -370,8 +371,9 @@ const actions = {
getRequestAccountTabIds, getRequestAccountTabIds,
setOpenMetamaskTabsIDs, setOpenMetamaskTabsIDs,
getOpenMetamaskTabsIds, getOpenMetamaskTabsIds,
isCreatedWithCorrectDPath, isCreatedWithCorrectDPath,
closeCurrentNotificationWindow,
closeNotificationWindow,
} }
module.exports = actions module.exports = actions
@ -945,9 +947,8 @@ function setCurrentCurrency (currencyCode) {
function signMsg (msgData) { function signMsg (msgData) {
log.debug('action - signMsg') log.debug('action - signMsg')
return (dispatch, getState) => { return (dispatch) => {
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
log.debug(`actions calling background.signMessage`) log.debug(`actions calling background.signMessage`)
background.signMessage(msgData, (err, newState) => { background.signMessage(msgData, (err, newState) => {
@ -962,10 +963,7 @@ function signMsg (msgData) {
} }
dispatch(actions.completedTx(msgData.metamaskId)) dispatch(actions.completedTx(msgData.metamaskId))
dispatch(closeCurrentNotificationWindow())
if (!hasUnconfirmedTransactions(getState())) {
return global.platform.closeNotificationWindow()
}
return resolve(msgData) return resolve(msgData)
}) })
@ -975,7 +973,7 @@ function signMsg (msgData) {
function signPersonalMsg (msgData) { function signPersonalMsg (msgData) {
log.debug('action - signPersonalMsg') log.debug('action - signPersonalMsg')
return (dispatch, getState) => { return (dispatch) => {
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -993,9 +991,7 @@ function signPersonalMsg (msgData) {
dispatch(actions.completedTx(msgData.metamaskId)) dispatch(actions.completedTx(msgData.metamaskId))
if (!hasUnconfirmedTransactions(getState())) { dispatch(actions.closeCurrentNotificationWindow())
return global.platform.closeNotificationWindow()
}
return resolve(msgData) return resolve(msgData)
}) })
@ -1005,7 +1001,7 @@ function signPersonalMsg (msgData) {
function signTypedMsg (msgData) { function signTypedMsg (msgData) {
log.debug('action - signTypedMsg') log.debug('action - signTypedMsg')
return (dispatch, getState) => { return (dispatch) => {
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -1023,9 +1019,7 @@ function signTypedMsg (msgData) {
dispatch(actions.completedTx(msgData.metamaskId)) dispatch(actions.completedTx(msgData.metamaskId))
if (!hasUnconfirmedTransactions(getState())) { dispatch(actions.closeCurrentNotificationWindow())
return global.platform.closeNotificationWindow()
}
return resolve(msgData) return resolve(msgData)
}) })
@ -1232,7 +1226,7 @@ function clearSend () {
function sendTx (txData) { function sendTx (txData) {
log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`) log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`)
return (dispatch, getState) => { return (dispatch) => {
log.debug(`actions calling background.approveTransaction`) log.debug(`actions calling background.approveTransaction`)
background.approveTransaction(txData.id, (err) => { background.approveTransaction(txData.id, (err) => {
if (err) { if (err) {
@ -1241,10 +1235,7 @@ function sendTx (txData) {
return log.error(err) return log.error(err)
} }
dispatch(actions.completedTx(txData.id)) dispatch(actions.completedTx(txData.id))
dispatch(actions.closeCurrentNotificationWindow())
if (!hasUnconfirmedTransactions(getState())) {
return global.platform.closeNotificationWindow()
}
}) })
} }
} }
@ -1294,10 +1285,9 @@ function updateTransaction (txData) {
function updateAndApproveTx (txData) { function updateAndApproveTx (txData) {
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData)) log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
return (dispatch, getState) => { return (dispatch) => {
log.debug(`actions calling background.updateAndApproveTx`) log.debug(`actions calling background.updateAndApproveTx`)
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
background.updateAndApproveTransaction(txData, err => { background.updateAndApproveTransaction(txData, err => {
dispatch(actions.updateTransactionParams(txData.id, txData.txParams)) dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
@ -1320,11 +1310,7 @@ function updateAndApproveTx (txData) {
dispatch(actions.clearSend()) dispatch(actions.clearSend())
dispatch(actions.completedTx(txData.id)) dispatch(actions.completedTx(txData.id))
dispatch(actions.hideLoadingIndication()) dispatch(actions.hideLoadingIndication())
dispatch(actions.setCurrentAccountTab('history')) dispatch(actions.closeCurrentNotificationWindow())
if (!hasUnconfirmedTransactions(getState())) {
return global.platform.closeNotificationWindow()
}
return txData return txData
}) })
@ -1358,7 +1344,7 @@ function txError (err) {
} }
function cancelMsg (msgData) { function cancelMsg (msgData) {
return (dispatch, getState) => { return (dispatch) => {
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -1373,9 +1359,7 @@ function cancelMsg (msgData) {
dispatch(actions.completedTx(msgData.id)) dispatch(actions.completedTx(msgData.id))
if (!hasUnconfirmedTransactions(getState())) { dispatch(actions.closeCurrentNotificationWindow())
return global.platform.closeNotificationWindow()
}
return resolve(msgData) return resolve(msgData)
}) })
@ -1384,7 +1368,7 @@ function cancelMsg (msgData) {
} }
function cancelPersonalMsg (msgData) { function cancelPersonalMsg (msgData) {
return (dispatch, getState) => { return (dispatch) => {
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -1399,9 +1383,7 @@ function cancelPersonalMsg (msgData) {
dispatch(actions.completedTx(id)) dispatch(actions.completedTx(id))
if (!hasUnconfirmedTransactions(getState())) { dispatch(actions.closeCurrentNotificationWindow())
return global.platform.closeNotificationWindow()
}
return resolve(msgData) return resolve(msgData)
}) })
@ -1410,7 +1392,7 @@ function cancelPersonalMsg (msgData) {
} }
function cancelTypedMsg (msgData) { function cancelTypedMsg (msgData) {
return (dispatch, getState) => { return (dispatch) => {
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -1425,9 +1407,7 @@ function cancelTypedMsg (msgData) {
dispatch(actions.completedTx(id)) dispatch(actions.completedTx(id))
if (!hasUnconfirmedTransactions(getState())) { dispatch(actions.closeCurrentNotificationWindow())
return global.platform.closeNotificationWindow()
}
return resolve(msgData) return resolve(msgData)
}) })
@ -1436,12 +1416,11 @@ function cancelTypedMsg (msgData) {
} }
function cancelTx (txData) { function cancelTx (txData) {
return (dispatch, getState) => { return (dispatch) => {
log.debug(`background.cancelTransaction`) log.debug(`background.cancelTransaction`)
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
background.cancelTransaction(txData.id, err => { background.cancelTransaction(txData.id, (err) => {
if (err) { if (err) {
return reject(err) return reject(err)
} }
@ -1450,15 +1429,12 @@ function cancelTx (txData) {
}) })
}) })
.then(() => updateMetamaskStateFromBackground()) .then(() => updateMetamaskStateFromBackground())
.then(newState => dispatch(actions.updateMetamaskState(newState))) .then((newState) => dispatch(actions.updateMetamaskState(newState)))
.then(() => { .then(() => {
dispatch(actions.clearSend()) dispatch(actions.clearSend())
dispatch(actions.completedTx(txData.id)) dispatch(actions.completedTx(txData.id))
dispatch(actions.hideLoadingIndication()) dispatch(actions.hideLoadingIndication())
dispatch(actions.closeCurrentNotificationWindow())
if (!hasUnconfirmedTransactions(getState())) {
return global.platform.closeNotificationWindow()
}
return txData return txData
}) })
@ -1471,9 +1447,9 @@ function cancelTx (txData) {
* @return {function(*): Promise<void>} * @return {function(*): Promise<void>}
*/ */
function cancelTxs (txDataList) { function cancelTxs (txDataList) {
return async (dispatch, getState) => { return async (dispatch) => {
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
const txIds = txDataList.map(({id}) => id) const txIds = txDataList.map(({ id }) => id)
const cancellations = txIds.map((id) => new Promise((resolve, reject) => { const cancellations = txIds.map((id) => new Promise((resolve, reject) => {
background.cancelTransaction(id, (err) => { background.cancelTransaction(id, (err) => {
if (err) { if (err) {
@ -1495,30 +1471,12 @@ function cancelTxs (txDataList) {
dispatch(actions.hideLoadingIndication()) dispatch(actions.hideLoadingIndication())
if (global.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION) { if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) {
return global.platform.closeCurrentWindow() 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 // initialize screen
// //
@ -1789,9 +1747,10 @@ function showConfTxPage (screenParams) {
} }
} }
function nextTx () { function nextTx (txId) {
return { return {
type: actions.NEXT_TX, type: actions.NEXT_TX,
value: txId,
} }
} }
@ -1802,12 +1761,6 @@ function viewPendingTx (txId) {
} }
} }
function previousTx () {
return {
type: actions.PREVIOUS_TX,
}
}
function editTx (txId) { function editTx (txId) {
return { return {
type: actions.EDIT_TX, type: actions.EDIT_TX,
@ -2158,6 +2111,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 }) { function showSidebar ({ transitionName, type }) {
return { return {
type: actions.SIDEBAR_OPEN, type: actions.SIDEBAR_OPEN,
@ -2362,7 +2332,7 @@ function showSendContractPage ({methodSelected, methodABI, inputValues}) {
function buyEth (opts) { function buyEth (opts) {
return (dispatch) => { return (dispatch) => {
const url = getBuyEthUrl(opts) const url = getBuyEthUrl(opts)
global.platform.openWindow({ url }) global.platform.openTab({ url })
dispatch({ dispatch({
type: actions.BUY_ETH, type: actions.BUY_ETH,
}) })

View File

@ -68,7 +68,7 @@ TokenMenuDropdown.prototype.render = function () {
onClick: (e) => { onClick: (e) => {
e.stopPropagation() e.stopPropagation()
const url = ethNetProps.explorerLinks.getExplorerAccountLinkFor(this.props.token.address, this.props.network) const url = ethNetProps.explorerLinks.getExplorerAccountLinkFor(this.props.token.address, this.props.network)
global.platform.openWindow({ url }) global.platform.openTab({ url })
this.props.onClose() this.props.onClose()
}, },
text: this.context.t('viewOnEtherscan'), text: this.context.t('viewOnEtherscan'),

View File

@ -79,7 +79,8 @@ function reduceApp (state, action) {
customHdPaths: customHdPaths, customHdPaths: customHdPaths,
}, state.appState) }, state.appState)
let curPendingTxIndex = appState.currentView.pendingTxIndex || 0 const curPendingTxIndex = appState.currentView.pendingTxIndex || 0
const curPendingTxId = appState.currentView.pendingTxId || 0
switch (action.type) { switch (action.type) {
// dropdown methods // dropdown methods
@ -507,6 +508,7 @@ function reduceApp (state, action) {
currentView: { currentView: {
name: 'confTx', name: 'confTx',
pendingTxIndex: action.id ? indexForPending(state, action.id) : 0, pendingTxIndex: action.id ? indexForPending(state, action.id) : 0,
pendingTxId: action.id,
screenParams: action.value, screenParams: action.value,
}, },
transForward: action.transForward, transForward: action.transForward,
@ -559,11 +561,14 @@ function reduceApp (state, action) {
} }
case actions.NEXT_TX: case actions.NEXT_TX:
const increment = (action.value - curPendingTxId)
return extend(appState, { return extend(appState, {
transForward: true, transForward: true,
currentView: { currentView: {
name: 'confTx', name: 'confTx',
pendingTxIndex: ++curPendingTxIndex, pendingTxIndex: curPendingTxIndex + increment,
pendingTxId: action.value,
index: curPendingTxIndex + increment,
warning: null, warning: null,
}, },
}) })
@ -575,16 +580,7 @@ function reduceApp (state, action) {
currentView: { currentView: {
name: 'confTx', name: 'confTx',
pendingTxIndex, pendingTxIndex,
warning: null, pendingTxId: action.value,
},
})
case actions.PREVIOUS_TX:
return extend(appState, {
transForward: false,
currentView: {
name: 'confTx',
pendingTxIndex: --curPendingTxIndex,
warning: null, warning: null,
}, },
}) })

View File

@ -6,6 +6,8 @@ import { roundExponential } from '../helpers/confirm-transaction/util'
const unapprovedTxsSelector = state => state.metamask.unapprovedTxs const unapprovedTxsSelector = state => state.metamask.unapprovedTxs
const unapprovedMsgsSelector = state => state.metamask.unapprovedMsgs const unapprovedMsgsSelector = state => state.metamask.unapprovedMsgs
const unapprovedPersonalMsgsSelector = state => state.metamask.unapprovedPersonalMsgs 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 unapprovedTypedMessagesSelector = state => state.metamask.unapprovedTypedMessages
const networkSelector = state => state.metamask.network const networkSelector = state => state.metamask.network
@ -13,18 +15,24 @@ export const unconfirmedTransactionsListSelector = createSelector(
unapprovedTxsSelector, unapprovedTxsSelector,
unapprovedMsgsSelector, unapprovedMsgsSelector,
unapprovedPersonalMsgsSelector, unapprovedPersonalMsgsSelector,
unapprovedDecryptMsgsSelector,
unapprovedEncryptionPublicKeyMsgsSelector,
unapprovedTypedMessagesSelector, unapprovedTypedMessagesSelector,
networkSelector, networkSelector,
( (
unapprovedTxs = {}, unapprovedTxs = {},
unapprovedMsgs = {}, unapprovedMsgs = {},
unapprovedPersonalMsgs = {}, unapprovedPersonalMsgs = {},
unapprovedDecryptMsgs = {},
unapprovedEncryptionPublicKeyMsgs = {},
unapprovedTypedMessages = {}, unapprovedTypedMessages = {},
network, network,
) => txHelper( ) => txHelper(
unapprovedTxs, unapprovedTxs,
unapprovedMsgs, unapprovedMsgs,
unapprovedPersonalMsgs, unapprovedPersonalMsgs,
unapprovedDecryptMsgs,
unapprovedEncryptionPublicKeyMsgs,
unapprovedTypedMessages, unapprovedTypedMessages,
network, network,
) || [], ) || [],
@ -34,12 +42,16 @@ export const unconfirmedTransactionsHashSelector = createSelector(
unapprovedTxsSelector, unapprovedTxsSelector,
unapprovedMsgsSelector, unapprovedMsgsSelector,
unapprovedPersonalMsgsSelector, unapprovedPersonalMsgsSelector,
unapprovedDecryptMsgsSelector,
unapprovedEncryptionPublicKeyMsgsSelector,
unapprovedTypedMessagesSelector, unapprovedTypedMessagesSelector,
networkSelector, networkSelector,
( (
unapprovedTxs = {}, unapprovedTxs = {},
unapprovedMsgs = {}, unapprovedMsgs = {},
unapprovedPersonalMsgs = {}, unapprovedPersonalMsgs = {},
unapprovedDecryptMsgs = {},
unapprovedEncryptionPublicKeyMsgs = {},
unapprovedTypedMessages = {}, unapprovedTypedMessages = {},
network, network,
) => { ) => {
@ -58,6 +70,8 @@ export const unconfirmedTransactionsHashSelector = createSelector(
...filteredUnapprovedTxs, ...filteredUnapprovedTxs,
...unapprovedMsgs, ...unapprovedMsgs,
...unapprovedPersonalMsgs, ...unapprovedPersonalMsgs,
...unapprovedDecryptMsgs,
...unapprovedEncryptionPublicKeyMsgs,
...unapprovedTypedMessages, ...unapprovedTypedMessages,
} }
}, },
@ -65,18 +79,24 @@ export const unconfirmedTransactionsHashSelector = createSelector(
const unapprovedMsgCountSelector = state => state.metamask.unapprovedMsgCount const unapprovedMsgCountSelector = state => state.metamask.unapprovedMsgCount
const unapprovedPersonalMsgCountSelector = state => state.metamask.unapprovedPersonalMsgCount const unapprovedPersonalMsgCountSelector = state => state.metamask.unapprovedPersonalMsgCount
const unapprovedDecryptMsgCountSelector = (state) => state.metamask.unapprovedDecryptMsgCount
const unapprovedEncryptionPublicKeyMsgCountSelector = (state) => state.metamask.unapprovedEncryptionPublicKeyMsgCount
const unapprovedTypedMessagesCountSelector = state => state.metamask.unapprovedTypedMessagesCount const unapprovedTypedMessagesCountSelector = state => state.metamask.unapprovedTypedMessagesCount
export const unconfirmedTransactionsCountSelector = createSelector( export const unconfirmedTransactionsCountSelector = createSelector(
unapprovedTxsSelector, unapprovedTxsSelector,
unapprovedMsgCountSelector, unapprovedMsgCountSelector,
unapprovedPersonalMsgCountSelector, unapprovedPersonalMsgCountSelector,
unapprovedDecryptMsgCountSelector,
unapprovedEncryptionPublicKeyMsgCountSelector,
unapprovedTypedMessagesCountSelector, unapprovedTypedMessagesCountSelector,
networkSelector, networkSelector,
( (
unapprovedTxs = {}, unapprovedTxs = {},
unapprovedMsgCount = 0, unapprovedMsgCount = 0,
unapprovedPersonalMsgCount = 0, unapprovedPersonalMsgCount = 0,
unapprovedDecryptMsgCount = 0,
unapprovedEncryptionPublicKeyMsgCount = 0,
unapprovedTypedMessagesCount = 0, unapprovedTypedMessagesCount = 0,
network, network,
) => { ) => {
@ -86,7 +106,7 @@ export const unconfirmedTransactionsCountSelector = createSelector(
}) })
return filteredUnapprovedTxIds.length + unapprovedTypedMessagesCount + unapprovedMsgCount + return filteredUnapprovedTxIds.length + unapprovedTypedMessagesCount + unapprovedMsgCount +
unapprovedPersonalMsgCount unapprovedPersonalMsgCount + unapprovedDecryptMsgCount + unapprovedEncryptionPublicKeyMsgCount
}, },
) )
@ -132,15 +152,16 @@ export const tokenAmountAndToAddressSelector = createSelector(
let tokenAmount = 0 let tokenAmount = 0
if (params && params.length) { if (params && params.length) {
const toParam = params.find(param => param.name === TOKEN_PARAM_TO) const toParam = params.find((param) => param.name === TOKEN_PARAM_TO)
const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE) const valueParam = params.find((param) => param.name === TOKEN_PARAM_VALUE)
toAddress = toParam ? toParam.value : params[0].value toAddress = toParam ? toParam.value : params[0].value
const value = valueParam ? Number(valueParam.value) : Number(params[1].value) const value = valueParam ? Number(valueParam.value) : Number(params[1].value)
tokenAmount = roundExponential(value)
if (tokenDecimals) { if (tokenDecimals) {
tokenAmount = calcTokenAmount(value, tokenDecimals) tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber()
} }
tokenAmount = roundExponential(tokenAmount)
} }
return { return {
@ -158,11 +179,11 @@ export const approveTokenAmountAndToAddressSelector = createSelector(
let tokenAmount = 0 let tokenAmount = 0
if (params && params.length) { if (params && params.length) {
toAddress = params.find(param => param.name === TOKEN_PARAM_SPENDER).value toAddress = params.find((param) => param.name === TOKEN_PARAM_SPENDER).value
const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value) const value = Number(params.find((param) => param.name === TOKEN_PARAM_VALUE).value)
if (tokenDecimals) { if (tokenDecimals) {
tokenAmount = calcTokenAmount(value, tokenDecimals) tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber()
} }
tokenAmount = roundExponential(tokenAmount) tokenAmount = roundExponential(tokenAmount)
@ -183,11 +204,11 @@ export const sendTokenTokenAmountAndToAddressSelector = createSelector(
let tokenAmount = 0 let tokenAmount = 0
if (params && params.length) { if (params && params.length) {
toAddress = params.find(param => param.name === TOKEN_PARAM_TO).value toAddress = params.find((param) => param.name === TOKEN_PARAM_TO).value
let value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value) let value = Number(params.find((param) => param.name === TOKEN_PARAM_VALUE).value)
if (tokenDecimals) { if (tokenDecimals) {
value = calcTokenAmount(value, tokenDecimals) value = calcTokenAmount(value, tokenDecimals).toNumber()
} }
tokenAmount = roundExponential(value) tokenAmount = roundExponential(value)

View File

@ -2,8 +2,8 @@ import log from 'loglevel'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import contractMapETH from 'eth-contract-metadata' import contractMapETH from 'eth-contract-metadata'
import contractMapPOA from 'poa-contract-metadata' import contractMapPOA from 'poa-contract-metadata'
import contractMapRSK from 'rsk-contract-metadata' import contractMapRSK from '@rsksmart/rsk-contract-metadata'
import contractMapRSKTest from 'rsk-test-contract-metadata' import contractMapRSKTest from '@rsksmart/rsk-testnet-contract-metadata'
const util = require('./util') const util = require('./util')
const casedContractMapETH = Object.keys(contractMapETH).reduce((acc, base) => { const casedContractMapETH = Object.keys(contractMapETH).reduce((acc, base) => {

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 unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedTypedMessages, metamaskState.network)
const numberOfUnapprivedTx = unapprovedTxsAll.length const numberOfUnapprivedTx = unapprovedTxsAll.length
if (numberOfUnapprivedTx > 0) { if (numberOfUnapprivedTx > 0) {
store.dispatch(actions.showConfTxPage({ store.dispatch(actions.showConfTxPage({
id: unapprovedTxsAll[numberOfUnapprivedTx - 1].id, id: unapprovedTxsAll[0].id,
})) }))
} }