refactor: transactions table info and details
This commit is contained in:
parent
6c1bc100b6
commit
926795eef1
|
@ -15,7 +15,6 @@ import Block from 'src/components/layout/Block'
|
||||||
import Col from 'src/components/layout/Col'
|
import Col from 'src/components/layout/Col'
|
||||||
import Img from 'src/components/layout/Img'
|
import Img from 'src/components/layout/Img'
|
||||||
import Paragraph from 'src/components/layout/Paragraph/index'
|
import Paragraph from 'src/components/layout/Paragraph/index'
|
||||||
import { TX_TYPE_CONFIRMATION } from 'src/logic/safe/transactions/send'
|
|
||||||
import { userAccountSelector } from 'src/logic/wallets/store/selectors'
|
import { userAccountSelector } from 'src/logic/wallets/store/selectors'
|
||||||
import { makeTransaction } from 'src/routes/safe/store/models/transaction'
|
import { makeTransaction } from 'src/routes/safe/store/models/transaction'
|
||||||
import { safeOwnersSelector, safeThresholdSelector } from 'src/routes/safe/store/selectors'
|
import { safeOwnersSelector, safeThresholdSelector } from 'src/routes/safe/store/selectors'
|
||||||
|
@ -29,11 +28,8 @@ function getOwnersConfirmations(tx, userAddress) {
|
||||||
currentUserAlreadyConfirmed = true
|
currentUserAlreadyConfirmed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf.type === TX_TYPE_CONFIRMATION) {
|
ownersWhoConfirmed.push(conf.owner)
|
||||||
ownersWhoConfirmed.push(conf.owner)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return [ownersWhoConfirmed, currentUserAlreadyConfirmed]
|
return [ownersWhoConfirmed, currentUserAlreadyConfirmed]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { SAFE_METHODS_NAMES } from 'src/logic/contracts/methodIds'
|
import { SAFE_METHODS_NAMES } from 'src/logic/contracts/methodIds'
|
||||||
import { getWeb3 } from 'src/logic/wallets/getWeb3'
|
|
||||||
|
|
||||||
const getSafeVersion = (data) => {
|
const getSafeVersion = (data) => {
|
||||||
const contractAddress = data.substr(340, 40).toLowerCase()
|
const contractAddress = data.substr(340, 40).toLowerCase()
|
||||||
|
@ -12,43 +11,50 @@ const getSafeVersion = (data) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTxData = (tx) => {
|
export const getTxData = (tx) => {
|
||||||
const web3 = getWeb3()
|
|
||||||
const { fromWei, toBN } = web3.utils
|
|
||||||
|
|
||||||
const txData: any = {}
|
const txData: any = {}
|
||||||
|
|
||||||
if (tx.isTokenTransfer && tx.decodedParams) {
|
if (tx.decodedParams) {
|
||||||
txData.recipient = tx.decodedParams.recipient
|
if (tx.isTokenTransfer) {
|
||||||
txData.value = fromWei(toBN(tx.decodedParams.value), 'ether')
|
const { to } = tx.decodedParams.transfer
|
||||||
|
txData.recipient = to
|
||||||
|
txData.isTokenTransfer = true
|
||||||
|
}
|
||||||
|
if (tx.isCollectibleTransfer) {
|
||||||
|
const { safeTransferFrom, transfer, transferFrom } = tx.decodedParams
|
||||||
|
const { to, value } = safeTransferFrom || transferFrom || transfer
|
||||||
|
txData.recipient = to
|
||||||
|
txData.tokenId = value
|
||||||
|
txData.isCollectibleTransfer = true
|
||||||
|
}
|
||||||
} else if (tx.customTx) {
|
} else if (tx.customTx) {
|
||||||
txData.recipient = tx.recipient
|
txData.recipient = tx.recipient
|
||||||
txData.value = fromWei(toBN(tx.value), 'ether')
|
|
||||||
txData.data = tx.data
|
txData.data = tx.data
|
||||||
txData.customTx = true
|
txData.customTx = true
|
||||||
} else if (Number(tx.value) > 0) {
|
} else if (Number(tx.value) > 0) {
|
||||||
txData.recipient = tx.recipient
|
txData.recipient = tx.recipient
|
||||||
txData.value = fromWei(toBN(tx.value), 'ether')
|
|
||||||
} else if (tx.modifySettingsTx) {
|
} else if (tx.modifySettingsTx) {
|
||||||
txData.recipient = tx.recipient
|
txData.recipient = tx.recipient
|
||||||
txData.modifySettingsTx = true
|
txData.modifySettingsTx = true
|
||||||
|
|
||||||
if (tx.decodedParams) {
|
if (tx.decodedParams) {
|
||||||
txData.action = tx.decodedParams.methodName
|
if (tx.decodedParams[SAFE_METHODS_NAMES.REMOVE_OWNER]) {
|
||||||
|
const { _threshold, owner } = tx.decodedParams[SAFE_METHODS_NAMES.REMOVE_OWNER]
|
||||||
if (txData.action === SAFE_METHODS_NAMES.REMOVE_OWNER) {
|
txData.removedOwner = owner
|
||||||
txData.removedOwner = tx.decodedParams.args[1]
|
txData.newThreshold = _threshold
|
||||||
txData.newThreshold = tx.decodedParams.args[2]
|
} else if (tx.decodedParams[SAFE_METHODS_NAMES.CHANGE_THRESHOLD]) {
|
||||||
} else if (txData.action === SAFE_METHODS_NAMES.CHANGE_THRESHOLD) {
|
const { _threshold } = tx.decodedParams[SAFE_METHODS_NAMES.CHANGE_THRESHOLD]
|
||||||
txData.newThreshold = tx.decodedParams.args[0]
|
txData.newThreshold = _threshold
|
||||||
} else if (txData.action === SAFE_METHODS_NAMES.ADD_OWNER_WITH_THRESHOLD) {
|
} else if (tx.decodedParams[SAFE_METHODS_NAMES.ADD_OWNER_WITH_THRESHOLD]) {
|
||||||
txData.addedOwner = tx.decodedParams.args[0]
|
const { _threshold, owner } = tx.decodedParams[SAFE_METHODS_NAMES.ADD_OWNER_WITH_THRESHOLD]
|
||||||
txData.newThreshold = tx.decodedParams.args[1]
|
txData.addedOwner = owner
|
||||||
} else if (txData.action === SAFE_METHODS_NAMES.SWAP_OWNER) {
|
txData.newThreshold = _threshold
|
||||||
txData.removedOwner = tx.decodedParams.args[1]
|
} else if (tx.decodedParams[SAFE_METHODS_NAMES.SWAP_OWNER]) {
|
||||||
txData.addedOwner = tx.decodedParams.args[2]
|
const { newOwner, oldOwner } = tx.decodedParams[SAFE_METHODS_NAMES.SWAP_OWNER]
|
||||||
|
txData.removedOwner = oldOwner
|
||||||
|
txData.addedOwner = newOwner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (tx.cancellationTx) {
|
} else if (tx.isCancellationTx) {
|
||||||
txData.cancellationTx = true
|
txData.cancellationTx = true
|
||||||
} else if (tx.creationTx) {
|
} else if (tx.creationTx) {
|
||||||
txData.creationTx = true
|
txData.creationTx = true
|
||||||
|
@ -57,7 +63,6 @@ export const getTxData = (tx) => {
|
||||||
txData.data = `The contract of this Safe is upgraded to Version ${getSafeVersion(tx.data)}`
|
txData.data = `The contract of this Safe is upgraded to Version ${getSafeVersion(tx.data)}`
|
||||||
} else {
|
} else {
|
||||||
txData.recipient = tx.recipient
|
txData.recipient = tx.recipient
|
||||||
txData.value = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return txData
|
return txData
|
||||||
|
|
|
@ -11,6 +11,8 @@ import { getAppInfoFromOrigin, getAppInfoFromUrl } from 'src/routes/safe/compone
|
||||||
|
|
||||||
const typeToIcon = {
|
const typeToIcon = {
|
||||||
outgoing: OutgoingTxIcon,
|
outgoing: OutgoingTxIcon,
|
||||||
|
token: OutgoingTxIcon,
|
||||||
|
collectible: OutgoingTxIcon,
|
||||||
incoming: IncomingTxIcon,
|
incoming: IncomingTxIcon,
|
||||||
custom: CustomTxIcon,
|
custom: CustomTxIcon,
|
||||||
settings: SettingsTxIcon,
|
settings: SettingsTxIcon,
|
||||||
|
@ -21,6 +23,8 @@ const typeToIcon = {
|
||||||
|
|
||||||
const typeToLabel = {
|
const typeToLabel = {
|
||||||
outgoing: 'Outgoing transfer',
|
outgoing: 'Outgoing transfer',
|
||||||
|
token: 'Outgoing transfer',
|
||||||
|
collectible: 'Outgoing transfer',
|
||||||
incoming: 'Incoming transfer',
|
incoming: 'Incoming transfer',
|
||||||
custom: 'Contract Interaction',
|
custom: 'Contract Interaction',
|
||||||
settings: 'Modify settings',
|
settings: 'Modify settings',
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { BigNumber } from 'bignumber.js'
|
||||||
import format from 'date-fns/format'
|
import format from 'date-fns/format'
|
||||||
import getTime from 'date-fns/getTime'
|
import getTime from 'date-fns/getTime'
|
||||||
import parseISO from 'date-fns/parseISO'
|
import parseISO from 'date-fns/parseISO'
|
||||||
import { List, Map } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import TxType from './TxType'
|
import TxType from './TxType'
|
||||||
|
@ -43,7 +43,7 @@ export const getIncomingTxAmount = (tx, formatted = true) => {
|
||||||
|
|
||||||
export const getTxAmount = (tx, formatted = true) => {
|
export const getTxAmount = (tx, formatted = true) => {
|
||||||
const { decimals = 18, decodedParams, isTokenTransfer, symbol } = tx
|
const { decimals = 18, decodedParams, isTokenTransfer, symbol } = tx
|
||||||
const { value } = isTokenTransfer && decodedParams && decodedParams.value ? decodedParams : tx
|
const { value } = isTokenTransfer && !!decodedParams && !!decodedParams.transfer ? decodedParams.transfer : tx
|
||||||
|
|
||||||
if (!isTokenTransfer && !(Number(value) > 0)) {
|
if (!isTokenTransfer && !(Number(value) > 0)) {
|
||||||
return NOT_AVAILABLE
|
return NOT_AVAILABLE
|
||||||
|
@ -65,22 +65,9 @@ const getIncomingTxTableData = (tx) => ({
|
||||||
const getTransactionTableData = (tx, cancelTx) => {
|
const getTransactionTableData = (tx, cancelTx) => {
|
||||||
const txDate = tx.submissionDate
|
const txDate = tx.submissionDate
|
||||||
|
|
||||||
let txType = 'outgoing'
|
|
||||||
if (tx.modifySettingsTx) {
|
|
||||||
txType = 'settings'
|
|
||||||
} else if (tx.cancellationTx) {
|
|
||||||
txType = 'cancellation'
|
|
||||||
} else if (tx.customTx) {
|
|
||||||
txType = 'custom'
|
|
||||||
} else if (tx.creationTx) {
|
|
||||||
txType = 'creation'
|
|
||||||
} else if (tx.upgradeTx) {
|
|
||||||
txType = 'upgrade'
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
[TX_TABLE_ID]: tx.blockNumber,
|
[TX_TABLE_ID]: tx.blockNumber,
|
||||||
[TX_TABLE_TYPE_ID]: <TxType origin={tx.origin} txType={txType} />,
|
[TX_TABLE_TYPE_ID]: <TxType origin={tx.origin} txType={tx.type} />,
|
||||||
[TX_TABLE_DATE_ID]: txDate ? formatDate(txDate) : '',
|
[TX_TABLE_DATE_ID]: txDate ? formatDate(txDate) : '',
|
||||||
[buildOrderFieldFrom(TX_TABLE_DATE_ID)]: txDate ? getTime(parseISO(txDate)) : null,
|
[buildOrderFieldFrom(TX_TABLE_DATE_ID)]: txDate ? getTime(parseISO(txDate)) : null,
|
||||||
[TX_TABLE_AMOUNT_ID]: getTxAmount(tx),
|
[TX_TABLE_AMOUNT_ID]: getTxAmount(tx),
|
||||||
|
@ -91,17 +78,12 @@ const getTransactionTableData = (tx, cancelTx) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTxTableData = (transactions, cancelTxs) => {
|
export const getTxTableData = (transactions, cancelTxs) => {
|
||||||
const cancelTxsByNonce = cancelTxs.reduce((acc, tx) => acc.set(tx.nonce, tx), Map())
|
|
||||||
|
|
||||||
return transactions.map((tx) => {
|
return transactions.map((tx) => {
|
||||||
if (INCOMING_TX_TYPES[tx.type]) {
|
if (INCOMING_TX_TYPES[tx.type] !== undefined) {
|
||||||
return getIncomingTxTableData(tx)
|
return getIncomingTxTableData(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getTransactionTableData(
|
return getTransactionTableData(tx, cancelTxs.get(`${tx.nonce}`))
|
||||||
tx,
|
|
||||||
Number.isInteger(Number.parseInt(tx.nonce, 10)) ? cancelTxsByNonce.get(tx.nonce) : undefined,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ import Table from 'src/components/Table'
|
||||||
import { cellWidth } from 'src/components/Table/TableHead'
|
import { cellWidth } from 'src/components/Table/TableHead'
|
||||||
import Block from 'src/components/layout/Block'
|
import Block from 'src/components/layout/Block'
|
||||||
import Row from 'src/components/layout/Row'
|
import Row from 'src/components/layout/Row'
|
||||||
import { extendedTransactionsSelector } from 'src/routes/safe/container/selector'
|
|
||||||
import { safeCancellationTransactionsSelector } from 'src/routes/safe/store/selectors'
|
import { safeCancellationTransactionsSelector } from 'src/routes/safe/store/selectors'
|
||||||
|
import { extendedTransactionsSelector } from '../../../store/selectors/transactions'
|
||||||
|
|
||||||
export const TRANSACTION_ROW_TEST_ID = 'transaction-row'
|
export const TRANSACTION_ROW_TEST_ID = 'transaction-row'
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ const TxsTable = ({ classes }) => {
|
||||||
const cancellationTransactions = useSelector(safeCancellationTransactionsSelector)
|
const cancellationTransactions = useSelector(safeCancellationTransactionsSelector)
|
||||||
const transactions = useSelector(extendedTransactionsSelector)
|
const transactions = useSelector(extendedTransactionsSelector)
|
||||||
|
|
||||||
const handleTxExpand = (safeTxHash) => {
|
const handleTxExpand = (rowCombinedId) => {
|
||||||
setExpandedTx((prevTx) => (prevTx === safeTxHash ? null : safeTxHash))
|
setExpandedTx((prevId) => (prevId === rowCombinedId ? null : rowCombinedId))
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns = generateColumns()
|
const columns = generateColumns()
|
||||||
|
@ -83,58 +83,65 @@ const TxsTable = ({ classes }) => {
|
||||||
size={filteredData.size}
|
size={filteredData.size}
|
||||||
>
|
>
|
||||||
{(sortedData) =>
|
{(sortedData) =>
|
||||||
sortedData.map((row, index) => (
|
sortedData.map((row, index) => {
|
||||||
<React.Fragment key={index}>
|
const rowCombinedId = `${row.tx.nonce + row.tx.data}`
|
||||||
<TableRow
|
|
||||||
className={cn(classes.row, expandedTx === row.tx.safeTxHash && classes.expandedRow)}
|
return (
|
||||||
data-testid={TRANSACTION_ROW_TEST_ID}
|
<React.Fragment key={index}>
|
||||||
onClick={() => handleTxExpand(row.tx.safeTxHash)}
|
<TableRow
|
||||||
tabIndex={-1}
|
className={cn(classes.row, expandedTx === rowCombinedId && classes.expandedRow)}
|
||||||
>
|
data-testid={TRANSACTION_ROW_TEST_ID}
|
||||||
{autoColumns.map((column: any) => (
|
onClick={() => handleTxExpand(rowCombinedId)}
|
||||||
<TableCell
|
tabIndex={-1}
|
||||||
align={column.align}
|
>
|
||||||
className={cn(classes.cell, ['cancelled', 'failed'].includes(row.status) && classes.cancelledRow)}
|
{autoColumns.map((column: any) => (
|
||||||
component="td"
|
<TableCell
|
||||||
key={column.id}
|
align={column.align}
|
||||||
style={cellWidth(column.width)}
|
className={cn(
|
||||||
>
|
classes.cell,
|
||||||
{row[column.id]}
|
['cancelled', 'failed'].includes(row.status) && classes.cancelledRow,
|
||||||
|
)}
|
||||||
|
component="td"
|
||||||
|
key={column.id}
|
||||||
|
style={cellWidth(column.width)}
|
||||||
|
>
|
||||||
|
{row[column.id]}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
<TableCell component="td">
|
||||||
|
<Row align="end" className={classes.actions}>
|
||||||
|
<Status status={row.status} />
|
||||||
|
</Row>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
))}
|
<TableCell style={expandCellStyle}>
|
||||||
<TableCell component="td">
|
{!row.tx.creationTx && (
|
||||||
<Row align="end" className={classes.actions}>
|
<IconButton disableRipple>
|
||||||
<Status status={row.status} />
|
{expandedTx === rowCombinedId ? <ExpandLess /> : <ExpandMore />}
|
||||||
</Row>
|
</IconButton>
|
||||||
</TableCell>
|
)}
|
||||||
<TableCell style={expandCellStyle}>
|
|
||||||
{!row.tx.creationTx && (
|
|
||||||
<IconButton disableRipple>
|
|
||||||
{expandedTx === row.safeTxHash ? <ExpandLess /> : <ExpandMore />}
|
|
||||||
</IconButton>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
{!row.tx.creationTx && (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell
|
|
||||||
className={classes.extendedTxContainer}
|
|
||||||
colSpan={6}
|
|
||||||
style={{ paddingBottom: 0, paddingTop: 0 }}
|
|
||||||
>
|
|
||||||
<CollapseAux
|
|
||||||
cancelTx={row[TX_TABLE_RAW_CANCEL_TX_ID]}
|
|
||||||
component={ExpandedTxComponent}
|
|
||||||
in={expandedTx === row.tx.safeTxHash}
|
|
||||||
timeout="auto"
|
|
||||||
tx={row[TX_TABLE_RAW_TX_ID]}
|
|
||||||
unmountOnExit
|
|
||||||
/>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
{!row.tx.creationTx && (
|
||||||
</React.Fragment>
|
<TableRow>
|
||||||
))
|
<TableCell
|
||||||
|
className={classes.extendedTxContainer}
|
||||||
|
colSpan={6}
|
||||||
|
style={{ paddingBottom: 0, paddingTop: 0 }}
|
||||||
|
>
|
||||||
|
<CollapseAux
|
||||||
|
cancelTx={row[TX_TABLE_RAW_CANCEL_TX_ID]}
|
||||||
|
component={ExpandedTxComponent}
|
||||||
|
in={expandedTx === rowCombinedId}
|
||||||
|
timeout="auto"
|
||||||
|
tx={row[TX_TABLE_RAW_TX_ID]}
|
||||||
|
unmountOnExit
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { List, Map } from 'immutable'
|
import { Map } from 'immutable'
|
||||||
import { createSelector } from 'reselect'
|
import { createSelector } from 'reselect'
|
||||||
|
|
||||||
import { tokensSelector } from 'src/logic/tokens/store/selectors'
|
import { tokensSelector } from 'src/logic/tokens/store/selectors'
|
||||||
|
@ -6,39 +6,7 @@ import { getEthAsToken } from 'src/logic/tokens/utils/tokenHelpers'
|
||||||
import { isUserOwner } from 'src/logic/wallets/ethAddresses'
|
import { isUserOwner } from 'src/logic/wallets/ethAddresses'
|
||||||
import { userAccountSelector } from 'src/logic/wallets/store/selectors'
|
import { userAccountSelector } from 'src/logic/wallets/store/selectors'
|
||||||
|
|
||||||
import {
|
import { safeActiveTokensSelector, safeBalancesSelector, safeSelector } from 'src/routes/safe/store/selectors'
|
||||||
safeActiveTokensSelector,
|
|
||||||
safeBalancesSelector,
|
|
||||||
safeCancellationTransactionsSelector,
|
|
||||||
safeIncomingTransactionsSelector,
|
|
||||||
safeSelector,
|
|
||||||
safeTransactionsSelector,
|
|
||||||
} from 'src/routes/safe/store/selectors'
|
|
||||||
|
|
||||||
const getTxStatus = (tx, userAddress, safe) => {
|
|
||||||
let txStatus
|
|
||||||
if (tx.executionTxHash) {
|
|
||||||
txStatus = 'success'
|
|
||||||
} else if (tx.cancelled) {
|
|
||||||
txStatus = 'cancelled'
|
|
||||||
} else if (tx.confirmations.size === safe.threshold) {
|
|
||||||
txStatus = 'awaiting_execution'
|
|
||||||
} else if (tx.creationTx) {
|
|
||||||
txStatus = 'success'
|
|
||||||
} else if (!tx.confirmations.size) {
|
|
||||||
txStatus = 'pending'
|
|
||||||
} else {
|
|
||||||
const userConfirmed = tx.confirmations.filter((conf) => conf.owner === userAddress).size === 1
|
|
||||||
const userIsSafeOwner = safe.owners.filter((owner) => owner.address === userAddress).size === 1
|
|
||||||
txStatus = !userConfirmed && userIsSafeOwner ? 'awaiting_your_confirmation' : 'awaiting_confirmations'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx.isSuccessful === false) {
|
|
||||||
txStatus = 'failed'
|
|
||||||
}
|
|
||||||
|
|
||||||
return txStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
export const grantedSelector = createSelector(userAccountSelector, safeSelector, (userAccount, safe) =>
|
export const grantedSelector = createSelector(userAccountSelector, safeSelector, (userAccount, safe) =>
|
||||||
isUserOwner(safe, userAccount),
|
isUserOwner(safe, userAccount),
|
||||||
|
@ -76,31 +44,3 @@ export const extendedSafeTokensSelector = createSelector(
|
||||||
return extendedTokens.toList()
|
return extendedTokens.toList()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
export const extendedTransactionsSelector = createSelector(
|
|
||||||
safeSelector,
|
|
||||||
userAccountSelector,
|
|
||||||
safeTransactionsSelector,
|
|
||||||
safeCancellationTransactionsSelector,
|
|
||||||
safeIncomingTransactionsSelector,
|
|
||||||
(safe, userAddress, transactions, cancellationTransactions, incomingTransactions) => {
|
|
||||||
const cancellationTransactionsByNonce = cancellationTransactions.reduce((acc, tx) => acc.set(tx.nonce, tx), Map())
|
|
||||||
const extendedTransactions = transactions.map((tx) => {
|
|
||||||
let extendedTx = tx
|
|
||||||
|
|
||||||
if (!tx.isExecuted) {
|
|
||||||
if (
|
|
||||||
(cancellationTransactionsByNonce.get(tx.nonce) &&
|
|
||||||
cancellationTransactionsByNonce.get(tx.nonce).get('isExecuted')) ||
|
|
||||||
transactions.find((safeTx) => tx.nonce === safeTx.nonce && safeTx.isExecuted)
|
|
||||||
) {
|
|
||||||
extendedTx = tx.set('cancelled', true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return extendedTx.set('status', getTxStatus(extendedTx, userAddress, safe))
|
|
||||||
})
|
|
||||||
|
|
||||||
return List([...extendedTransactions, ...incomingTransactions])
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,65 +1,10 @@
|
||||||
import { List, Map } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { createSelector } from 'reselect'
|
import { createSelector } from 'reselect'
|
||||||
|
|
||||||
import { userAccountSelector } from 'src/logic/wallets/store/selectors'
|
import { safeIncomingTransactionsSelector, safeTransactionsSelector } from 'src/routes/safe/store/selectors'
|
||||||
import {
|
|
||||||
safeCancellationTransactionsSelector,
|
|
||||||
safeIncomingTransactionsSelector,
|
|
||||||
safeSelector,
|
|
||||||
safeTransactionsSelector,
|
|
||||||
} from 'src/routes/safe/store/selectors'
|
|
||||||
|
|
||||||
const getTxStatus = (tx: any, userAddress: string, safe): string => {
|
|
||||||
let txStatus
|
|
||||||
|
|
||||||
if (tx.executionTxHash) {
|
|
||||||
txStatus = 'success'
|
|
||||||
} else if (tx.cancelled) {
|
|
||||||
txStatus = 'cancelled'
|
|
||||||
} else if (tx.confirmations.size === safe.threshold) {
|
|
||||||
txStatus = 'awaiting_execution'
|
|
||||||
} else if (tx.creationTx) {
|
|
||||||
txStatus = 'success'
|
|
||||||
} else if (!tx.confirmations.size) {
|
|
||||||
txStatus = 'pending'
|
|
||||||
} else {
|
|
||||||
const userConfirmed = tx.confirmations.filter((conf) => conf.owner === userAddress).size === 1
|
|
||||||
const userIsSafeOwner = safe.owners.filter((owner) => owner.address === userAddress).size === 1
|
|
||||||
txStatus = !userConfirmed && userIsSafeOwner ? 'awaiting_your_confirmation' : 'awaiting_confirmations'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx.isSuccessful === false) {
|
|
||||||
txStatus = 'failed'
|
|
||||||
}
|
|
||||||
|
|
||||||
return txStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
export const extendedTransactionsSelector = createSelector(
|
export const extendedTransactionsSelector = createSelector(
|
||||||
safeSelector,
|
|
||||||
userAccountSelector,
|
|
||||||
safeTransactionsSelector,
|
safeTransactionsSelector,
|
||||||
safeCancellationTransactionsSelector,
|
|
||||||
safeIncomingTransactionsSelector,
|
safeIncomingTransactionsSelector,
|
||||||
(safe, userAddress, transactions, cancellationTransactions, incomingTransactions) => {
|
(transactions, incomingTransactions) => List([...transactions, ...incomingTransactions]),
|
||||||
const cancellationTransactionsByNonce = cancellationTransactions.reduce((acc, tx) => acc.set(tx.nonce, tx), Map())
|
|
||||||
const extendedTransactions = transactions.map((tx: any) =>
|
|
||||||
tx.withMutations((transaction) => {
|
|
||||||
if (!transaction.isExecuted) {
|
|
||||||
if (
|
|
||||||
(cancellationTransactionsByNonce.get(tx.nonce) &&
|
|
||||||
cancellationTransactionsByNonce.get(tx.nonce).get('isExecuted')) ||
|
|
||||||
transactions.find((safeTx) => tx.nonce === safeTx.nonce && safeTx.isExecuted)
|
|
||||||
) {
|
|
||||||
transaction.set('cancelled', true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transaction.set('status', getTxStatus(transaction, userAddress, safe))
|
|
||||||
|
|
||||||
return transaction
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
return List([...extendedTransactions, ...incomingTransactions])
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue