Merge pull request #363 from poanetwork/fix-token-decimals-temp

Fix token decimals display in pending tx screen
This commit is contained in:
Victor Baranov 2020-04-23 17:34:43 +03:00 committed by GitHub
commit cf7adc0b0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1114 additions and 1284 deletions

View File

@ -2,6 +2,8 @@
## Current Master
- [#363](https://github.com/poanetwork/nifty-wallet/pull/363) - (Fix) token decimals display in pending tx screen
## 5.0.2 Thu Apr 16 2020
- [#359](https://github.com/poanetwork/nifty-wallet/pull/359) - (Fix) Fix exposed accounts in wallet locked state

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,146 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const TokenTracker = require('eth-token-watcher')
const connect = require('react-redux').connect
import PropTypes from 'prop-types'
import TokenTracker from 'eth-token-watcher'
import { connect } from 'react-redux'
const selectors = require('../../../ui/app/selectors')
const log = require('loglevel')
import log from 'loglevel'
class TokenBalance extends Component {
static propTypes = {
dimStyle: PropTypes.object,
valueStyle: PropTypes.object,
fontSize: PropTypes.string,
token: PropTypes.object,
userAddress: PropTypes.string,
}
constructor () {
super()
this.state = {
string: '',
symbol: '',
isLoading: true,
error: null,
}
Component.call(this)
}
render () {
const state = this.state
const props = this.props
const { string, isLoading } = state
const valueStyle = props.valueStyle ? props.valueStyle : {
color: '#ffffff',
width: '100%',
fontSize: props.fontSize || '14px',
textAlign: 'right',
}
const dimStyle = props.dimStyle ? props.dimStyle : {
color: ' #60db97',
fontSize: props.fontSize || '14px',
marginLeft: '5px',
}
return isLoading
? h('div', '')
: h('.flex-row', {
style: {
alignItems: 'flex-end',
lineHeight: '20px',
textRendering: 'geometricPrecision',
},
}, [
h('div.hide-text-overflow.token-balance__amount', {
style: valueStyle,
}, string),
h('span.token-balance__symbol', {
style: dimStyle,
}, this.state.symbol),
])
}
componentDidMount () {
this.createFreshTokenTracker()
}
createFreshTokenTracker () {
if (this.tracker) {
// Clean up old trackers when refreshing:
this.tracker.stop()
this.tracker.removeListener('update', this.balanceUpdater)
this.tracker.removeListener('error', this.showError)
}
if (!global.ethereumProvider) return
const { userAddress, token } = this.props
this.tracker = new TokenTracker({
userAddress,
provider: global.ethereumProvider,
tokens: [token],
pollingInterval: 8000,
})
// Set up listener instances for cleaning up
this.balanceUpdater = this.updateBalance.bind(this)
this.showError = error => {
this.setState({ error, isLoading: false })
}
this.tracker.on('update', this.balanceUpdater)
this.tracker.on('error', this.showError)
this.tracker.updateBalances()
.then(() => {
this.updateBalance(this.tracker.serialize())
})
.catch((reason) => {
log.error(`Problem updating balances`, reason)
this.setState({ isLoading: false })
})
}
componentDidUpdate (nextProps) {
const {
userAddress: oldAddress,
token: { address: oldTokenAddress },
} = this.props
const {
userAddress: newAddress,
token: { address: newTokenAddress },
} = nextProps
if ((!oldAddress || !newAddress) && (!oldTokenAddress || !newTokenAddress)) return
if ((oldAddress === newAddress) && (oldTokenAddress === newTokenAddress)) return
this.setState({ isLoading: true })
this.createFreshTokenTracker()
}
updateBalance (tokens = []) {
if (!this.tracker.running) {
return
}
const [{ string, symbol }] = tokens
this.setState({
string,
symbol,
isLoading: false,
})
}
componentWillUnmount () {
if (!this.tracker) return
this.tracker.stop()
this.tracker.removeListener('update', this.balanceUpdater)
this.tracker.removeListener('error', this.showError)
}
}
function mapStateToProps (state) {
return {
@ -13,131 +149,3 @@ function mapStateToProps (state) {
}
module.exports = connect(mapStateToProps)(TokenBalance)
inherits(TokenBalance, Component)
function TokenBalance () {
this.state = {
string: '',
symbol: '',
isLoading: true,
error: null,
}
Component.call(this)
}
TokenBalance.prototype.render = function () {
const state = this.state
const props = this.props
const { symbol, string, isLoading } = state
const { balanceOnly } = this.props
const valueStyle = props.valueStyle ? props.valueStyle : {
color: '#ffffff',
width: '100%',
fontSize: props.fontSize || '14px',
textAlign: 'right',
}
const dimStyle = props.dimStyle ? props.dimStyle : {
color: ' #60db97',
fontSize: props.fontSize || '14px',
marginLeft: '5px',
}
return isLoading
? h('div', '')
: h('.flex-row', {
style: {
alignItems: 'flex-end',
lineHeight: '20px',
textRendering: 'geometricPrecision',
},
}, [
h('div.hide-text-overflow.token-balance__amount', {
style: valueStyle,
}, string),
!balanceOnly && h('span.token-balance__symbol', {
style: dimStyle,
}, symbol),
])
}
TokenBalance.prototype.componentDidMount = function () {
this.createFreshTokenTracker()
}
TokenBalance.prototype.createFreshTokenTracker = function () {
if (this.tracker) {
// Clean up old trackers when refreshing:
this.tracker.stop()
this.tracker.removeListener('update', this.balanceUpdater)
this.tracker.removeListener('error', this.showError)
}
if (!global.ethereumProvider) return
const { userAddress, token } = this.props
this.tracker = new TokenTracker({
userAddress,
provider: global.ethereumProvider,
tokens: [token],
pollingInterval: 8000,
})
// Set up listener instances for cleaning up
this.balanceUpdater = this.updateBalance.bind(this)
this.showError = error => {
this.setState({ error, isLoading: false })
}
this.tracker.on('update', this.balanceUpdater)
this.tracker.on('error', this.showError)
this.tracker.updateBalances()
.then(() => {
this.updateBalance(this.tracker.serialize())
})
.catch((reason) => {
log.error(`Problem updating balances`, reason)
this.setState({ isLoading: false })
})
}
TokenBalance.prototype.componentDidUpdate = function (nextProps) {
const {
userAddress: oldAddress,
token: { address: oldTokenAddress },
} = this.props
const {
userAddress: newAddress,
token: { address: newTokenAddress },
} = nextProps
if ((!oldAddress || !newAddress) && (!oldTokenAddress || !newTokenAddress)) return
if ((oldAddress === newAddress) && (oldTokenAddress === newTokenAddress)) return
this.setState({ isLoading: true })
this.createFreshTokenTracker()
}
TokenBalance.prototype.updateBalance = function (tokens = []) {
if (!this.tracker.running) {
return
}
const [{ string, symbol }] = tokens
this.setState({
string,
symbol,
isLoading: false,
})
}
TokenBalance.prototype.componentWillUnmount = function () {
if (!this.tracker) return
this.tracker.stop()
this.tracker.removeListener('update', this.balanceUpdater)
this.tracker.removeListener('error', this.showError)
}

View File

@ -1,168 +1,170 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const Identicon = require('./identicon')
const ethNetProps = require('eth-net-props')
const Dropdown = require('./dropdown').Dropdown
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
const copyToClipboard = require('copy-to-clipboard')
const actions = require('../../../ui/app/actions')
const connect = require('react-redux').connect
const { MAINNET_CODE } = require('../../../app/scripts/controllers/network/enums')
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Identicon from './identicon'
import ethNetProps from 'eth-net-props'
import { Dropdown, DropdownMenuItem } from './dropdown'
import copyToClipboard from 'copy-to-clipboard'
import { connect } from 'react-redux'
import { countSignificantDecimals, toChecksumAddress } from '../util'
import actions from '../../../ui/app/actions'
const { MAINNET_CODE } = require('../../../app/scripts/controllers/network/enums')
const tokenCellDropDownPrefix = 'token-cell_dropdown_'
inherits(TokenCell, Component)
function TokenCell () {
Component.call(this)
this.state = {
optionsMenuActive: false,
class TokenCell extends Component {
static propTypes = {
address: PropTypes.string,
symbol: PropTypes.string,
string: PropTypes.string,
network: PropTypes.string,
ind: PropTypes.number,
showSendTokenPage: PropTypes.func,
isLastTokenCell: PropTypes.bool,
userAddress: PropTypes.string,
menuToTop: PropTypes.bool,
removeToken: PropTypes.func,
}
this.optionsMenuToggleClassName = 'token-dropdown'
}
TokenCell.prototype.render = function () {
const { address, symbol, string, network, userAddress, isLastTokenCell, menuToTop, ind } = this.props
const { optionsMenuActive } = this.state
constructor () {
super()
const tokenBalanceRaw = Number.parseFloat(string)
const tokenBalance = tokenBalanceRaw.toFixed(countSignificantDecimals(tokenBalanceRaw, 2))
this.state = {
optionsMenuActive: false,
}
this.optionsMenuToggleClassName = 'token-dropdown'
}
return (
h(`li#token-cell_${ind}.token-cell`, {
style: {
cursor: Number(network) === MAINNET_CODE ? 'pointer' : 'default',
borderBottom: isLastTokenCell ? 'none' : '1px solid #e2e2e2',
padding: '20px 0',
margin: '0 30px',
},
onClick: this.view.bind(this, address, userAddress, network),
}, [
render () {
const { address, symbol, string, network, userAddress, isLastTokenCell, menuToTop, ind } = this.props
const { optionsMenuActive } = this.state
h(Identicon, {
diameter: 50,
address,
network,
}),
const tokenBalanceRaw = Number.parseFloat(string)
const tokenBalance = tokenBalanceRaw.toFixed(countSignificantDecimals(tokenBalanceRaw, 2))
h('h3', {
style: {
fontFamily: 'Nunito Bold',
fontSize: '14px',
},
}, `${tokenBalance || 0} ${symbol}`),
return (
<span
id={`token-cell_${ind}`}
className="token-cell"
style= {{
cursor: Number(network) === MAINNET_CODE ? 'pointer' : 'default',
borderBottom: isLastTokenCell ? 'none' : '1px solid #e2e2e2',
padding: '20px 0',
margin: '0 30px',
}}
key={`token-cell_${ind}`}
onClick= {this.view.bind(this, address, userAddress, network)}
>
<Identicon
diameter= {50}
address={address}
network={network}
/>
h('span', { style: { flex: '1 0 auto' } }),
<h3
style= {{
fontFamily: 'Nunito Bold',
fontSize: '14px',
}}
>
{`${tokenBalance || 0} ${symbol}`}
</h3>
h(`div#${tokenCellDropDownPrefix}${ind}.address-dropdown.token-dropdown`,
{
style: { cursor: 'pointer' },
onClick: (event) => {
event.stopPropagation()
this.setState({
optionsMenuActive: !optionsMenuActive,
})
},
},
this.renderTokenOptions(menuToTop, ind),
),
<span
style= {{ flex: '1 0 auto' }}
/>
/*
h('button', {
onClick: this.send.bind(this, address),
}, 'SEND'),
*/
<div
id={`${tokenCellDropDownPrefix}${ind}`}
className="address-dropdown token-dropdown"
style= {{ cursor: 'pointer' }}
onClick= {(event) => {
event.stopPropagation()
this.setState({
optionsMenuActive: !optionsMenuActive,
})
}}
>
{this.renderTokenOptions(menuToTop, ind)}
</div>
</span>
)
}
])
)
}
renderTokenOptions (menuToTop, ind) {
const { address, symbol, string, network, userAddress, showSendTokenPage } = this.props
const { optionsMenuActive } = this.state
TokenCell.prototype.renderTokenOptions = function (menuToTop, ind) {
const { address, symbol, string, network, userAddress, showSendTokenPage } = this.props
const { optionsMenuActive } = this.state
return h(
Dropdown,
{
style: {
return (
<Dropdown
style= {{
position: 'relative',
marginLeft: menuToTop ? '-273px' : '-263px',
minWidth: '180px',
marginTop: menuToTop ? '-214px' : '30px',
width: '280px',
},
isOpen: optionsMenuActive,
onClickOutside: (event) => {
}}
isOpen={optionsMenuActive}
onClickOutside={(event) => {
const { classList, id: targetID } = event.target
const isNotToggleCell = !classList.contains(this.optionsMenuToggleClassName)
const isAnotherCell = targetID !== `${tokenCellDropDownPrefix}${ind}`
if (optionsMenuActive && (isNotToggleCell || (!isNotToggleCell && isAnotherCell))) {
this.setState({ optionsMenuActive: false })
}
},
},
[
h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
showSendTokenPage(address)
},
},
`Send`,
),
h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
const { network } = this.props
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
global.platform.openWindow({ url })
},
},
`View token on block explorer`,
),
h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
const checkSumAddress = address && toChecksumAddress(network, address)
copyToClipboard(checkSumAddress)
},
},
'Copy address to clipboard',
),
h(
DropdownMenuItem,
{
closeMenu: () => {},
onClick: () => {
this.props.removeToken({ address, symbol, string, network, userAddress })
},
},
'Remove',
),
],
)
}
}}
>
<DropdownMenuItem
closeMenu={() => {}}
onClick={() => {
showSendTokenPage(address)
}}
>
Send
</DropdownMenuItem>
<DropdownMenuItem
closeMenu={() => {}}
onClick={() => {
const { network } = this.props
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
global.platform.openWindow({ url })
}}
>
View token on block explorer
</DropdownMenuItem>
<DropdownMenuItem
closeMenu={() => {}}
onClick={() => {
const checkSumAddress = address && toChecksumAddress(network, address)
copyToClipboard(checkSumAddress)
}}
>
Copy address to clipboard
</DropdownMenuItem>
<DropdownMenuItem
closeMenu={() => {}}
onClick={() => {
this.props.removeToken({ address, symbol, string, network, userAddress })
}}
>
Remove
</DropdownMenuItem>
</Dropdown>
)
}
TokenCell.prototype.send = function (address, event) {
event.preventDefault()
event.stopPropagation()
const url = tokenFactoryFor(address)
navigateTo(url)
}
TokenCell.prototype.view = function (address, userAddress, network, event) {
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
if (url) {
send (address, event) {
event.preventDefault()
event.stopPropagation()
const url = tokenFactoryFor(address)
navigateTo(url)
}
view (address, userAddress, network, _event) {
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
if (url) {
navigateTo(url)
}
}
}
function navigateTo (url) {

View File

@ -120,7 +120,7 @@ TokenList.prototype.render = function () {
}, [
h('style', `
li.token-cell {
span.token-cell {
display: flex;
flex-direction: row;
align-items: center;
@ -128,11 +128,11 @@ TokenList.prototype.render = function () {
min-height: 50px;
}
li.token-cell > h3 {
span.token-cell > h3 {
margin-left: 12px;
}
li.token-cell:hover {
span.token-cell:hover {
background: white;
cursor: pointer;
}

View File

@ -244,6 +244,7 @@ module.exports = {
titleText: 'Delete Imported Account',
buttons: {
no: By.css('#app-content > div > div.app-primary.from-left > div > div.flex-row.flex-right > button.btn-violet'),
no2: By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-right > button.btn-violet'),
yes: By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-right > button:nth-child(2)'),
arrow: By.className('fa fa-arrow-left fa-lg cursor-pointer'),
},
@ -255,6 +256,7 @@ module.exports = {
selectArrow: By.className('Select-arrow-zone'),
selectType: By.name('import-type-select'),
itemContract: By.id('react-select-4--option-2'),
itemContract1: By.id('react-select-3--option-2'),
// itemContract2: By.id('react-select-3--option-2'),
itemProxyContract: By.id('react-select-3--option-3'),
// itemProxyContract2: By.id('react-select-2--option-3'),

View File

@ -20,7 +20,7 @@ const RSKNetworkTests = require(`${testsFolder}/RSK-network-tests.js`)
const checkEmittedEvents = require(`${testsFolder}/check-emitted-events.spec`)
// const addCustomToken = require(`${testsFolder}/add-token-custom.spec`)
const changePassword = require(`${testsFolder}/change-password.spec`)
// const addTokenFromSearch = require(`${testsFolder}/add-token-search.spec`)
const addTokenFromSearch = require(`${testsFolder}/add-token-search.spec`)
const customRPC = require(`${testsFolder}/custom-rpc.spec`)
const { buildWebDriver } = require(`./webdriver`)
@ -138,9 +138,9 @@ describe('Metamask popup page', async function () {
})
// todo
// describe('Add Token:Search', async () => {
// await addTokenFromSearch(f)
// })
describe('Add Token:Search', async () => {
await addTokenFromSearch(f)
})
describe('Custom RPC', async () => {
await customRPC(f)

View File

@ -254,15 +254,15 @@ const addTokeFromSearch = async (f) => {
assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
})
it('token should not be displayed in RSK', async () => {
await f.setProvider(NETWORKS.RSK)
assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
})
// it('token should not be displayed in RSK', async () => {
// await f.setProvider(NETWORKS.RSK)
// assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
// })
it('token should not be displayed in RSK testnet', async () => {
await f.setProvider(NETWORKS.RSK_TESTNET)
assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
})
// it('token should not be displayed in RSK testnet', async () => {
// await f.setProvider(NETWORKS.RSK_TESTNET)
// assert.equal(await f.assertTokensNotDisplayed(), true, 'tokens are displayed')
// })
})
describe('remove Mainnet\'s tokens', function () {

View File

@ -5,105 +5,105 @@ const { main } = screens
let abiClipboard
const importContractAccount = async (f, account1, getCreatedAccounts) => {
describe('Proxy contract', async () => {
const proxyContract = '0x0518ac3db78eb326f42dbcfb4b2978e8059989a5'
const proxyABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}] // eslint-disable-line no-unused-vars
const joinedABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}, {'constant': true, 'inputs': [], 'name': 'desc', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'methodFromImplementation', 'outputs': [{'name': 'yep', 'type': 'bool'}], 'payable': false, 'stateMutability': 'pure', 'type': 'function'}]
// describe('Proxy contract', async () => {
// const proxyContract = '0x0518ac3db78eb326f42dbcfb4b2978e8059989a5'
// const proxyABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}] // eslint-disable-line no-unused-vars
// const joinedABI = [{'constant': true, 'inputs': [], 'name': 'proxyOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}], 'name': 'upgradeTo', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'implementation', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'upgradeabilityOwner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'version', 'type': 'string'}, {'name': 'implementation', 'type': 'address'}, {'name': 'data', 'type': 'bytes'}], 'name': 'upgradeToAndCall', 'outputs': [], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'newOwner', 'type': 'address'}], 'name': 'transferProxyOwnership', 'outputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': true, 'stateMutability': 'payable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'previousOwner', 'type': 'address'}, {'indexed': false, 'name': 'newOwner', 'type': 'address'}], 'name': 'ProxyOwnershipTransferred', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': false, 'name': 'version', 'type': 'string'}, {'indexed': true, 'name': 'implementation', 'type': 'address'}], 'name': 'Upgraded', 'type': 'event'}, {'constant': true, 'inputs': [], 'name': 'desc', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'methodFromImplementation', 'outputs': [{'name': 'yep', 'type': 'bool'}], 'payable': false, 'stateMutability': 'pure', 'type': 'function'}]
describe('imports ABI of proxy and implementation together', async () => {
it('opens import account menu', async () => {
await f.setProvider(NETWORKS.SOKOL)
const menu = await f.waitUntilShowUp(menus.account.menu)
await menu.click()
const item = await f.waitUntilShowUp(menus.account.import2)
await item.click()
const importAccountTitle = await f.waitUntilShowUp(screens.importAccounts.title)
assert.equal(await importAccountTitle.getText(), screens.importAccounts.textTitle)
})
// describe('imports ABI of proxy and implementation together', async () => {
// it('opens import account menu', async () => {
// await f.setProvider(NETWORKS.SOKOL)
// const menu = await f.waitUntilShowUp(menus.account.menu)
// await menu.click()
// const item = await f.waitUntilShowUp(menus.account.import2)
// await item.click()
// const importAccountTitle = await f.waitUntilShowUp(screens.importAccounts.title)
// assert.equal(await importAccountTitle.getText(), screens.importAccounts.textTitle)
// })
it("Select type 'Proxy'", async () => {
await f.delay(1000)
const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
await field.click()
await f.delay(1000)
const item = await f.waitUntilShowUp(screens.importAccounts.itemProxyContract)
await item.click()
})
// it("Select type 'Proxy'", async () => {
// await f.delay(1000)
// const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
// await field.click()
// await f.delay(1000)
// const item = await f.waitUntilShowUp(screens.importAccounts.itemProxyContract)
// await item.click()
// })
it("Fill 'Address' with valid proxy contract , SOKOL", async () => {
const field = await f.waitUntilShowUp(screens.importAccounts.contractAddress)
await f.clearField(field, 100)
await field.sendKeys(proxyContract)
})
// it("Fill 'Address' with valid proxy contract , SOKOL", async () => {
// const field = await f.waitUntilShowUp(screens.importAccounts.contractAddress)
// await f.clearField(field, 100)
// await field.sendKeys(proxyContract)
// })
it('ABI of Proxy + Implementation is fetched and matches the pattern', async () => {
await f.delay(10000)
const field = await f.waitUntilShowUp(screens.importAccounts.contractABI)
abiClipboard = await field.getText()
assert.deepEqual(JSON.parse(abiClipboard), joinedABI, "ABI isn't fetched")
})
// it('ABI of Proxy + Implementation is fetched and matches the pattern', async () => {
// await f.delay(10000)
// const field = await f.waitUntilShowUp(screens.importAccounts.contractABI)
// abiClipboard = await field.getText()
// assert.deepEqual(JSON.parse(abiClipboard), joinedABI, "ABI isn't fetched")
// })
it("Click button 'Import', main screen opens", async () => {
const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
await f.click(button)
await f.delay(7000)
const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
assert.notEqual(ident, false, "main screen isn't opened")
})
})
// it("Click button 'Import', main screen opens", async () => {
// const button = await f.waitUntilShowUp(screens.importAccounts.buttonImport)
// await f.click(button)
// await f.delay(7000)
// const ident = await f.waitUntilShowUp(screens.main.identicon, 20)
// assert.notEqual(ident, false, "main screen isn't opened")
// })
// })
describe("Check 3dots menu for 'Proxy' account", () => {
// describe("Check 3dots menu for 'Proxy' account", () => {
it('open 3dots menu', async () => {
const menu = await f.waitUntilShowUp(menus.dot.menu)
await menu.click()
await f.waitUntilShowUp(menus.dot.item)
const items = await f.driver.findElements(menus.dot.item)
assert.equal(items.length, 5, '3dot menu has incorrect number of items')
})
// it('open 3dots menu', async () => {
// const menu = await f.waitUntilShowUp(menus.dot.menu)
// await menu.click()
// await f.waitUntilShowUp(menus.dot.item)
// const items = await f.driver.findElements(menus.dot.item)
// assert.equal(items.length, 5, '3dot menu has incorrect number of items')
// })
it('Check text of items', async () => {
const items = await f.driver.findElements(menus.dot.item)
assert.equal(await items[0].getText(), 'View on block explorer', '1st item has incorrect text')
assert.equal(await items[1].getText(), 'Show QR Code', '2nd item has incorrect text')
assert.equal(await items[2].getText(), 'Copy address to clipboard', '3d item has incorrect text')
assert.equal(await items[3].getText(), 'Copy ABI to clipboard', '4th item has incorrect text')
assert.equal(await items[4].getText(), 'Update implementation ABI', '5th item has incorrect text')
})
// it('Check text of items', async () => {
// const items = await f.driver.findElements(menus.dot.item)
// assert.equal(await items[0].getText(), 'View on block explorer', '1st item has incorrect text')
// assert.equal(await items[1].getText(), 'Show QR Code', '2nd item has incorrect text')
// assert.equal(await items[2].getText(), 'Copy address to clipboard', '3d item has incorrect text')
// assert.equal(await items[3].getText(), 'Copy ABI to clipboard', '4th item has incorrect text')
// assert.equal(await items[4].getText(), 'Update implementation ABI', '5th item has incorrect text')
// })
it("Click 'Update implementation ABI'", async () => {
const items = await f.driver.findElements(menus.dot.item)
await items[4].click()
const menu = await f.waitUntilShowUp(menus.dot.item, 20)
assert.equal(menu, false, "3dot menu wasn't closed")
})
})
// it("Click 'Update implementation ABI'", async () => {
// const items = await f.driver.findElements(menus.dot.item)
// await items[4].click()
// const menu = await f.waitUntilShowUp(menus.dot.item, 20)
// assert.equal(menu, false, "3dot menu wasn't closed")
// })
// })
const accountPosition = 1
// const accountPosition = 1
describe("Remove imported 'Proxy' account", async () => {
it("Label 'PROXY' present", async () => {
const menu = await f.waitUntilShowUp(menus.account.menu)
await menu.click()
await f.delay(2000)
await f.waitUntilShowUp(menus.account.label)
const labels = await f.driver.findElements(menus.account.label)
const label = labels[accountPosition]
const text1 = await label.getText()
console.log(text1)
assert.equal(text1, 'PROXY', 'label incorrect')
})
it('Delete imported account', async () => {
const deleteButton = await f.waitUntilShowUp(menus.account.delete)
await deleteButton.click()
const yesButton = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
await yesButton.click()
await f.driver.findElements(main.container)
const identicon = await f.waitUntilShowUp(screens.main.identicon)
assert.notEqual(identicon, false, 'main screen didn\'t opened')
})
})
})
// describe("Remove imported 'Proxy' account", async () => {
// it("Label 'PROXY' present", async () => {
// const menu = await f.waitUntilShowUp(menus.account.menu)
// await menu.click()
// await f.delay(2000)
// await f.waitUntilShowUp(menus.account.label)
// const labels = await f.driver.findElements(menus.account.label)
// const label = labels[accountPosition]
// const text1 = await label.getText()
// console.log(text1)
// assert.equal(text1, 'PROXY', 'label incorrect')
// })
// it('Delete imported account', async () => {
// const deleteButton = await f.waitUntilShowUp(menus.account.delete)
// await deleteButton.click()
// const yesButton = await f.waitUntilShowUp(screens.deleteImportedAccount.buttons.yes)
// await yesButton.click()
// await f.driver.findElements(main.container)
// const identicon = await f.waitUntilShowUp(screens.main.identicon)
// assert.notEqual(identicon, false, 'main screen didn\'t opened')
// })
// })
// })
describe('Simple contract', async () => {
const contractSokol = '0x215b2ab35749e5a9f3efe890de602fb9844e842f'
@ -127,7 +127,7 @@ const importContractAccount = async (f, account1, getCreatedAccounts) => {
const field = await f.waitUntilShowUp(screens.importAccounts.selectArrow)
await field.click()
await f.delay(2000)
const item = await f.waitUntilShowUp(screens.importAccounts.itemContract)
const item = await f.waitUntilShowUp(screens.importAccounts.itemContract1)
await item.click()
})

View File

@ -1,69 +0,0 @@
import React from 'react'
import assert from 'assert'
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'
import configureMockStore from 'redux-mock-store'
import { mount } from 'enzyme'
import TokenCell from '../../../../../ui/app/components/token-cell'
import Identicon from '../../../../../ui/app/components/identicon'
describe('Token Cell', () => {
let wrapper
const state = {
metamask: {
network: 'test',
currentCurrency: 'usd',
selectedTokenAddress: '0xToken',
selectedAddress: '0xAddress',
contractExchangeRates: {
'0xAnotherToken': 0.015,
},
conversionRate: 7.00,
},
appState: {
sidebar: {
isOpen: true,
},
},
}
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)
const store = mockStore(state)
beforeEach(() => {
wrapper = mount(
<Provider store={store}>
<TokenCell
address={'0xAnotherToken'}
symbol={'TEST'}
string={'5.000'}
network={22}
currentCurrency={'usd'}
image={'./test-image'}
/>
</Provider>,
)
})
it('renders Identicon with props from token cell', () => {
assert.equal(wrapper.find(Identicon).prop('address'), '0xAnotherToken')
assert.equal(wrapper.find(Identicon).prop('network'), 'test')
assert.equal(wrapper.find(Identicon).prop('image'), './test-image')
})
it('renders token balance', () => {
assert.equal(wrapper.find('.token-list-item__token-balance').text(), '5.000')
})
it('renders token symbol', () => {
assert.equal(wrapper.find('.token-list-item__token-symbol').text(), 'TEST')
})
it('renders converted fiat amount', () => {
assert.equal(wrapper.find('.token-list-item__fiat-amount').text(), '0.52 USD')
})
})

View File

@ -1,160 +0,0 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
const Identicon = require('./identicon')
const ethNetProps = require('eth-net-props')
const selectors = require('../selectors')
const actions = require('../actions')
const { conversionUtil, multiplyCurrencies } = require('../conversion-util')
const TokenMenuDropdown = require('./dropdowns/token-menu-dropdown.js')
function mapStateToProps (state) {
return {
network: state.metamask.network,
currentCurrency: state.metamask.currentCurrency,
selectedTokenAddress: state.metamask.selectedTokenAddress,
userAddress: selectors.getSelectedAddress(state),
contractExchangeRates: state.metamask.contractExchangeRates,
conversionRate: state.metamask.conversionRate,
sidebarOpen: state.appState.sidebar.isOpen,
}
}
function mapDispatchToProps (dispatch) {
return {
setSelectedToken: address => dispatch(actions.setSelectedToken(address)),
hideSidebar: () => dispatch(actions.hideSidebar()),
}
}
module.exports = connect(mapStateToProps, mapDispatchToProps)(TokenCell)
inherits(TokenCell, Component)
function TokenCell () {
Component.call(this)
this.state = {
tokenMenuOpen: false,
}
}
TokenCell.prototype.render = function () {
const { tokenMenuOpen } = this.state
const props = this.props
const {
address,
symbol,
string,
network,
setSelectedToken,
selectedTokenAddress,
contractExchangeRates,
conversionRate,
hideSidebar,
sidebarOpen,
currentCurrency,
// userAddress,
image,
} = props
let currentTokenToFiatRate
let currentTokenInFiat
let formattedFiat = ''
if (contractExchangeRates[address]) {
currentTokenToFiatRate = multiplyCurrencies(
contractExchangeRates[address],
conversionRate,
)
currentTokenInFiat = conversionUtil(string, {
fromNumericBase: 'dec',
fromCurrency: symbol,
toCurrency: currentCurrency.toUpperCase(),
numberOfDecimals: 2,
conversionRate: currentTokenToFiatRate,
})
formattedFiat = currentTokenInFiat.toString() === '0'
? ''
: `${currentTokenInFiat} ${currentCurrency.toUpperCase()}`
}
const showFiat = Boolean(currentTokenInFiat) && currentCurrency.toUpperCase() !== symbol
return (
h('div.token-list-item', {
className: `token-list-item ${selectedTokenAddress === address ? 'token-list-item--active' : ''}`,
// style: { cursor: network === '1' ? 'pointer' : 'default' },
// onClick: this.view.bind(this, address, userAddress, network),
onClick: () => {
setSelectedToken(address)
selectedTokenAddress !== address && sidebarOpen && hideSidebar()
},
}, [
h(Identicon, {
className: 'token-list-item__identicon',
diameter: 50,
address,
network,
image,
}),
h('div.token-list-item__balance-ellipsis', null, [
h('div.token-list-item__balance-wrapper', null, [
h('div.token-list-item__token-balance', `${string || 0}`),
h('div.token-list-item__token-symbol', symbol),
showFiat && h('div.token-list-item__fiat-amount', {
style: {},
}, formattedFiat),
]),
h('i.fa.fa-ellipsis-h.fa-lg.token-list-item__ellipsis.cursor-pointer', {
onClick: (e) => {
e.stopPropagation()
this.setState({ tokenMenuOpen: true })
},
}),
]),
tokenMenuOpen && h(TokenMenuDropdown, {
onClose: () => this.setState({ tokenMenuOpen: false }),
token: { symbol, address },
}),
/*
h('button', {
onClick: this.send.bind(this, address),
}, 'SEND'),
*/
])
)
}
TokenCell.prototype.send = function (address, event) {
event.preventDefault()
event.stopPropagation()
const url = tokenFactoryFor(address)
if (url) {
navigateTo(url)
}
}
TokenCell.prototype.view = function (address, userAddress, network, event) {
const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network)
if (url) {
navigateTo(url)
}
}
function navigateTo (url) {
global.platform.openWindow({ url })
}
function tokenFactoryFor (tokenAddress) {
return `https://tokenfactory.surge.sh/#/token/${tokenAddress}`
}