Merge branch 'develop' into vb-rsk-dpath-update
This commit is contained in:
commit
fa96fd072e
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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__",
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
module.exports = setupMetamaskMeshMetrics
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injects an iframe into the current document for testing
|
|
||||||
*/
|
|
||||||
function setupMetamaskMeshMetrics () {
|
|
||||||
const testingContainer = document.createElement('iframe')
|
|
||||||
testingContainer.src = 'https://metamask.github.io/mesh-testing/'
|
|
||||||
console.log('Injecting Nifty Wallet Mesh testing client')
|
|
||||||
document.head.appendChild(testingContainer)
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@ const {
|
||||||
ENVIRONMENT_TYPE_POPUP,
|
ENVIRONMENT_TYPE_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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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', {
|
||||||
|
|
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 })
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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()),
|
||||||
},
|
},
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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)'),
|
||||||
|
|
|
@ -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')
|
||||||
})
|
})
|
||||||
|
|
|
@ -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' },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue