Fix shapeshift transactions. Delete unused files

feature/default_network_editable
Alexander Tseung 6 years ago
parent 33a94332e4
commit e104744d3b
  1. 2
      ui/app/components/pages/home/home.component.js
  2. 1
      ui/app/components/token-view/token-view.component.js
  3. 6
      ui/app/components/transaction-list/index.scss
  4. 44
      ui/app/components/transaction-list/transaction-list.component.js
  5. 356
      ui/app/components/tx-list-item.js
  6. 171
      ui/app/components/tx-list.js
  7. 121
      ui/app/components/tx-view.js
  8. 2
      ui/app/constants/transactions.js
  9. 20
      ui/app/css/itcss/components/newui-sections.scss

@ -3,7 +3,6 @@ import PropTypes from 'prop-types'
import Media from 'react-media'
import { Redirect } from 'react-router-dom'
import WalletView from '../../wallet-view'
import TxView from '../../tx-view'
import TokenView from '../../token-view'
import {
INITIALIZE_BACKUP_PHRASE_ROUTE,
@ -60,7 +59,6 @@ export default class Home extends PureComponent {
render={() => <WalletView />}
/>
<TokenView />
{/* <TxView /> */}
</div>
</div>
)

@ -3,7 +3,6 @@ import PropTypes from 'prop-types'
import Media from 'react-media'
import MenuBar from '../menu-bar'
import TokenViewBalance from '../token-view-balance'
// import TransactionList from '../tx-list'
import TransactionList from '../transaction-list'
export default class TokenView extends PureComponent {

@ -4,6 +4,12 @@
flex: 1;
overflow-y: hidden;
&__completed-transactions {
display: flex;
flex-direction: column;
height: 100%;
}
&__header {
flex: 0 0 auto;
font-size: .875rem;

@ -1,6 +1,8 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import TransactionListItem from '../transaction-list-item'
import ShapeShiftTransactionListItem from '../shift-list-item'
import { TRANSACTION_TYPE_SHAPESHIFT } from '../../constants/transactions'
export default class TransactionList extends PureComponent {
static contextTypes = {
@ -28,11 +30,7 @@ export default class TransactionList extends PureComponent {
renderTransactions () {
const { t } = this.context
const {
pendingTransactions = [],
completedTransactions = [],
selectedToken,
} = this.props
const { pendingTransactions = [], completedTransactions = [] } = this.props
return (
<div className="transaction-list__transactions">
@ -43,13 +41,8 @@ export default class TransactionList extends PureComponent {
{ `${t('queue')} (${pendingTransactions.length})` }
</div>
{
pendingTransactions.map(transaction => (
<TransactionListItem
transaction={transaction}
key={transaction.id}
showRetry={this.shouldShowRetry(transaction)}
token={selectedToken}
/>
pendingTransactions.map((transaction, index) => (
this.renderTransaction(transaction, index)
))
}
</div>
@ -61,12 +54,8 @@ export default class TransactionList extends PureComponent {
</div>
{
completedTransactions.length > 0
? completedTransactions.map(transaction => (
<TransactionListItem
transaction={transaction}
key={transaction.id}
token={selectedToken}
/>
? completedTransactions.map((transaction, index) => (
this.renderTransaction(transaction, index)
))
: this.renderEmpty()
}
@ -75,6 +64,25 @@ export default class TransactionList extends PureComponent {
)
}
renderTransaction (transaction, index) {
const { selectedToken } = this.props
return transaction.key === TRANSACTION_TYPE_SHAPESHIFT
? (
<ShapeShiftTransactionListItem
{ ...transaction }
key={`shapeshift${index}`}
/>
) : (
<TransactionListItem
transaction={transaction}
key={transaction.id}
showRetry={this.shouldShowRetry(transaction)}
token={selectedToken}
/>
)
}
renderEmpty () {
return (
<div className="transaction-list__empty">

@ -1,356 +0,0 @@
const Component = require('react').Component
const PropTypes = require('prop-types')
const { compose } = require('recompose')
const { withRouter } = require('react-router-dom')
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const inherits = require('util').inherits
const classnames = require('classnames')
const abi = require('human-standard-token-abi')
const abiDecoder = require('abi-decoder')
abiDecoder.addABI(abi)
const Identicon = require('./identicon')
const contractMap = require('eth-contract-metadata')
const { checksumAddress } = require('../util')
const actions = require('../actions')
const { conversionUtil, multiplyCurrencies } = require('../conversion-util')
const { calcTokenAmount } = require('../token-util')
const { getCurrentCurrency } = require('../selectors')
const { CONFIRM_TRANSACTION_ROUTE } = require('../routes')
TxListItem.contextTypes = {
t: PropTypes.func,
}
module.exports = compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps)
)(TxListItem)
function mapStateToProps (state) {
return {
tokens: state.metamask.tokens,
currentCurrency: getCurrentCurrency(state),
contractExchangeRates: state.metamask.contractExchangeRates,
selectedAddressTxList: state.metamask.selectedAddressTxList,
networkNonce: state.appState.networkNonce,
}
}
function mapDispatchToProps (dispatch) {
return {
setSelectedToken: tokenAddress => dispatch(actions.setSelectedToken(tokenAddress)),
retryTransaction: transactionId => dispatch(actions.retryTransaction(transactionId)),
}
}
inherits(TxListItem, Component)
function TxListItem () {
Component.call(this)
this.state = {
total: null,
fiatTotal: null,
isTokenTx: null,
}
this.unmounted = false
}
TxListItem.prototype.componentDidMount = async function () {
const { txParams = {} } = this.props
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
const { name: txDataName } = decodedData || {}
const isTokenTx = txDataName === 'transfer'
const { total, fiatTotal } = isTokenTx
? await this.getSendTokenTotal()
: this.getSendEtherTotal()
if (this.unmounted) {
return
}
this.setState({ total, fiatTotal, isTokenTx })
}
TxListItem.prototype.componentWillUnmount = function () {
this.unmounted = true
}
TxListItem.prototype.getAddressText = function () {
const {
address,
txParams = {},
isMsg,
} = this.props
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
const { name: txDataName, params = [] } = decodedData || {}
const { value } = params[0] || {}
const checksummedAddress = checksumAddress(address)
const checksummedValue = checksumAddress(value)
let addressText
if (txDataName === 'transfer' || address) {
const addressToRender = txDataName === 'transfer' ? checksummedValue : checksummedAddress
addressText = `${addressToRender.slice(0, 10)}...${addressToRender.slice(-4)}`
} else if (isMsg) {
addressText = this.context.t('sigRequest')
} else {
addressText = this.context.t('contractDeployment')
}
return addressText
}
TxListItem.prototype.getSendEtherTotal = function () {
const {
transactionAmount,
conversionRate,
address,
currentCurrency,
} = this.props
if (!address) {
return {}
}
const totalInFiat = conversionUtil(transactionAmount, {
fromNumericBase: 'hex',
toNumericBase: 'dec',
fromCurrency: 'ETH',
toCurrency: currentCurrency,
fromDenomination: 'WEI',
numberOfDecimals: 2,
conversionRate,
})
const totalInETH = conversionUtil(transactionAmount, {
fromNumericBase: 'hex',
toNumericBase: 'dec',
fromCurrency: 'ETH',
toCurrency: 'ETH',
fromDenomination: 'WEI',
conversionRate,
numberOfDecimals: 6,
})
return {
total: `${totalInETH} ETH`,
fiatTotal: `${totalInFiat} ${currentCurrency.toUpperCase()}`,
}
}
TxListItem.prototype.getTokenInfo = async function () {
const { txParams = {}, tokenInfoGetter, tokens } = this.props
const toAddress = txParams.to
let decimals
let symbol
({ decimals, symbol } = tokens.filter(({ address }) => address === toAddress)[0] || {})
if (!decimals && !symbol) {
({ decimals, symbol } = contractMap[toAddress] || {})
}
if (!decimals && !symbol) {
({ decimals, symbol } = await tokenInfoGetter(toAddress))
}
return { decimals, symbol, address: toAddress }
}
TxListItem.prototype.getSendTokenTotal = async function () {
const {
txParams = {},
conversionRate,
contractExchangeRates,
currentCurrency,
} = this.props
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
const { params = [] } = decodedData || {}
const { value } = params[1] || {}
const { decimals, symbol, address } = await this.getTokenInfo()
const total = calcTokenAmount(value, decimals)
let tokenToFiatRate
let totalInFiat
if (contractExchangeRates[address]) {
tokenToFiatRate = multiplyCurrencies(
contractExchangeRates[address],
conversionRate
)
totalInFiat = conversionUtil(total, {
fromNumericBase: 'dec',
toNumericBase: 'dec',
fromCurrency: symbol,
toCurrency: currentCurrency,
numberOfDecimals: 2,
conversionRate: tokenToFiatRate,
})
}
const showFiat = Boolean(totalInFiat) && currentCurrency.toUpperCase() !== symbol
return {
total: `${total} ${symbol}`,
fiatTotal: showFiat && `${totalInFiat} ${currentCurrency.toUpperCase()}`,
}
}
TxListItem.prototype.showRetryButton = function () {
const {
transactionSubmittedTime,
selectedAddressTxList,
transactionId,
txParams,
networkNonce,
} = this.props
if (!txParams) {
return false
}
let currentTxSharesEarliestNonce = false
const currentNonce = txParams.nonce
const currentNonceTxs = selectedAddressTxList.filter(tx => tx.txParams.nonce === currentNonce)
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
const currentSubmittedTxs = selectedAddressTxList.filter(tx => tx.status === 'submitted')
const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[currentNonceSubmittedTxs.length - 1]
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce &&
lastSubmittedTxWithCurrentNonce.id === transactionId
if (currentSubmittedTxs.length > 0) {
currentTxSharesEarliestNonce = currentNonce === networkNonce
}
return currentTxSharesEarliestNonce && currentTxIsLatestWithNonce && Date.now() - transactionSubmittedTime > 30000
}
TxListItem.prototype.setSelectedToken = function (tokenAddress) {
this.props.setSelectedToken(tokenAddress)
}
TxListItem.prototype.resubmit = function () {
const { transactionId } = this.props
this.props.retryTransaction(transactionId)
.then(id => this.props.history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`))
}
TxListItem.prototype.render = function () {
const {
transactionStatus,
onClick,
transactionId,
dateString,
address,
className,
txParams,
} = this.props
const { total, fiatTotal, isTokenTx } = this.state
return h(`div${className || ''}`, {
key: transactionId,
onClick: () => onClick && onClick(transactionId),
}, [
h(`div.flex-column.tx-list-item-wrapper`, {}, [
h('div.tx-list-date-wrapper', {
style: {},
}, [
h('span.tx-list-date', {}, [
dateString,
]),
]),
h('div.flex-row.tx-list-content-wrapper', {
style: {},
}, [
h('div.tx-list-identicon-wrapper', {
style: {},
}, [
h(Identicon, {
address,
diameter: 28,
}),
]),
h('div.tx-list-account-and-status-wrapper', {}, [
h('div.tx-list-account-wrapper', {
style: {},
}, [
h('span.tx-list-account', {}, [
this.getAddressText(address),
]),
]),
h('div.tx-list-status-wrapper', {
style: {},
}, [
h('span', {
className: classnames('tx-list-status', {
'tx-list-status--rejected': transactionStatus === 'rejected',
'tx-list-status--failed': transactionStatus === 'failed',
'tx-list-status--dropped': transactionStatus === 'dropped',
}),
},
this.txStatusIndicator(),
),
]),
]),
h('div.flex-column.tx-list-details-wrapper', {
style: {},
}, [
h('span.tx-list-value', total),
fiatTotal && h('span.tx-list-fiat-value', fiatTotal),
]),
]),
this.showRetryButton() && h('.tx-list-item-retry-container', {
onClick: (event) => {
event.stopPropagation()
if (isTokenTx) {
this.setSelectedToken(txParams.to)
}
this.resubmit()
},
}, [
h('span', 'Taking too long? Increase the gas price on your transaction'),
]),
]), // holding on icon from design
])
}
TxListItem.prototype.txStatusIndicator = function () {
const { transactionStatus } = this.props
let name
if (transactionStatus === 'unapproved') {
name = this.context.t('unapproved')
} else if (transactionStatus === 'rejected') {
name = this.context.t('rejected')
} else if (transactionStatus === 'approved') {
name = this.context.t('approved')
} else if (transactionStatus === 'signed') {
name = this.context.t('signed')
} else if (transactionStatus === 'submitted') {
name = this.context.t('submitted')
} else if (transactionStatus === 'confirmed') {
name = this.context.t('confirmed')
} else if (transactionStatus === 'failed') {
name = this.context.t('failed')
} else if (transactionStatus === 'dropped') {
name = this.context.t('dropped')
}
return name
}

@ -1,171 +0,0 @@
const Component = require('react').Component
const PropTypes = require('prop-types')
const connect = require('react-redux').connect
const h = require('react-hyperscript')
const inherits = require('util').inherits
const prefixForNetwork = require('../../lib/etherscan-prefix-for-network')
const selectors = require('../selectors')
const TxListItem = require('./tx-list-item')
const ShiftListItem = require('./shift-list-item')
const { formatDate } = require('../util')
const { showConfTxPage, updateNetworkNonce } = require('../actions')
const classnames = require('classnames')
const { tokenInfoGetter } = require('../token-util')
const { withRouter } = require('react-router-dom')
const { compose } = require('recompose')
const { CONFIRM_TRANSACTION_ROUTE } = require('../routes')
module.exports = compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps)
)(TxList)
TxList.contextTypes = {
t: PropTypes.func,
}
function mapStateToProps (state) {
return {
txsToRender: selectors.transactionsSelector(state),
conversionRate: selectors.conversionRateSelector(state),
selectedAddress: selectors.getSelectedAddress(state),
}
}
function mapDispatchToProps (dispatch) {
return {
showConfTxPage: ({ id }) => dispatch(showConfTxPage({ id })),
updateNetworkNonce: (address) => dispatch(updateNetworkNonce(address)),
}
}
inherits(TxList, Component)
function TxList () {
Component.call(this)
}
TxList.prototype.componentWillMount = function () {
this.tokenInfoGetter = tokenInfoGetter()
this.props.updateNetworkNonce(this.props.selectedAddress)
}
TxList.prototype.componentDidUpdate = function (prevProps) {
const oldTxsToRender = prevProps.txsToRender
const {
txsToRender: newTxsToRender,
selectedAddress,
updateNetworkNonce,
} = this.props
if (newTxsToRender.length > oldTxsToRender.length) {
updateNetworkNonce(selectedAddress)
}
}
TxList.prototype.render = function () {
return h('div.flex-column', [
h('div.flex-row.tx-list-header-wrapper', [
h('div.flex-row.tx-list-header', [
h('div', this.context.t('transactions')),
]),
]),
h('div.flex-column.tx-list-container', {}, [
this.renderTransaction(),
]),
])
}
TxList.prototype.renderTransaction = function () {
const { txsToRender, conversionRate } = this.props
return txsToRender.length
? txsToRender.map((transaction, i) => this.renderTransactionListItem(transaction, conversionRate, i))
: [h(
'div.tx-list-item.tx-list-item--empty',
{ key: 'tx-list-none' },
[ this.context.t('noTransactions') ],
)]
}
// TODO: Consider moving TxListItem into a separate component
TxList.prototype.renderTransactionListItem = function (transaction, conversionRate, index) {
// console.log({transaction})
// refer to transaction-list.js:line 58
if (transaction.key === 'shapeshift') {
return h(ShiftListItem, { ...transaction, key: `shapeshift${index}` })
}
const props = {
dateString: formatDate(transaction.time),
address: transaction.txParams && transaction.txParams.to,
transactionStatus: transaction.status,
transactionAmount: transaction.txParams && transaction.txParams.value,
transactionId: transaction.id,
transactionHash: transaction.hash,
transactionNetworkId: transaction.metamaskNetworkId,
transactionSubmittedTime: transaction.submittedTime,
}
const {
address,
transactionStatus,
transactionAmount,
dateString,
transactionId,
transactionHash,
transactionNetworkId,
transactionSubmittedTime,
} = props
const { history } = this.props
const opts = {
key: transactionId || transactionHash,
txParams: transaction.txParams,
isMsg: Boolean(transaction.msgParams),
transactionStatus,
transactionId,
dateString,
address,
transactionAmount,
transactionHash,
conversionRate,
tokenInfoGetter: this.tokenInfoGetter,
transactionSubmittedTime,
}
const isUnapproved = transactionStatus === 'unapproved'
if (isUnapproved) {
opts.onClick = () => {
this.props.showConfTxPage({ id: transactionId })
history.push(CONFIRM_TRANSACTION_ROUTE)
}
opts.transactionStatus = this.context.t('notStarted')
} else if (transactionHash) {
opts.onClick = () => this.view(transactionHash, transactionNetworkId)
}
opts.className = classnames('.tx-list-item', {
'.tx-list-pending-item-container': isUnapproved,
'.tx-list-clickable': Boolean(transactionHash) || isUnapproved,
})
return h(TxListItem, opts)
}
TxList.prototype.view = function (txHash, network) {
const url = etherscanLinkFor(txHash, network)
if (url) {
navigateTo(url)
}
}
function navigateTo (url) {
global.platform.openWindow({ url })
}
function etherscanLinkFor (txHash, network) {
const prefix = prefixForNetwork(network)
return `https://${prefix}etherscan.io/tx/${txHash}`
}

@ -1,121 +0,0 @@
const Component = require('react').Component
const PropTypes = require('prop-types')
const connect = require('react-redux').connect
const h = require('react-hyperscript')
const inherits = require('util').inherits
const { withRouter } = require('react-router-dom')
const { compose } = require('recompose')
const actions = require('../actions')
const selectors = require('../selectors')
const { SEND_ROUTE } = require('../routes')
const { checksumAddress: toChecksumAddress } = require('../util')
const BalanceComponent = require('./balance-component')
const Tooltip = require('./tooltip')
const TxList = require('./tx-list')
const SelectedAccount = require('./selected-account')
import Media from 'react-media'
import MenuBar from './menu-bar'
module.exports = compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps)
)(TxView)
TxView.contextTypes = {
t: PropTypes.func,
}
function mapStateToProps (state) {
const sidebarOpen = state.appState.sidebarOpen
const isMascara = state.appState.isMascara
const identities = state.metamask.identities
const accounts = state.metamask.accounts
const network = state.metamask.network
const selectedTokenAddress = state.metamask.selectedTokenAddress
const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
const checksumAddress = toChecksumAddress(selectedAddress)
const identity = identities[selectedAddress]
return {
sidebarOpen,
selectedAddress,
checksumAddress,
selectedTokenAddress,
selectedToken: selectors.getSelectedToken(state),
identity,
network,
isMascara,
}
}
function mapDispatchToProps (dispatch) {
return {
showSidebar: () => { dispatch(actions.showSidebar()) },
hideSidebar: () => { dispatch(actions.hideSidebar()) },
showModal: (payload) => { dispatch(actions.showModal(payload)) },
showSendPage: () => { dispatch(actions.showSendPage()) },
showSendTokenPage: () => { dispatch(actions.showSendTokenPage()) },
}
}
inherits(TxView, Component)
function TxView () {
Component.call(this)
}
TxView.prototype.renderHeroBalance = function () {
const { selectedToken } = this.props
return h('div.hero-balance', {}, [
h(BalanceComponent, { token: selectedToken }),
this.renderButtons(),
])
}
TxView.prototype.renderButtons = function () {
const {selectedToken, showModal, history } = this.props
return !selectedToken
? (
h('div.flex-row.flex-center.hero-balance-buttons', [
h('button.btn-primary.hero-balance-button', {
onClick: () => showModal({
name: 'DEPOSIT_ETHER',
}),
}, this.context.t('deposit')),
h('button.btn-primary.hero-balance-button', {
style: {
marginLeft: '0.8em',
},
onClick: () => history.push(SEND_ROUTE),
}, this.context.t('send')),
])
)
: (
h('div.flex-row.flex-center.hero-balance-buttons', [
h('button.btn-primary.hero-balance-button', {
onClick: () => history.push(SEND_ROUTE),
}, this.context.t('send')),
])
)
}
TxView.prototype.render = function () {
return h('div.tx-view.flex-column', [
h(Media, {
query: '(max-width: 575px)',
render: () => h(MenuBar),
}),
this.renderHeroBalance(),
h(TxList),
])
}

@ -16,3 +16,5 @@ export const DEPLOY_CONTRACT_ACTION_KEY = 'contractDeployment'
export const APPROVE_ACTION_KEY = 'approve'
export const SEND_TOKEN_ACTION_KEY = 'outgoing'
export const TRANSFER_FROM_ACTION_KEY = 'transferFrom'
export const TRANSACTION_TYPE_SHAPESHIFT = 'shapeshift'

@ -6,7 +6,6 @@ $sub-mid-size-breakpoint-range: "screen and (min-width: #{$break-large}) and (ma
*/
// Component Colors
$tx-view-bg: $white;
$wallet-view-bg: $alabaster;
// Main container
@ -30,25 +29,6 @@ $wallet-view-bg: $alabaster;
min-width: 0;
}
// tx view
.tx-view {
flex: 1 1 66.5%;
background: $tx-view-bg;
min-width: 0;
// No title on mobile
@media screen and (max-width: 575px) {
.identicon-wrapper {
display: none;
}
.account-name {
display: none;
}
}
}
// wallet view and sidebar
.wallet-view {

Loading…
Cancel
Save