mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
commit
337a4e1b4e
@ -324,7 +324,7 @@ jobs:
|
|||||||
command: >
|
command: >
|
||||||
git config user.name metamaskbot &&
|
git config user.name metamaskbot &&
|
||||||
git config user.email admin@metamask.io &&
|
git config user.email admin@metamask.io &&
|
||||||
gh-pages -d docs/jsdocs
|
npm run publish-docs
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
docker:
|
docker:
|
||||||
|
12
CHANGELOG.md
12
CHANGELOG.md
@ -2,6 +2,18 @@
|
|||||||
|
|
||||||
## Current Develop Branch
|
## Current Develop Branch
|
||||||
|
|
||||||
|
## 4.17.0 Thursday November 1 2018
|
||||||
|
|
||||||
|
- Fix bug where data lookups like balances would get stale data (stopped block-tracker bug)
|
||||||
|
- Transaction Details now show entry for onchain failure
|
||||||
|
- [#5559](https://github.com/MetaMask/metamask-extension/pull/5559) Localize language names in translation select list
|
||||||
|
- [#5283](https://github.com/MetaMask/metamask-extension/pull/5283): Fix bug when eth.getCode() called with no contract
|
||||||
|
- [#5563](https://github.com/MetaMask/metamask-extension/pull/5563#pullrequestreview-166769174) Feature: improve Hatian Creole translations
|
||||||
|
- Feature: improve Slovenian translations
|
||||||
|
- Add support for alternate `wallet_watchAsset` rpc method name
|
||||||
|
- Attempt chain ID lookup via `eth_chainId` before `net_version`
|
||||||
|
- Fix account display width for large currency values
|
||||||
|
|
||||||
## 4.16.0 Wednesday October 17 2018
|
## 4.16.0 Wednesday October 17 2018
|
||||||
|
|
||||||
- Feature: Add toggle for primary currency (eth/fiat)
|
- Feature: Add toggle for primary currency (eth/fiat)
|
||||||
|
@ -692,9 +692,27 @@
|
|||||||
"newRecipient": {
|
"newRecipient": {
|
||||||
"message": "New Recipient"
|
"message": "New Recipient"
|
||||||
},
|
},
|
||||||
"newRPC": {
|
"newNetwork": {
|
||||||
|
"message": "New Network"
|
||||||
|
},
|
||||||
|
"rpcURL": {
|
||||||
"message": "New RPC URL"
|
"message": "New RPC URL"
|
||||||
},
|
},
|
||||||
|
"showAdvancedOptions": {
|
||||||
|
"message": "Show Advanced Options"
|
||||||
|
},
|
||||||
|
"hideAdvancedOptions": {
|
||||||
|
"message": "Hide Advanced Options"
|
||||||
|
},
|
||||||
|
"optionalChainId": {
|
||||||
|
"message": "ChainID (optional)"
|
||||||
|
},
|
||||||
|
"optionalSymbol": {
|
||||||
|
"message": "Symbol (optional)"
|
||||||
|
},
|
||||||
|
"optionalNickname": {
|
||||||
|
"message": "Nickname (optional)"
|
||||||
|
},
|
||||||
"next": {
|
"next": {
|
||||||
"message": "Next"
|
"message": "Next"
|
||||||
},
|
},
|
||||||
@ -803,7 +821,7 @@
|
|||||||
"message": "Primary Currency"
|
"message": "Primary Currency"
|
||||||
},
|
},
|
||||||
"primaryCurrencySettingDescription": {
|
"primaryCurrencySettingDescription": {
|
||||||
"message": "Select ETH to prioritize displaying values in ETH. Select Fiat to prioritize displaying values in your selected currency."
|
"message": "Select native to prioritize displaying values in the native currency of the chain (e.g. ETH). Select Fiat to prioritize displaying values in your selected fiat currency."
|
||||||
},
|
},
|
||||||
"privacyMsg": {
|
"privacyMsg": {
|
||||||
"message": "Privacy Policy"
|
"message": "Privacy Policy"
|
||||||
@ -1169,12 +1187,18 @@
|
|||||||
"transactionUpdatedGas": {
|
"transactionUpdatedGas": {
|
||||||
"message": "Transaction updated with a gas price of $1 on $2."
|
"message": "Transaction updated with a gas price of $1 on $2."
|
||||||
},
|
},
|
||||||
|
"transactionErrored": {
|
||||||
|
"message": "Transaction encountered an error."
|
||||||
|
},
|
||||||
"transactions": {
|
"transactions": {
|
||||||
"message": "transactions"
|
"message": "transactions"
|
||||||
},
|
},
|
||||||
"transactionError": {
|
"transactionError": {
|
||||||
"message": "Transaction Error. Exception thrown in contract code."
|
"message": "Transaction Error. Exception thrown in contract code."
|
||||||
},
|
},
|
||||||
|
"transactionErrorNoContract": {
|
||||||
|
"message": "Trying to call a function on a non-contract address."
|
||||||
|
},
|
||||||
"transactionMemo": {
|
"transactionMemo": {
|
||||||
"message": "Transaction memo (optional)"
|
"message": "Transaction memo (optional)"
|
||||||
},
|
},
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
|||||||
[
|
[
|
||||||
{ "code": "cs", "name": "Czech" },
|
{ "code": "cs", "name": "Čeština" },
|
||||||
{ "code": "de", "name": "German" },
|
{ "code": "de", "name": "Deutsche" },
|
||||||
{ "code": "en", "name": "English" },
|
{ "code": "en", "name": "English" },
|
||||||
{ "code": "es", "name": "Spanish" },
|
{ "code": "es", "name": "Español" },
|
||||||
{ "code": "fr", "name": "French" },
|
{ "code": "fr", "name": "Français" },
|
||||||
{ "code": "ht", "name": "Haitian Creole" },
|
{ "code": "ht", "name": "Kreyòl ayisyen" },
|
||||||
{ "code": "hn", "name": "Hindi" },
|
{ "code": "hn", "name": "हिन्दी" },
|
||||||
{ "code": "it", "name": "Italian" },
|
{ "code": "it", "name": "Italiano" },
|
||||||
{ "code": "ja", "name": "Japanese" },
|
{ "code": "ja", "name": "日本語" },
|
||||||
{ "code": "ko", "name": "Korean" },
|
{ "code": "ko", "name": "한국어" },
|
||||||
{ "code": "nl", "name": "Dutch" },
|
{ "code": "nl", "name": "Nederlands" },
|
||||||
{ "code": "ph", "name": "Tagalog" },
|
{ "code": "ph", "name": "Pilipino" },
|
||||||
{ "code": "pl", "name": "Polish" },
|
{ "code": "pl", "name": "Polskie" },
|
||||||
{ "code": "pt", "name": "Portuguese" },
|
{ "code": "pt", "name": "Português" },
|
||||||
{ "code": "ru", "name": "Russian" },
|
{ "code": "ru", "name": "Русский" },
|
||||||
{ "code": "sl", "name": "Slovenian" },
|
{ "code": "sl", "name": "Slovenščina" },
|
||||||
{ "code": "th", "name": "Thai" },
|
{ "code": "th", "name": "ไทย" },
|
||||||
{ "code": "tml", "name": "Tamil" },
|
{ "code": "tml", "name": "தமிழ்" },
|
||||||
{ "code": "tr", "name": "Turkish" },
|
{ "code": "tr", "name": "Türkçe" },
|
||||||
{ "code": "vi", "name": "Vietnamese" },
|
{ "code": "vi", "name": "Tiếng Việt" },
|
||||||
{ "code": "zh_CN", "name": "Chinese (Simplified)" },
|
{ "code": "zh_CN", "name": "中文(简体)" },
|
||||||
{ "code": "zh_TW", "name": "Chinese (Traditional)" }
|
{ "code": "zh_TW", "name": "中文(繁體)" }
|
||||||
]
|
]
|
||||||
|
@ -435,7 +435,7 @@
|
|||||||
"message": "back-up woorden hebben alleen kleine letters"
|
"message": "back-up woorden hebben alleen kleine letters"
|
||||||
},
|
},
|
||||||
"mainnet": {
|
"mainnet": {
|
||||||
"message": "belangrijkste Ethereum-netwerk"
|
"message": "Main Netwerk"
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"message": "Bericht"
|
"message": "Bericht"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,9 @@
|
|||||||
<html>
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<title>MetaMask Loading</title>
|
<title>MetaMask Loading</title>
|
||||||
<style>
|
<style>
|
||||||
#div-logo {
|
#div-logo {
|
||||||
@ -31,5 +35,11 @@
|
|||||||
<div id="div-logo">
|
<div id="div-logo">
|
||||||
<img id="logo" src="./images/loginglogo.svg">
|
<img id="logo" src="./images/loginglogo.svg">
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
// redirect to 404 after one minute
|
||||||
|
setTimeout(() => {
|
||||||
|
location.href = './404.html'
|
||||||
|
}, 60000)
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "__MSG_appName__",
|
"name": "__MSG_appName__",
|
||||||
"short_name": "__MSG_appName__",
|
"short_name": "__MSG_appName__",
|
||||||
"version": "4.16.0",
|
"version": "4.17.0",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"author": "https://metamask.io",
|
"author": "https://metamask.io",
|
||||||
"description": "__MSG_appDescription__",
|
"description": "__MSG_appDescription__",
|
||||||
|
@ -23,13 +23,13 @@ const createStreamSink = require('./lib/createStreamSink')
|
|||||||
const NotificationManager = require('./lib/notification-manager.js')
|
const NotificationManager = require('./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 setupSentry = require('./lib/setupSentry')
|
||||||
const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry')
|
const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry')
|
||||||
const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
|
const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
|
||||||
const EdgeEncryptor = require('./edge-encryptor')
|
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')
|
||||||
const ipfsContent = require('./lib/ipfsContent.js')
|
const setupEnsIpfsResolver = require('./lib/ens-ipfs/setup')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ENVIRONMENT_TYPE_POPUP,
|
ENVIRONMENT_TYPE_POPUP,
|
||||||
@ -50,7 +50,7 @@ global.METAMASK_NOTIFIER = notificationManager
|
|||||||
|
|
||||||
// setup sentry error reporting
|
// setup sentry error reporting
|
||||||
const release = platform.getVersion()
|
const release = platform.getVersion()
|
||||||
const raven = setupRaven({ release })
|
const sentry = setupSentry({ release })
|
||||||
|
|
||||||
// browser check if it is Edge - https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
|
// 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
|
// Internet Explorer 6-11
|
||||||
@ -58,7 +58,6 @@ const isIE = !!document.documentMode
|
|||||||
// Edge 20+
|
// Edge 20+
|
||||||
const isEdge = !isIE && !!window.StyleMedia
|
const isEdge = !isIE && !!window.StyleMedia
|
||||||
|
|
||||||
let ipfsHandle
|
|
||||||
let popupIsOpen = false
|
let popupIsOpen = false
|
||||||
let notificationIsOpen = false
|
let notificationIsOpen = false
|
||||||
const openMetamaskTabsIDs = {}
|
const openMetamaskTabsIDs = {}
|
||||||
@ -164,7 +163,6 @@ async function initialize () {
|
|||||||
const initLangCode = await getFirstPreferredLangCode()
|
const initLangCode = await getFirstPreferredLangCode()
|
||||||
await setupController(initState, initLangCode)
|
await setupController(initState, initLangCode)
|
||||||
log.debug('MetaMask initialization complete.')
|
log.debug('MetaMask initialization complete.')
|
||||||
ipfsHandle = ipfsContent(initState.NetworkController.provider)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -197,14 +195,14 @@ async function loadStateFromPersistence () {
|
|||||||
// we were able to recover (though it might be old)
|
// we were able to recover (though it might be old)
|
||||||
versionedData = diskStoreState
|
versionedData = diskStoreState
|
||||||
const vaultStructure = getObjStructure(versionedData)
|
const vaultStructure = getObjStructure(versionedData)
|
||||||
raven.captureMessage('MetaMask - Empty vault found - recovered from diskStore', {
|
sentry.captureMessage('MetaMask - Empty vault found - recovered from diskStore', {
|
||||||
// "extra" key is required by Sentry
|
// "extra" key is required by Sentry
|
||||||
extra: { vaultStructure },
|
extra: { vaultStructure },
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// unable to recover, clear state
|
// unable to recover, clear state
|
||||||
versionedData = migrator.generateInitialState(firstTimeState)
|
versionedData = migrator.generateInitialState(firstTimeState)
|
||||||
raven.captureMessage('MetaMask - Empty vault found - unable to recover')
|
sentry.captureMessage('MetaMask - Empty vault found - unable to recover')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +210,7 @@ async function loadStateFromPersistence () {
|
|||||||
migrator.on('error', (err) => {
|
migrator.on('error', (err) => {
|
||||||
// get vault structure without secrets
|
// get vault structure without secrets
|
||||||
const vaultStructure = getObjStructure(versionedData)
|
const vaultStructure = getObjStructure(versionedData)
|
||||||
raven.captureException(err, {
|
sentry.captureException(err, {
|
||||||
// "extra" key is required by Sentry
|
// "extra" key is required by Sentry
|
||||||
extra: { vaultStructure },
|
extra: { vaultStructure },
|
||||||
})
|
})
|
||||||
@ -269,17 +267,15 @@ function setupController (initState, initLangCode) {
|
|||||||
})
|
})
|
||||||
global.metamaskController = controller
|
global.metamaskController = controller
|
||||||
|
|
||||||
controller.networkController.on('networkDidChange', () => {
|
const provider = controller.provider
|
||||||
ipfsHandle && ipfsHandle.remove()
|
setupEnsIpfsResolver({ provider })
|
||||||
ipfsHandle = ipfsContent(controller.networkController.providerStore.getState())
|
|
||||||
})
|
|
||||||
|
|
||||||
// report failed transactions to Sentry
|
// report failed transactions to Sentry
|
||||||
controller.txController.on(`tx:status-update`, (txId, status) => {
|
controller.txController.on(`tx:status-update`, (txId, status) => {
|
||||||
if (status !== 'failed') return
|
if (status !== 'failed') return
|
||||||
const txMeta = controller.txController.txStateManager.getTx(txId)
|
const txMeta = controller.txController.txStateManager.getTx(txId)
|
||||||
try {
|
try {
|
||||||
reportFailedTxToSentry({ raven, txMeta })
|
reportFailedTxToSentry({ sentry, txMeta })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
|
@ -83,8 +83,25 @@ class BlacklistController {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
async updatePhishingList () {
|
async updatePhishingList () {
|
||||||
const response = await fetch('https://api.infura.io/v2/blacklist')
|
// make request
|
||||||
const phishing = await response.json()
|
let response
|
||||||
|
try {
|
||||||
|
response = await fetch('https://api.infura.io/v2/blacklist')
|
||||||
|
} catch (err) {
|
||||||
|
log.error(new Error(`BlacklistController - failed to fetch blacklist:\n${err.stack}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// parse response
|
||||||
|
let rawResponse
|
||||||
|
let phishing
|
||||||
|
try {
|
||||||
|
const rawResponse = await response.text()
|
||||||
|
phishing = JSON.parse(rawResponse)
|
||||||
|
} catch (err) {
|
||||||
|
log.error(new Error(`BlacklistController - failed to parse blacklist:\n${rawResponse}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// update current blacklist
|
||||||
this.store.updateState({ phishing })
|
this.store.updateState({ phishing })
|
||||||
this._setupPhishingDetector(phishing)
|
this._setupPhishingDetector(phishing)
|
||||||
return phishing
|
return phishing
|
||||||
@ -97,9 +114,9 @@ class BlacklistController {
|
|||||||
*/
|
*/
|
||||||
scheduleUpdates () {
|
scheduleUpdates () {
|
||||||
if (this._phishingUpdateIntervalRef) return
|
if (this._phishingUpdateIntervalRef) return
|
||||||
this.updatePhishingList().catch(log.warn)
|
this.updatePhishingList()
|
||||||
this._phishingUpdateIntervalRef = setInterval(() => {
|
this._phishingUpdateIntervalRef = setInterval(() => {
|
||||||
this.updatePhishingList().catch(log.warn)
|
this.updatePhishingList()
|
||||||
}, POLLING_INTERVAL)
|
}, POLLING_INTERVAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ class CurrencyController {
|
|||||||
* since midnight of January 1, 1970
|
* since midnight of January 1, 1970
|
||||||
* @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method.
|
* @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method.
|
||||||
* Used to clear an existing interval on subsequent calls of that method.
|
* Used to clear an existing interval on subsequent calls of that method.
|
||||||
|
* @property {string} nativeCurrency The ticker/symbol of the native chain currency
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
constructor (opts = {}) {
|
constructor (opts = {}) {
|
||||||
@ -28,6 +29,7 @@ class CurrencyController {
|
|||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
conversionRate: 0,
|
conversionRate: 0,
|
||||||
conversionDate: 'N/A',
|
conversionDate: 'N/A',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
}, opts.initState)
|
}, opts.initState)
|
||||||
this.store = new ObservableStore(initState)
|
this.store = new ObservableStore(initState)
|
||||||
}
|
}
|
||||||
@ -36,6 +38,29 @@ class CurrencyController {
|
|||||||
// PUBLIC METHODS
|
// PUBLIC METHODS
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A getter for the nativeCurrency property
|
||||||
|
*
|
||||||
|
* @returns {string} A 2-4 character shorthand that describes the specific currency
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getNativeCurrency () {
|
||||||
|
return this.store.getState().nativeCurrency
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A setter for the nativeCurrency property
|
||||||
|
*
|
||||||
|
* @param {string} nativeCurrency The new currency to set as the nativeCurrency in the store
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
setNativeCurrency (nativeCurrency) {
|
||||||
|
this.store.updateState({
|
||||||
|
nativeCurrency,
|
||||||
|
ticker: nativeCurrency,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A getter for the currentCurrency property
|
* A getter for the currentCurrency property
|
||||||
*
|
*
|
||||||
@ -104,17 +129,60 @@ class CurrencyController {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
async updateConversionRate () {
|
async updateConversionRate () {
|
||||||
let currentCurrency
|
let currentCurrency, nativeCurrency
|
||||||
try {
|
try {
|
||||||
currentCurrency = this.getCurrentCurrency()
|
currentCurrency = this.getCurrentCurrency()
|
||||||
const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`)
|
nativeCurrency = this.getNativeCurrency()
|
||||||
const parsedResponse = await response.json()
|
// select api
|
||||||
this.setConversionRate(Number(parsedResponse.bid))
|
let apiUrl
|
||||||
this.setConversionDate(Number(parsedResponse.timestamp))
|
if (nativeCurrency === 'ETH') {
|
||||||
|
// ETH
|
||||||
|
apiUrl = `https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`
|
||||||
|
} else {
|
||||||
|
// ETC
|
||||||
|
apiUrl = `https://min-api.cryptocompare.com/data/price?fsym=${nativeCurrency.toUpperCase()}&tsyms=${currentCurrency.toUpperCase()}`
|
||||||
|
}
|
||||||
|
// attempt request
|
||||||
|
let response
|
||||||
|
try {
|
||||||
|
response = await fetch(apiUrl)
|
||||||
|
} catch (err) {
|
||||||
|
log.error(new Error(`CurrencyController - Failed to request currency from Infura:\n${err.stack}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// parse response
|
||||||
|
let rawResponse
|
||||||
|
let parsedResponse
|
||||||
|
try {
|
||||||
|
rawResponse = await response.text()
|
||||||
|
parsedResponse = JSON.parse(rawResponse)
|
||||||
|
} catch (err) {
|
||||||
|
log.error(new Error(`CurrencyController - Failed to parse response "${rawResponse}"`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// set conversion rate
|
||||||
|
if (nativeCurrency === 'ETH') {
|
||||||
|
// ETH
|
||||||
|
this.setConversionRate(Number(parsedResponse.bid))
|
||||||
|
this.setConversionDate(Number(parsedResponse.timestamp))
|
||||||
|
} else {
|
||||||
|
// ETC
|
||||||
|
if (parsedResponse[currentCurrency.toUpperCase()]) {
|
||||||
|
this.setConversionRate(Number(parsedResponse[currentCurrency.toUpperCase()]))
|
||||||
|
this.setConversionDate(parseInt((new Date()).getTime() / 1000))
|
||||||
|
} else {
|
||||||
|
this.setConversionRate(0)
|
||||||
|
this.setConversionDate('N/A')
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err)
|
// reset current conversion rate
|
||||||
|
log.warn(`MetaMask - Failed to query currency conversion:`, nativeCurrency, currentCurrency, err)
|
||||||
this.setConversionRate(0)
|
this.setConversionRate(0)
|
||||||
this.setConversionDate('N/A')
|
this.setConversionDate('N/A')
|
||||||
|
// throw error
|
||||||
|
log.error(new Error(`CurrencyController - Failed to query rate for currency "${currentCurrency}":\n${err.stack}`))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ function createMetamaskMiddleware ({
|
|||||||
processTransaction,
|
processTransaction,
|
||||||
processEthSignMessage,
|
processEthSignMessage,
|
||||||
processTypedMessage,
|
processTypedMessage,
|
||||||
|
processTypedMessageV3,
|
||||||
processPersonalMessage,
|
processPersonalMessage,
|
||||||
getPendingNonce,
|
getPendingNonce,
|
||||||
}) {
|
}) {
|
||||||
@ -25,6 +26,7 @@ function createMetamaskMiddleware ({
|
|||||||
processTransaction,
|
processTransaction,
|
||||||
processEthSignMessage,
|
processEthSignMessage,
|
||||||
processTypedMessage,
|
processTypedMessage,
|
||||||
|
processTypedMessageV3,
|
||||||
processPersonalMessage,
|
processPersonalMessage,
|
||||||
}),
|
}),
|
||||||
createPendingNonceMiddleware({ getPendingNonce }),
|
createPendingNonceMiddleware({ getPendingNonce }),
|
||||||
|
@ -11,6 +11,8 @@ const createInfuraClient = require('./createInfuraClient')
|
|||||||
const createJsonRpcClient = require('./createJsonRpcClient')
|
const createJsonRpcClient = require('./createJsonRpcClient')
|
||||||
const createLocalhostClient = require('./createLocalhostClient')
|
const createLocalhostClient = require('./createLocalhostClient')
|
||||||
const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy')
|
const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy')
|
||||||
|
const extend = require('extend')
|
||||||
|
const networks = { networkList: {} }
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ROPSTEN,
|
ROPSTEN,
|
||||||
@ -29,6 +31,10 @@ const defaultProviderConfig = {
|
|||||||
type: testMode ? RINKEBY : MAINNET,
|
type: testMode ? RINKEBY : MAINNET,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultNetworkConfig = {
|
||||||
|
ticker: 'ETH',
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = class NetworkController extends EventEmitter {
|
module.exports = class NetworkController extends EventEmitter {
|
||||||
|
|
||||||
constructor (opts = {}) {
|
constructor (opts = {}) {
|
||||||
@ -39,7 +45,8 @@ module.exports = class NetworkController extends EventEmitter {
|
|||||||
// create stores
|
// create stores
|
||||||
this.providerStore = new ObservableStore(providerConfig)
|
this.providerStore = new ObservableStore(providerConfig)
|
||||||
this.networkStore = new ObservableStore('loading')
|
this.networkStore = new ObservableStore('loading')
|
||||||
this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore })
|
this.networkConfig = new ObservableStore(defaultNetworkConfig)
|
||||||
|
this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore, settings: this.networkConfig })
|
||||||
this.on('networkDidChange', this.lookupNetwork)
|
this.on('networkDidChange', this.lookupNetwork)
|
||||||
// provider and block tracker
|
// provider and block tracker
|
||||||
this._provider = null
|
this._provider = null
|
||||||
@ -51,8 +58,8 @@ module.exports = class NetworkController extends EventEmitter {
|
|||||||
|
|
||||||
initializeProvider (providerParams) {
|
initializeProvider (providerParams) {
|
||||||
this._baseProviderParams = providerParams
|
this._baseProviderParams = providerParams
|
||||||
const { type, rpcTarget } = this.providerStore.getState()
|
const { type, rpcTarget, chainId, ticker, nickname } = this.providerStore.getState()
|
||||||
this._configureProvider({ type, rpcTarget })
|
this._configureProvider({ type, rpcTarget, chainId, ticker, nickname })
|
||||||
this.lookupNetwork()
|
this.lookupNetwork()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +79,20 @@ module.exports = class NetworkController extends EventEmitter {
|
|||||||
return this.networkStore.getState()
|
return this.networkStore.getState()
|
||||||
}
|
}
|
||||||
|
|
||||||
setNetworkState (network) {
|
getNetworkConfig () {
|
||||||
|
return this.networkConfig.getState()
|
||||||
|
}
|
||||||
|
|
||||||
|
setNetworkState (network, type) {
|
||||||
|
if (network === 'loading') {
|
||||||
|
return this.networkStore.putState(network)
|
||||||
|
}
|
||||||
|
|
||||||
|
// type must be defined
|
||||||
|
if (!type) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
network = networks.networkList[type] && networks.networkList[type].chainId ? networks.networkList[type].chainId : network
|
||||||
return this.networkStore.putState(network)
|
return this.networkStore.putState(network)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,18 +105,32 @@ module.exports = class NetworkController extends EventEmitter {
|
|||||||
if (!this._provider) {
|
if (!this._provider) {
|
||||||
return log.warn('NetworkController - lookupNetwork aborted due to missing provider')
|
return log.warn('NetworkController - lookupNetwork aborted due to missing provider')
|
||||||
}
|
}
|
||||||
|
var { type } = this.providerStore.getState()
|
||||||
const ethQuery = new EthQuery(this._provider)
|
const ethQuery = new EthQuery(this._provider)
|
||||||
ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
|
// first attempt to perform lookup via eth_chainId
|
||||||
if (err) return this.setNetworkState('loading')
|
ethQuery.sendAsync({ method: 'eth_chainId' }, (err, chainIdHex) => {
|
||||||
log.info('web3.getNetwork returned ' + network)
|
if (err) {
|
||||||
this.setNetworkState(network)
|
// if eth_chainId is not supported, fallback to net_verion
|
||||||
|
ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
|
||||||
|
if (err) return this.setNetworkState('loading')
|
||||||
|
log.info(`net_version returned ${network}`)
|
||||||
|
this.setNetworkState(network, type)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const chainId = Number.parseInt(chainIdHex, 16)
|
||||||
|
log.info(`net_version returned ${chainId}`)
|
||||||
|
this.setNetworkState(chainId, type)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setRpcTarget (rpcTarget) {
|
setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '') {
|
||||||
const providerConfig = {
|
const providerConfig = {
|
||||||
type: 'rpc',
|
type: 'rpc',
|
||||||
rpcTarget,
|
rpcTarget,
|
||||||
|
chainId,
|
||||||
|
ticker,
|
||||||
|
nickname,
|
||||||
}
|
}
|
||||||
this.providerConfig = providerConfig
|
this.providerConfig = providerConfig
|
||||||
}
|
}
|
||||||
@ -132,7 +166,7 @@ module.exports = class NetworkController extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_configureProvider (opts) {
|
_configureProvider (opts) {
|
||||||
const { type, rpcTarget } = opts
|
const { type, rpcTarget, chainId, ticker, nickname } = opts
|
||||||
// infura type-based endpoints
|
// infura type-based endpoints
|
||||||
const isInfura = INFURA_PROVIDER_TYPES.includes(type)
|
const isInfura = INFURA_PROVIDER_TYPES.includes(type)
|
||||||
if (isInfura) {
|
if (isInfura) {
|
||||||
@ -142,7 +176,7 @@ module.exports = class NetworkController extends EventEmitter {
|
|||||||
this._configureLocalhostProvider()
|
this._configureLocalhostProvider()
|
||||||
// url-based rpc endpoints
|
// url-based rpc endpoints
|
||||||
} else if (type === 'rpc') {
|
} else if (type === 'rpc') {
|
||||||
this._configureStandardProvider({ rpcUrl: rpcTarget })
|
this._configureStandardProvider({ rpcUrl: rpcTarget, chainId, ticker, nickname })
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
|
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
|
||||||
}
|
}
|
||||||
@ -152,6 +186,11 @@ module.exports = class NetworkController extends EventEmitter {
|
|||||||
log.info('NetworkController - configureInfuraProvider', type)
|
log.info('NetworkController - configureInfuraProvider', type)
|
||||||
const networkClient = createInfuraClient({ network: type })
|
const networkClient = createInfuraClient({ network: type })
|
||||||
this._setNetworkClient(networkClient)
|
this._setNetworkClient(networkClient)
|
||||||
|
// setup networkConfig
|
||||||
|
var settings = {
|
||||||
|
ticker: 'ETH',
|
||||||
|
}
|
||||||
|
this.networkConfig.putState(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
_configureLocalhostProvider () {
|
_configureLocalhostProvider () {
|
||||||
@ -160,9 +199,22 @@ module.exports = class NetworkController extends EventEmitter {
|
|||||||
this._setNetworkClient(networkClient)
|
this._setNetworkClient(networkClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
_configureStandardProvider ({ rpcUrl }) {
|
_configureStandardProvider ({ rpcUrl, chainId, ticker, nickname }) {
|
||||||
log.info('NetworkController - configureStandardProvider', rpcUrl)
|
log.info('NetworkController - configureStandardProvider', rpcUrl)
|
||||||
const networkClient = createJsonRpcClient({ rpcUrl })
|
const networkClient = createJsonRpcClient({ rpcUrl })
|
||||||
|
// hack to add a 'rpc' network with chainId
|
||||||
|
networks.networkList['rpc'] = {
|
||||||
|
chainId: chainId,
|
||||||
|
rpcUrl,
|
||||||
|
ticker: ticker || 'ETH',
|
||||||
|
nickname,
|
||||||
|
}
|
||||||
|
// setup networkConfig
|
||||||
|
var settings = {
|
||||||
|
network: chainId,
|
||||||
|
}
|
||||||
|
settings = extend(settings, networks.networkList['rpc'])
|
||||||
|
this.networkConfig.putState(settings)
|
||||||
this._setNetworkClient(networkClient)
|
this._setNetworkClient(networkClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class PreferencesController {
|
|||||||
*/
|
*/
|
||||||
constructor (opts = {}) {
|
constructor (opts = {}) {
|
||||||
const initState = extend({
|
const initState = extend({
|
||||||
frequentRpcList: [],
|
frequentRpcListDetail: [],
|
||||||
currentAccountTab: 'history',
|
currentAccountTab: 'history',
|
||||||
accountTokens: {},
|
accountTokens: {},
|
||||||
assetImages: {},
|
assetImages: {},
|
||||||
@ -39,7 +39,7 @@ class PreferencesController {
|
|||||||
seedWords: null,
|
seedWords: null,
|
||||||
forgottenPassword: false,
|
forgottenPassword: false,
|
||||||
preferences: {
|
preferences: {
|
||||||
useETHAsPrimaryCurrency: true,
|
useNativeCurrencyAsPrimaryCurrency: true,
|
||||||
},
|
},
|
||||||
}, opts.initState)
|
}, opts.initState)
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ class PreferencesController {
|
|||||||
* @param {Function} - end
|
* @param {Function} - end
|
||||||
*/
|
*/
|
||||||
async requestWatchAsset (req, res, next, end) {
|
async requestWatchAsset (req, res, next, end) {
|
||||||
if (req.method === 'metamask_watchAsset') {
|
if (req.method === 'metamask_watchAsset' || req.method === 'wallet_watchAsset') {
|
||||||
const { type, options } = req.params
|
const { type, options } = req.params
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'ERC20':
|
case 'ERC20':
|
||||||
@ -374,22 +374,6 @@ class PreferencesController {
|
|||||||
return Promise.resolve(label)
|
return Promise.resolve(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an updated rpc list from this.addToFrequentRpcList() and sets the `frequentRpcList` to this update list.
|
|
||||||
*
|
|
||||||
* @param {string} _url The the new rpc url to add to the updated list
|
|
||||||
* @param {bool} remove Remove selected url
|
|
||||||
* @returns {Promise<void>} Promise resolves with undefined
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
updateFrequentRpcList (_url, remove = false) {
|
|
||||||
return this.addToFrequentRpcList(_url, remove)
|
|
||||||
.then((rpcList) => {
|
|
||||||
this.store.updateState({ frequentRpcList: rpcList })
|
|
||||||
return Promise.resolve()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setter for the `currentAccountTab` property
|
* Setter for the `currentAccountTab` property
|
||||||
*
|
*
|
||||||
@ -405,35 +389,53 @@ class PreferencesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an updated rpcList based on the passed url and the current list.
|
* Adds custom RPC url to state.
|
||||||
* The returned list will have a max length of 3. If the _url currently exists it the list, it will be moved to the
|
|
||||||
* end of the list. The current list is modified and returned as a promise.
|
|
||||||
*
|
*
|
||||||
* @param {string} _url The rpc url to add to the frequentRpcList.
|
* @param {string} url The RPC url to add to frequentRpcList.
|
||||||
* @param {bool} remove Remove selected url
|
* @param {number} chainId Optional chainId of the selected network.
|
||||||
* @returns {Promise<array>} The updated frequentRpcList.
|
* @param {string} ticker Optional ticker symbol of the selected network.
|
||||||
|
* @param {string} nickname Optional nickname of the selected network.
|
||||||
|
* @returns {Promise<array>} Promise resolving to updated frequentRpcList.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
addToFrequentRpcList (_url, remove = false) {
|
addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '') {
|
||||||
const rpcList = this.getFrequentRpcList()
|
const rpcList = this.getFrequentRpcListDetail()
|
||||||
const index = rpcList.findIndex((element) => { return element === _url })
|
const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
rpcList.splice(index, 1)
|
rpcList.splice(index, 1)
|
||||||
}
|
}
|
||||||
if (!remove && _url !== 'http://localhost:8545') {
|
if (url !== 'http://localhost:8545') {
|
||||||
rpcList.push(_url)
|
rpcList.push({ rpcUrl: url, chainId, ticker, nickname })
|
||||||
}
|
}
|
||||||
|
this.store.updateState({ frequentRpcListDetail: rpcList })
|
||||||
return Promise.resolve(rpcList)
|
return Promise.resolve(rpcList)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for the `frequentRpcList` property.
|
* Removes custom RPC url from state.
|
||||||
*
|
*
|
||||||
* @returns {array<string>} An array of one or two rpc urls.
|
* @param {string} url The RPC url to remove from frequentRpcList.
|
||||||
|
* @returns {Promise<array>} Promise resolving to updated frequentRpcList.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
getFrequentRpcList () {
|
removeFromFrequentRpcList (url) {
|
||||||
return this.store.getState().frequentRpcList
|
const rpcList = this.getFrequentRpcListDetail()
|
||||||
|
const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
|
||||||
|
if (index !== -1) {
|
||||||
|
rpcList.splice(index, 1)
|
||||||
|
}
|
||||||
|
this.store.updateState({ frequentRpcListDetail: rpcList })
|
||||||
|
return Promise.resolve(rpcList)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the `frequentRpcListDetail` property.
|
||||||
|
*
|
||||||
|
* @returns {array<array>} An array of rpc urls.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getFrequentRpcListDetail () {
|
||||||
|
return this.store.getState().frequentRpcListDetail
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,6 +7,8 @@ const {
|
|||||||
const { addHexPrefix } = require('ethereumjs-util')
|
const { addHexPrefix } = require('ethereumjs-util')
|
||||||
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
|
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
|
||||||
|
|
||||||
|
import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/constants/error-keys'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
tx-gas-utils are gas utility methods for Transaction manager
|
tx-gas-utils are gas utility methods for Transaction manager
|
||||||
its passed ethquery
|
its passed ethquery
|
||||||
@ -32,6 +34,7 @@ class TxGasUtil {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
txMeta.simulationFails = {
|
txMeta.simulationFails = {
|
||||||
reason: err.message,
|
reason: err.message,
|
||||||
|
errorKey: err.errorKey,
|
||||||
}
|
}
|
||||||
return txMeta
|
return txMeta
|
||||||
}
|
}
|
||||||
@ -56,24 +59,38 @@ class TxGasUtil {
|
|||||||
return txParams.gas
|
return txParams.gas
|
||||||
}
|
}
|
||||||
|
|
||||||
// if recipient has no code, gas is 21k max:
|
|
||||||
const recipient = txParams.to
|
const recipient = txParams.to
|
||||||
const hasRecipient = Boolean(recipient)
|
const hasRecipient = Boolean(recipient)
|
||||||
let code
|
|
||||||
if (recipient) code = await this.query.getCode(recipient)
|
|
||||||
|
|
||||||
if (hasRecipient && (!code || code === '0x')) {
|
// see if we can set the gas based on the recipient
|
||||||
txParams.gas = SIMPLE_GAS_COST
|
if (hasRecipient) {
|
||||||
txMeta.simpleSend = true // Prevents buffer addition
|
const code = await this.query.getCode(recipient)
|
||||||
return SIMPLE_GAS_COST
|
// For an address with no code, geth will return '0x', and ganache-core v2.2.1 will return '0x0'
|
||||||
|
const codeIsEmpty = !code || code === '0x' || code === '0x0'
|
||||||
|
|
||||||
|
if (codeIsEmpty) {
|
||||||
|
// if there's data in the params, but there's no contract code, it's not a valid transaction
|
||||||
|
if (txParams.data) {
|
||||||
|
const err = new Error('TxGasUtil - Trying to call a function on a non-contract address')
|
||||||
|
// set error key so ui can display localized error message
|
||||||
|
err.errorKey = TRANSACTION_NO_CONTRACT_ERROR_KEY
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a standard ether simple send, gas requirement is exactly 21k
|
||||||
|
txParams.gas = SIMPLE_GAS_COST
|
||||||
|
// prevents buffer addition
|
||||||
|
txMeta.simpleSend = true
|
||||||
|
return SIMPLE_GAS_COST
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not, fall back to block gasLimit
|
// fallback to block gasLimit
|
||||||
const blockGasLimitBN = hexToBn(blockGasLimitHex)
|
const blockGasLimitBN = hexToBn(blockGasLimitHex)
|
||||||
const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20)
|
const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20)
|
||||||
txParams.gas = bnToHex(saferGasLimitBN)
|
txParams.gas = bnToHex(saferGasLimitBN)
|
||||||
|
|
||||||
// run tx
|
// estimate tx gas requirements
|
||||||
return await this.query.estimateGas(txParams)
|
return await this.query.estimateGas(txParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
54
app/scripts/lib/ens-ipfs/resolver.js
Normal file
54
app/scripts/lib/ens-ipfs/resolver.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
const namehash = require('eth-ens-namehash')
|
||||||
|
const multihash = require('multihashes')
|
||||||
|
const Eth = require('ethjs-query')
|
||||||
|
const EthContract = require('ethjs-contract')
|
||||||
|
const registrarAbi = require('./contracts/registrar')
|
||||||
|
const resolverAbi = require('./contracts/resolver')
|
||||||
|
|
||||||
|
module.exports = resolveEnsToIpfsContentId
|
||||||
|
|
||||||
|
|
||||||
|
async function resolveEnsToIpfsContentId ({ provider, name }) {
|
||||||
|
const eth = new Eth(provider)
|
||||||
|
const hash = namehash.hash(name)
|
||||||
|
const contract = new EthContract(eth)
|
||||||
|
// lookup registrar
|
||||||
|
const chainId = Number.parseInt(await eth.net_version(), 10)
|
||||||
|
const registrarAddress = getRegistrarForChainId(chainId)
|
||||||
|
if (!registrarAddress) {
|
||||||
|
throw new Error(`EnsIpfsResolver - no known ens-ipfs registrar for chainId "${chainId}"`)
|
||||||
|
}
|
||||||
|
const Registrar = contract(registrarAbi).at(registrarAddress)
|
||||||
|
// lookup resolver
|
||||||
|
const resolverLookupResult = await Registrar.resolver(hash)
|
||||||
|
const resolverAddress = resolverLookupResult[0]
|
||||||
|
if (hexValueIsEmpty(resolverAddress)) {
|
||||||
|
throw new Error(`EnsIpfsResolver - no resolver found for name "${name}"`)
|
||||||
|
}
|
||||||
|
const Resolver = contract(resolverAbi).at(resolverAddress)
|
||||||
|
// lookup content id
|
||||||
|
const contentLookupResult = await Resolver.content(hash)
|
||||||
|
const contentHash = contentLookupResult[0]
|
||||||
|
if (hexValueIsEmpty(contentHash)) {
|
||||||
|
throw new Error(`EnsIpfsResolver - no content ID found for name "${name}"`)
|
||||||
|
}
|
||||||
|
const nonPrefixedHex = contentHash.slice(2)
|
||||||
|
const buffer = multihash.fromHexString(nonPrefixedHex)
|
||||||
|
const contentId = multihash.toB58String(multihash.encode(buffer, 'sha2-256'))
|
||||||
|
return contentId
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexValueIsEmpty(value) {
|
||||||
|
return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRegistrarForChainId (chainId) {
|
||||||
|
switch (chainId) {
|
||||||
|
// mainnet
|
||||||
|
case 1:
|
||||||
|
return '0x314159265dd8dbb310642f98f50c066173c1259b'
|
||||||
|
// ropsten
|
||||||
|
case 3:
|
||||||
|
return '0x112234455c3a32fd11230c42e7bccd4a84e02010'
|
||||||
|
}
|
||||||
|
}
|
63
app/scripts/lib/ens-ipfs/setup.js
Normal file
63
app/scripts/lib/ens-ipfs/setup.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
const urlUtil = require('url')
|
||||||
|
const extension = require('extensionizer')
|
||||||
|
const resolveEnsToIpfsContentId = require('./resolver.js')
|
||||||
|
|
||||||
|
const supportedTopLevelDomains = ['eth']
|
||||||
|
|
||||||
|
module.exports = setupEnsIpfsResolver
|
||||||
|
|
||||||
|
function setupEnsIpfsResolver({ provider }) {
|
||||||
|
|
||||||
|
// install listener
|
||||||
|
const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`)
|
||||||
|
extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { urls: urlPatterns })
|
||||||
|
|
||||||
|
// return api object
|
||||||
|
return {
|
||||||
|
// uninstall listener
|
||||||
|
remove () {
|
||||||
|
extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
async function webRequestDidFail (details) {
|
||||||
|
const { tabId, url } = details
|
||||||
|
// ignore requests that are not associated with tabs
|
||||||
|
if (tabId === -1) return
|
||||||
|
// parse ens name
|
||||||
|
const urlData = urlUtil.parse(url)
|
||||||
|
const { hostname: name, path, search } = urlData
|
||||||
|
const domainParts = name.split('.')
|
||||||
|
const topLevelDomain = domainParts[domainParts.length - 1]
|
||||||
|
// if unsupported TLD, abort
|
||||||
|
if (!supportedTopLevelDomains.includes(topLevelDomain)) return
|
||||||
|
// otherwise attempt resolve
|
||||||
|
attemptResolve({ tabId, name, path, search })
|
||||||
|
}
|
||||||
|
|
||||||
|
async function attemptResolve({ tabId, name, path, search }) {
|
||||||
|
extension.tabs.update(tabId, { url: `loading.html` })
|
||||||
|
try {
|
||||||
|
const ipfsContentId = await resolveEnsToIpfsContentId({ provider, name })
|
||||||
|
let url = `https://gateway.ipfs.io/ipfs/${ipfsContentId}${path}${search || ''}`
|
||||||
|
try {
|
||||||
|
// check if ipfs gateway has result
|
||||||
|
const response = await fetch(url, { method: 'HEAD' })
|
||||||
|
// if failure, redirect to 404 page
|
||||||
|
if (response.status !== 200) {
|
||||||
|
extension.tabs.update(tabId, { url: '404.html' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// otherwise redirect to the correct page
|
||||||
|
extension.tabs.update(tabId, { url })
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(err)
|
||||||
|
// if HEAD fetch failed, redirect so user can see relevant error page
|
||||||
|
extension.tabs.update(tabId, { url })
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(err)
|
||||||
|
extension.tabs.update(tabId, { url: `error.html?name=${name}` })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,46 +0,0 @@
|
|||||||
const extension = require('extensionizer')
|
|
||||||
const resolver = require('./resolver.js')
|
|
||||||
|
|
||||||
module.exports = function (provider) {
|
|
||||||
function ipfsContent (details) {
|
|
||||||
const name = details.url.substring(7, details.url.length - 1)
|
|
||||||
let clearTime = null
|
|
||||||
if (/^.+\.eth$/.test(name) === false) return
|
|
||||||
|
|
||||||
extension.tabs.query({active: true}, tab => {
|
|
||||||
extension.tabs.update(tab.id, { url: 'loading.html' })
|
|
||||||
|
|
||||||
clearTime = setTimeout(() => {
|
|
||||||
return extension.tabs.update(tab.id, { url: '404.html' })
|
|
||||||
}, 60000)
|
|
||||||
|
|
||||||
resolver.resolve(name, provider).then(ipfsHash => {
|
|
||||||
clearTimeout(clearTime)
|
|
||||||
let url = 'https://ipfs.infura.io/ipfs/' + ipfsHash
|
|
||||||
return fetch(url, { method: 'HEAD' }).then(response => response.status).then(statusCode => {
|
|
||||||
if (statusCode !== 200) return extension.tabs.update(tab.id, { url: '404.html' })
|
|
||||||
extension.tabs.update(tab.id, { url: url })
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
url = 'https://ipfs.infura.io/ipfs/' + ipfsHash
|
|
||||||
extension.tabs.update(tab.id, {url: url})
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
clearTimeout(clearTime)
|
|
||||||
const url = err === 'unsupport' ? 'unsupport' : 'error'
|
|
||||||
extension.tabs.update(tab.id, {url: `${url}.html?name=${name}`})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return { cancel: true }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension.webRequest.onErrorOccurred.addListener(ipfsContent, {urls: ['*://*.eth/'], types: ['main_frame']})
|
|
||||||
|
|
||||||
return {
|
|
||||||
remove () {
|
|
||||||
extension.webRequest.onErrorOccurred.removeListener(ipfsContent)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,10 +7,10 @@ module.exports = reportFailedTxToSentry
|
|||||||
// for sending to sentry
|
// for sending to sentry
|
||||||
//
|
//
|
||||||
|
|
||||||
function reportFailedTxToSentry ({ raven, txMeta }) {
|
function reportFailedTxToSentry ({ sentry, txMeta }) {
|
||||||
const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message)
|
const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message)
|
||||||
raven.captureMessage(errorMessage, {
|
sentry.captureMessage(errorMessage, {
|
||||||
// "extra" key is required by Sentry
|
// "extra" key is required by Sentry
|
||||||
extra: txMeta,
|
extra: { txMeta },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
const namehash = require('eth-ens-namehash')
|
|
||||||
const multihash = require('multihashes')
|
|
||||||
const HttpProvider = require('ethjs-provider-http')
|
|
||||||
const Eth = require('ethjs-query')
|
|
||||||
const EthContract = require('ethjs-contract')
|
|
||||||
const registrarAbi = require('./contracts/registrar')
|
|
||||||
const resolverAbi = require('./contracts/resolver')
|
|
||||||
|
|
||||||
function ens (name, provider) {
|
|
||||||
const eth = new Eth(new HttpProvider(getProvider(provider.type)))
|
|
||||||
const hash = namehash.hash(name)
|
|
||||||
const contract = new EthContract(eth)
|
|
||||||
const Registrar = contract(registrarAbi).at(getRegistrar(provider.type))
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (provider.type === 'mainnet' || provider.type === 'ropsten') {
|
|
||||||
Registrar.resolver(hash).then((address) => {
|
|
||||||
if (address === '0x0000000000000000000000000000000000000000') {
|
|
||||||
reject(null)
|
|
||||||
} else {
|
|
||||||
const Resolver = contract(resolverAbi).at(address['0'])
|
|
||||||
return Resolver.content(hash)
|
|
||||||
}
|
|
||||||
}).then((contentHash) => {
|
|
||||||
if (contentHash['0'] === '0x0000000000000000000000000000000000000000000000000000000000000000') reject(null)
|
|
||||||
if (contentHash.ret !== '0x') {
|
|
||||||
const hex = contentHash['0'].substring(2)
|
|
||||||
const buf = multihash.fromHexString(hex)
|
|
||||||
resolve(multihash.toB58String(multihash.encode(buf, 'sha2-256')))
|
|
||||||
} else {
|
|
||||||
reject(null)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return reject('unsupport')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getProvider (type) {
|
|
||||||
switch (type) {
|
|
||||||
case 'mainnet':
|
|
||||||
return 'https://mainnet.infura.io/'
|
|
||||||
case 'ropsten':
|
|
||||||
return 'https://ropsten.infura.io/'
|
|
||||||
default:
|
|
||||||
return 'http://localhost:8545/'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRegistrar (type) {
|
|
||||||
switch (type) {
|
|
||||||
case 'mainnet':
|
|
||||||
return '0x314159265dd8dbb310642f98f50c066173c1259b'
|
|
||||||
case 'ropsten':
|
|
||||||
return '0x112234455c3a32fd11230c42e7bccd4a84e02010'
|
|
||||||
default:
|
|
||||||
return '0x0000000000000000000000000000000000000000'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.resolve = function (name, provider) {
|
|
||||||
const path = name.split('.')
|
|
||||||
const topLevelDomain = path[path.length - 1]
|
|
||||||
if (topLevelDomain === 'eth' || topLevelDomain === 'test') {
|
|
||||||
return ens(name, provider)
|
|
||||||
} else {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
reject(null)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ module.exports = setupFetchDebugging
|
|||||||
|
|
||||||
//
|
//
|
||||||
// This is a utility to help resolve cases where `window.fetch` throws a
|
// This is a utility to help resolve cases where `window.fetch` throws a
|
||||||
// `TypeError: Failed to Fetch` without any stack or context for the request
|
// `TypeError: Failed to Fetch` without any stack or context for the request
|
||||||
// https://github.com/getsentry/sentry-javascript/pull/1293
|
// https://github.com/getsentry/sentry-javascript/pull/1293
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -17,9 +17,11 @@ function setupFetchDebugging() {
|
|||||||
try {
|
try {
|
||||||
return await originalFetch.call(window, ...args)
|
return await originalFetch.call(window, ...args)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('FetchDebugger - fetch encountered an Error', err)
|
if (!err.stack) {
|
||||||
console.warn('FetchDebugger - overriding stack to point of original call')
|
console.warn('FetchDebugger - fetch encountered an Error without a stack', err)
|
||||||
err.stack = initialStack
|
console.warn('FetchDebugger - overriding stack to point of original call')
|
||||||
|
err.stack = initialStack
|
||||||
|
}
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,58 +1,55 @@
|
|||||||
const Raven = require('raven-js')
|
const Sentry = require('@sentry/browser')
|
||||||
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
|
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
|
||||||
const extractEthjsErrorMessage = require('./extractEthjsErrorMessage')
|
const extractEthjsErrorMessage = require('./extractEthjsErrorMessage')
|
||||||
const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505'
|
const SENTRY_DSN_PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505'
|
||||||
const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
|
const SENTRY_DSN_DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
|
||||||
|
|
||||||
module.exports = setupRaven
|
module.exports = setupSentry
|
||||||
|
|
||||||
// Setup raven / sentry remote error reporting
|
// Setup sentry remote error reporting
|
||||||
function setupRaven (opts) {
|
function setupSentry (opts) {
|
||||||
const { release } = opts
|
const { release, getState } = opts
|
||||||
let ravenTarget
|
let sentryTarget
|
||||||
// detect brave
|
// detect brave
|
||||||
const isBrave = Boolean(window.chrome.ipcRenderer)
|
const isBrave = Boolean(window.chrome.ipcRenderer)
|
||||||
|
|
||||||
if (METAMASK_DEBUG) {
|
if (METAMASK_DEBUG) {
|
||||||
console.log('Setting up Sentry Remote Error Reporting: DEV')
|
console.log('Setting up Sentry Remote Error Reporting: SENTRY_DSN_DEV')
|
||||||
ravenTarget = DEV
|
sentryTarget = SENTRY_DSN_DEV
|
||||||
} else {
|
} else {
|
||||||
console.log('Setting up Sentry Remote Error Reporting: PROD')
|
console.log('Setting up Sentry Remote Error Reporting: SENTRY_DSN_PROD')
|
||||||
ravenTarget = PROD
|
sentryTarget = SENTRY_DSN_PROD
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = Raven.config(ravenTarget, {
|
Sentry.init({
|
||||||
|
dsn: sentryTarget,
|
||||||
|
debug: METAMASK_DEBUG,
|
||||||
release,
|
release,
|
||||||
transport: function (opts) {
|
beforeSend: (report) => rewriteReport(report),
|
||||||
opts.data.extra.isBrave = isBrave
|
})
|
||||||
const report = opts.data
|
|
||||||
|
|
||||||
try {
|
Sentry.configureScope(scope => {
|
||||||
// handle error-like non-error exceptions
|
scope.setExtra('isBrave', isBrave)
|
||||||
rewriteErrorLikeExceptions(report)
|
})
|
||||||
// simplify certain complex error messages (e.g. Ethjs)
|
|
||||||
simplifyErrorMessages(report)
|
function rewriteReport(report) {
|
||||||
// modify report urls
|
try {
|
||||||
rewriteReportUrls(report)
|
// simplify certain complex error messages (e.g. Ethjs)
|
||||||
} catch (err) {
|
simplifyErrorMessages(report)
|
||||||
console.warn(err)
|
// modify report urls
|
||||||
|
rewriteReportUrls(report)
|
||||||
|
// append app state
|
||||||
|
if (getState) {
|
||||||
|
const appState = getState()
|
||||||
|
report.extra.appState = appState
|
||||||
}
|
}
|
||||||
// make request normally
|
} catch (err) {
|
||||||
client._makeRequest(opts)
|
console.warn(err)
|
||||||
},
|
}
|
||||||
})
|
return report
|
||||||
client.install()
|
}
|
||||||
|
|
||||||
return Raven
|
return Sentry
|
||||||
}
|
|
||||||
|
|
||||||
function rewriteErrorLikeExceptions (report) {
|
|
||||||
// handle errors that lost their error-ness in serialization (e.g. dnode)
|
|
||||||
rewriteErrorMessages(report, (errorMessage) => {
|
|
||||||
if (!errorMessage.includes('Non-Error exception captured with keys:')) return errorMessage
|
|
||||||
if (!(report.extra && report.extra.__serialized__ && report.extra.__serialized__.message)) return errorMessage
|
|
||||||
return `Non-Error Exception: ${report.extra.__serialized__.message}`
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function simplifyErrorMessages (report) {
|
function simplifyErrorMessages (report) {
|
@ -138,12 +138,12 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
this.accountTracker.stop()
|
this.accountTracker.stop()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// ensure accountTracker updates balances after network change
|
// ensure accountTracker updates balances after network change
|
||||||
this.networkController.on('networkDidChange', () => {
|
this.networkController.on('networkDidChange', () => {
|
||||||
this.accountTracker._updateAccounts()
|
this.accountTracker._updateAccounts()
|
||||||
})
|
})
|
||||||
|
|
||||||
// key mgmt
|
// key mgmt
|
||||||
const additionalKeyrings = [TrezorKeyring, LedgerBridgeKeyring]
|
const additionalKeyrings = [TrezorKeyring, LedgerBridgeKeyring]
|
||||||
this.keyringController = new KeyringController({
|
this.keyringController = new KeyringController({
|
||||||
@ -197,6 +197,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
})
|
})
|
||||||
this.networkController.on('networkDidChange', () => {
|
this.networkController.on('networkDidChange', () => {
|
||||||
this.balancesController.updateAllBalances()
|
this.balancesController.updateAllBalances()
|
||||||
|
var currentCurrency = this.currencyController.getCurrentCurrency()
|
||||||
|
this.setCurrentCurrency(currentCurrency, function() {})
|
||||||
})
|
})
|
||||||
this.balancesController.updateAllBalances()
|
this.balancesController.updateAllBalances()
|
||||||
|
|
||||||
@ -275,6 +277,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
processTransaction: this.newUnapprovedTransaction.bind(this),
|
processTransaction: this.newUnapprovedTransaction.bind(this),
|
||||||
// msg signing
|
// msg signing
|
||||||
processEthSignMessage: this.newUnsignedMessage.bind(this),
|
processEthSignMessage: this.newUnsignedMessage.bind(this),
|
||||||
|
processTypedMessage: this.newUnsignedTypedMessage.bind(this),
|
||||||
|
processTypedMessageV3: this.newUnsignedTypedMessage.bind(this),
|
||||||
processPersonalMessage: this.newUnsignedPersonalMessage.bind(this),
|
processPersonalMessage: this.newUnsignedPersonalMessage.bind(this),
|
||||||
getPendingNonce: this.getPendingNonce.bind(this),
|
getPendingNonce: this.getPendingNonce.bind(this),
|
||||||
}
|
}
|
||||||
@ -978,8 +982,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
* @param {Object} msgParams - The params passed to eth_signTypedData.
|
* @param {Object} msgParams - The params passed to eth_signTypedData.
|
||||||
* @param {Function} cb - The callback function, called with the signature.
|
* @param {Function} cb - The callback function, called with the signature.
|
||||||
*/
|
*/
|
||||||
newUnsignedTypedMessage (msgParams, req) {
|
newUnsignedTypedMessage (msgParams, req, version) {
|
||||||
const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req)
|
const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req, version)
|
||||||
this.sendUpdate()
|
this.sendUpdate()
|
||||||
this.opts.showUnconfirmedMessage()
|
this.opts.showUnconfirmedMessage()
|
||||||
return promise
|
return promise
|
||||||
@ -1273,10 +1277,6 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
engine.push(subscriptionManager.middleware)
|
engine.push(subscriptionManager.middleware)
|
||||||
// watch asset
|
// watch asset
|
||||||
engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController))
|
engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController))
|
||||||
// sign typed data middleware
|
|
||||||
engine.push(this.createTypedDataMiddleware('eth_signTypedData', 'V1').bind(this))
|
|
||||||
engine.push(this.createTypedDataMiddleware('eth_signTypedData_v1', 'V1').bind(this))
|
|
||||||
engine.push(this.createTypedDataMiddleware('eth_signTypedData_v3', 'V3', true).bind(this))
|
|
||||||
// forward to metamask primary provider
|
// forward to metamask primary provider
|
||||||
engine.push(createProviderMiddleware({ provider }))
|
engine.push(createProviderMiddleware({ provider }))
|
||||||
|
|
||||||
@ -1412,10 +1412,13 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
* @param {Function} cb - A callback function returning currency info.
|
* @param {Function} cb - A callback function returning currency info.
|
||||||
*/
|
*/
|
||||||
setCurrentCurrency (currencyCode, cb) {
|
setCurrentCurrency (currencyCode, cb) {
|
||||||
|
const { ticker } = this.networkController.getNetworkConfig()
|
||||||
try {
|
try {
|
||||||
|
this.currencyController.setNativeCurrency(ticker)
|
||||||
this.currencyController.setCurrentCurrency(currencyCode)
|
this.currencyController.setCurrentCurrency(currencyCode)
|
||||||
this.currencyController.updateConversionRate()
|
this.currencyController.updateConversionRate()
|
||||||
const data = {
|
const data = {
|
||||||
|
nativeCurrency: ticker || 'ETH',
|
||||||
conversionRate: this.currencyController.getConversionRate(),
|
conversionRate: this.currencyController.getConversionRate(),
|
||||||
currentCurrency: this.currencyController.getCurrentCurrency(),
|
currentCurrency: this.currencyController.getCurrentCurrency(),
|
||||||
conversionDate: this.currencyController.getConversionDate(),
|
conversionDate: this.currencyController.getConversionDate(),
|
||||||
@ -1454,11 +1457,14 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* A method for selecting a custom URL for an ethereum RPC provider.
|
* A method for selecting a custom URL for an ethereum RPC provider.
|
||||||
* @param {string} rpcTarget - A URL for a valid Ethereum RPC API.
|
* @param {string} rpcTarget - A URL for a valid Ethereum RPC API.
|
||||||
|
* @param {number} chainId - The chainId of the selected network.
|
||||||
|
* @param {string} ticker - The ticker symbol of the selected network.
|
||||||
|
* @param {string} nickname - Optional nickname of the selected network.
|
||||||
* @returns {Promise<String>} - The RPC Target URL confirmed.
|
* @returns {Promise<String>} - The RPC Target URL confirmed.
|
||||||
*/
|
*/
|
||||||
async setCustomRpc (rpcTarget) {
|
async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '') {
|
||||||
this.networkController.setRpcTarget(rpcTarget)
|
this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname)
|
||||||
await this.preferencesController.updateFrequentRpcList(rpcTarget)
|
await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname)
|
||||||
return rpcTarget
|
return rpcTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1467,7 +1473,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
* @param {string} rpcTarget - A RPC URL to delete.
|
* @param {string} rpcTarget - A RPC URL to delete.
|
||||||
*/
|
*/
|
||||||
async delCustomRpc (rpcTarget) {
|
async delCustomRpc (rpcTarget) {
|
||||||
await this.preferencesController.updateFrequentRpcList(rpcTarget, true)
|
await this.preferencesController.removeFromFrequentRpcList(rpcTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1542,27 +1548,6 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
* @param {Function} - next
|
* @param {Function} - next
|
||||||
* @param {Function} - end
|
* @param {Function} - end
|
||||||
*/
|
*/
|
||||||
createTypedDataMiddleware (methodName, version, reverse) {
|
|
||||||
return async (req, res, next, end) => {
|
|
||||||
const { method, params } = req
|
|
||||||
if (method === methodName) {
|
|
||||||
const promise = this.typedMessageManager.addUnapprovedMessageAsync({
|
|
||||||
data: reverse ? params[1] : params[0],
|
|
||||||
from: reverse ? params[0] : params[1],
|
|
||||||
}, req, version)
|
|
||||||
this.sendUpdate()
|
|
||||||
this.opts.showUnconfirmedMessage()
|
|
||||||
try {
|
|
||||||
res.result = await promise
|
|
||||||
end()
|
|
||||||
} catch (error) {
|
|
||||||
end(error)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a domain to the {@link BlacklistController} whitelist
|
* Adds a domain to the {@link BlacklistController} whitelist
|
||||||
|
@ -9,7 +9,7 @@ const extension = require('extensionizer')
|
|||||||
const ExtensionPlatform = require('./platforms/extension')
|
const ExtensionPlatform = require('./platforms/extension')
|
||||||
const NotificationManager = require('./lib/notification-manager')
|
const NotificationManager = require('./lib/notification-manager')
|
||||||
const notificationManager = new NotificationManager()
|
const notificationManager = new NotificationManager()
|
||||||
const setupRaven = require('./lib/setupRaven')
|
const setupSentry = require('./lib/setupSentry')
|
||||||
const log = require('loglevel')
|
const log = require('loglevel')
|
||||||
|
|
||||||
start().catch(log.error)
|
start().catch(log.error)
|
||||||
@ -21,7 +21,17 @@ async function start () {
|
|||||||
|
|
||||||
// setup sentry error reporting
|
// setup sentry error reporting
|
||||||
const release = global.platform.getVersion()
|
const release = global.platform.getVersion()
|
||||||
setupRaven({ release })
|
setupSentry({ release, getState })
|
||||||
|
// provide app state to append to error logs
|
||||||
|
function getState() {
|
||||||
|
// get app state
|
||||||
|
const state = window.getCleanAppState()
|
||||||
|
// remove unnecessary data
|
||||||
|
delete state.localeMessages
|
||||||
|
delete state.metamask.recentBlocks
|
||||||
|
// return state to be added to request
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
// inject css
|
// inject css
|
||||||
// const css = MetaMaskUiCss()
|
// const css = MetaMaskUiCss()
|
||||||
|
@ -109,7 +109,7 @@
|
|||||||
},
|
},
|
||||||
"currentLocale": "en",
|
"currentLocale": "en",
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useETHAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"appState": {
|
"appState": {
|
||||||
|
@ -152,7 +152,7 @@
|
|||||||
},
|
},
|
||||||
"currentLocale": "en",
|
"currentLocale": "en",
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useETHAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"appState": {
|
"appState": {
|
||||||
|
@ -110,7 +110,7 @@
|
|||||||
},
|
},
|
||||||
"currentLocale": "en",
|
"currentLocale": "en",
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useETHAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"appState": {
|
"appState": {
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
"tokens": [],
|
"tokens": [],
|
||||||
"currentLocale": "en",
|
"currentLocale": "en",
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useETHAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"appState": {
|
"appState": {
|
||||||
|
@ -111,7 +111,7 @@
|
|||||||
},
|
},
|
||||||
"currentLocale": "en",
|
"currentLocale": "en",
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useETHAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"appState": {
|
"appState": {
|
||||||
|
@ -104,7 +104,7 @@
|
|||||||
"send": {},
|
"send": {},
|
||||||
"currentLocale": "en",
|
"currentLocale": "en",
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useETHAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"appState": {
|
"appState": {
|
||||||
|
@ -462,7 +462,9 @@ function generateBundler (opts, performBundle) {
|
|||||||
bundler.transform(envify({
|
bundler.transform(envify({
|
||||||
METAMASK_DEBUG: opts.devMode,
|
METAMASK_DEBUG: opts.devMode,
|
||||||
NODE_ENV: opts.devMode ? 'development' : 'production',
|
NODE_ENV: opts.devMode ? 'development' : 'production',
|
||||||
}))
|
}), {
|
||||||
|
global: true,
|
||||||
|
})
|
||||||
|
|
||||||
if (opts.watch) {
|
if (opts.watch) {
|
||||||
bundler = watchify(bundler)
|
bundler = watchify(bundler)
|
||||||
|
@ -73,7 +73,7 @@ function mapStateToProps (state) {
|
|||||||
forgottenPassword: state.appState.forgottenPassword,
|
forgottenPassword: state.appState.forgottenPassword,
|
||||||
nextUnreadNotice: state.metamask.nextUnreadNotice,
|
nextUnreadNotice: state.metamask.nextUnreadNotice,
|
||||||
lostAccounts: state.metamask.lostAccounts,
|
lostAccounts: state.metamask.lostAccounts,
|
||||||
frequentRpcList: state.metamask.frequentRpcList || [],
|
frequentRpcListDetail: state.metamask.frequentRpcListDetail || [],
|
||||||
featureFlags,
|
featureFlags,
|
||||||
suggestedTokens: state.metamask.suggestedTokens,
|
suggestedTokens: state.metamask.suggestedTokens,
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ module.exports = class AppBar extends Component {
|
|||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
frequentRpcList: PropTypes.array.isRequired,
|
frequentRpcListDetail: PropTypes.array.isRequired,
|
||||||
isMascara: PropTypes.bool.isRequired,
|
isMascara: PropTypes.bool.isRequired,
|
||||||
isOnboarding: PropTypes.bool.isRequired,
|
isOnboarding: PropTypes.bool.isRequired,
|
||||||
identities: PropTypes.any.isRequired,
|
identities: PropTypes.any.isRequired,
|
||||||
@ -196,7 +196,7 @@ module.exports = class AppBar extends Component {
|
|||||||
renderNetworkDropdown () {
|
renderNetworkDropdown () {
|
||||||
const {
|
const {
|
||||||
dispatch,
|
dispatch,
|
||||||
frequentRpcList: rpcList,
|
frequentRpcListDetail: rpcList,
|
||||||
provider,
|
provider,
|
||||||
} = this.props
|
} = this.props
|
||||||
const {
|
const {
|
||||||
@ -321,8 +321,8 @@ module.exports = class AppBar extends Component {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCustomOption ({ rpcTarget, type }) {
|
renderCustomOption ({ rpcTarget, type, ticker }) {
|
||||||
const {dispatch} = this.props
|
const {dispatch, network} = this.props
|
||||||
|
|
||||||
if (type !== 'rpc') {
|
if (type !== 'rpc') {
|
||||||
return null
|
return null
|
||||||
@ -340,7 +340,7 @@ module.exports = class AppBar extends Component {
|
|||||||
default:
|
default:
|
||||||
return h(DropdownMenuItem, {
|
return h(DropdownMenuItem, {
|
||||||
key: rpcTarget,
|
key: rpcTarget,
|
||||||
onClick: () => dispatch(actions.setRpcTarget(rpcTarget)),
|
onClick: () => dispatch(actions.setRpcTarget(rpcTarget, network, ticker)),
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
|
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
|
||||||
}, [
|
}, [
|
||||||
h('i.fa.fa-question-circle.fa-lg.menu-icon'),
|
h('i.fa.fa-question-circle.fa-lg.menu-icon'),
|
||||||
@ -354,7 +354,8 @@ module.exports = class AppBar extends Component {
|
|||||||
const {dispatch} = this.props
|
const {dispatch} = this.props
|
||||||
const reversedRpcList = rpcList.slice().reverse()
|
const reversedRpcList = rpcList.slice().reverse()
|
||||||
|
|
||||||
return reversedRpcList.map((rpc) => {
|
return reversedRpcList.map((entry) => {
|
||||||
|
const rpc = entry.rpcUrl
|
||||||
const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget
|
const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget
|
||||||
|
|
||||||
if ((rpc === LOCALHOST_RPC_URL) || currentRpcTarget) {
|
if ((rpc === LOCALHOST_RPC_URL) || currentRpcTarget) {
|
||||||
@ -363,7 +364,7 @@ module.exports = class AppBar extends Component {
|
|||||||
return h(DropdownMenuItem, {
|
return h(DropdownMenuItem, {
|
||||||
key: `common${rpc}`,
|
key: `common${rpc}`,
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
|
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
|
||||||
onClick: () => dispatch(actions.setRpcTarget(rpc)),
|
onClick: () => dispatch(actions.setRpcTarget(rpc, entry.chainId, entry.ticker)),
|
||||||
}, [
|
}, [
|
||||||
h('i.fa.fa-question-circle.fa-lg.menu-icon'),
|
h('i.fa.fa-question-circle.fa-lg.menu-icon'),
|
||||||
rpc,
|
rpc,
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
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
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const formatBalance = require('../util').formatBalance
|
const formatBalance = require('../util').formatBalance
|
||||||
const generateBalanceObject = require('../util').generateBalanceObject
|
const generateBalanceObject = require('../util').generateBalanceObject
|
||||||
const Tooltip = require('./tooltip.js')
|
const Tooltip = require('./tooltip.js')
|
||||||
const FiatValue = require('./fiat-value.js')
|
const FiatValue = require('./fiat-value.js')
|
||||||
|
|
||||||
module.exports = EthBalanceComponent
|
module.exports = connect(mapStateToProps)(EthBalanceComponent)
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
return {
|
||||||
|
ticker: state.metamask.ticker,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inherits(EthBalanceComponent, Component)
|
inherits(EthBalanceComponent, Component)
|
||||||
function EthBalanceComponent () {
|
function EthBalanceComponent () {
|
||||||
@ -16,9 +22,10 @@ function EthBalanceComponent () {
|
|||||||
EthBalanceComponent.prototype.render = function () {
|
EthBalanceComponent.prototype.render = function () {
|
||||||
var props = this.props
|
var props = this.props
|
||||||
let { value } = props
|
let { value } = props
|
||||||
|
const { ticker } = props
|
||||||
var style = props.style
|
var style = props.style
|
||||||
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
|
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
|
||||||
value = value ? formatBalance(value, 6, needsParse) : '...'
|
value = value ? formatBalance(value, 6, needsParse, ticker) : '...'
|
||||||
var width = props.width
|
var width = props.width
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
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
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const formatBalance = require('../util').formatBalance
|
const formatBalance = require('../util').formatBalance
|
||||||
const generateBalanceObject = require('../util').generateBalanceObject
|
const generateBalanceObject = require('../util').generateBalanceObject
|
||||||
const Tooltip = require('./tooltip.js')
|
const Tooltip = require('./tooltip.js')
|
||||||
const FiatValue = require('./fiat-value.js')
|
const FiatValue = require('./fiat-value.js')
|
||||||
|
|
||||||
module.exports = EthBalanceComponent
|
module.exports = connect(mapStateToProps)(EthBalanceComponent)
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
return {
|
||||||
|
ticker: state.metamask.ticker,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inherits(EthBalanceComponent, Component)
|
inherits(EthBalanceComponent, Component)
|
||||||
function EthBalanceComponent () {
|
function EthBalanceComponent () {
|
||||||
@ -16,9 +22,9 @@ function EthBalanceComponent () {
|
|||||||
EthBalanceComponent.prototype.render = function () {
|
EthBalanceComponent.prototype.render = function () {
|
||||||
var props = this.props
|
var props = this.props
|
||||||
let { value } = props
|
let { value } = props
|
||||||
const { style, width } = props
|
const { ticker, style, width } = props
|
||||||
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
|
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
|
||||||
value = value ? formatBalance(value, 6, needsParse) : '...'
|
value = value ? formatBalance(value, 6, needsParse, ticker) : '...'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const actions = require('../../../ui/app/actions')
|
const actions = require('../../../ui/app/actions')
|
||||||
@ -19,7 +20,9 @@ const BNInput = require('./bn-as-decimal-input')
|
|||||||
const MIN_GAS_PRICE_BN = new BN('0')
|
const MIN_GAS_PRICE_BN = new BN('0')
|
||||||
const MIN_GAS_LIMIT_BN = new BN('21000')
|
const MIN_GAS_LIMIT_BN = new BN('21000')
|
||||||
|
|
||||||
module.exports = PendingTx
|
module.exports = connect()(PendingTx)
|
||||||
|
|
||||||
|
|
||||||
inherits(PendingTx, Component)
|
inherits(PendingTx, Component)
|
||||||
function PendingTx () {
|
function PendingTx () {
|
||||||
Component.call(this)
|
Component.call(this)
|
||||||
@ -445,7 +448,8 @@ PendingTx.prototype.onSubmit = function (event) {
|
|||||||
const txMeta = this.gatherTxMeta()
|
const txMeta = this.gatherTxMeta()
|
||||||
const valid = this.checkValidity()
|
const valid = this.checkValidity()
|
||||||
this.setState({ valid, submitting: true })
|
this.setState({ valid, submitting: true })
|
||||||
if (valid && this.verifyGasParams()) {
|
const validGasParams = this.verifyGasParams()
|
||||||
|
if (valid && validGasParams) {
|
||||||
this.props.sendTransaction(txMeta, event)
|
this.props.sendTransaction(txMeta, event)
|
||||||
} else {
|
} else {
|
||||||
this.props.dispatch(actions.displayWarning('Invalid Gas Parameters'))
|
this.props.dispatch(actions.displayWarning('Invalid Gas Parameters'))
|
||||||
@ -488,8 +492,12 @@ PendingTx.prototype.verifyGasParams = function () {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingTx.prototype._notZeroOrEmptyString = function (obj) {
|
PendingTx.prototype._notZeroOrEmptyString = function (value) {
|
||||||
return obj !== '' && obj !== '0x0'
|
// allow undefined values
|
||||||
|
if (value === undefined) return true
|
||||||
|
// Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
|
||||||
|
const valueIsEmpty = !value || value === '0x' || value === '0x0'
|
||||||
|
return !valueIsEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingTx.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) {
|
PendingTx.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) {
|
||||||
|
@ -68,7 +68,7 @@ ConfigScreen.prototype.render = function () {
|
|||||||
|
|
||||||
currentProviderDisplay(metamaskState),
|
currentProviderDisplay(metamaskState),
|
||||||
|
|
||||||
h('div', { style: {display: 'flex'} }, [
|
h('div', { style: {display: 'block'} }, [
|
||||||
h('input#new_rpc', {
|
h('input#new_rpc', {
|
||||||
placeholder: 'New RPC URL',
|
placeholder: 'New RPC URL',
|
||||||
style: {
|
style: {
|
||||||
@ -81,7 +81,70 @@ ConfigScreen.prototype.render = function () {
|
|||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
var element = event.target
|
var element = event.target
|
||||||
var newRpc = element.value
|
var newRpc = element.value
|
||||||
rpcValidation(newRpc, state)
|
var chainid = document.querySelector('input#chainid')
|
||||||
|
var ticker = document.querySelector('input#ticker')
|
||||||
|
var nickname = document.querySelector('input#nickname')
|
||||||
|
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h('br'),
|
||||||
|
h('input#chainid', {
|
||||||
|
placeholder: 'ChainId (optional)',
|
||||||
|
style: {
|
||||||
|
width: 'inherit',
|
||||||
|
flex: '1 0 auto',
|
||||||
|
height: '30px',
|
||||||
|
margin: '8px',
|
||||||
|
},
|
||||||
|
onKeyPress (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
var element = document.querySelector('input#new_rpc')
|
||||||
|
var newRpc = element.value
|
||||||
|
var chainid = document.querySelector('input#chainid')
|
||||||
|
var ticker = document.querySelector('input#ticker')
|
||||||
|
var nickname = document.querySelector('input#nickname')
|
||||||
|
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h('br'),
|
||||||
|
h('input#ticker', {
|
||||||
|
placeholder: 'Symbol (optional)',
|
||||||
|
style: {
|
||||||
|
width: 'inherit',
|
||||||
|
flex: '1 0 auto',
|
||||||
|
height: '30px',
|
||||||
|
margin: '8px',
|
||||||
|
},
|
||||||
|
onKeyPress (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
var element = document.querySelector('input#new_rpc')
|
||||||
|
var newRpc = element.value
|
||||||
|
var chainid = document.querySelector('input#chainid')
|
||||||
|
var ticker = document.querySelector('input#ticker')
|
||||||
|
var nickname = document.querySelector('input#nickname')
|
||||||
|
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h('br'),
|
||||||
|
h('input#nickname', {
|
||||||
|
placeholder: 'Nickname (optional)',
|
||||||
|
style: {
|
||||||
|
width: 'inherit',
|
||||||
|
flex: '1 0 auto',
|
||||||
|
height: '30px',
|
||||||
|
margin: '8px',
|
||||||
|
},
|
||||||
|
onKeyPress (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
var element = document.querySelector('input#new_rpc')
|
||||||
|
var newRpc = element.value
|
||||||
|
var chainid = document.querySelector('input#chainid')
|
||||||
|
var ticker = document.querySelector('input#ticker')
|
||||||
|
var nickname = document.querySelector('input#nickname')
|
||||||
|
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -93,7 +156,10 @@ ConfigScreen.prototype.render = function () {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
var element = document.querySelector('input#new_rpc')
|
var element = document.querySelector('input#new_rpc')
|
||||||
var newRpc = element.value
|
var newRpc = element.value
|
||||||
rpcValidation(newRpc, state)
|
var chainid = document.querySelector('input#chainid')
|
||||||
|
var ticker = document.querySelector('input#ticker')
|
||||||
|
var nickname = document.querySelector('input#nickname')
|
||||||
|
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state)
|
||||||
},
|
},
|
||||||
}, 'Save'),
|
}, 'Save'),
|
||||||
]),
|
]),
|
||||||
@ -189,9 +255,9 @@ ConfigScreen.prototype.render = function () {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function rpcValidation (newRpc, state) {
|
function rpcValidation (newRpc, chainid, ticker = 'ETH', nickname = '', state) {
|
||||||
if (validUrl.isWebUri(newRpc)) {
|
if (validUrl.isWebUri(newRpc)) {
|
||||||
state.dispatch(actions.setRpcTarget(newRpc))
|
state.dispatch(actions.setRpcTarget(newRpc, chainid, ticker, nickname))
|
||||||
} else {
|
} else {
|
||||||
var appendedRpc = `http://${newRpc}`
|
var appendedRpc = `http://${newRpc}`
|
||||||
if (validUrl.isWebUri(appendedRpc)) {
|
if (validUrl.isWebUri(appendedRpc)) {
|
||||||
|
@ -102,7 +102,7 @@ function parseBalance (balance) {
|
|||||||
|
|
||||||
// Takes wei hex, returns an object with three properties.
|
// Takes wei hex, returns an object with three properties.
|
||||||
// Its "formatted" property is what we generally use to render values.
|
// Its "formatted" property is what we generally use to render values.
|
||||||
function formatBalance (balance, decimalsToKeep, needsParse = true) {
|
function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ETH') {
|
||||||
var parsed = needsParse ? parseBalance(balance) : balance.split('.')
|
var parsed = needsParse ? parseBalance(balance) : balance.split('.')
|
||||||
var beforeDecimal = parsed[0]
|
var beforeDecimal = parsed[0]
|
||||||
var afterDecimal = parsed[1]
|
var afterDecimal = parsed[1]
|
||||||
@ -112,14 +112,14 @@ function formatBalance (balance, decimalsToKeep, needsParse = true) {
|
|||||||
if (afterDecimal !== '0') {
|
if (afterDecimal !== '0') {
|
||||||
var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits
|
var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits
|
||||||
if (sigFigs) { afterDecimal = sigFigs[0] }
|
if (sigFigs) { afterDecimal = sigFigs[0] }
|
||||||
formatted = '0.' + afterDecimal + ' ETH'
|
formatted = '0.' + afterDecimal + ` ${ticker}`
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ' ETH'
|
formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ` ${ticker}`
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
afterDecimal += Array(decimalsToKeep).join('0')
|
afterDecimal += Array(decimalsToKeep).join('0')
|
||||||
formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ' ETH'
|
formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ` ${ticker}`
|
||||||
}
|
}
|
||||||
return formatted
|
return formatted
|
||||||
}
|
}
|
||||||
|
504
package-lock.json
generated
504
package-lock.json
generated
@ -489,6 +489,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@sentry/browser": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-XvuIc1aclz4zuP2LamDuSy62/gl1mmNxzF+Ni5L8mcghBDq0urnOdkblVQgzqGoH8mc2QfjEctGa5djWxg3Bpg==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/core": "4.2.3",
|
||||||
|
"@sentry/types": "4.2.3",
|
||||||
|
"@sentry/utils": "4.2.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@sentry/cli": {
|
"@sentry/cli": {
|
||||||
"version": "1.30.3",
|
"version": "1.30.3",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.30.3.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.30.3.tgz",
|
||||||
@ -531,6 +541,48 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@sentry/core": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-xo5rvksftnaEdnKbdokyfuqgMnuqw1DFp0lDboIFHlEBcQde/AdThEgLujJWmbVNI3Cg7g8/HvP65f7QBjKfOw==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/hub": "4.2.3",
|
||||||
|
"@sentry/minimal": "4.2.3",
|
||||||
|
"@sentry/types": "4.2.3",
|
||||||
|
"@sentry/utils": "4.2.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sentry/hub": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-7Jc/wz3vybYm1RX2wk/4zAQS8fo3uxvXYBkRfpm3OmnGgTlwDEmJwtegeGWFqufxLl85brZ19V1KAdulmO206A==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/types": "4.2.3",
|
||||||
|
"@sentry/utils": "4.2.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sentry/minimal": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-Hus7LUeJDGsYpT2RTe6bUjG7mHG9uQoyDmW6pYUMN2dhD+cP5cPoTIXO4yxokwgAeDa+GH2/UXoASWc4s2eA2w==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/hub": "4.2.3",
|
||||||
|
"@sentry/types": "4.2.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@sentry/types": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-Z7laXlLtLSEXcKzgcD2caWPMTM8sAvR86rssYM5uYb3azC5PO0aAvuhjokkdv1+Ke1Bg7lkaNZamiCSyaH/9xg=="
|
||||||
|
},
|
||||||
|
"@sentry/utils": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-D6+M1081wCwGp8adWV3KFOxrxFmVyjMJ45x6/TnYvXdgDyc+t28oil21FHeKhwjld9eMqgQ5Tf1OOvos1MNBQg==",
|
||||||
|
"requires": {
|
||||||
|
"@sentry/types": "4.2.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@sinonjs/formatio": {
|
"@sinonjs/formatio": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz",
|
||||||
@ -6131,9 +6183,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"clone": {
|
"clone": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||||
"integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs="
|
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
|
||||||
},
|
},
|
||||||
"clone-buffer": {
|
"clone-buffer": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@ -9570,9 +9622,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eth-block-tracker": {
|
"eth-block-tracker": {
|
||||||
"version": "4.0.3",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.1.0.tgz",
|
||||||
"integrity": "sha512-Uy+5hEvOT1/C6N1Lw/uQ10v03ArnNEQEkM0yhJQWwpd8Ymy3sw4jk75SE58s1spfOBBtnr8JaSAFioAFSeg6HA==",
|
"integrity": "sha512-991xTy6CzYYbizkHmgRFFI9iGx1OCISve8sSLuOlt7/yD7VFH1Jd8mOmBqxaG5ywGkIXdwAR78nQ2WDReETzBg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"eth-json-rpc-infura": "^3.1.2",
|
"eth-json-rpc-infura": "^3.1.2",
|
||||||
"eth-query": "^2.1.0",
|
"eth-query": "^2.1.0",
|
||||||
@ -9604,7 +9656,7 @@
|
|||||||
},
|
},
|
||||||
"eth-json-rpc-middleware": {
|
"eth-json-rpc-middleware": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz",
|
"resolved": "http://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz",
|
||||||
"integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==",
|
"integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async": "^2.5.0",
|
"async": "^2.5.0",
|
||||||
@ -9643,12 +9695,12 @@
|
|||||||
},
|
},
|
||||||
"node-fetch": {
|
"node-fetch": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
|
"resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
|
||||||
"integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
|
"integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
|
||||||
},
|
},
|
||||||
"whatwg-fetch": {
|
"whatwg-fetch": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
|
"resolved": "http://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
|
||||||
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
|
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9899,29 +9951,26 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eth-json-rpc-middleware": {
|
"eth-json-rpc-middleware": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-3.1.6.tgz",
|
||||||
"integrity": "sha512-glp/mCefhsqrgVOTTuYlHYiTL+9mMPfaZsuQv4vnRg3kqNigblS1nqARaMeVW9WOM8ssh9TqIFpuUr7JDgNmKQ==",
|
"integrity": "sha512-yf17/rAM4ElKMul8oSvuK7JuYIYEFFdy2YGPo2EZbuOEv2Wq1bteMlppgqZ9NYHriXLAOWV+ojY9kWHGbcU4xA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"async": "^2.5.0",
|
|
||||||
"btoa": "^1.2.1",
|
"btoa": "^1.2.1",
|
||||||
"clone": "^2.1.1",
|
"clone": "^2.1.1",
|
||||||
"eth-query": "^2.1.2",
|
"eth-query": "^2.1.2",
|
||||||
"eth-sig-util": "^1.4.2",
|
"eth-sig-util": "^1.4.2",
|
||||||
"eth-tx-summary": "^3.1.2",
|
"eth-tx-summary": "^3.2.3",
|
||||||
"ethereumjs-block": "^1.6.0",
|
"ethereumjs-block": "^1.6.0",
|
||||||
"ethereumjs-tx": "^1.3.3",
|
"ethereumjs-tx": "^1.3.3",
|
||||||
"ethereumjs-util": "^5.1.2",
|
"ethereumjs-util": "^5.1.2",
|
||||||
"ethereumjs-vm": "^2.1.0",
|
"ethereumjs-vm": "^2.4.0",
|
||||||
"fetch-ponyfill": "^4.0.0",
|
"fetch-ponyfill": "^4.0.0",
|
||||||
"json-rpc-engine": "^3.6.3",
|
"json-rpc-engine": "^3.8.0",
|
||||||
"json-rpc-error": "^2.0.0",
|
"json-rpc-error": "^2.0.0",
|
||||||
"json-stable-stringify": "^1.0.1",
|
"json-stable-stringify": "^1.0.1",
|
||||||
"pify": "^3.0.0",
|
"pify": "^3.0.0",
|
||||||
"promise-to-callback": "^1.0.0",
|
"safe-event-emitter": "^1.0.1"
|
||||||
"safe-event-emitter": "^1.0.1",
|
|
||||||
"tape": "^4.6.3"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eth-sig-util": {
|
"eth-sig-util": {
|
||||||
@ -9930,12 +9979,12 @@
|
|||||||
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
|
"integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
|
"ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799",
|
||||||
"ethereumjs-util": "^5.1.1"
|
"ethereumjs-util": "^5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ethereumjs-abi": {
|
"ethereumjs-abi": {
|
||||||
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
|
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799",
|
||||||
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
|
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
@ -9957,6 +10006,31 @@
|
|||||||
"safe-buffer": "^5.1.1",
|
"safe-buffer": "^5.1.1",
|
||||||
"secp256k1": "^3.0.1"
|
"secp256k1": "^3.0.1"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ethereumjs-vm": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-MJ4lCWa5c6LhahhhvoDKW+YGjK00ZQn0RHHLh4L+WaH1k6Qv7/q3uTluew6sJGNCZdlO0yYMDXYW9qyxLHKlgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"async": "^2.1.2",
|
||||||
|
"async-eventemitter": "^0.2.2",
|
||||||
|
"ethereumjs-account": "^2.0.3",
|
||||||
|
"ethereumjs-block": "~1.7.0",
|
||||||
|
"ethereumjs-common": "~0.4.0",
|
||||||
|
"ethereumjs-util": "^5.2.0",
|
||||||
|
"fake-merkle-patricia-tree": "^1.0.1",
|
||||||
|
"functional-red-black-tree": "^1.0.1",
|
||||||
|
"merkle-patricia-tree": "^2.1.2",
|
||||||
|
"rustbn.js": "~0.2.0",
|
||||||
|
"safe-buffer": "^5.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rustbn.js": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -10390,7 +10464,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babelify": {
|
"babelify": {
|
||||||
"version": "7.3.0",
|
"version": "7.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz",
|
||||||
"integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=",
|
"integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"babel-core": "^6.0.14",
|
"babel-core": "^6.0.14",
|
||||||
@ -10907,6 +10981,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ethereumjs-common": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-ywYGsOeGCsMNWso5Y4GhjWI24FJv9FK7+VyVKiQgXg8ZRDPXJ7F/kJ1CnjtkjTvDF4e0yqU+FWswlqR3bmZQ9Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ethereumjs-tx": {
|
"ethereumjs-tx": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.3.tgz",
|
||||||
@ -14249,14 +14329,354 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"glob-watcher": {
|
"glob-watcher": {
|
||||||
"version": "4.0.0",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.1.tgz",
|
||||||
"integrity": "sha1-nmOo/25h6TLebMLK7OUHGm1zcyk=",
|
"integrity": "sha512-fK92r2COMC199WCyGUblrZKhjra3cyVMDiypDdqg1vsSDmexnbYivK1kNR4QItiNXLKmGlqan469ks67RtNa2g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async-done": "^1.2.0",
|
"async-done": "^1.2.0",
|
||||||
"chokidar": "^1.4.3",
|
"chokidar": "^2.0.0",
|
||||||
"just-debounce": "^1.0.0",
|
"just-debounce": "^1.0.0",
|
||||||
"object.defaults": "^1.1.0"
|
"object.defaults": "^1.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"anymatch": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
|
||||||
|
"requires": {
|
||||||
|
"micromatch": "^3.1.4",
|
||||||
|
"normalize-path": "^2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"arr-diff": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
|
||||||
|
},
|
||||||
|
"array-unique": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
|
||||||
|
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
|
||||||
|
},
|
||||||
|
"braces": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
|
||||||
|
"requires": {
|
||||||
|
"arr-flatten": "^1.1.0",
|
||||||
|
"array-unique": "^0.3.2",
|
||||||
|
"extend-shallow": "^2.0.1",
|
||||||
|
"fill-range": "^4.0.0",
|
||||||
|
"isobject": "^3.0.1",
|
||||||
|
"repeat-element": "^1.1.2",
|
||||||
|
"snapdragon": "^0.8.1",
|
||||||
|
"snapdragon-node": "^2.0.1",
|
||||||
|
"split-string": "^3.0.2",
|
||||||
|
"to-regex": "^3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"extend-shallow": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||||
|
"requires": {
|
||||||
|
"is-extendable": "^0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chokidar": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==",
|
||||||
|
"requires": {
|
||||||
|
"anymatch": "^2.0.0",
|
||||||
|
"async-each": "^1.0.0",
|
||||||
|
"braces": "^2.3.0",
|
||||||
|
"fsevents": "^1.2.2",
|
||||||
|
"glob-parent": "^3.1.0",
|
||||||
|
"inherits": "^2.0.1",
|
||||||
|
"is-binary-path": "^1.0.0",
|
||||||
|
"is-glob": "^4.0.0",
|
||||||
|
"lodash.debounce": "^4.0.8",
|
||||||
|
"normalize-path": "^2.1.1",
|
||||||
|
"path-is-absolute": "^1.0.0",
|
||||||
|
"readdirp": "^2.0.0",
|
||||||
|
"upath": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"define-property": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
|
||||||
|
"requires": {
|
||||||
|
"is-descriptor": "^1.0.2",
|
||||||
|
"isobject": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expand-brackets": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
|
||||||
|
"integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^2.3.3",
|
||||||
|
"define-property": "^0.2.5",
|
||||||
|
"extend-shallow": "^2.0.1",
|
||||||
|
"posix-character-classes": "^0.1.0",
|
||||||
|
"regex-not": "^1.0.0",
|
||||||
|
"snapdragon": "^0.8.1",
|
||||||
|
"to-regex": "^3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"define-property": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
|
||||||
|
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
|
||||||
|
"requires": {
|
||||||
|
"is-descriptor": "^0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extend-shallow": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||||
|
"requires": {
|
||||||
|
"is-extendable": "^0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is-descriptor": {
|
||||||
|
"version": "0.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
|
||||||
|
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
|
||||||
|
"requires": {
|
||||||
|
"is-accessor-descriptor": "^0.1.6",
|
||||||
|
"is-data-descriptor": "^0.1.4",
|
||||||
|
"kind-of": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"kind-of": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extend-shallow": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
|
||||||
|
"integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
|
||||||
|
"requires": {
|
||||||
|
"assign-symbols": "^1.0.0",
|
||||||
|
"is-extendable": "^1.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"is-extendable": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
|
||||||
|
"requires": {
|
||||||
|
"is-plain-object": "^2.0.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extglob": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
|
||||||
|
"requires": {
|
||||||
|
"array-unique": "^0.3.2",
|
||||||
|
"define-property": "^1.0.0",
|
||||||
|
"expand-brackets": "^2.1.4",
|
||||||
|
"extend-shallow": "^2.0.1",
|
||||||
|
"fragment-cache": "^0.2.1",
|
||||||
|
"regex-not": "^1.0.0",
|
||||||
|
"snapdragon": "^0.8.1",
|
||||||
|
"to-regex": "^3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"define-property": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
|
||||||
|
"requires": {
|
||||||
|
"is-descriptor": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extend-shallow": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||||
|
"requires": {
|
||||||
|
"is-extendable": "^0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fill-range": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
|
||||||
|
"requires": {
|
||||||
|
"extend-shallow": "^2.0.1",
|
||||||
|
"is-number": "^3.0.0",
|
||||||
|
"repeat-string": "^1.6.1",
|
||||||
|
"to-regex-range": "^2.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"extend-shallow": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||||
|
"requires": {
|
||||||
|
"is-extendable": "^0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"glob-parent": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
||||||
|
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
|
||||||
|
"requires": {
|
||||||
|
"is-glob": "^3.1.0",
|
||||||
|
"path-dirname": "^1.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"is-glob": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
|
||||||
|
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
|
||||||
|
"requires": {
|
||||||
|
"is-extglob": "^2.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is-accessor-descriptor": {
|
||||||
|
"version": "0.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
|
||||||
|
"integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
|
||||||
|
"requires": {
|
||||||
|
"kind-of": "^3.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"kind-of": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||||
|
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||||
|
"requires": {
|
||||||
|
"is-buffer": "^1.1.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is-data-descriptor": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
|
||||||
|
"integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
|
||||||
|
"requires": {
|
||||||
|
"kind-of": "^3.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"kind-of": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||||
|
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||||
|
"requires": {
|
||||||
|
"is-buffer": "^1.1.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is-extglob": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
|
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
|
||||||
|
},
|
||||||
|
"is-glob": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
|
||||||
|
"requires": {
|
||||||
|
"is-extglob": "^2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is-number": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
|
||||||
|
"requires": {
|
||||||
|
"kind-of": "^3.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"kind-of": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||||
|
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||||
|
"requires": {
|
||||||
|
"is-buffer": "^1.1.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isobject": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||||
|
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
||||||
|
},
|
||||||
|
"kind-of": {
|
||||||
|
"version": "6.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||||
|
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
|
||||||
|
},
|
||||||
|
"micromatch": {
|
||||||
|
"version": "3.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
||||||
|
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
|
||||||
|
"requires": {
|
||||||
|
"arr-diff": "^4.0.0",
|
||||||
|
"array-unique": "^0.3.2",
|
||||||
|
"braces": "^2.3.1",
|
||||||
|
"define-property": "^2.0.2",
|
||||||
|
"extend-shallow": "^3.0.2",
|
||||||
|
"extglob": "^2.0.4",
|
||||||
|
"fragment-cache": "^0.2.1",
|
||||||
|
"kind-of": "^6.0.2",
|
||||||
|
"nanomatch": "^1.2.9",
|
||||||
|
"object.pick": "^1.3.0",
|
||||||
|
"regex-not": "^1.0.0",
|
||||||
|
"snapdragon": "^0.8.1",
|
||||||
|
"to-regex": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"to-regex": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
|
||||||
|
"requires": {
|
||||||
|
"define-property": "^2.0.2",
|
||||||
|
"extend-shallow": "^3.0.2",
|
||||||
|
"regex-not": "^1.0.2",
|
||||||
|
"safe-regex": "^1.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"regex-not": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
|
||||||
|
"requires": {
|
||||||
|
"extend-shallow": "^3.0.2",
|
||||||
|
"safe-regex": "^1.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"upath": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"glob2base": {
|
"glob2base": {
|
||||||
@ -14381,10 +14801,10 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"gulp": {
|
"gulp": {
|
||||||
"version": "github:gulpjs/gulp#71c094a51c7972d26f557899ddecab0210ef3776",
|
"version": "github:gulpjs/gulp#55eb23a268dcc7340bb40808600fd4802848c06f",
|
||||||
"from": "github:gulpjs/gulp#4.0",
|
"from": "github:gulpjs/gulp#v4.0.0",
|
||||||
"requires": {
|
"requires": {
|
||||||
"glob-watcher": "^4.0.0",
|
"glob-watcher": "^5.0.0",
|
||||||
"gulp-cli": "^2.0.0",
|
"gulp-cli": "^2.0.0",
|
||||||
"undertaker": "^1.0.0",
|
"undertaker": "^1.0.0",
|
||||||
"vinyl-fs": "^3.0.0"
|
"vinyl-fs": "^3.0.0"
|
||||||
@ -21494,9 +21914,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mute-stdout": {
|
"mute-stdout": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
|
||||||
"integrity": "sha1-WzLqB+tDyd7WEwQ0z5JvRrKn/U0="
|
"integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg=="
|
||||||
},
|
},
|
||||||
"mute-stream": {
|
"mute-stream": {
|
||||||
"version": "0.0.7",
|
"version": "0.0.7",
|
||||||
@ -27090,11 +27510,6 @@
|
|||||||
"eve-raphael": "0.5.0"
|
"eve-raphael": "0.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"raven-js": {
|
|
||||||
"version": "3.24.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.24.2.tgz",
|
|
||||||
"integrity": "sha512-Dy/FHDxuo5pXywVf8Nrs5utB2juMATpkxWGqHjVbpFD3m8CaWYLvkB5SEXjWFUZ5GvUsrBVVQ+Dfcp0x6Z7SOg=="
|
|
||||||
},
|
|
||||||
"raw-body": {
|
"raw-body": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
|
||||||
@ -33471,9 +33886,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"v8flags": {
|
"v8flags": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.1.tgz",
|
||||||
"integrity": "sha512-0m69VIK2dudEf2Ub0xwLQhZkDZu85OmiOpTw+UGDt56ibviYICHziM/3aE+oVg7IjGPp0c83w3eSVqa+lYZ9UQ==",
|
"integrity": "sha512-iw/1ViSEaff8NJ3HLyEjawk/8hjJib3E7pvG4pddVXfUg1983s3VGsiClDjhK64MQVDGqc1Q8r18S4VKQZS9EQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"homedir-polyfill": "^1.0.1"
|
"homedir-polyfill": "^1.0.1"
|
||||||
}
|
}
|
||||||
@ -33700,9 +34115,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"convert-source-map": {
|
"convert-source-map": {
|
||||||
"version": "1.5.1",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
|
||||||
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU="
|
"integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
10
package.json
10
package.json
@ -82,6 +82,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "1.0.0",
|
"@material-ui/core": "1.0.0",
|
||||||
|
"@sentry/browser": "^4.1.1",
|
||||||
"@zxing/library": "^0.8.0",
|
"@zxing/library": "^0.8.0",
|
||||||
"abi-decoder": "^1.0.9",
|
"abi-decoder": "^1.0.9",
|
||||||
"asmcrypto.js": "0.22.0",
|
"asmcrypto.js": "0.22.0",
|
||||||
@ -97,7 +98,7 @@
|
|||||||
"browserify-derequire": "^0.9.4",
|
"browserify-derequire": "^0.9.4",
|
||||||
"browserify-unibabel": "^3.0.0",
|
"browserify-unibabel": "^3.0.0",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"clone": "^2.1.1",
|
"clone": "^2.1.2",
|
||||||
"copy-to-clipboard": "^3.0.8",
|
"copy-to-clipboard": "^3.0.8",
|
||||||
"css-loader": "^0.28.11",
|
"css-loader": "^0.28.11",
|
||||||
"currency-formatter": "^1.4.2",
|
"currency-formatter": "^1.4.2",
|
||||||
@ -112,7 +113,7 @@
|
|||||||
"ensnare": "^1.0.0",
|
"ensnare": "^1.0.0",
|
||||||
"eslint-plugin-react": "^7.4.0",
|
"eslint-plugin-react": "^7.4.0",
|
||||||
"eth-bin-to-ops": "^1.0.1",
|
"eth-bin-to-ops": "^1.0.1",
|
||||||
"eth-block-tracker": "^4.0.3",
|
"eth-block-tracker": "^4.1.0",
|
||||||
"eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master",
|
"eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master",
|
||||||
"eth-ens-namehash": "^2.0.8",
|
"eth-ens-namehash": "^2.0.8",
|
||||||
"eth-hd-keyring": "^1.2.2",
|
"eth-hd-keyring": "^1.2.2",
|
||||||
@ -143,7 +144,7 @@
|
|||||||
"fast-levenshtein": "^2.0.6",
|
"fast-levenshtein": "^2.0.6",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"fuse.js": "^3.2.0",
|
"fuse.js": "^3.2.0",
|
||||||
"gulp": "github:gulpjs/gulp#4.0",
|
"gulp": "github:gulpjs/gulp#v4.0.0",
|
||||||
"gulp-autoprefixer": "^5.0.0",
|
"gulp-autoprefixer": "^5.0.0",
|
||||||
"gulp-debug": "^3.2.0",
|
"gulp-debug": "^3.2.0",
|
||||||
"gulp-eslint": "^4.0.0",
|
"gulp-eslint": "^4.0.0",
|
||||||
@ -186,7 +187,6 @@
|
|||||||
"pumpify": "^1.3.4",
|
"pumpify": "^1.3.4",
|
||||||
"qrcode-npm": "0.0.3",
|
"qrcode-npm": "0.0.3",
|
||||||
"ramda": "^0.24.1",
|
"ramda": "^0.24.1",
|
||||||
"raven-js": "^3.24.2",
|
|
||||||
"react": "^15.6.2",
|
"react": "^15.6.2",
|
||||||
"react-addons-css-transition-group": "^15.6.0",
|
"react-addons-css-transition-group": "^15.6.0",
|
||||||
"react-dom": "^15.6.2",
|
"react-dom": "^15.6.2",
|
||||||
@ -261,7 +261,7 @@
|
|||||||
"eslint-plugin-json": "^1.2.0",
|
"eslint-plugin-json": "^1.2.0",
|
||||||
"eslint-plugin-mocha": "^5.0.0",
|
"eslint-plugin-mocha": "^5.0.0",
|
||||||
"eslint-plugin-react": "^7.4.0",
|
"eslint-plugin-react": "^7.4.0",
|
||||||
"eth-json-rpc-middleware": "^3.1.3",
|
"eth-json-rpc-middleware": "^3.1.6",
|
||||||
"eth-keyring-controller": "^3.3.1",
|
"eth-keyring-controller": "^3.3.1",
|
||||||
"fetch-mock": "^6.5.2",
|
"fetch-mock": "^6.5.2",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
|
@ -111,7 +111,9 @@
|
|||||||
"0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": 0.00039345803819379796,
|
"0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": 0.00039345803819379796,
|
||||||
"0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": 0.00008189274407698049
|
"0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": 0.00008189274407698049
|
||||||
},
|
},
|
||||||
|
"ticker": "ETH",
|
||||||
"currentCurrency": "usd",
|
"currentCurrency": "usd",
|
||||||
|
"nativeCurrency": "ETH",
|
||||||
"conversionRate": 556.12,
|
"conversionRate": 556.12,
|
||||||
"addressBook": [
|
"addressBook": [
|
||||||
{
|
{
|
||||||
@ -1248,4 +1250,4 @@
|
|||||||
"context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
|
"context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,7 +319,7 @@ describe('Using MetaMask with an existing account', function () {
|
|||||||
|
|
||||||
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
assert.equal(txValues.length, 1)
|
assert.equal(txValues.length, 1)
|
||||||
assert.equal(await txValues[0].getText(), '-1 ETH')
|
assert.ok(/-1\s*ETH/.test(await txValues[0].getText()))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ describe('MetaMask', function () {
|
|||||||
|
|
||||||
it('balance renders', async () => {
|
it('balance renders', async () => {
|
||||||
const balance = await findElement(driver, By.css('.balance-display .token-amount'))
|
const balance = await findElement(driver, By.css('.balance-display .token-amount'))
|
||||||
await driver.wait(until.elementTextMatches(balance, /100.+ETH/))
|
await driver.wait(until.elementTextMatches(balance, /100\s*ETH/))
|
||||||
await delay(regularDelayMs)
|
await delay(regularDelayMs)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -420,7 +420,7 @@ describe('MetaMask', function () {
|
|||||||
|
|
||||||
if (process.env.SELENIUM_BROWSER !== 'firefox') {
|
if (process.env.SELENIUM_BROWSER !== 'firefox') {
|
||||||
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
|
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txValues, /-1\sETH/), 10000)
|
await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -462,7 +462,7 @@ describe('MetaMask', function () {
|
|||||||
assert.equal(transactions.length, 2)
|
assert.equal(transactions.length, 2)
|
||||||
|
|
||||||
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
|
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txValues, /-3\sETH/), 10000)
|
await driver.wait(until.elementTextMatches(txValues, /-3\s*ETH/), 10000)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -540,7 +540,7 @@ describe('MetaMask', function () {
|
|||||||
|
|
||||||
await findElements(driver, By.css('.transaction-list-item'))
|
await findElements(driver, By.css('.transaction-list-item'))
|
||||||
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txListValue, /-4\sETH/), 10000)
|
await driver.wait(until.elementTextMatches(txListValue, /-4\s*ETH/), 10000)
|
||||||
await txListValue.click()
|
await txListValue.click()
|
||||||
await delay(regularDelayMs)
|
await delay(regularDelayMs)
|
||||||
|
|
||||||
@ -574,7 +574,7 @@ describe('MetaMask', function () {
|
|||||||
}, 10000)
|
}, 10000)
|
||||||
|
|
||||||
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txValues[0], /-4\sETH/), 10000)
|
await driver.wait(until.elementTextMatches(txValues[0], /-4\s*ETH/), 10000)
|
||||||
|
|
||||||
// const txAccounts = await findElements(driver, By.css('.tx-list-account'))
|
// const txAccounts = await findElements(driver, By.css('.tx-list-account'))
|
||||||
// const firstTxAddress = await txAccounts[0].getText()
|
// const firstTxAddress = await txAccounts[0].getText()
|
||||||
@ -606,7 +606,7 @@ describe('MetaMask', function () {
|
|||||||
}, 10000)
|
}, 10000)
|
||||||
|
|
||||||
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
|
const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txValues, /-0\sETH/), 10000)
|
await driver.wait(until.elementTextMatches(txValues, /-0\s*ETH/), 10000)
|
||||||
|
|
||||||
await closeAllWindowHandlesExcept(driver, [extension, dapp])
|
await closeAllWindowHandlesExcept(driver, [extension, dapp])
|
||||||
await driver.switchTo().window(extension)
|
await driver.switchTo().window(extension)
|
||||||
@ -616,9 +616,9 @@ describe('MetaMask', function () {
|
|||||||
const balance = await findElement(driver, By.css('.transaction-view-balance__primary-balance'))
|
const balance = await findElement(driver, By.css('.transaction-view-balance__primary-balance'))
|
||||||
await delay(regularDelayMs)
|
await delay(regularDelayMs)
|
||||||
if (process.env.SELENIUM_BROWSER !== 'firefox') {
|
if (process.env.SELENIUM_BROWSER !== 'firefox') {
|
||||||
await driver.wait(until.elementTextMatches(balance, /^92.*ETH.*$/), 10000)
|
await driver.wait(until.elementTextMatches(balance, /^92.*\s*ETH.*$/), 10000)
|
||||||
const tokenAmount = await balance.getText()
|
const tokenAmount = await balance.getText()
|
||||||
assert.ok(/^92.*ETH.*$/.test(tokenAmount))
|
assert.ok(/^92.*\s*ETH.*$/.test(tokenAmount))
|
||||||
await delay(regularDelayMs)
|
await delay(regularDelayMs)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -764,7 +764,7 @@ describe('MetaMask', function () {
|
|||||||
// test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved,
|
// test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved,
|
||||||
// or possibly until we use latest version of firefox in the tests
|
// or possibly until we use latest version of firefox in the tests
|
||||||
if (process.env.SELENIUM_BROWSER !== 'firefox') {
|
if (process.env.SELENIUM_BROWSER !== 'firefox') {
|
||||||
await driver.wait(until.elementTextMatches(txValues[0], /-50\sTST/), 10000)
|
await driver.wait(until.elementTextMatches(txValues[0], /-50\s*TST/), 10000)
|
||||||
}
|
}
|
||||||
|
|
||||||
driver.wait(async () => {
|
driver.wait(async () => {
|
||||||
@ -798,7 +798,7 @@ describe('MetaMask', function () {
|
|||||||
|
|
||||||
await findElements(driver, By.css('.transaction-list__pending-transactions'))
|
await findElements(driver, By.css('.transaction-list__pending-transactions'))
|
||||||
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txListValue, /-7\sTST/), 10000)
|
await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/), 10000)
|
||||||
await txListValue.click()
|
await txListValue.click()
|
||||||
await delay(regularDelayMs)
|
await delay(regularDelayMs)
|
||||||
|
|
||||||
@ -851,7 +851,7 @@ describe('MetaMask', function () {
|
|||||||
}, 10000)
|
}, 10000)
|
||||||
|
|
||||||
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txValues[0], /-7\sTST/))
|
await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/))
|
||||||
const txStatuses = await findElements(driver, By.css('.transaction-list-item__action'))
|
const txStatuses = await findElements(driver, By.css('.transaction-list-item__action'))
|
||||||
await driver.wait(until.elementTextMatches(txStatuses[0], /Sent\sToken/))
|
await driver.wait(until.elementTextMatches(txStatuses[0], /Sent\sToken/))
|
||||||
|
|
||||||
@ -897,7 +897,7 @@ describe('MetaMask', function () {
|
|||||||
|
|
||||||
const [txListItem] = await findElements(driver, By.css('.transaction-list-item'))
|
const [txListItem] = await findElements(driver, By.css('.transaction-list-item'))
|
||||||
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txListValue, /-7\sTST/))
|
await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/))
|
||||||
await txListItem.click()
|
await txListItem.click()
|
||||||
await delay(regularDelayMs)
|
await delay(regularDelayMs)
|
||||||
})
|
})
|
||||||
@ -974,7 +974,7 @@ describe('MetaMask', function () {
|
|||||||
}, 10000)
|
}, 10000)
|
||||||
|
|
||||||
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
||||||
await driver.wait(until.elementTextMatches(txValues[0], /-7\sTST/))
|
await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/))
|
||||||
const txStatuses = await findElements(driver, By.css('.transaction-list-item__action'))
|
const txStatuses = await findElements(driver, By.css('.transaction-list-item__action'))
|
||||||
await driver.wait(until.elementTextMatches(txStatuses[0], /Approve/))
|
await driver.wait(until.elementTextMatches(txStatuses[0], /Approve/))
|
||||||
})
|
})
|
||||||
@ -1027,7 +1027,7 @@ describe('MetaMask', function () {
|
|||||||
|
|
||||||
it('renders the balance for the chosen token', async () => {
|
it('renders the balance for the chosen token', async () => {
|
||||||
const balance = await findElement(driver, By.css('.transaction-view-balance__token-balance'))
|
const balance = await findElement(driver, By.css('.transaction-view-balance__token-balance'))
|
||||||
await driver.wait(until.elementTextMatches(balance, /0\sBAT/))
|
await driver.wait(until.elementTextMatches(balance, /0\s*BAT/))
|
||||||
await delay(regularDelayMs)
|
await delay(regularDelayMs)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -11,7 +11,7 @@ sleep 5
|
|||||||
cd test/e2e/beta/
|
cd test/e2e/beta/
|
||||||
rm -rf drizzle-test
|
rm -rf drizzle-test
|
||||||
mkdir drizzle-test && cd drizzle-test
|
mkdir drizzle-test && cd drizzle-test
|
||||||
npm install truffle
|
sudo npm install -g truffle
|
||||||
truffle unbox drizzle
|
truffle unbox drizzle
|
||||||
echo "Deploying contracts for Drizzle test..."
|
echo "Deploying contracts for Drizzle test..."
|
||||||
truffle compile && truffle migrate
|
truffle compile && truffle migrate
|
||||||
|
@ -25,5 +25,5 @@ async function runCurrencyLocalizationTest (assert, done) {
|
|||||||
const txView = await queryAsync($, '.transaction-view')
|
const txView = await queryAsync($, '.transaction-view')
|
||||||
const heroBalance = await findAsync($(txView), '.transaction-view-balance__balance')
|
const heroBalance = await findAsync($(txView), '.transaction-view-balance__balance')
|
||||||
const fiatAmount = await findAsync($(heroBalance), '.transaction-view-balance__secondary-balance')
|
const fiatAmount = await findAsync($(heroBalance), '.transaction-view-balance__secondary-balance')
|
||||||
assert.equal(fiatAmount[0].textContent, '₱102,707.97 PHP')
|
assert.equal(fiatAmount[0].textContent, '₱102,707.97PHP')
|
||||||
}
|
}
|
||||||
|
@ -112,9 +112,9 @@ async function runSendFlowTest (assert, done) {
|
|||||||
errorMessage = $('.send-v2__error')
|
errorMessage = $('.send-v2__error')
|
||||||
assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected')
|
assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected')
|
||||||
|
|
||||||
await customizeGas(assert, 0, 21000, '0 ETH', '$0.00 USD')
|
await customizeGas(assert, 0, 21000, '0ETH', '$0.00USD')
|
||||||
await customizeGas(assert, 1, 21000, '0.000021 ETH', '$0.03 USD')
|
await customizeGas(assert, 1, 21000, '0.000021ETH', '$0.03USD')
|
||||||
await customizeGas(assert, 500, 60000, '0.03 ETH', '$36.03 USD')
|
await customizeGas(assert, 500, 60000, '0.03ETH', '$36.03USD')
|
||||||
|
|
||||||
const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button')
|
const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button')
|
||||||
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
|
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
|
||||||
|
@ -47,7 +47,7 @@ describe('# Network Controller', function () {
|
|||||||
|
|
||||||
describe('#setNetworkState', function () {
|
describe('#setNetworkState', function () {
|
||||||
it('should update the network', function () {
|
it('should update the network', function () {
|
||||||
networkController.setNetworkState(1)
|
networkController.setNetworkState(1, 'rpc')
|
||||||
const networkState = networkController.getNetworkState()
|
const networkState = networkController.getNetworkState()
|
||||||
assert.equal(networkState, 1, 'network is 1')
|
assert.equal(networkState, 1, 'network is 1')
|
||||||
})
|
})
|
||||||
|
@ -375,6 +375,11 @@ describe('preferences controller', function () {
|
|||||||
await preferencesController.requestWatchAsset(req, res, asy.next, asy.end)
|
await preferencesController.requestWatchAsset(req, res, asy.next, asy.end)
|
||||||
sandbox.assert.called(stubEnd)
|
sandbox.assert.called(stubEnd)
|
||||||
sandbox.assert.notCalled(stubNext)
|
sandbox.assert.notCalled(stubNext)
|
||||||
|
req.method = 'wallet_watchAsset'
|
||||||
|
req.params.type = 'someasset'
|
||||||
|
await preferencesController.requestWatchAsset(req, res, asy.next, asy.end)
|
||||||
|
sandbox.assert.calledTwice(stubEnd)
|
||||||
|
sandbox.assert.notCalled(stubNext)
|
||||||
})
|
})
|
||||||
it('should through error if method is supported but asset type is not', async function () {
|
it('should through error if method is supported but asset type is not', async function () {
|
||||||
req.method = 'metamask_watchAsset'
|
req.method = 'metamask_watchAsset'
|
||||||
@ -479,5 +484,24 @@ describe('preferences controller', function () {
|
|||||||
assert.equal(preferencesController.store.getState().seedWords, 'foo bar baz')
|
assert.equal(preferencesController.store.getState().seedWords, 'foo bar baz')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('on updateFrequentRpcList', function () {
|
||||||
|
it('should add custom RPC url to state', function () {
|
||||||
|
preferencesController.addToFrequentRpcList('rpc_url', 1)
|
||||||
|
preferencesController.addToFrequentRpcList('http://localhost:8545', 1)
|
||||||
|
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] )
|
||||||
|
preferencesController.addToFrequentRpcList('rpc_url', 1)
|
||||||
|
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should remove custom RPC url from state', function () {
|
||||||
|
preferencesController.addToFrequentRpcList('rpc_url', 1)
|
||||||
|
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] )
|
||||||
|
preferencesController.removeFromFrequentRpcList('other_rpc_url')
|
||||||
|
preferencesController.removeFromFrequentRpcList('http://localhost:8545')
|
||||||
|
preferencesController.removeFromFrequentRpcList('rpc_url')
|
||||||
|
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [])
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1133,7 +1133,7 @@ describe('Actions', () => {
|
|||||||
{ type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' },
|
{ type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' },
|
||||||
]
|
]
|
||||||
|
|
||||||
setRpcTargetSpy.callsFake((newRpc, callback) => {
|
setRpcTargetSpy.callsFake((newRpc, chainId, ticker, nickname, callback) => {
|
||||||
callback(new Error('error'))
|
callback(new Error('error'))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -309,7 +309,7 @@ var actions = {
|
|||||||
setPreference,
|
setPreference,
|
||||||
updatePreferences,
|
updatePreferences,
|
||||||
UPDATE_PREFERENCES: 'UPDATE_PREFERENCES',
|
UPDATE_PREFERENCES: 'UPDATE_PREFERENCES',
|
||||||
setUseETHAsPrimaryCurrencyPreference,
|
setUseNativeCurrencyAsPrimaryCurrencyPreference,
|
||||||
|
|
||||||
setMouseUserState,
|
setMouseUserState,
|
||||||
SET_MOUSE_USER_STATE: 'SET_MOUSE_USER_STATE',
|
SET_MOUSE_USER_STATE: 'SET_MOUSE_USER_STATE',
|
||||||
@ -1874,10 +1874,10 @@ function updateProviderType (type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setRpcTarget (newRpc) {
|
function setRpcTarget (newRpc, chainId, ticker = 'ETH', nickname = '') {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
log.debug(`background.setRpcTarget: ${newRpc}`)
|
log.debug(`background.setRpcTarget: ${newRpc} ${chainId} ${ticker} ${nickname}`)
|
||||||
background.setCustomRpc(newRpc, (err, result) => {
|
background.setCustomRpc(newRpc, chainId, ticker, nickname, (err, result) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.error(err)
|
log.error(err)
|
||||||
return dispatch(actions.displayWarning('Had a problem changing networks!'))
|
return dispatch(actions.displayWarning('Had a problem changing networks!'))
|
||||||
@ -2330,8 +2330,8 @@ function updatePreferences (value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUseETHAsPrimaryCurrencyPreference (value) {
|
function setUseNativeCurrencyAsPrimaryCurrencyPreference (value) {
|
||||||
return setPreference('useETHAsPrimaryCurrency', value)
|
return setPreference('useNativeCurrencyAsPrimaryCurrency', value)
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNetworkNonce (networkNonce) {
|
function setNetworkNonce (networkNonce) {
|
||||||
|
@ -101,7 +101,7 @@ class App extends Component {
|
|||||||
network,
|
network,
|
||||||
isMouseUser,
|
isMouseUser,
|
||||||
provider,
|
provider,
|
||||||
frequentRpcList,
|
frequentRpcListDetail,
|
||||||
currentView,
|
currentView,
|
||||||
setMouseUserState,
|
setMouseUserState,
|
||||||
sidebar,
|
sidebar,
|
||||||
@ -147,7 +147,7 @@ class App extends Component {
|
|||||||
// network dropdown
|
// network dropdown
|
||||||
h(NetworkDropdown, {
|
h(NetworkDropdown, {
|
||||||
provider,
|
provider,
|
||||||
frequentRpcList,
|
frequentRpcListDetail,
|
||||||
}, []),
|
}, []),
|
||||||
|
|
||||||
h(AccountMenu),
|
h(AccountMenu),
|
||||||
@ -230,7 +230,7 @@ App.propTypes = {
|
|||||||
alertMessage: PropTypes.string,
|
alertMessage: PropTypes.string,
|
||||||
network: PropTypes.string,
|
network: PropTypes.string,
|
||||||
provider: PropTypes.object,
|
provider: PropTypes.object,
|
||||||
frequentRpcList: PropTypes.array,
|
frequentRpcListDetail: PropTypes.array,
|
||||||
currentView: PropTypes.object,
|
currentView: PropTypes.object,
|
||||||
sidebar: PropTypes.object,
|
sidebar: PropTypes.object,
|
||||||
alertOpen: PropTypes.bool,
|
alertOpen: PropTypes.bool,
|
||||||
@ -322,7 +322,7 @@ function mapStateToProps (state) {
|
|||||||
forgottenPassword: state.appState.forgottenPassword,
|
forgottenPassword: state.appState.forgottenPassword,
|
||||||
nextUnreadNotice,
|
nextUnreadNotice,
|
||||||
lostAccounts,
|
lostAccounts,
|
||||||
frequentRpcList: state.metamask.frequentRpcList || [],
|
frequentRpcListDetail: state.metamask.frequentRpcListDetail || [],
|
||||||
currentCurrency: state.metamask.currentCurrency,
|
currentCurrency: state.metamask.currentCurrency,
|
||||||
isMouseUser: state.appState.isMouseUser,
|
isMouseUser: state.appState.isMouseUser,
|
||||||
betaUI: state.metamask.featureFlags.betaUI,
|
betaUI: state.metamask.featureFlags.betaUI,
|
||||||
|
@ -6,10 +6,11 @@ const genAccountLink = require('etherscan-link').createAccountLink
|
|||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const Dropdown = require('./dropdown').Dropdown
|
const Dropdown = require('./dropdown').Dropdown
|
||||||
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
||||||
const Identicon = require('./identicon')
|
|
||||||
const copyToClipboard = require('copy-to-clipboard')
|
const copyToClipboard = require('copy-to-clipboard')
|
||||||
const { checksumAddress } = require('../util')
|
const { checksumAddress } = require('../util')
|
||||||
|
|
||||||
|
import Identicon from './identicon'
|
||||||
|
|
||||||
class AccountDropdowns extends Component {
|
class AccountDropdowns extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
@ -7,10 +7,10 @@ const PropTypes = require('prop-types')
|
|||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const actions = require('../../actions')
|
const actions = require('../../actions')
|
||||||
const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu')
|
const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu')
|
||||||
const Identicon = require('../identicon')
|
|
||||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums')
|
const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums')
|
||||||
const { getEnvironmentType } = require('../../../../app/scripts/lib/util')
|
const { getEnvironmentType } = require('../../../../app/scripts/lib/util')
|
||||||
const Tooltip = require('../tooltip')
|
const Tooltip = require('../tooltip')
|
||||||
|
import Identicon from '../identicon'
|
||||||
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
|
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
|
||||||
import { PRIMARY } from '../../constants/common'
|
import { PRIMARY } from '../../constants/common'
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const Component = require('react').Component
|
const Component = require('react').Component
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const Identicon = require('./identicon')
|
import Identicon from './identicon'
|
||||||
const formatBalance = require('../util').formatBalance
|
const formatBalance = require('../util').formatBalance
|
||||||
const addressSummary = require('../util').addressSummary
|
const addressSummary = require('../util').addressSummary
|
||||||
|
|
||||||
|
@ -2,13 +2,13 @@ import React, { PureComponent } from 'react'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { matchPath } from 'react-router-dom'
|
import { matchPath } from 'react-router-dom'
|
||||||
|
import Identicon from '../identicon'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
ENVIRONMENT_TYPE_NOTIFICATION,
|
||||||
ENVIRONMENT_TYPE_POPUP,
|
ENVIRONMENT_TYPE_POPUP,
|
||||||
} = require('../../../../app/scripts/lib/enums')
|
} = require('../../../../app/scripts/lib/enums')
|
||||||
const { DEFAULT_ROUTE, INITIALIZE_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes')
|
const { DEFAULT_ROUTE, INITIALIZE_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes')
|
||||||
const Identicon = require('../identicon')
|
|
||||||
const NetworkIndicator = require('../network')
|
const NetworkIndicator = require('../network')
|
||||||
|
|
||||||
export default class AppHeader extends PureComponent {
|
export default class AppHeader extends PureComponent {
|
||||||
|
@ -2,11 +2,11 @@ const Component = require('react').Component
|
|||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const TokenBalance = require('./token-balance')
|
import TokenBalance from './token-balance'
|
||||||
const Identicon = require('./identicon')
|
import Identicon from './identicon'
|
||||||
import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display'
|
import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display'
|
||||||
import { PRIMARY, SECONDARY } from '../constants/common'
|
import { PRIMARY, SECONDARY } from '../constants/common'
|
||||||
const { getAssetImages, conversionRateSelector, getCurrentCurrency} = require('../selectors')
|
const { getNativeCurrency, getAssetImages, conversionRateSelector, getCurrentCurrency} = require('../selectors')
|
||||||
|
|
||||||
const { formatBalance } = require('../util')
|
const { formatBalance } = require('../util')
|
||||||
|
|
||||||
@ -21,6 +21,7 @@ function mapStateToProps (state) {
|
|||||||
return {
|
return {
|
||||||
account,
|
account,
|
||||||
network,
|
network,
|
||||||
|
nativeCurrency: getNativeCurrency(state),
|
||||||
conversionRate: conversionRateSelector(state),
|
conversionRate: conversionRateSelector(state),
|
||||||
currentCurrency: getCurrentCurrency(state),
|
currentCurrency: getCurrentCurrency(state),
|
||||||
assetImages: getAssetImages(state),
|
assetImages: getAssetImages(state),
|
||||||
@ -66,10 +67,10 @@ BalanceComponent.prototype.renderTokenBalance = function () {
|
|||||||
|
|
||||||
BalanceComponent.prototype.renderBalance = function () {
|
BalanceComponent.prototype.renderBalance = function () {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
const { account } = props
|
const { account, nativeCurrency } = props
|
||||||
const balanceValue = account && account.balance
|
const balanceValue = account && account.balance
|
||||||
const needsParse = 'needsParse' in props ? props.needsParse : true
|
const needsParse = 'needsParse' in props ? props.needsParse : true
|
||||||
const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse) : '...'
|
const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse, nativeCurrency) : '...'
|
||||||
const showFiat = 'showFiat' in props ? props.showFiat : true
|
const showFiat = 'showFiat' in props ? props.showFiat : true
|
||||||
|
|
||||||
if (formattedBalance === 'None' || formattedBalance === '...') {
|
if (formattedBalance === 'None' || formattedBalance === '...') {
|
||||||
@ -81,11 +82,12 @@ BalanceComponent.prototype.renderBalance = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return h('div.flex-column.balance-display', {}, [
|
return h('div.flex-column.balance-display', {}, [
|
||||||
h('div.token-amount', {}, h(UserPreferencedCurrencyDisplay, {
|
h(UserPreferencedCurrencyDisplay, {
|
||||||
|
className: 'token-amount',
|
||||||
value: balanceValue,
|
value: balanceValue,
|
||||||
type: PRIMARY,
|
type: PRIMARY,
|
||||||
ethNumberOfDecimals: 3,
|
ethNumberOfDecimals: 3,
|
||||||
})),
|
}),
|
||||||
|
|
||||||
showFiat && h(UserPreferencedCurrencyDisplay, {
|
showFiat && h(UserPreferencedCurrencyDisplay, {
|
||||||
value: balanceValue,
|
value: balanceValue,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { ETH, GWEI } from '../../constants/common'
|
import { GWEI } from '../../constants/common'
|
||||||
|
|
||||||
export default class CurrencyDisplay extends PureComponent {
|
export default class CurrencyDisplay extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -10,8 +10,9 @@ export default class CurrencyDisplay extends PureComponent {
|
|||||||
prefix: PropTypes.string,
|
prefix: PropTypes.string,
|
||||||
prefixComponent: PropTypes.node,
|
prefixComponent: PropTypes.node,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
|
suffix: PropTypes.string,
|
||||||
// Used in container
|
// Used in container
|
||||||
currency: PropTypes.oneOf([ETH]),
|
currency: PropTypes.string,
|
||||||
denomination: PropTypes.oneOf([GWEI]),
|
denomination: PropTypes.oneOf([GWEI]),
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
@ -19,17 +20,25 @@ export default class CurrencyDisplay extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { className, displayValue, prefix, prefixComponent, style } = this.props
|
const { className, displayValue, prefix, prefixComponent, style, suffix } = this.props
|
||||||
const text = `${prefix || ''}${displayValue}`
|
const text = `${prefix || ''}${displayValue}`
|
||||||
|
const title = `${text} ${suffix}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('currency-display-component', className)}
|
className={classnames('currency-display-component', className)}
|
||||||
style={style}
|
style={style}
|
||||||
title={text}
|
title={title}
|
||||||
>
|
>
|
||||||
{ prefixComponent}
|
{ prefixComponent}
|
||||||
<span className="currency-display-component__text">{ text }</span>
|
<span className="currency-display-component__text">{ text }</span>
|
||||||
|
{
|
||||||
|
suffix && (
|
||||||
|
<span className="currency-display-component__suffix">
|
||||||
|
{ suffix }
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,17 @@ import CurrencyDisplay from './currency-display.component'
|
|||||||
import { getValueFromWeiHex, formatCurrency } from '../../helpers/confirm-transaction/util'
|
import { getValueFromWeiHex, formatCurrency } from '../../helpers/confirm-transaction/util'
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
const { metamask: { currentCurrency, conversionRate } } = state
|
const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentCurrency,
|
currentCurrency,
|
||||||
conversionRate,
|
conversionRate,
|
||||||
|
nativeCurrency,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||||
const { currentCurrency, conversionRate, ...restStateProps } = stateProps
|
const { nativeCurrency, currentCurrency, conversionRate, ...restStateProps } = stateProps
|
||||||
const {
|
const {
|
||||||
value,
|
value,
|
||||||
numberOfDecimals = 2,
|
numberOfDecimals = 2,
|
||||||
@ -24,16 +25,17 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
|||||||
|
|
||||||
const toCurrency = currency || currentCurrency
|
const toCurrency = currency || currentCurrency
|
||||||
const convertedValue = getValueFromWeiHex({
|
const convertedValue = getValueFromWeiHex({
|
||||||
value, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination,
|
value, fromCurrency: nativeCurrency, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination,
|
||||||
})
|
})
|
||||||
const formattedValue = formatCurrency(convertedValue, toCurrency)
|
const displayValue = formatCurrency(convertedValue, toCurrency)
|
||||||
const displayValue = hideLabel ? formattedValue : `${formattedValue} ${toCurrency.toUpperCase()}`
|
const suffix = hideLabel ? undefined : toCurrency.toUpperCase()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...restStateProps,
|
...restStateProps,
|
||||||
...dispatchProps,
|
...dispatchProps,
|
||||||
...restOwnProps,
|
...restOwnProps,
|
||||||
displayValue,
|
displayValue,
|
||||||
|
suffix,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,4 +7,8 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__suffix {
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,14 @@ describe('CurrencyDisplay container', () => {
|
|||||||
metamask: {
|
metamask: {
|
||||||
conversionRate: 280.45,
|
conversionRate: 280.45,
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.deepEqual(mapStateToProps(mockState), {
|
assert.deepEqual(mapStateToProps(mockState), {
|
||||||
conversionRate: 280.45,
|
conversionRate: 280.45,
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -35,6 +37,7 @@ describe('CurrencyDisplay container', () => {
|
|||||||
const mockStateProps = {
|
const mockStateProps = {
|
||||||
conversionRate: 280.45,
|
conversionRate: 280.45,
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
}
|
}
|
||||||
|
|
||||||
const tests = [
|
const tests = [
|
||||||
@ -43,71 +46,93 @@ describe('CurrencyDisplay container', () => {
|
|||||||
value: '0x2386f26fc10000',
|
value: '0x2386f26fc10000',
|
||||||
numberOfDecimals: 2,
|
numberOfDecimals: 2,
|
||||||
currency: 'usd',
|
currency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
displayValue: '$2.80 USD',
|
displayValue: '$2.80',
|
||||||
|
suffix: 'USD',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
props: {
|
props: {
|
||||||
value: '0x2386f26fc10000',
|
value: '0x2386f26fc10000',
|
||||||
|
currency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
displayValue: '$2.80 USD',
|
displayValue: '$2.80',
|
||||||
|
suffix: 'USD',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
props: {
|
props: {
|
||||||
value: '0x1193461d01595930',
|
value: '0x1193461d01595930',
|
||||||
currency: 'ETH',
|
currency: 'ETH',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
numberOfDecimals: 3,
|
numberOfDecimals: 3,
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
displayValue: '1.266 ETH',
|
displayValue: '1.266',
|
||||||
|
suffix: 'ETH',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
props: {
|
props: {
|
||||||
value: '0x1193461d01595930',
|
value: '0x1193461d01595930',
|
||||||
currency: 'ETH',
|
currency: 'ETH',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
numberOfDecimals: 3,
|
numberOfDecimals: 3,
|
||||||
hideLabel: true,
|
hideLabel: true,
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
displayValue: '1.266',
|
displayValue: '1.266',
|
||||||
|
suffix: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
props: {
|
props: {
|
||||||
value: '0x3b9aca00',
|
value: '0x3b9aca00',
|
||||||
currency: 'ETH',
|
currency: 'ETH',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
denomination: 'GWEI',
|
denomination: 'GWEI',
|
||||||
hideLabel: true,
|
hideLabel: true,
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
displayValue: '1',
|
displayValue: '1',
|
||||||
|
suffix: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
props: {
|
props: {
|
||||||
value: '0x3b9aca00',
|
value: '0x3b9aca00',
|
||||||
currency: 'ETH',
|
currency: 'ETH',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
denomination: 'WEI',
|
denomination: 'WEI',
|
||||||
hideLabel: true,
|
hideLabel: true,
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
displayValue: '1000000000',
|
displayValue: '1000000000',
|
||||||
|
suffix: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
props: {
|
props: {
|
||||||
value: '0x3b9aca00',
|
value: '0x3b9aca00',
|
||||||
currency: 'ETH',
|
currency: 'ETH',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
numberOfDecimals: 100,
|
numberOfDecimals: 100,
|
||||||
hideLabel: true,
|
hideLabel: true,
|
||||||
},
|
},
|
||||||
result: {
|
result: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
displayValue: '1e-9',
|
displayValue: '1e-9',
|
||||||
|
suffix: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -14,6 +14,7 @@ export default class CurrencyInput extends PureComponent {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
conversionRate: PropTypes.number,
|
conversionRate: PropTypes.number,
|
||||||
currentCurrency: PropTypes.string,
|
currentCurrency: PropTypes.string,
|
||||||
|
nativeCurrency: PropTypes.string,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
onBlur: PropTypes.func,
|
onBlur: PropTypes.func,
|
||||||
suffix: PropTypes.string,
|
suffix: PropTypes.string,
|
||||||
@ -77,13 +78,13 @@ export default class CurrencyInput extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderConversionComponent () {
|
renderConversionComponent () {
|
||||||
const { useFiat, currentCurrency } = this.props
|
const { useFiat, currentCurrency, nativeCurrency } = this.props
|
||||||
const { hexValue } = this.state
|
const { hexValue } = this.state
|
||||||
let currency, numberOfDecimals
|
let currency, numberOfDecimals
|
||||||
|
|
||||||
if (useFiat) {
|
if (useFiat) {
|
||||||
// Display ETH
|
// Display ETH
|
||||||
currency = ETH
|
currency = nativeCurrency || ETH
|
||||||
numberOfDecimals = 6
|
numberOfDecimals = 6
|
||||||
} else {
|
} else {
|
||||||
// Display Fiat
|
// Display Fiat
|
||||||
|
@ -3,18 +3,19 @@ import CurrencyInput from './currency-input.component'
|
|||||||
import { ETH } from '../../constants/common'
|
import { ETH } from '../../constants/common'
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
const { metamask: { currentCurrency, conversionRate } } = state
|
const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
nativeCurrency,
|
||||||
currentCurrency,
|
currentCurrency,
|
||||||
conversionRate,
|
conversionRate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||||
const { currentCurrency } = stateProps
|
const { nativeCurrency, currentCurrency } = stateProps
|
||||||
const { useFiat } = ownProps
|
const { useFiat } = ownProps
|
||||||
const suffix = useFiat ? currentCurrency.toUpperCase() : ETH
|
const suffix = useFiat ? currentCurrency.toUpperCase() : nativeCurrency || ETH
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...stateProps,
|
...stateProps,
|
||||||
|
@ -22,6 +22,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
it('should render properly with a suffix', () => {
|
it('should render properly with a suffix', () => {
|
||||||
const mockStore = {
|
const mockStore = {
|
||||||
metamask: {
|
metamask: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
conversionRate: 231.06,
|
conversionRate: 231.06,
|
||||||
},
|
},
|
||||||
@ -32,6 +33,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<CurrencyInput
|
<CurrencyInput
|
||||||
suffix="ETH"
|
suffix="ETH"
|
||||||
|
nativeCurrency="ETH"
|
||||||
/>
|
/>
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
||||||
@ -45,6 +47,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
it('should render properly with an ETH value', () => {
|
it('should render properly with an ETH value', () => {
|
||||||
const mockStore = {
|
const mockStore = {
|
||||||
metamask: {
|
metamask: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
conversionRate: 231.06,
|
conversionRate: 231.06,
|
||||||
},
|
},
|
||||||
@ -56,6 +59,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
<CurrencyInput
|
<CurrencyInput
|
||||||
value="de0b6b3a7640000"
|
value="de0b6b3a7640000"
|
||||||
suffix="ETH"
|
suffix="ETH"
|
||||||
|
nativeCurrency="ETH"
|
||||||
currentCurrency="usd"
|
currentCurrency="usd"
|
||||||
conversionRate={231.06}
|
conversionRate={231.06}
|
||||||
/>
|
/>
|
||||||
@ -69,12 +73,13 @@ describe('CurrencyInput Component', () => {
|
|||||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
||||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH')
|
assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH')
|
||||||
assert.equal(wrapper.find('.unit-input__input').props().value, '1')
|
assert.equal(wrapper.find('.unit-input__input').props().value, '1')
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '$231.06 USD')
|
assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render properly with a fiat value', () => {
|
it('should render properly with a fiat value', () => {
|
||||||
const mockStore = {
|
const mockStore = {
|
||||||
metamask: {
|
metamask: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
conversionRate: 231.06,
|
conversionRate: 231.06,
|
||||||
},
|
},
|
||||||
@ -87,6 +92,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
value="f602f2234d0ea"
|
value="f602f2234d0ea"
|
||||||
suffix="USD"
|
suffix="USD"
|
||||||
useFiat
|
useFiat
|
||||||
|
nativeCurrency="ETH"
|
||||||
currentCurrency="usd"
|
currentCurrency="usd"
|
||||||
conversionRate={231.06}
|
conversionRate={231.06}
|
||||||
/>
|
/>
|
||||||
@ -100,7 +106,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
||||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'USD')
|
assert.equal(wrapper.find('.unit-input__suffix').text(), 'USD')
|
||||||
assert.equal(wrapper.find('.unit-input__input').props().value, '1')
|
assert.equal(wrapper.find('.unit-input__input').props().value, '1')
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '0.004328 ETH')
|
assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -116,6 +122,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
it('should call onChange and onBlur on input changes with the hex value for ETH', () => {
|
it('should call onChange and onBlur on input changes with the hex value for ETH', () => {
|
||||||
const mockStore = {
|
const mockStore = {
|
||||||
metamask: {
|
metamask: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
conversionRate: 231.06,
|
conversionRate: 231.06,
|
||||||
},
|
},
|
||||||
@ -127,6 +134,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
onChange={handleChangeSpy}
|
onChange={handleChangeSpy}
|
||||||
onBlur={handleBlurSpy}
|
onBlur={handleBlurSpy}
|
||||||
suffix="ETH"
|
suffix="ETH"
|
||||||
|
nativeCurrency="ETH"
|
||||||
currentCurrency="usd"
|
currentCurrency="usd"
|
||||||
conversionRate={231.06}
|
conversionRate={231.06}
|
||||||
/>
|
/>
|
||||||
@ -140,14 +148,14 @@ describe('CurrencyInput Component', () => {
|
|||||||
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 0)
|
assert.equal(currencyInputInstance.state.decimalValue, 0)
|
||||||
assert.equal(currencyInputInstance.state.hexValue, undefined)
|
assert.equal(currencyInputInstance.state.hexValue, undefined)
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '$0.00 USD')
|
assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD')
|
||||||
const input = wrapper.find('input')
|
const input = wrapper.find('input')
|
||||||
assert.equal(input.props().value, 0)
|
assert.equal(input.props().value, 0)
|
||||||
|
|
||||||
input.simulate('change', { target: { value: 1 } })
|
input.simulate('change', { target: { value: 1 } })
|
||||||
assert.equal(handleChangeSpy.callCount, 1)
|
assert.equal(handleChangeSpy.callCount, 1)
|
||||||
assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000'))
|
assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000'))
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '$231.06 USD')
|
assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD')
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 1)
|
assert.equal(currencyInputInstance.state.decimalValue, 1)
|
||||||
assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000')
|
assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000')
|
||||||
|
|
||||||
@ -160,6 +168,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
it('should call onChange and onBlur on input changes with the hex value for fiat', () => {
|
it('should call onChange and onBlur on input changes with the hex value for fiat', () => {
|
||||||
const mockStore = {
|
const mockStore = {
|
||||||
metamask: {
|
metamask: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
conversionRate: 231.06,
|
conversionRate: 231.06,
|
||||||
},
|
},
|
||||||
@ -171,6 +180,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
onChange={handleChangeSpy}
|
onChange={handleChangeSpy}
|
||||||
onBlur={handleBlurSpy}
|
onBlur={handleBlurSpy}
|
||||||
suffix="USD"
|
suffix="USD"
|
||||||
|
nativeCurrency="ETH"
|
||||||
currentCurrency="usd"
|
currentCurrency="usd"
|
||||||
conversionRate={231.06}
|
conversionRate={231.06}
|
||||||
useFiat
|
useFiat
|
||||||
@ -185,14 +195,14 @@ describe('CurrencyInput Component', () => {
|
|||||||
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 0)
|
assert.equal(currencyInputInstance.state.decimalValue, 0)
|
||||||
assert.equal(currencyInputInstance.state.hexValue, undefined)
|
assert.equal(currencyInputInstance.state.hexValue, undefined)
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '0 ETH')
|
assert.equal(wrapper.find('.currency-display-component').text(), '0ETH')
|
||||||
const input = wrapper.find('input')
|
const input = wrapper.find('input')
|
||||||
assert.equal(input.props().value, 0)
|
assert.equal(input.props().value, 0)
|
||||||
|
|
||||||
input.simulate('change', { target: { value: 1 } })
|
input.simulate('change', { target: { value: 1 } })
|
||||||
assert.equal(handleChangeSpy.callCount, 1)
|
assert.equal(handleChangeSpy.callCount, 1)
|
||||||
assert.ok(handleChangeSpy.calledWith('f602f2234d0ea'))
|
assert.ok(handleChangeSpy.calledWith('f602f2234d0ea'))
|
||||||
assert.equal(wrapper.find('.currency-display-component').text(), '0.004328 ETH')
|
assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH')
|
||||||
assert.equal(currencyInputInstance.state.decimalValue, 1)
|
assert.equal(currencyInputInstance.state.decimalValue, 1)
|
||||||
assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea')
|
assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea')
|
||||||
|
|
||||||
@ -205,6 +215,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
it('should change the state and pass in a new decimalValue when props.value changes', () => {
|
it('should change the state and pass in a new decimalValue when props.value changes', () => {
|
||||||
const mockStore = {
|
const mockStore = {
|
||||||
metamask: {
|
metamask: {
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
conversionRate: 231.06,
|
conversionRate: 231.06,
|
||||||
},
|
},
|
||||||
@ -216,6 +227,7 @@ describe('CurrencyInput Component', () => {
|
|||||||
onChange={handleChangeSpy}
|
onChange={handleChangeSpy}
|
||||||
onBlur={handleBlurSpy}
|
onBlur={handleBlurSpy}
|
||||||
suffix="USD"
|
suffix="USD"
|
||||||
|
nativeCurrency="ETH"
|
||||||
currentCurrency="usd"
|
currentCurrency="usd"
|
||||||
conversionRate={231.06}
|
conversionRate={231.06}
|
||||||
useFiat
|
useFiat
|
||||||
|
@ -20,12 +20,14 @@ describe('CurrencyInput container', () => {
|
|||||||
metamask: {
|
metamask: {
|
||||||
conversionRate: 280.45,
|
conversionRate: 280.45,
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.deepEqual(mapStateToProps(mockState), {
|
assert.deepEqual(mapStateToProps(mockState), {
|
||||||
conversionRate: 280.45,
|
conversionRate: 280.45,
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -35,12 +37,14 @@ describe('CurrencyInput container', () => {
|
|||||||
const mockStateProps = {
|
const mockStateProps = {
|
||||||
conversionRate: 280.45,
|
conversionRate: 280.45,
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
}
|
}
|
||||||
const mockDispatchProps = {}
|
const mockDispatchProps = {}
|
||||||
|
|
||||||
assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, { useFiat: true }), {
|
assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, { useFiat: true }), {
|
||||||
conversionRate: 280.45,
|
conversionRate: 280.45,
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
useFiat: true,
|
useFiat: true,
|
||||||
suffix: 'USD',
|
suffix: 'USD',
|
||||||
})
|
})
|
||||||
@ -48,6 +52,7 @@ describe('CurrencyInput container', () => {
|
|||||||
assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, {}), {
|
assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, {}), {
|
||||||
conversionRate: 280.45,
|
conversionRate: 280.45,
|
||||||
currentCurrency: 'usd',
|
currentCurrency: 'usd',
|
||||||
|
nativeCurrency: 'ETH',
|
||||||
suffix: 'ETH',
|
suffix: 'ETH',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -6,7 +6,7 @@ const genAccountLink = require('../../../../lib/account-link.js')
|
|||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const Dropdown = require('./dropdown').Dropdown
|
const Dropdown = require('./dropdown').Dropdown
|
||||||
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
||||||
const Identicon = require('../../identicon')
|
import Identicon from '../../identicon'
|
||||||
const { checksumAddress } = require('../../../util')
|
const { checksumAddress } = require('../../../util')
|
||||||
const copyToClipboard = require('copy-to-clipboard')
|
const copyToClipboard = require('copy-to-clipboard')
|
||||||
const { formatBalance } = require('../../../util')
|
const { formatBalance } = require('../../../util')
|
||||||
@ -26,14 +26,14 @@ class AccountDropdowns extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderAccounts () {
|
renderAccounts () {
|
||||||
const { identities, accounts, selected, menuItemStyles, actions, keyrings } = this.props
|
const { identities, accounts, selected, menuItemStyles, actions, keyrings, ticker } = this.props
|
||||||
|
|
||||||
return Object.keys(identities).map((key, index) => {
|
return Object.keys(identities).map((key, index) => {
|
||||||
const identity = identities[key]
|
const identity = identities[key]
|
||||||
const isSelected = identity.address === selected
|
const isSelected = identity.address === selected
|
||||||
|
|
||||||
const balanceValue = accounts[key].balance
|
const balanceValue = accounts[key].balance
|
||||||
const formattedBalance = balanceValue ? formatBalance(balanceValue, 6) : '...'
|
const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, true, ticker) : '...'
|
||||||
const simpleAddress = identity.address.substring(2).toLowerCase()
|
const simpleAddress = identity.address.substring(2).toLowerCase()
|
||||||
|
|
||||||
const keyring = keyrings.find((kr) => {
|
const keyring = keyrings.find((kr) => {
|
||||||
@ -421,6 +421,7 @@ AccountDropdowns.propTypes = {
|
|||||||
network: PropTypes.number,
|
network: PropTypes.number,
|
||||||
// actions.showExportPrivateKeyModal: ,
|
// actions.showExportPrivateKeyModal: ,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
|
ticker: PropTypes.string,
|
||||||
enableAccountsSelector: PropTypes.bool,
|
enableAccountsSelector: PropTypes.bool,
|
||||||
enableAccountOption: PropTypes.bool,
|
enableAccountOption: PropTypes.bool,
|
||||||
enableAccountOptions: PropTypes.bool,
|
enableAccountOptions: PropTypes.bool,
|
||||||
@ -458,6 +459,7 @@ const mapDispatchToProps = (dispatch) => {
|
|||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
return {
|
return {
|
||||||
|
ticker: state.metamask.ticker,
|
||||||
keyrings: state.metamask.keyrings,
|
keyrings: state.metamask.keyrings,
|
||||||
sidebarOpen: state.appState.sidebar.isOpen,
|
sidebarOpen: state.appState.sidebar.isOpen,
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,9 @@ const notToggleElementClassnames = [
|
|||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
return {
|
return {
|
||||||
provider: state.metamask.provider,
|
provider: state.metamask.provider,
|
||||||
frequentRpcList: state.metamask.frequentRpcList || [],
|
frequentRpcListDetail: state.metamask.frequentRpcListDetail || [],
|
||||||
networkDropdownOpen: state.appState.networkDropdownOpen,
|
networkDropdownOpen: state.appState.networkDropdownOpen,
|
||||||
|
network: state.metamask.network,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +41,8 @@ function mapDispatchToProps (dispatch) {
|
|||||||
setDefaultRpcTarget: type => {
|
setDefaultRpcTarget: type => {
|
||||||
dispatch(actions.setDefaultRpcTarget(type))
|
dispatch(actions.setDefaultRpcTarget(type))
|
||||||
},
|
},
|
||||||
setRpcTarget: (target) => {
|
setRpcTarget: (target, network, ticker, nickname) => {
|
||||||
dispatch(actions.setRpcTarget(target))
|
dispatch(actions.setRpcTarget(target, network, ticker, nickname))
|
||||||
},
|
},
|
||||||
delRpcTarget: (target) => {
|
delRpcTarget: (target) => {
|
||||||
dispatch(actions.delRpcTarget(target))
|
dispatch(actions.delRpcTarget(target))
|
||||||
@ -71,7 +72,7 @@ module.exports = compose(
|
|||||||
NetworkDropdown.prototype.render = function () {
|
NetworkDropdown.prototype.render = function () {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
const { provider: { type: providerType, rpcTarget: activeNetwork } } = props
|
const { provider: { type: providerType, rpcTarget: activeNetwork } } = props
|
||||||
const rpcList = props.frequentRpcList
|
const rpcListDetail = props.frequentRpcListDetail
|
||||||
const isOpen = this.props.networkDropdownOpen
|
const isOpen = this.props.networkDropdownOpen
|
||||||
const dropdownMenuItemStyle = {
|
const dropdownMenuItemStyle = {
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
@ -225,7 +226,7 @@ NetworkDropdown.prototype.render = function () {
|
|||||||
),
|
),
|
||||||
|
|
||||||
this.renderCustomOption(props.provider),
|
this.renderCustomOption(props.provider),
|
||||||
this.renderCommonRpc(rpcList, props.provider),
|
this.renderCommonRpc(rpcListDetail, props.provider),
|
||||||
|
|
||||||
h(
|
h(
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
@ -267,28 +268,33 @@ NetworkDropdown.prototype.getNetworkName = function () {
|
|||||||
} else if (providerName === 'rinkeby') {
|
} else if (providerName === 'rinkeby') {
|
||||||
name = this.context.t('rinkeby')
|
name = this.context.t('rinkeby')
|
||||||
} else {
|
} else {
|
||||||
name = this.context.t('unknownNetwork')
|
name = provider.nickname || this.context.t('unknownNetwork')
|
||||||
}
|
}
|
||||||
|
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) {
|
NetworkDropdown.prototype.renderCommonRpc = function (rpcListDetail, provider) {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
const reversedRpcList = rpcList.slice().reverse()
|
const reversedRpcListDetail = rpcListDetail.slice().reverse()
|
||||||
|
const network = props.network
|
||||||
|
|
||||||
return reversedRpcList.map((rpc) => {
|
return reversedRpcListDetail.map((entry) => {
|
||||||
|
const rpc = entry.rpcUrl
|
||||||
|
const ticker = entry.ticker || 'ETH'
|
||||||
|
const nickname = entry.nickname || ''
|
||||||
const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget
|
const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget
|
||||||
|
|
||||||
if ((rpc === 'http://localhost:8545') || currentRpcTarget) {
|
if ((rpc === 'http://localhost:8545') || currentRpcTarget) {
|
||||||
return null
|
return null
|
||||||
} else {
|
} else {
|
||||||
|
const chainId = entry.chainId || network
|
||||||
return h(
|
return h(
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
{
|
{
|
||||||
key: `common${rpc}`,
|
key: `common${rpc}`,
|
||||||
closeMenu: () => this.props.hideNetworkDropdown(),
|
closeMenu: () => this.props.hideNetworkDropdown(),
|
||||||
onClick: () => props.setRpcTarget(rpc),
|
onClick: () => props.setRpcTarget(rpc, chainId, ticker, nickname),
|
||||||
style: {
|
style: {
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
lineHeight: '20px',
|
lineHeight: '20px',
|
||||||
@ -302,7 +308,7 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) {
|
|||||||
style: {
|
style: {
|
||||||
color: currentRpcTarget ? '#ffffff' : '#9b9b9b',
|
color: currentRpcTarget ? '#ffffff' : '#9b9b9b',
|
||||||
},
|
},
|
||||||
}, rpc),
|
}, nickname || rpc),
|
||||||
h('i.fa.fa-times.delete',
|
h('i.fa.fa-times.delete',
|
||||||
{
|
{
|
||||||
onClick: (e) => {
|
onClick: (e) => {
|
||||||
@ -317,8 +323,9 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NetworkDropdown.prototype.renderCustomOption = function (provider) {
|
NetworkDropdown.prototype.renderCustomOption = function (provider) {
|
||||||
const { rpcTarget, type } = provider
|
const { rpcTarget, type, ticker, nickname } = provider
|
||||||
const props = this.props
|
const props = this.props
|
||||||
|
const network = props.network
|
||||||
|
|
||||||
if (type !== 'rpc') return null
|
if (type !== 'rpc') return null
|
||||||
|
|
||||||
@ -332,7 +339,7 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
{
|
{
|
||||||
key: rpcTarget,
|
key: rpcTarget,
|
||||||
onClick: () => props.setRpcTarget(rpcTarget),
|
onClick: () => props.setRpcTarget(rpcTarget, network, ticker, nickname),
|
||||||
closeMenu: () => this.props.hideNetworkDropdown(),
|
closeMenu: () => this.props.hideNetworkDropdown(),
|
||||||
style: {
|
style: {
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
@ -347,7 +354,7 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) {
|
|||||||
style: {
|
style: {
|
||||||
color: '#ffffff',
|
color: '#ffffff',
|
||||||
},
|
},
|
||||||
}, rpcTarget),
|
}, nickname || rpcTarget),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,8 @@ describe('Network Dropdown', () => {
|
|||||||
provider: {
|
provider: {
|
||||||
'type': 'test',
|
'type': 'test',
|
||||||
},
|
},
|
||||||
frequentRpcList: [
|
frequentRpcListDetail: [
|
||||||
'http://localhost:7545',
|
{ rpcUrl: 'http://localhost:7545' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
appState: {
|
appState: {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const { Component } = require('react')
|
const { Component } = require('react')
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
|
const connect = require('react-redux').connect
|
||||||
const { inherits } = require('util')
|
const { inherits } = require('util')
|
||||||
const {
|
const {
|
||||||
formatBalance,
|
formatBalance,
|
||||||
@ -8,7 +9,12 @@ const {
|
|||||||
const Tooltip = require('./tooltip.js')
|
const Tooltip = require('./tooltip.js')
|
||||||
const FiatValue = require('./fiat-value.js')
|
const FiatValue = require('./fiat-value.js')
|
||||||
|
|
||||||
module.exports = EthBalanceComponent
|
module.exports = connect(mapStateToProps)(EthBalanceComponent)
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
return {
|
||||||
|
ticker: state.metamask.ticker,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inherits(EthBalanceComponent, Component)
|
inherits(EthBalanceComponent, Component)
|
||||||
function EthBalanceComponent () {
|
function EthBalanceComponent () {
|
||||||
@ -17,9 +23,9 @@ function EthBalanceComponent () {
|
|||||||
|
|
||||||
EthBalanceComponent.prototype.render = function () {
|
EthBalanceComponent.prototype.render = function () {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
const { value, style, width, needsParse = true } = props
|
const { ticker, value, style, width, needsParse = true } = props
|
||||||
|
|
||||||
const formattedValue = value ? formatBalance(value, 6, needsParse) : '...'
|
const formattedValue = value ? formatBalance(value, 6, needsParse, ticker) : '...'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
const Component = require('react').Component
|
|
||||||
const h = require('react-hyperscript')
|
|
||||||
const inherits = require('util').inherits
|
|
||||||
const connect = require('react-redux').connect
|
|
||||||
const isNode = require('detect-node')
|
|
||||||
const findDOMNode = require('react-dom').findDOMNode
|
|
||||||
const jazzicon = require('jazzicon')
|
|
||||||
const iconFactoryGen = require('../../lib/icon-factory')
|
|
||||||
const iconFactory = iconFactoryGen(jazzicon)
|
|
||||||
const { toDataUrl } = require('../../lib/blockies')
|
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(IdenticonComponent)
|
|
||||||
|
|
||||||
inherits(IdenticonComponent, Component)
|
|
||||||
function IdenticonComponent () {
|
|
||||||
Component.call(this)
|
|
||||||
|
|
||||||
this.defaultDiameter = 46
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
|
||||||
return {
|
|
||||||
useBlockie: state.metamask.useBlockie,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IdenticonComponent.prototype.render = function () {
|
|
||||||
var props = this.props
|
|
||||||
const { className = '', address, image } = props
|
|
||||||
var diameter = props.diameter || this.defaultDiameter
|
|
||||||
const style = {
|
|
||||||
height: diameter,
|
|
||||||
width: diameter,
|
|
||||||
borderRadius: diameter / 2,
|
|
||||||
}
|
|
||||||
if (image) {
|
|
||||||
return h('img', {
|
|
||||||
className: `${className} identicon`,
|
|
||||||
src: image,
|
|
||||||
style: {
|
|
||||||
...style,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else if (address) {
|
|
||||||
return h('div', {
|
|
||||||
className: `${className} identicon`,
|
|
||||||
key: 'identicon-' + address,
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
flexShrink: 0,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
...style,
|
|
||||||
overflow: 'hidden',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return h('img.balance-icon', {
|
|
||||||
className,
|
|
||||||
src: './images/eth_logo.svg',
|
|
||||||
style: {
|
|
||||||
...style,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IdenticonComponent.prototype.componentDidMount = function () {
|
|
||||||
var props = this.props
|
|
||||||
const { address, useBlockie } = props
|
|
||||||
|
|
||||||
if (!address) return
|
|
||||||
|
|
||||||
if (!isNode) {
|
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
var container = findDOMNode(this)
|
|
||||||
|
|
||||||
const diameter = props.diameter || this.defaultDiameter
|
|
||||||
|
|
||||||
if (useBlockie) {
|
|
||||||
_generateBlockie(container, address, diameter)
|
|
||||||
} else {
|
|
||||||
_generateJazzicon(container, address, diameter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IdenticonComponent.prototype.componentDidUpdate = function () {
|
|
||||||
var props = this.props
|
|
||||||
const { address, useBlockie } = props
|
|
||||||
|
|
||||||
if (!address) return
|
|
||||||
|
|
||||||
if (!isNode) {
|
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
var container = findDOMNode(this)
|
|
||||||
|
|
||||||
var children = container.children
|
|
||||||
for (var i = 0; i < children.length; i++) {
|
|
||||||
container.removeChild(children[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
const diameter = props.diameter || this.defaultDiameter
|
|
||||||
|
|
||||||
if (useBlockie) {
|
|
||||||
_generateBlockie(container, address, diameter)
|
|
||||||
} else {
|
|
||||||
_generateJazzicon(container, address, diameter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _generateBlockie (container, address, diameter) {
|
|
||||||
const img = new Image()
|
|
||||||
img.src = toDataUrl(address)
|
|
||||||
img.height = diameter
|
|
||||||
img.width = diameter
|
|
||||||
container.appendChild(img)
|
|
||||||
}
|
|
||||||
|
|
||||||
function _generateJazzicon (container, address, diameter) {
|
|
||||||
const img = iconFactory.iconForAddress(address, diameter)
|
|
||||||
container.appendChild(img)
|
|
||||||
}
|
|
99
ui/app/components/identicon/identicon.component.js
Normal file
99
ui/app/components/identicon/identicon.component.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import React, { PureComponent } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import { toDataUrl } from '../../../lib/blockies'
|
||||||
|
import contractMap from 'eth-contract-metadata'
|
||||||
|
import { checksumAddress } from '../../../app/util'
|
||||||
|
import Jazzicon from '../jazzicon'
|
||||||
|
|
||||||
|
const getStyles = diameter => (
|
||||||
|
{
|
||||||
|
height: diameter,
|
||||||
|
width: diameter,
|
||||||
|
borderRadius: diameter / 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default class Identicon extends PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
address: PropTypes.string,
|
||||||
|
className: PropTypes.string,
|
||||||
|
diameter: PropTypes.number,
|
||||||
|
image: PropTypes.string,
|
||||||
|
useBlockie: PropTypes.bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
diameter: 46,
|
||||||
|
}
|
||||||
|
|
||||||
|
renderImage () {
|
||||||
|
const { className, diameter, image } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
className={classnames('identicon', className)}
|
||||||
|
src={image}
|
||||||
|
style={getStyles(diameter)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderJazzicon () {
|
||||||
|
const { address, className, diameter } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Jazzicon
|
||||||
|
address={address}
|
||||||
|
diameter={diameter}
|
||||||
|
className={classnames('identicon', className)}
|
||||||
|
style={getStyles(diameter)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBlockie () {
|
||||||
|
const { address, className, diameter } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classnames('identicon', className)}
|
||||||
|
style={getStyles(diameter)}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={toDataUrl(address)}
|
||||||
|
height={diameter}
|
||||||
|
width={diameter}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { className, address, image, diameter, useBlockie } = this.props
|
||||||
|
|
||||||
|
if (image) {
|
||||||
|
return this.renderImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address) {
|
||||||
|
const checksummedAddress = checksumAddress(address)
|
||||||
|
|
||||||
|
if (contractMap[checksummedAddress] && contractMap[checksummedAddress].logo) {
|
||||||
|
return this.renderJazzicon()
|
||||||
|
}
|
||||||
|
|
||||||
|
return useBlockie
|
||||||
|
? this.renderBlockie()
|
||||||
|
: this.renderJazzicon()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
className={classnames('balance-icon', className)}
|
||||||
|
src="./images/eth_logo.svg"
|
||||||
|
style={getStyles(diameter)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
12
ui/app/components/identicon/identicon.container.js
Normal file
12
ui/app/components/identicon/identicon.container.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { connect } from 'react-redux'
|
||||||
|
import Identicon from './identicon.component'
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const { metamask: { useBlockie } } = state
|
||||||
|
|
||||||
|
return {
|
||||||
|
useBlockie,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(Identicon)
|
1
ui/app/components/identicon/index.js
Normal file
1
ui/app/components/identicon/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './identicon.container'
|
7
ui/app/components/identicon/index.scss
Normal file
7
ui/app/components/identicon/index.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.identicon {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
@ -3,11 +3,9 @@ import assert from 'assert'
|
|||||||
import thunk from 'redux-thunk'
|
import thunk from 'redux-thunk'
|
||||||
import configureMockStore from 'redux-mock-store'
|
import configureMockStore from 'redux-mock-store'
|
||||||
import { mount } from 'enzyme'
|
import { mount } from 'enzyme'
|
||||||
|
import Identicon from '../identicon.component'
|
||||||
|
|
||||||
import IdenticonComponent from '../../../../../ui/app/components/identicon'
|
describe('Identicon', () => {
|
||||||
|
|
||||||
describe('Identicon Component', () => {
|
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
metamask: {
|
metamask: {
|
||||||
useBlockie: false,
|
useBlockie: false,
|
||||||
@ -19,18 +17,35 @@ describe('Identicon Component', () => {
|
|||||||
const store = mockStore(state)
|
const store = mockStore(state)
|
||||||
|
|
||||||
it('renders default eth_logo identicon with no props', () => {
|
it('renders default eth_logo identicon with no props', () => {
|
||||||
const wrapper = mount(<IdenticonComponent store={store}/>)
|
const wrapper = mount(
|
||||||
|
<Identicon store={store}/>
|
||||||
|
)
|
||||||
|
|
||||||
assert.equal(wrapper.find('img.balance-icon').prop('src'), './images/eth_logo.svg')
|
assert.equal(wrapper.find('img.balance-icon').prop('src'), './images/eth_logo.svg')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders custom image and add className props', () => {
|
it('renders custom image and add className props', () => {
|
||||||
const wrapper = mount(<IdenticonComponent store={store} className={'test-image'} image={'test-image'} />)
|
const wrapper = mount(
|
||||||
assert.equal(wrapper.find('img.test-image').prop('className'), 'test-image identicon')
|
<Identicon
|
||||||
|
store={store}
|
||||||
|
className="test-image"
|
||||||
|
image="test-image"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal(wrapper.find('img.test-image').prop('className'), 'identicon test-image')
|
||||||
assert.equal(wrapper.find('img.test-image').prop('src'), 'test-image')
|
assert.equal(wrapper.find('img.test-image').prop('src'), 'test-image')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders div with address prop', () => {
|
it('renders div with address prop', () => {
|
||||||
const wrapper = mount(<IdenticonComponent store={store} className={'test-address'} address={'0xTest'} />)
|
const wrapper = mount(
|
||||||
assert.equal(wrapper.find('div.test-address').prop('className'), 'test-address identicon')
|
<Identicon
|
||||||
|
store={store}
|
||||||
|
className="test-address"
|
||||||
|
address="0xTest"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal(wrapper.find('div.test-address').prop('className'), 'identicon test-address')
|
||||||
})
|
})
|
||||||
})
|
})
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
@import './export-text-container/index';
|
@import './export-text-container/index';
|
||||||
|
|
||||||
|
@import './identicon/index';
|
||||||
|
|
||||||
@import './info-box/index';
|
@import './info-box/index';
|
||||||
|
|
||||||
@import './menu-bar/index';
|
@import './menu-bar/index';
|
||||||
|
1
ui/app/components/jazzicon/index.js
Normal file
1
ui/app/components/jazzicon/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './jazzicon.component'
|
69
ui/app/components/jazzicon/jazzicon.component.js
Normal file
69
ui/app/components/jazzicon/jazzicon.component.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import React, { PureComponent } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import isNode from 'detect-node'
|
||||||
|
import { findDOMNode } from 'react-dom'
|
||||||
|
import jazzicon from 'jazzicon'
|
||||||
|
import iconFactoryGenerator from '../../../lib/icon-factory'
|
||||||
|
const iconFactory = iconFactoryGenerator(jazzicon)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around the jazzicon library to return a React component, as the library returns an
|
||||||
|
* HTMLDivElement which needs to be appended.
|
||||||
|
*/
|
||||||
|
export default class Jazzicon extends PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
address: PropTypes.string.isRequired,
|
||||||
|
className: PropTypes.string,
|
||||||
|
diameter: PropTypes.number,
|
||||||
|
style: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
diameter: 46,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
if (!isNode) {
|
||||||
|
this.appendJazzicon()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate (prevProps) {
|
||||||
|
const { address: prevAddress } = prevProps
|
||||||
|
const { address } = this.props
|
||||||
|
|
||||||
|
if (!isNode && address !== prevAddress) {
|
||||||
|
this.removeExistingChildren()
|
||||||
|
this.appendJazzicon()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeExistingChildren () {
|
||||||
|
// eslint-disable-next-line react/no-find-dom-node
|
||||||
|
const container = findDOMNode(this)
|
||||||
|
const { children } = container
|
||||||
|
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
container.removeChild(children[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendJazzicon () {
|
||||||
|
// eslint-disable-next-line react/no-find-dom-node
|
||||||
|
const container = findDOMNode(this)
|
||||||
|
const { address, diameter } = this.props
|
||||||
|
const image = iconFactory.iconForAddress(address, diameter)
|
||||||
|
container.appendChild(image)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { className, style } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={className}
|
||||||
|
style={style}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ const inherits = require('util').inherits
|
|||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const actions = require('../../actions')
|
const actions = require('../../actions')
|
||||||
const { getSelectedIdentity } = require('../../selectors')
|
const { getSelectedIdentity } = require('../../selectors')
|
||||||
const Identicon = require('../identicon')
|
import Identicon from '../identicon'
|
||||||
|
|
||||||
function mapStateToProps (state, ownProps) {
|
function mapStateToProps (state, ownProps) {
|
||||||
return {
|
return {
|
||||||
|
@ -4,7 +4,7 @@ const h = require('react-hyperscript')
|
|||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const actions = require('../../actions')
|
const actions = require('../../actions')
|
||||||
const Identicon = require('../identicon')
|
import Identicon from '../identicon'
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
return {
|
return {
|
||||||
|
@ -27,7 +27,6 @@ import TransactionConfirmed from './transaction-confirmed'
|
|||||||
import ConfirmCustomizeGasModal from './customize-gas'
|
import ConfirmCustomizeGasModal from './customize-gas'
|
||||||
import CancelTransaction from './cancel-transaction'
|
import CancelTransaction from './cancel-transaction'
|
||||||
import WelcomeBeta from './welcome-beta'
|
import WelcomeBeta from './welcome-beta'
|
||||||
import TransactionDetails from './transaction-details'
|
|
||||||
import RejectTransactions from './reject-transactions'
|
import RejectTransactions from './reject-transactions'
|
||||||
|
|
||||||
const modalContainerBaseStyle = {
|
const modalContainerBaseStyle = {
|
||||||
@ -366,19 +365,6 @@ const MODALS = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
TRANSACTION_DETAILS: {
|
|
||||||
contents: h(TransactionDetails),
|
|
||||||
mobileModalStyle: {
|
|
||||||
...modalContainerMobileStyle,
|
|
||||||
},
|
|
||||||
laptopModalStyle: {
|
|
||||||
...modalContainerLaptopStyle,
|
|
||||||
},
|
|
||||||
contentStyle: {
|
|
||||||
borderRadius: '8px',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
REJECT_TRANSACTIONS: {
|
REJECT_TRANSACTIONS: {
|
||||||
contents: h(RejectTransactions),
|
contents: h(RejectTransactions),
|
||||||
mobileModalStyle: {
|
mobileModalStyle: {
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export { default } from './transaction-details.container'
|
|
@ -1,54 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Modal from '../../modal'
|
|
||||||
import TransactionListItemDetails from '../../transaction-list-item-details'
|
|
||||||
import { hexToDecimal } from '../../../helpers/conversions.util'
|
|
||||||
|
|
||||||
export default class TransactionConfirmed extends PureComponent {
|
|
||||||
static contextTypes = {
|
|
||||||
t: PropTypes.func,
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
hideModal: PropTypes.func,
|
|
||||||
transaction: PropTypes.object,
|
|
||||||
onRetry: PropTypes.func,
|
|
||||||
showRetry: PropTypes.bool,
|
|
||||||
onCancel: PropTypes.func,
|
|
||||||
showCancel: PropTypes.bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSubmit = () => {
|
|
||||||
this.props.hideModal()
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRetry = () => {
|
|
||||||
const { onRetry, hideModal } = this.props
|
|
||||||
|
|
||||||
Promise.resolve(onRetry()).then(() => hideModal())
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { t } = this.context
|
|
||||||
const { transaction, showRetry, onCancel, showCancel } = this.props
|
|
||||||
const { txParams: { nonce } = {} } = transaction
|
|
||||||
const decimalNonce = nonce && hexToDecimal(nonce)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
onSubmit={this.handleSubmit}
|
|
||||||
onClose={this.handleSubmit}
|
|
||||||
submitText={t('ok')}
|
|
||||||
headerText={t('transactionWithNonce', [`#${decimalNonce}`])}
|
|
||||||
>
|
|
||||||
<TransactionListItemDetails
|
|
||||||
transaction={transaction}
|
|
||||||
onRetry={this.handleRetry}
|
|
||||||
showRetry={showRetry}
|
|
||||||
onCancel={() => onCancel()}
|
|
||||||
showCancel={showCancel}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
import TransactionDetails from './transaction-details.component'
|
|
||||||
import withModalProps from '../../../higher-order-components/with-modal-props'
|
|
||||||
|
|
||||||
export default withModalProps(TransactionDetails)
|
|
@ -41,7 +41,7 @@ export default class NetworkDisplay extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { network, provider: { type } } = this.props
|
const { network, provider: { type, nickname } } = this.props
|
||||||
const networkClass = networkToClassHash[network]
|
const networkClass = networkToClassHash[network]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -61,7 +61,7 @@ export default class NetworkDisplay extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div className="network-display__name">
|
<div className="network-display__name">
|
||||||
{ this.context.t(type) }
|
{ type === 'rpc' && nickname ? nickname : this.context.t(type) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -23,9 +23,10 @@ Network.prototype.render = function () {
|
|||||||
const props = this.props
|
const props = this.props
|
||||||
const context = this.context
|
const context = this.context
|
||||||
const networkNumber = props.network
|
const networkNumber = props.network
|
||||||
let providerName
|
let providerName, providerNick
|
||||||
try {
|
try {
|
||||||
providerName = props.provider.type
|
providerName = props.provider.type
|
||||||
|
providerNick = props.provider.nickname || ''
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
providerName = null
|
providerName = null
|
||||||
}
|
}
|
||||||
@ -131,7 +132,7 @@ Network.prototype.render = function () {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
h('.network-name', context.t('privateNetwork')),
|
h('.network-name', providerNick || context.t('privateNetwork')),
|
||||||
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
|
h('i.fa.fa-chevron-down.fa-lg.network-caret'),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
if (simulationFails) {
|
if (simulationFails) {
|
||||||
return {
|
return {
|
||||||
valid: true,
|
valid: true,
|
||||||
errorKey: TRANSACTION_ERROR_KEY,
|
errorKey: simulationFails.errorKey ? simulationFails.errorKey : TRANSACTION_ERROR_KEY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,9 @@
|
|||||||
color: $crimson;
|
color: $crimson;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__rpc-save-button {
|
&__advanced-link {
|
||||||
align-self: flex-end;
|
color: $curious-blue;
|
||||||
padding: 5px;
|
padding-left: 5px;
|
||||||
text-transform: uppercase;
|
|
||||||
color: $dusty-gray;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__rpc-save-button {
|
&__rpc-save-button {
|
||||||
@ -19,6 +16,9 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: $dusty-gray;
|
color: $dusty-gray;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
width: 25%;
|
||||||
|
min-width: 80px;
|
||||||
|
height: 33px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__button--red {
|
&__button--red {
|
||||||
|
@ -55,12 +55,17 @@ export default class SettingsTab extends PureComponent {
|
|||||||
sendHexData: PropTypes.bool,
|
sendHexData: PropTypes.bool,
|
||||||
currentCurrency: PropTypes.string,
|
currentCurrency: PropTypes.string,
|
||||||
conversionDate: PropTypes.number,
|
conversionDate: PropTypes.number,
|
||||||
useETHAsPrimaryCurrency: PropTypes.bool,
|
nativeCurrency: PropTypes.string,
|
||||||
setUseETHAsPrimaryCurrencyPreference: PropTypes.func,
|
useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
|
||||||
|
setUseNativeCurrencyAsPrimaryCurrencyPreference: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
newRpc: '',
|
newRpc: '',
|
||||||
|
chainId: '',
|
||||||
|
showOptions: false,
|
||||||
|
ticker: '',
|
||||||
|
nickname: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCurrentConversion () {
|
renderCurrentConversion () {
|
||||||
@ -121,37 +126,98 @@ export default class SettingsTab extends PureComponent {
|
|||||||
|
|
||||||
renderNewRpcUrl () {
|
renderNewRpcUrl () {
|
||||||
const { t } = this.context
|
const { t } = this.context
|
||||||
const { newRpc } = this.state
|
const { newRpc, chainId, ticker, nickname } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="settings-page__content-row">
|
<div className="settings-page__content-row">
|
||||||
<div className="settings-page__content-item">
|
<div className="settings-page__content-item">
|
||||||
<span>{ t('newRPC') }</span>
|
<span>{ t('newNetwork') }</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-page__content-item">
|
<div className="settings-page__content-item">
|
||||||
<div className="settings-page__content-item-col">
|
<div className="settings-page__content-item-col">
|
||||||
<TextField
|
<TextField
|
||||||
type="text"
|
type="text"
|
||||||
id="new-rpc"
|
id="new-rpc"
|
||||||
placeholder={t('newRPC')}
|
placeholder={t('rpcURL')}
|
||||||
value={newRpc}
|
value={newRpc}
|
||||||
onChange={e => this.setState({ newRpc: e.target.value })}
|
onChange={e => this.setState({ newRpc: e.target.value })}
|
||||||
onKeyPress={e => {
|
onKeyPress={e => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
this.validateRpc(newRpc)
|
this.validateRpc(newRpc, chainId, ticker, nickname)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
fullWidth
|
fullWidth
|
||||||
margin="none"
|
margin="dense"
|
||||||
/>
|
/>
|
||||||
<div
|
<TextField
|
||||||
className="settings-tab__rpc-save-button"
|
type="text"
|
||||||
onClick={e => {
|
id="chainid"
|
||||||
e.preventDefault()
|
placeholder={t('optionalChainId')}
|
||||||
this.validateRpc(newRpc)
|
value={chainId}
|
||||||
|
onChange={e => this.setState({ chainId: e.target.value })}
|
||||||
|
onKeyPress={e => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.validateRpc(newRpc, chainId, ticker, nickname)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
style={{
|
||||||
{ t('save') }
|
display: this.state.showOptions ? null : 'none',
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
margin="dense"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
type="text"
|
||||||
|
id="ticker"
|
||||||
|
placeholder={t('optionalSymbol')}
|
||||||
|
value={ticker}
|
||||||
|
onChange={e => this.setState({ ticker: e.target.value })}
|
||||||
|
onKeyPress={e => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.validateRpc(newRpc, chainId, ticker, nickname)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
display: this.state.showOptions ? null : 'none',
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
margin="dense"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
type="text"
|
||||||
|
id="nickname"
|
||||||
|
placeholder={t('optionalNickname')}
|
||||||
|
value={nickname}
|
||||||
|
onChange={e => this.setState({ nickname: e.target.value })}
|
||||||
|
onKeyPress={e => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.validateRpc(newRpc, chainId, ticker, nickname)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
display: this.state.showOptions ? null : 'none',
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
margin="dense"
|
||||||
|
/>
|
||||||
|
<div className="flex-row flex-align-center space-between">
|
||||||
|
<span className="settings-tab__advanced-link"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
this.setState({ showOptions: !this.state.showOptions })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ t(this.state.showOptions ? 'hideAdvancedOptions' : 'showAdvancedOptions') }
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
className="button btn-primary settings-tab__rpc-save-button"
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
this.validateRpc(newRpc, chainId, ticker, nickname)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ t('save') }
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -159,11 +225,11 @@ export default class SettingsTab extends PureComponent {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
validateRpc (newRpc) {
|
validateRpc (newRpc, chainId, ticker = 'ETH', nickname) {
|
||||||
const { setRpcTarget, displayWarning } = this.props
|
const { setRpcTarget, displayWarning } = this.props
|
||||||
|
|
||||||
if (validUrl.isWebUri(newRpc)) {
|
if (validUrl.isWebUri(newRpc)) {
|
||||||
setRpcTarget(newRpc)
|
setRpcTarget(newRpc, chainId, ticker, nickname)
|
||||||
} else {
|
} else {
|
||||||
const appendedRpc = `http://${newRpc}`
|
const appendedRpc = `http://${newRpc}`
|
||||||
|
|
||||||
@ -341,9 +407,13 @@ export default class SettingsTab extends PureComponent {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderUseEthAsPrimaryCurrency () {
|
renderUsePrimaryCurrencyOptions () {
|
||||||
const { t } = this.context
|
const { t } = this.context
|
||||||
const { useETHAsPrimaryCurrency, setUseETHAsPrimaryCurrencyPreference } = this.props
|
const {
|
||||||
|
nativeCurrency,
|
||||||
|
setUseNativeCurrencyAsPrimaryCurrencyPreference,
|
||||||
|
useNativeCurrencyAsPrimaryCurrency,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="settings-page__content-row">
|
<div className="settings-page__content-row">
|
||||||
@ -359,23 +429,23 @@ export default class SettingsTab extends PureComponent {
|
|||||||
<div className="settings-tab__radio-button">
|
<div className="settings-tab__radio-button">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
id="eth-primary-currency"
|
id="native-primary-currency"
|
||||||
onChange={() => setUseETHAsPrimaryCurrencyPreference(true)}
|
onChange={() => setUseNativeCurrencyAsPrimaryCurrencyPreference(true)}
|
||||||
checked={Boolean(useETHAsPrimaryCurrency)}
|
checked={Boolean(useNativeCurrencyAsPrimaryCurrency)}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor="eth-primary-currency"
|
htmlFor="native-primary-currency"
|
||||||
className="settings-tab__radio-label"
|
className="settings-tab__radio-label"
|
||||||
>
|
>
|
||||||
{ t('eth') }
|
{ nativeCurrency }
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-tab__radio-button">
|
<div className="settings-tab__radio-button">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
id="fiat-primary-currency"
|
id="fiat-primary-currency"
|
||||||
onChange={() => setUseETHAsPrimaryCurrencyPreference(false)}
|
onChange={() => setUseNativeCurrencyAsPrimaryCurrencyPreference(false)}
|
||||||
checked={!useETHAsPrimaryCurrency}
|
checked={!useNativeCurrencyAsPrimaryCurrency}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor="fiat-primary-currency"
|
htmlFor="fiat-primary-currency"
|
||||||
@ -398,7 +468,7 @@ export default class SettingsTab extends PureComponent {
|
|||||||
<div className="settings-page__content">
|
<div className="settings-page__content">
|
||||||
{ warning && <div className="settings-tab__error">{ warning }</div> }
|
{ warning && <div className="settings-tab__error">{ warning }</div> }
|
||||||
{ this.renderCurrentConversion() }
|
{ this.renderCurrentConversion() }
|
||||||
{ this.renderUseEthAsPrimaryCurrency() }
|
{ this.renderUsePrimaryCurrencyOptions() }
|
||||||
{ this.renderCurrentLocale() }
|
{ this.renderCurrentLocale() }
|
||||||
{ this.renderNewRpcUrl() }
|
{ this.renderNewRpcUrl() }
|
||||||
{ this.renderStateLogs() }
|
{ this.renderStateLogs() }
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
updateCurrentLocale,
|
updateCurrentLocale,
|
||||||
setFeatureFlag,
|
setFeatureFlag,
|
||||||
showModal,
|
showModal,
|
||||||
setUseETHAsPrimaryCurrencyPreference,
|
setUseNativeCurrencyAsPrimaryCurrencyPreference,
|
||||||
} from '../../../../actions'
|
} from '../../../../actions'
|
||||||
import { preferencesSelector } from '../../../../selectors'
|
import { preferencesSelector } from '../../../../selectors'
|
||||||
|
|
||||||
@ -20,13 +20,14 @@ const mapStateToProps = state => {
|
|||||||
const {
|
const {
|
||||||
currentCurrency,
|
currentCurrency,
|
||||||
conversionDate,
|
conversionDate,
|
||||||
|
nativeCurrency,
|
||||||
useBlockie,
|
useBlockie,
|
||||||
featureFlags: { sendHexData } = {},
|
featureFlags: { sendHexData } = {},
|
||||||
provider = {},
|
provider = {},
|
||||||
isMascara,
|
isMascara,
|
||||||
currentLocale,
|
currentLocale,
|
||||||
} = metamask
|
} = metamask
|
||||||
const { useETHAsPrimaryCurrency } = preferencesSelector(state)
|
const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
warning,
|
warning,
|
||||||
@ -34,17 +35,18 @@ const mapStateToProps = state => {
|
|||||||
currentLocale,
|
currentLocale,
|
||||||
currentCurrency,
|
currentCurrency,
|
||||||
conversionDate,
|
conversionDate,
|
||||||
|
nativeCurrency,
|
||||||
useBlockie,
|
useBlockie,
|
||||||
sendHexData,
|
sendHexData,
|
||||||
provider,
|
provider,
|
||||||
useETHAsPrimaryCurrency,
|
useNativeCurrencyAsPrimaryCurrency,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
setCurrentCurrency: currency => dispatch(setCurrentCurrency(currency)),
|
setCurrentCurrency: currency => dispatch(setCurrentCurrency(currency)),
|
||||||
setRpcTarget: newRpc => dispatch(setRpcTarget(newRpc)),
|
setRpcTarget: (newRpc, chainId, ticker, nickname) => dispatch(setRpcTarget(newRpc, chainId, ticker, nickname)),
|
||||||
displayWarning: warning => dispatch(displayWarning(warning)),
|
displayWarning: warning => dispatch(displayWarning(warning)),
|
||||||
revealSeedConfirmation: () => dispatch(revealSeedConfirmation()),
|
revealSeedConfirmation: () => dispatch(revealSeedConfirmation()),
|
||||||
setUseBlockie: value => dispatch(setUseBlockie(value)),
|
setUseBlockie: value => dispatch(setUseBlockie(value)),
|
||||||
@ -54,8 +56,8 @@ const mapDispatchToProps = dispatch => {
|
|||||||
},
|
},
|
||||||
setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)),
|
setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)),
|
||||||
showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })),
|
showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })),
|
||||||
setUseETHAsPrimaryCurrencyPreference: value => {
|
setUseNativeCurrencyAsPrimaryCurrencyPreference: value => {
|
||||||
return dispatch(setUseETHAsPrimaryCurrencyPreference(value))
|
return dispatch(setUseNativeCurrencyAsPrimaryCurrencyPreference(value))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { connect } from 'react-redux'
|
|||||||
import {
|
import {
|
||||||
getConversionRate,
|
getConversionRate,
|
||||||
getCurrentCurrency,
|
getCurrentCurrency,
|
||||||
|
getNativeCurrency,
|
||||||
} from '../send.selectors.js'
|
} from '../send.selectors.js'
|
||||||
import AccountListItem from './account-list-item.component'
|
import AccountListItem from './account-list-item.component'
|
||||||
|
|
||||||
@ -11,5 +12,6 @@ function mapStateToProps (state) {
|
|||||||
return {
|
return {
|
||||||
conversionRate: getConversionRate(state),
|
conversionRate: getConversionRate(state),
|
||||||
currentCurrency: getCurrentCurrency(state),
|
currentCurrency: getCurrentCurrency(state),
|
||||||
|
nativeCurrency: getNativeCurrency(state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ describe('AccountListItem Component', function () {
|
|||||||
className={'mockClassName'}
|
className={'mockClassName'}
|
||||||
conversionRate={4}
|
conversionRate={4}
|
||||||
currentCurrency={'mockCurrentyCurrency'}
|
currentCurrency={'mockCurrentyCurrency'}
|
||||||
|
nativeCurrency={'ETH'}
|
||||||
displayAddress={false}
|
displayAddress={false}
|
||||||
displayBalance={false}
|
displayBalance={false}
|
||||||
handleClick={propsMethodSpies.handleClick}
|
handleClick={propsMethodSpies.handleClick}
|
||||||
|
@ -13,6 +13,7 @@ proxyquire('../account-list-item.container.js', {
|
|||||||
'../send.selectors.js': {
|
'../send.selectors.js': {
|
||||||
getConversionRate: (s) => `mockConversionRate:${s}`,
|
getConversionRate: (s) => `mockConversionRate:${s}`,
|
||||||
getCurrentCurrency: (s) => `mockCurrentCurrency:${s}`,
|
getCurrentCurrency: (s) => `mockCurrentCurrency:${s}`,
|
||||||
|
getNativeCurrency: (s) => `mockNativeCurrency:${s}`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ describe('account-list-item container', () => {
|
|||||||
assert.deepEqual(mapStateToProps('mockState'), {
|
assert.deepEqual(mapStateToProps('mockState'), {
|
||||||
conversionRate: 'mockConversionRate:mockState',
|
conversionRate: 'mockConversionRate:mockState',
|
||||||
currentCurrency: 'mockCurrentCurrency:mockState',
|
currentCurrency: 'mockCurrentCurrency:mockState',
|
||||||
|
nativeCurrency: 'mockNativeCurrency:mockState',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -151,7 +151,6 @@ describe('SendAmountRow Component', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should render a UserPreferencedTokenInput as the second child of the SendRowWrapper', () => {
|
it('should render a UserPreferencedTokenInput as the second child of the SendRowWrapper', () => {
|
||||||
console.log('HI', wrapper.find(SendRowWrapper).childAt(1))
|
|
||||||
assert(wrapper.find(SendRowWrapper).childAt(1).is(UserPreferencedTokenInput))
|
assert(wrapper.find(SendRowWrapper).childAt(1).is(UserPreferencedTokenInput))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ const selectors = {
|
|||||||
getCurrentNetwork,
|
getCurrentNetwork,
|
||||||
getCurrentViewContext,
|
getCurrentViewContext,
|
||||||
getForceGasMin,
|
getForceGasMin,
|
||||||
|
getNativeCurrency,
|
||||||
getGasLimit,
|
getGasLimit,
|
||||||
getGasPrice,
|
getGasPrice,
|
||||||
getGasPriceFromRecentBlocks,
|
getGasPriceFromRecentBlocks,
|
||||||
@ -111,6 +112,10 @@ function getCurrentCurrency (state) {
|
|||||||
return state.metamask.currentCurrency
|
return state.metamask.currentCurrency
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getNativeCurrency (state) {
|
||||||
|
return state.metamask.nativeCurrency
|
||||||
|
}
|
||||||
|
|
||||||
function getCurrentNetwork (state) {
|
function getCurrentNetwork (state) {
|
||||||
return state.metamask.network
|
return state.metamask.network
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,9 @@ async function estimateGas ({
|
|||||||
// if recipient has no code, gas is 21k max:
|
// if recipient has no code, gas is 21k max:
|
||||||
if (!selectedToken && !data) {
|
if (!selectedToken && !data) {
|
||||||
const code = Boolean(to) && await global.eth.getCode(to)
|
const code = Boolean(to) && await global.eth.getCode(to)
|
||||||
if (!code || code === '0x') {
|
// Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
|
||||||
|
const codeIsEmpty = !code || code === '0x' || code === '0x0'
|
||||||
|
if (codeIsEmpty) {
|
||||||
return SIMPLE_GAS_COST
|
return SIMPLE_GAS_COST
|
||||||
}
|
}
|
||||||
} else if (selectedToken && !to) {
|
} else if (selectedToken && !to) {
|
||||||
|
@ -26,6 +26,7 @@ module.exports = {
|
|||||||
'currentCurrency': 'USD',
|
'currentCurrency': 'USD',
|
||||||
'conversionRate': 1200.88200327,
|
'conversionRate': 1200.88200327,
|
||||||
'conversionDate': 1489013762,
|
'conversionDate': 1489013762,
|
||||||
|
'nativeCurrency': 'ETH',
|
||||||
'noActiveNotices': true,
|
'noActiveNotices': true,
|
||||||
'frequentRpcList': [],
|
'frequentRpcList': [],
|
||||||
'network': '3',
|
'network': '3',
|
||||||
|
@ -12,6 +12,7 @@ const {
|
|||||||
getCurrentCurrency,
|
getCurrentCurrency,
|
||||||
getCurrentNetwork,
|
getCurrentNetwork,
|
||||||
getCurrentViewContext,
|
getCurrentViewContext,
|
||||||
|
getNativeCurrency,
|
||||||
getForceGasMin,
|
getForceGasMin,
|
||||||
getGasLimit,
|
getGasLimit,
|
||||||
getGasPrice,
|
getGasPrice,
|
||||||
@ -178,6 +179,15 @@ describe('send selectors', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('getNativeCurrency()', () => {
|
||||||
|
it('should return the ticker symbol of the selected network', () => {
|
||||||
|
assert.equal(
|
||||||
|
getNativeCurrency(mockState),
|
||||||
|
'ETH'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('getCurrentNetwork()', () => {
|
describe('getCurrentNetwork()', () => {
|
||||||
it('should return the id of the currently selected network', () => {
|
it('should return the id of the currently selected network', () => {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user