mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge branch 'develop' of github.com:MetaMask/metamask-extension into HowardBraham-develop
This commit is contained in:
commit
9b42416fc0
@ -324,7 +324,7 @@ jobs:
|
||||
command: >
|
||||
git config user.name metamaskbot &&
|
||||
git config user.email admin@metamask.io &&
|
||||
gh-pages -d docs/jsdocs
|
||||
npm run publish-docs
|
||||
|
||||
test-unit:
|
||||
docker:
|
||||
|
@ -3,6 +3,8 @@
|
||||
## Current Develop Branch
|
||||
|
||||
- [#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
|
||||
- [#5559](https://github.com/MetaMask/metamask-extension/pull/5559) Localize language names in translation select list
|
||||
|
||||
## 4.16.0 Wednesday October 17 2018
|
||||
|
||||
|
@ -1169,6 +1169,9 @@
|
||||
"transactionUpdatedGas": {
|
||||
"message": "Transaction updated with a gas price of $1 on $2."
|
||||
},
|
||||
"transactionErrored": {
|
||||
"message": "Transaction encountered an error."
|
||||
},
|
||||
"transactions": {
|
||||
"message": "transactions"
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
||||
[
|
||||
{ "code": "cs", "name": "Czech" },
|
||||
{ "code": "de", "name": "German" },
|
||||
{ "code": "cs", "name": "Čeština" },
|
||||
{ "code": "de", "name": "Deutsche" },
|
||||
{ "code": "en", "name": "English" },
|
||||
{ "code": "es", "name": "Spanish" },
|
||||
{ "code": "fr", "name": "French" },
|
||||
{ "code": "ht", "name": "Haitian Creole" },
|
||||
{ "code": "hn", "name": "Hindi" },
|
||||
{ "code": "it", "name": "Italian" },
|
||||
{ "code": "ja", "name": "Japanese" },
|
||||
{ "code": "ko", "name": "Korean" },
|
||||
{ "code": "nl", "name": "Dutch" },
|
||||
{ "code": "ph", "name": "Tagalog" },
|
||||
{ "code": "pl", "name": "Polish" },
|
||||
{ "code": "pt", "name": "Portuguese" },
|
||||
{ "code": "ru", "name": "Russian" },
|
||||
{ "code": "sl", "name": "Slovenian" },
|
||||
{ "code": "th", "name": "Thai" },
|
||||
{ "code": "tml", "name": "Tamil" },
|
||||
{ "code": "tr", "name": "Turkish" },
|
||||
{ "code": "vi", "name": "Vietnamese" },
|
||||
{ "code": "zh_CN", "name": "Chinese (Simplified)" },
|
||||
{ "code": "zh_TW", "name": "Chinese (Traditional)" }
|
||||
{ "code": "es", "name": "Español" },
|
||||
{ "code": "fr", "name": "Français" },
|
||||
{ "code": "ht", "name": "Kreyòl ayisyen" },
|
||||
{ "code": "hn", "name": "हिन्दी" },
|
||||
{ "code": "it", "name": "Italiano" },
|
||||
{ "code": "ja", "name": "日本語" },
|
||||
{ "code": "ko", "name": "한국어" },
|
||||
{ "code": "nl", "name": "Nederlands" },
|
||||
{ "code": "ph", "name": "Pilipino" },
|
||||
{ "code": "pl", "name": "Polskie" },
|
||||
{ "code": "pt", "name": "Português" },
|
||||
{ "code": "ru", "name": "Русский" },
|
||||
{ "code": "sl", "name": "Slovenščina" },
|
||||
{ "code": "th", "name": "ไทย" },
|
||||
{ "code": "tml", "name": "தமிழ்" },
|
||||
{ "code": "tr", "name": "Türkçe" },
|
||||
{ "code": "vi", "name": "Tiếng Việt" },
|
||||
{ "code": "zh_CN", "name": "中文(简体)" },
|
||||
{ "code": "zh_TW", "name": "中文(繁體)" }
|
||||
]
|
||||
|
@ -435,7 +435,7 @@
|
||||
"message": "back-up woorden hebben alleen kleine letters"
|
||||
},
|
||||
"mainnet": {
|
||||
"message": "belangrijkste Ethereum-netwerk"
|
||||
"message": "Main Netwerk"
|
||||
},
|
||||
"message": {
|
||||
"message": "Bericht"
|
||||
|
@ -1,5 +1,9 @@
|
||||
<html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<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>
|
||||
<style>
|
||||
#div-logo {
|
||||
@ -31,5 +35,11 @@
|
||||
<div id="div-logo">
|
||||
<img id="logo" src="./images/loginglogo.svg">
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// redirect to 404 after one minute
|
||||
setTimeout(() => {
|
||||
location.href = './404.html'
|
||||
}, 60000)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -29,7 +29,7 @@ const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
|
||||
const EdgeEncryptor = require('./edge-encryptor')
|
||||
const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code')
|
||||
const getObjStructure = require('./lib/getObjStructure')
|
||||
const ipfsContent = require('./lib/ipfsContent.js')
|
||||
const setupEnsIpfsResolver = require('./lib/ens-ipfs/setup')
|
||||
|
||||
const {
|
||||
ENVIRONMENT_TYPE_POPUP,
|
||||
@ -58,7 +58,6 @@ const isIE = !!document.documentMode
|
||||
// Edge 20+
|
||||
const isEdge = !isIE && !!window.StyleMedia
|
||||
|
||||
let ipfsHandle
|
||||
let popupIsOpen = false
|
||||
let notificationIsOpen = false
|
||||
const openMetamaskTabsIDs = {}
|
||||
@ -164,7 +163,6 @@ async function initialize () {
|
||||
const initLangCode = await getFirstPreferredLangCode()
|
||||
await setupController(initState, initLangCode)
|
||||
log.debug('MetaMask initialization complete.')
|
||||
ipfsHandle = ipfsContent(initState.NetworkController.provider)
|
||||
}
|
||||
|
||||
//
|
||||
@ -269,10 +267,8 @@ function setupController (initState, initLangCode) {
|
||||
})
|
||||
global.metamaskController = controller
|
||||
|
||||
controller.networkController.on('networkDidChange', () => {
|
||||
ipfsHandle && ipfsHandle.remove()
|
||||
ipfsHandle = ipfsContent(controller.networkController.providerStore.getState())
|
||||
})
|
||||
const provider = controller.provider
|
||||
setupEnsIpfsResolver({ provider })
|
||||
|
||||
// report failed transactions to Sentry
|
||||
controller.txController.on(`tx:status-update`, (txId, status) => {
|
||||
|
@ -104,7 +104,7 @@ class PreferencesController {
|
||||
* @param {Function} - 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
|
||||
switch (type) {
|
||||
case 'ERC20':
|
||||
|
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)
|
||||
},
|
||||
}
|
||||
}
|
@ -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
package-lock.json
generated
2
package-lock.json
generated
@ -35267,4 +35267,4 @@
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -319,7 +319,7 @@ describe('Using MetaMask with an existing account', function () {
|
||||
|
||||
const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary'))
|
||||
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 () => {
|
||||
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)
|
||||
})
|
||||
})
|
||||
@ -420,7 +420,7 @@ describe('MetaMask', function () {
|
||||
|
||||
if (process.env.SELENIUM_BROWSER !== 'firefox') {
|
||||
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)
|
||||
|
||||
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'))
|
||||
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 delay(regularDelayMs)
|
||||
|
||||
@ -574,7 +574,7 @@ describe('MetaMask', function () {
|
||||
}, 10000)
|
||||
|
||||
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 firstTxAddress = await txAccounts[0].getText()
|
||||
@ -606,7 +606,7 @@ describe('MetaMask', function () {
|
||||
}, 10000)
|
||||
|
||||
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 driver.switchTo().window(extension)
|
||||
@ -616,9 +616,9 @@ describe('MetaMask', function () {
|
||||
const balance = await findElement(driver, By.css('.transaction-view-balance__primary-balance'))
|
||||
await delay(regularDelayMs)
|
||||
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()
|
||||
assert.ok(/^92.*ETH.*$/.test(tokenAmount))
|
||||
assert.ok(/^92.*\s*ETH.*$/.test(tokenAmount))
|
||||
await delay(regularDelayMs)
|
||||
}
|
||||
})
|
||||
@ -764,7 +764,7 @@ describe('MetaMask', function () {
|
||||
// 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
|
||||
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 () => {
|
||||
@ -798,7 +798,7 @@ describe('MetaMask', function () {
|
||||
|
||||
await findElements(driver, By.css('.transaction-list__pending-transactions'))
|
||||
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 delay(regularDelayMs)
|
||||
|
||||
@ -851,7 +851,7 @@ describe('MetaMask', function () {
|
||||
}, 10000)
|
||||
|
||||
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'))
|
||||
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 [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 delay(regularDelayMs)
|
||||
})
|
||||
@ -974,7 +974,7 @@ describe('MetaMask', function () {
|
||||
}, 10000)
|
||||
|
||||
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'))
|
||||
await driver.wait(until.elementTextMatches(txStatuses[0], /Approve/))
|
||||
})
|
||||
@ -1027,7 +1027,7 @@ describe('MetaMask', function () {
|
||||
|
||||
it('renders the balance for the chosen token', async () => {
|
||||
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)
|
||||
})
|
||||
})
|
||||
|
@ -11,7 +11,7 @@ sleep 5
|
||||
cd test/e2e/beta/
|
||||
rm -rf drizzle-test
|
||||
mkdir drizzle-test && cd drizzle-test
|
||||
npm install truffle
|
||||
sudo npm install -g truffle
|
||||
truffle unbox drizzle
|
||||
echo "Deploying contracts for Drizzle test..."
|
||||
truffle compile && truffle migrate
|
||||
|
@ -25,5 +25,5 @@ async function runCurrencyLocalizationTest (assert, done) {
|
||||
const txView = await queryAsync($, '.transaction-view')
|
||||
const heroBalance = await findAsync($(txView), '.transaction-view-balance__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')
|
||||
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, 1, 21000, '0.000021 ETH', '$0.03 USD')
|
||||
await customizeGas(assert, 500, 60000, '0.03 ETH', '$36.03 USD')
|
||||
await customizeGas(assert, 0, 21000, '0ETH', '$0.00USD')
|
||||
await customizeGas(assert, 1, 21000, '0.000021ETH', '$0.03USD')
|
||||
await customizeGas(assert, 500, 60000, '0.03ETH', '$36.03USD')
|
||||
|
||||
const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button')
|
||||
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
|
||||
|
@ -375,6 +375,11 @@ describe('preferences controller', function () {
|
||||
await preferencesController.requestWatchAsset(req, res, asy.next, asy.end)
|
||||
sandbox.assert.called(stubEnd)
|
||||
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 () {
|
||||
req.method = 'metamask_watchAsset'
|
||||
|
@ -6,10 +6,11 @@ const genAccountLink = require('etherscan-link').createAccountLink
|
||||
const connect = require('react-redux').connect
|
||||
const Dropdown = require('./dropdown').Dropdown
|
||||
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
||||
const Identicon = require('./identicon')
|
||||
const copyToClipboard = require('copy-to-clipboard')
|
||||
const { checksumAddress } = require('../util')
|
||||
|
||||
import Identicon from './identicon'
|
||||
|
||||
class AccountDropdowns extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
@ -7,10 +7,10 @@ const PropTypes = require('prop-types')
|
||||
const h = require('react-hyperscript')
|
||||
const actions = require('../../actions')
|
||||
const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu')
|
||||
const Identicon = require('../identicon')
|
||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums')
|
||||
const { getEnvironmentType } = require('../../../../app/scripts/lib/util')
|
||||
const Tooltip = require('../tooltip')
|
||||
import Identicon from '../identicon'
|
||||
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
|
||||
import { PRIMARY } from '../../constants/common'
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
const inherits = require('util').inherits
|
||||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const Identicon = require('./identicon')
|
||||
import Identicon from './identicon'
|
||||
const formatBalance = require('../util').formatBalance
|
||||
const addressSummary = require('../util').addressSummary
|
||||
|
||||
|
@ -2,13 +2,13 @@ import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
import { matchPath } from 'react-router-dom'
|
||||
import Identicon from '../identicon'
|
||||
|
||||
const {
|
||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
||||
ENVIRONMENT_TYPE_POPUP,
|
||||
} = require('../../../../app/scripts/lib/enums')
|
||||
const { DEFAULT_ROUTE, INITIALIZE_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes')
|
||||
const Identicon = require('../identicon')
|
||||
const NetworkIndicator = require('../network')
|
||||
|
||||
export default class AppHeader extends PureComponent {
|
||||
|
@ -2,8 +2,8 @@ const Component = require('react').Component
|
||||
const connect = require('react-redux').connect
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const TokenBalance = require('./token-balance')
|
||||
const Identicon = require('./identicon')
|
||||
import TokenBalance from './token-balance'
|
||||
import Identicon from './identicon'
|
||||
import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display'
|
||||
import { PRIMARY, SECONDARY } from '../constants/common'
|
||||
const { getAssetImages, conversionRateSelector, getCurrentCurrency} = require('../selectors')
|
||||
@ -81,11 +81,12 @@ BalanceComponent.prototype.renderBalance = function () {
|
||||
}
|
||||
|
||||
return h('div.flex-column.balance-display', {}, [
|
||||
h('div.token-amount', {}, h(UserPreferencedCurrencyDisplay, {
|
||||
h(UserPreferencedCurrencyDisplay, {
|
||||
className: 'token-amount',
|
||||
value: balanceValue,
|
||||
type: PRIMARY,
|
||||
ethNumberOfDecimals: 3,
|
||||
})),
|
||||
}),
|
||||
|
||||
showFiat && h(UserPreferencedCurrencyDisplay, {
|
||||
value: balanceValue,
|
||||
|
@ -10,6 +10,7 @@ export default class CurrencyDisplay extends PureComponent {
|
||||
prefix: PropTypes.string,
|
||||
prefixComponent: PropTypes.node,
|
||||
style: PropTypes.object,
|
||||
suffix: PropTypes.string,
|
||||
// Used in container
|
||||
currency: PropTypes.oneOf([ETH]),
|
||||
denomination: PropTypes.oneOf([GWEI]),
|
||||
@ -19,17 +20,25 @@ export default class CurrencyDisplay extends PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, displayValue, prefix, prefixComponent, style } = this.props
|
||||
const { className, displayValue, prefix, prefixComponent, style, suffix } = this.props
|
||||
const text = `${prefix || ''}${displayValue}`
|
||||
const title = `${text} ${suffix}`
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('currency-display-component', className)}
|
||||
style={style}
|
||||
title={text}
|
||||
title={title}
|
||||
>
|
||||
{ prefixComponent}
|
||||
<span className="currency-display-component__text">{ text }</span>
|
||||
{
|
||||
suffix && (
|
||||
<span className="currency-display-component__suffix">
|
||||
{ suffix }
|
||||
</span>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -26,14 +26,15 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||
const convertedValue = getValueFromWeiHex({
|
||||
value, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination,
|
||||
})
|
||||
const formattedValue = formatCurrency(convertedValue, toCurrency)
|
||||
const displayValue = hideLabel ? formattedValue : `${formattedValue} ${toCurrency.toUpperCase()}`
|
||||
const displayValue = formatCurrency(convertedValue, toCurrency)
|
||||
const suffix = hideLabel ? undefined : toCurrency.toUpperCase()
|
||||
|
||||
return {
|
||||
...restStateProps,
|
||||
...dispatchProps,
|
||||
...restOwnProps,
|
||||
displayValue,
|
||||
suffix,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,4 +7,8 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__suffix {
|
||||
padding-left: 4px;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,8 @@ describe('CurrencyDisplay container', () => {
|
||||
currency: 'usd',
|
||||
},
|
||||
result: {
|
||||
displayValue: '$2.80 USD',
|
||||
displayValue: '$2.80',
|
||||
suffix: 'USD',
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -53,7 +54,8 @@ describe('CurrencyDisplay container', () => {
|
||||
value: '0x2386f26fc10000',
|
||||
},
|
||||
result: {
|
||||
displayValue: '$2.80 USD',
|
||||
displayValue: '$2.80',
|
||||
suffix: 'USD',
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -63,7 +65,8 @@ describe('CurrencyDisplay container', () => {
|
||||
numberOfDecimals: 3,
|
||||
},
|
||||
result: {
|
||||
displayValue: '1.266 ETH',
|
||||
displayValue: '1.266',
|
||||
suffix: 'ETH',
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -75,6 +78,7 @@ describe('CurrencyDisplay container', () => {
|
||||
},
|
||||
result: {
|
||||
displayValue: '1.266',
|
||||
suffix: undefined,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -86,6 +90,7 @@ describe('CurrencyDisplay container', () => {
|
||||
},
|
||||
result: {
|
||||
displayValue: '1',
|
||||
suffix: undefined,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -97,6 +102,7 @@ describe('CurrencyDisplay container', () => {
|
||||
},
|
||||
result: {
|
||||
displayValue: '1000000000',
|
||||
suffix: undefined,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -108,6 +114,7 @@ describe('CurrencyDisplay container', () => {
|
||||
},
|
||||
result: {
|
||||
displayValue: '1e-9',
|
||||
suffix: undefined,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
@ -69,7 +69,7 @@ describe('CurrencyInput Component', () => {
|
||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH')
|
||||
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', () => {
|
||||
@ -100,7 +100,7 @@ describe('CurrencyInput Component', () => {
|
||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'USD')
|
||||
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')
|
||||
})
|
||||
})
|
||||
|
||||
@ -140,14 +140,14 @@ describe('CurrencyInput Component', () => {
|
||||
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
||||
assert.equal(currencyInputInstance.state.decimalValue, 0)
|
||||
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')
|
||||
assert.equal(input.props().value, 0)
|
||||
|
||||
input.simulate('change', { target: { value: 1 } })
|
||||
assert.equal(handleChangeSpy.callCount, 1)
|
||||
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.hexValue, 'de0b6b3a7640000')
|
||||
|
||||
@ -185,14 +185,14 @@ describe('CurrencyInput Component', () => {
|
||||
const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
|
||||
assert.equal(currencyInputInstance.state.decimalValue, 0)
|
||||
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')
|
||||
assert.equal(input.props().value, 0)
|
||||
|
||||
input.simulate('change', { target: { value: 1 } })
|
||||
assert.equal(handleChangeSpy.callCount, 1)
|
||||
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.hexValue, 'f602f2234d0ea')
|
||||
|
||||
|
@ -6,7 +6,7 @@ const genAccountLink = require('../../../../lib/account-link.js')
|
||||
const connect = require('react-redux').connect
|
||||
const Dropdown = require('./dropdown').Dropdown
|
||||
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
|
||||
const Identicon = require('../../identicon')
|
||||
import Identicon from '../../identicon'
|
||||
const { checksumAddress } = require('../../../util')
|
||||
const copyToClipboard = require('copy-to-clipboard')
|
||||
const { formatBalance } = require('../../../util')
|
||||
|
@ -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 configureMockStore from 'redux-mock-store'
|
||||
import { mount } from 'enzyme'
|
||||
import Identicon from '../identicon.component'
|
||||
|
||||
import IdenticonComponent from '../../../../../ui/app/components/identicon'
|
||||
|
||||
describe('Identicon Component', () => {
|
||||
|
||||
describe('Identicon', () => {
|
||||
const state = {
|
||||
metamask: {
|
||||
useBlockie: false,
|
||||
@ -19,18 +17,35 @@ describe('Identicon Component', () => {
|
||||
const store = mockStore(state)
|
||||
|
||||
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')
|
||||
})
|
||||
|
||||
it('renders custom image and add className props', () => {
|
||||
const wrapper = mount(<IdenticonComponent store={store} className={'test-image'} image={'test-image'} />)
|
||||
assert.equal(wrapper.find('img.test-image').prop('className'), 'test-image identicon')
|
||||
const wrapper = mount(
|
||||
<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')
|
||||
})
|
||||
|
||||
it('renders div with address prop', () => {
|
||||
const wrapper = mount(<IdenticonComponent store={store} className={'test-address'} address={'0xTest'} />)
|
||||
assert.equal(wrapper.find('div.test-address').prop('className'), 'test-address identicon')
|
||||
const wrapper = mount(
|
||||
<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 './identicon/index';
|
||||
|
||||
@import './info-box/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 actions = require('../../actions')
|
||||
const { getSelectedIdentity } = require('../../selectors')
|
||||
const Identicon = require('../identicon')
|
||||
import Identicon from '../identicon'
|
||||
|
||||
function mapStateToProps (state, ownProps) {
|
||||
return {
|
||||
|
@ -4,7 +4,7 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('../../actions')
|
||||
const Identicon = require('../identicon')
|
||||
import Identicon from '../identicon'
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
|
@ -27,7 +27,6 @@ import TransactionConfirmed from './transaction-confirmed'
|
||||
import ConfirmCustomizeGasModal from './customize-gas'
|
||||
import CancelTransaction from './cancel-transaction'
|
||||
import WelcomeBeta from './welcome-beta'
|
||||
import TransactionDetails from './transaction-details'
|
||||
import RejectTransactions from './reject-transactions'
|
||||
|
||||
const modalContainerBaseStyle = {
|
||||
@ -366,19 +365,6 @@ const MODALS = {
|
||||
},
|
||||
},
|
||||
|
||||
TRANSACTION_DETAILS: {
|
||||
contents: h(TransactionDetails),
|
||||
mobileModalStyle: {
|
||||
...modalContainerMobileStyle,
|
||||
},
|
||||
laptopModalStyle: {
|
||||
...modalContainerLaptopStyle,
|
||||
},
|
||||
contentStyle: {
|
||||
borderRadius: '8px',
|
||||
},
|
||||
},
|
||||
|
||||
REJECT_TRANSACTIONS: {
|
||||
contents: h(RejectTransactions),
|
||||
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)
|
@ -151,7 +151,6 @@ describe('SendAmountRow Component', function () {
|
||||
})
|
||||
|
||||
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))
|
||||
})
|
||||
|
||||
|
@ -2,7 +2,7 @@ const Component = require('react').Component
|
||||
const PropTypes = require('prop-types')
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const Identicon = require('./identicon')
|
||||
import Identicon from './identicon'
|
||||
const connect = require('react-redux').connect
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const classnames = require('classnames')
|
||||
|
@ -2,7 +2,7 @@ const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const connect = require('react-redux').connect
|
||||
const Identicon = require('./identicon')
|
||||
import Identicon from './identicon'
|
||||
const prefixForNetwork = require('../../lib/etherscan-prefix-for-network')
|
||||
const selectors = require('../selectors')
|
||||
const actions = require('../actions')
|
||||
|
@ -122,7 +122,7 @@ describe('TokenInput Component', () => {
|
||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC')
|
||||
assert.equal(wrapper.find('.unit-input__input').props().value, '1')
|
||||
assert.equal(wrapper.find('.currency-display-component').text(), '2 ETH')
|
||||
assert.equal(wrapper.find('.currency-display-component').text(), '2ETH')
|
||||
})
|
||||
|
||||
it('should render properly with a token value for fiat', () => {
|
||||
@ -157,7 +157,7 @@ describe('TokenInput Component', () => {
|
||||
assert.equal(wrapper.find('.unit-input__suffix').length, 1)
|
||||
assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC')
|
||||
assert.equal(wrapper.find('.unit-input__input').props().value, '1')
|
||||
assert.equal(wrapper.find('.currency-display-component').text(), '$462.12 USD')
|
||||
assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD')
|
||||
})
|
||||
})
|
||||
|
||||
@ -201,14 +201,14 @@ describe('TokenInput Component', () => {
|
||||
const tokenInputInstance = wrapper.find(TokenInput).at(0).instance()
|
||||
assert.equal(tokenInputInstance.state.decimalValue, 0)
|
||||
assert.equal(tokenInputInstance.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')
|
||||
assert.equal(input.props().value, 0)
|
||||
|
||||
input.simulate('change', { target: { value: 1 } })
|
||||
assert.equal(handleChangeSpy.callCount, 1)
|
||||
assert.ok(handleChangeSpy.calledWith('2710'))
|
||||
assert.equal(wrapper.find('.currency-display-component').text(), '2 ETH')
|
||||
assert.equal(wrapper.find('.currency-display-component').text(), '2ETH')
|
||||
assert.equal(tokenInputInstance.state.decimalValue, 1)
|
||||
assert.equal(tokenInputInstance.state.hexValue, '2710')
|
||||
|
||||
@ -250,14 +250,14 @@ describe('TokenInput Component', () => {
|
||||
const tokenInputInstance = wrapper.find(TokenInput).at(0).instance()
|
||||
assert.equal(tokenInputInstance.state.decimalValue, 0)
|
||||
assert.equal(tokenInputInstance.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')
|
||||
assert.equal(input.props().value, 0)
|
||||
|
||||
input.simulate('change', { target: { value: 1 } })
|
||||
assert.equal(handleChangeSpy.callCount, 1)
|
||||
assert.ok(handleChangeSpy.calledWith('2710'))
|
||||
assert.equal(wrapper.find('.currency-display-component').text(), '$462.12 USD')
|
||||
assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD')
|
||||
assert.equal(tokenInputInstance.state.decimalValue, 1)
|
||||
assert.equal(tokenInputInstance.state.hexValue, '2710')
|
||||
|
||||
|
@ -27,10 +27,14 @@ export default class TransactionActivityLog extends PureComponent {
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
const { transaction: { history: prevHistory = [] } = {} } = prevProps
|
||||
const { transaction: { history = [] } = {} } = this.props
|
||||
const {
|
||||
transaction: { history: prevHistory = [], txReceipt: { status: prevStatus } = {} } = {},
|
||||
} = prevProps
|
||||
const {
|
||||
transaction: { history = [], txReceipt: { status } = {} } = {},
|
||||
} = this.props
|
||||
|
||||
if (prevHistory.length !== history.length) {
|
||||
if (prevHistory.length !== history.length || prevStatus !== status) {
|
||||
this.setActivites()
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ const TRANSACTION_SUBMITTED_EVENT = 'transactionSubmitted'
|
||||
const TRANSACTION_CONFIRMED_EVENT = 'transactionConfirmed'
|
||||
const TRANSACTION_DROPPED_EVENT = 'transactionDropped'
|
||||
const TRANSACTION_UPDATED_EVENT = 'transactionUpdated'
|
||||
const TRANSACTION_ERRORED_EVENT = 'transactionErrored'
|
||||
|
||||
const eventPathsHash = {
|
||||
[STATUS_PATH]: true,
|
||||
@ -39,9 +40,9 @@ function eventCreator (eventKey, timestamp, value) {
|
||||
}
|
||||
|
||||
export function getActivities (transaction) {
|
||||
const { history = [] } = transaction
|
||||
const { history = [], txReceipt: { status } = {} } = transaction
|
||||
|
||||
return history.reduce((acc, base) => {
|
||||
const historyActivities = history.reduce((acc, base) => {
|
||||
// First history item should be transaction creation
|
||||
if (!Array.isArray(base) && base.status === UNAPPROVED_STATUS && base.txParams) {
|
||||
const { time, txParams: { value } = {} } = base
|
||||
@ -83,4 +84,10 @@ export function getActivities (transaction) {
|
||||
|
||||
return acc
|
||||
}, [])
|
||||
|
||||
// If txReceipt.status is '0x0', that means that an on-chain error occured for the transaction,
|
||||
// so we add an error entry to the Activity Log.
|
||||
return status === '0x0'
|
||||
? historyActivities.concat(eventCreator(TRANSACTION_ERRORED_EVENT))
|
||||
: historyActivities
|
||||
}
|
||||
|
@ -85,6 +85,7 @@
|
||||
text-align: end;
|
||||
grid-area: primary-amount;
|
||||
align-self: end;
|
||||
justify-self: end;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
padding-bottom: 2px;
|
||||
@ -97,6 +98,7 @@
|
||||
color: #5e6064;
|
||||
grid-area: secondary-amount;
|
||||
align-self: start;
|
||||
justify-self: end;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ import TransactionListItemDetails from '../transaction-list-item-details'
|
||||
import { CONFIRM_TRANSACTION_ROUTE } from '../../routes'
|
||||
import { UNAPPROVED_STATUS, TOKEN_METHOD_TRANSFER } from '../../constants/transactions'
|
||||
import { PRIMARY, SECONDARY } from '../../constants/common'
|
||||
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../app/scripts/lib/enums'
|
||||
import { getStatusKey } from '../../helpers/transactions.util'
|
||||
|
||||
export default class TransactionListItem extends PureComponent {
|
||||
@ -24,7 +23,6 @@ export default class TransactionListItem extends PureComponent {
|
||||
showCancelModal: PropTypes.func,
|
||||
showCancel: PropTypes.bool,
|
||||
showRetry: PropTypes.bool,
|
||||
showTransactionDetailsModal: PropTypes.func,
|
||||
token: PropTypes.object,
|
||||
tokenData: PropTypes.object,
|
||||
transaction: PropTypes.object,
|
||||
@ -39,31 +37,16 @@ export default class TransactionListItem extends PureComponent {
|
||||
const {
|
||||
transaction,
|
||||
history,
|
||||
showTransactionDetailsModal,
|
||||
methodData,
|
||||
showCancel,
|
||||
showRetry,
|
||||
} = this.props
|
||||
const { id, status } = transaction
|
||||
const { showTransactionDetails } = this.state
|
||||
const windowType = window.METAMASK_UI_TYPE
|
||||
|
||||
if (status === UNAPPROVED_STATUS) {
|
||||
history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`)
|
||||
return
|
||||
}
|
||||
|
||||
if (windowType === ENVIRONMENT_TYPE_FULLSCREEN) {
|
||||
this.setState({ showTransactionDetails: !showTransactionDetails })
|
||||
} else {
|
||||
showTransactionDetailsModal({
|
||||
transaction,
|
||||
onRetry: this.handleRetry,
|
||||
showRetry: showRetry && methodData.done,
|
||||
onCancel: this.handleCancel,
|
||||
showCancel,
|
||||
})
|
||||
}
|
||||
this.setState({ showTransactionDetails: !showTransactionDetails })
|
||||
}
|
||||
|
||||
handleCancel = () => {
|
||||
|
@ -28,16 +28,6 @@ const mapDispatchToProps = dispatch => {
|
||||
showCancelModal: (transactionId, originalGasPrice) => {
|
||||
return dispatch(showModal({ name: 'CANCEL_TRANSACTION', transactionId, originalGasPrice }))
|
||||
},
|
||||
showTransactionDetailsModal: ({ transaction, onRetry, showRetry, onCancel, showCancel }) => {
|
||||
return dispatch(showModal({
|
||||
name: 'TRANSACTION_DETAILS',
|
||||
transaction,
|
||||
onRetry,
|
||||
showRetry,
|
||||
onCancel,
|
||||
showCancel,
|
||||
}))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
margin-top: 8px;
|
||||
border-top: 1px solid $geyser;
|
||||
|
||||
&__completed-transactions {
|
||||
display: flex;
|
||||
@ -26,7 +24,6 @@
|
||||
|
||||
&__transactions {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&__pending-transactions {
|
||||
|
@ -4,11 +4,13 @@
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
height: 54px;
|
||||
min-width: 0;
|
||||
|
||||
&__balance {
|
||||
margin-left: 12px;
|
||||
margin: 0 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
align-items: center;
|
||||
@ -21,7 +23,8 @@
|
||||
font-size: 1.5rem;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
margin-bottom: 12px;
|
||||
margin: 12px 0;
|
||||
margin-left: 0;
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
@ -30,7 +33,6 @@
|
||||
font-size: 1.5rem;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
margin-bottom: 12px;
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
@ -45,6 +47,7 @@
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
flex-direction: column;
|
||||
|
@ -4,6 +4,7 @@
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
|
||||
&__balance-wrapper {
|
||||
@media screen and (max-width: $break-small) {
|
||||
|
@ -7,7 +7,7 @@ const { compose } = require('recompose')
|
||||
const inherits = require('util').inherits
|
||||
const classnames = require('classnames')
|
||||
const { checksumAddress } = require('../util')
|
||||
const Identicon = require('./identicon')
|
||||
import Identicon from './identicon'
|
||||
// const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns
|
||||
const Tooltip = require('./tooltip-v2.js').default
|
||||
const copyToClipboard = require('copy-to-clipboard')
|
||||
@ -127,7 +127,6 @@ WalletView.prototype.render = function () {
|
||||
identities,
|
||||
} = this.props
|
||||
// temporary logs + fake extra wallets
|
||||
// console.log('walletview, selectedAccount:', selectedAccount)
|
||||
|
||||
const checksummedAddress = checksumAddress(selectedAddress)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
.button {
|
||||
height: 44px;
|
||||
min-height: 44px;
|
||||
background: $white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -87,7 +87,7 @@
|
||||
}
|
||||
|
||||
.btn--large {
|
||||
height: 54px;
|
||||
min-height: 54px;
|
||||
}
|
||||
|
||||
.btn-green {
|
||||
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
|
||||
@media screen and (min-width: $break-large) {
|
||||
max-height: 620px;
|
||||
height: 620px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
|
||||
align-items: center;
|
||||
margin: 20px 24px;
|
||||
flex-direction: row;
|
||||
flex-grow: 3;
|
||||
min-width: 0;
|
||||
|
||||
@media #{$wallet-balance-breakpoint-range} {
|
||||
margin: 10% 4%;
|
||||
@ -38,8 +38,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
|
||||
|
||||
.balance-display {
|
||||
margin-left: 15px;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
min-width: 0;
|
||||
|
||||
.token-amount {
|
||||
font-size: 1.5rem;
|
||||
|
@ -329,7 +329,6 @@ export function updateTxDataAndCalculate (txData) {
|
||||
|
||||
const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount)
|
||||
const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount)
|
||||
console.log('HIHIH', value, hexTransactionFee)
|
||||
const hexTransactionTotal = sumHexes(value, hexTransactionFee)
|
||||
|
||||
dispatch(updateTransactionTotals({
|
||||
|
@ -27,10 +27,21 @@ export function getTokenData (data = '') {
|
||||
|
||||
const registry = new MethodRegistry({ provider: global.ethereumProvider })
|
||||
|
||||
/**
|
||||
* Attempts to return the method data from the MethodRegistry library, if the method exists in the
|
||||
* registry. Otherwise, returns an empty object.
|
||||
* @param {string} data - The hex data (@code txParams.data) of a transaction
|
||||
* @returns {Object}
|
||||
*/
|
||||
export async function getMethodData (data = '') {
|
||||
const prefixedData = ethUtil.addHexPrefix(data)
|
||||
const fourBytePrefix = prefixedData.slice(0, 10)
|
||||
const sig = await registry.lookup(fourBytePrefix)
|
||||
|
||||
if (!sig) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const parsedResult = registry.parse(sig)
|
||||
|
||||
return {
|
||||
|
Loading…
x
Reference in New Issue
Block a user