(Fix) Pending transaction amount set to zero (#1316)
* fix: prevent runtime error when prev is `undefined` * fix: prevent runtime error when prev is `undefined` * fix: prevent runtime error when 'safes' is `undefined` * fix: add `dataDecoded` to the mocked tx so information is properly displayed for known methods * fix: set 'pending' status for tx being processed - given that the confirmations key is no longer an empty array, tx status must be explicitly set this way * fix: properly update mockedTx * fix: hide buttons when tx is pending * fix: type error * Rollback patches trying to fix bug Co-authored-by: Daniel Sanchez <daniel.sanchez@gnosis.pm> Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com>
This commit is contained in:
parent
5b99ceaa6d
commit
ac92f49c72
|
@ -5,6 +5,7 @@ import semverSatisfies from 'semver/functions/satisfies'
|
||||||
import { ThunkAction } from 'redux-thunk'
|
import { ThunkAction } from 'redux-thunk'
|
||||||
|
|
||||||
import { onboardUser } from 'src/components/ConnectButton'
|
import { onboardUser } from 'src/components/ConnectButton'
|
||||||
|
import { decodeMethods } from 'src/logic/contracts/methodIds'
|
||||||
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
|
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
|
||||||
import { getNotificationsFromTxType } from 'src/logic/notifications'
|
import { getNotificationsFromTxType } from 'src/logic/notifications'
|
||||||
import {
|
import {
|
||||||
|
@ -205,6 +206,7 @@ const createTransaction = (
|
||||||
confirmations: [], // this is used to determine if a tx is pending or not. See `calculateTransactionStatus` helper
|
confirmations: [], // this is used to determine if a tx is pending or not. See `calculateTransactionStatus` helper
|
||||||
value: txArgs.valueInWei,
|
value: txArgs.valueInWei,
|
||||||
safeTxHash,
|
safeTxHash,
|
||||||
|
dataDecoded: decodeMethods(txArgs.data),
|
||||||
submissionDate: new Date().toISOString(),
|
submissionDate: new Date().toISOString(),
|
||||||
}
|
}
|
||||||
const mockedTx = await mockTransaction(txToMock, safeAddress, state)
|
const mockedTx = await mockTransaction(txToMock, safeAddress, state)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { fromJS } from 'immutable'
|
|
||||||
import semverSatisfies from 'semver/functions/satisfies'
|
import semverSatisfies from 'semver/functions/satisfies'
|
||||||
|
|
||||||
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
|
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
|
||||||
|
@ -20,9 +19,9 @@ import {
|
||||||
import { getLastTx, getNewTxNonce, shouldExecuteTransaction } from 'src/logic/safe/store/actions/utils'
|
import { getLastTx, getNewTxNonce, shouldExecuteTransaction } from 'src/logic/safe/store/actions/utils'
|
||||||
|
|
||||||
import { getErrorMessage } from 'src/test/utils/ethereumErrors'
|
import { getErrorMessage } from 'src/test/utils/ethereumErrors'
|
||||||
import { makeConfirmation } from '../models/confirmation'
|
|
||||||
import { storeTx } from './createTransaction'
|
import { storeTx } from './createTransaction'
|
||||||
import { TransactionStatus } from '../models/types/transaction'
|
import { TransactionStatus } from 'src/logic/safe/store/models/types/transaction'
|
||||||
|
import { makeConfirmation } from 'src/logic/safe/store/models/confirmation'
|
||||||
|
|
||||||
const processTransaction = ({ approveAndExecute, notifiedTransaction, safeAddress, tx, userAddress }) => async (
|
const processTransaction = ({ approveAndExecute, notifiedTransaction, safeAddress, tx, userAddress }) => async (
|
||||||
dispatch,
|
dispatch,
|
||||||
|
@ -85,6 +84,8 @@ const processTransaction = ({ approveAndExecute, notifiedTransaction, safeAddres
|
||||||
dispatch(closeSnackbarAction(beforeExecutionKey))
|
dispatch(closeSnackbarAction(beforeExecutionKey))
|
||||||
|
|
||||||
await saveTxToHistory({ ...txArgs, signature })
|
await saveTxToHistory({ ...txArgs, signature })
|
||||||
|
// TODO: while we wait for the tx to be stored in the service and later update the tx info
|
||||||
|
// we should update the tx status in the store to disable owners' action buttons
|
||||||
dispatch(enqueueSnackbar(notificationsQueue.afterExecution.moreConfirmationsNeeded))
|
dispatch(enqueueSnackbar(notificationsQueue.afterExecution.moreConfirmationsNeeded))
|
||||||
|
|
||||||
dispatch(fetchTransactions(safeAddress))
|
dispatch(fetchTransactions(safeAddress))
|
||||||
|
@ -105,9 +106,7 @@ const processTransaction = ({ approveAndExecute, notifiedTransaction, safeAddres
|
||||||
|
|
||||||
const txToMock: TxToMock = {
|
const txToMock: TxToMock = {
|
||||||
...txArgs,
|
...txArgs,
|
||||||
confirmations: txArgs.confirmations, // this is used to determine if a tx is pending or not. See `calculateTransactionStatus` helper
|
|
||||||
value: txArgs.valueInWei,
|
value: txArgs.valueInWei,
|
||||||
submissionDate: txArgs.submissionDate,
|
|
||||||
}
|
}
|
||||||
const mockedTx = await mockTransaction(txToMock, safeAddress, state)
|
const mockedTx = await mockTransaction(txToMock, safeAddress, state)
|
||||||
|
|
||||||
|
@ -123,10 +122,14 @@ const processTransaction = ({ approveAndExecute, notifiedTransaction, safeAddres
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
saveTxToHistory({ ...txArgs, txHash }),
|
saveTxToHistory({ ...txArgs, txHash }),
|
||||||
storeTx(
|
storeTx(
|
||||||
mockedTx.updateIn(
|
mockedTx.withMutations((record) => {
|
||||||
['ownersWithPendingActions', mockedTx.isCancellationTx ? 'reject' : 'confirm'],
|
record
|
||||||
(previous) => previous.push(from),
|
.updateIn(
|
||||||
),
|
['ownersWithPendingActions', mockedTx.isCancellationTx ? 'reject' : 'confirm'],
|
||||||
|
(previous) => previous.push(from),
|
||||||
|
)
|
||||||
|
.set('status', TransactionStatus.PENDING)
|
||||||
|
}),
|
||||||
safeAddress,
|
safeAddress,
|
||||||
dispatch,
|
dispatch,
|
||||||
state,
|
state,
|
||||||
|
@ -175,16 +178,20 @@ const processTransaction = ({ approveAndExecute, notifiedTransaction, safeAddres
|
||||||
: TransactionStatus.FAILED,
|
: TransactionStatus.FAILED,
|
||||||
)
|
)
|
||||||
.updateIn(['ownersWithPendingActions', 'reject'], (prev) => prev.clear())
|
.updateIn(['ownersWithPendingActions', 'reject'], (prev) => prev.clear())
|
||||||
|
.updateIn(['ownersWithPendingActions', 'confirm'], (prev) => prev.clear())
|
||||||
|
})
|
||||||
|
: mockedTx.withMutations((record) => {
|
||||||
|
record
|
||||||
|
.updateIn(['ownersWithPendingActions', toStoreTx.isCancellationTx ? 'reject' : 'confirm'], (previous) =>
|
||||||
|
previous.pop(),
|
||||||
|
)
|
||||||
|
.set('status', TransactionStatus.AWAITING_CONFIRMATIONS)
|
||||||
})
|
})
|
||||||
: mockedTx.set('status', TransactionStatus.AWAITING_CONFIRMATIONS)
|
|
||||||
|
|
||||||
await storeTx(
|
await storeTx(
|
||||||
toStoreTx.withMutations((record) => {
|
toStoreTx.update('confirmations', (confirmations) => {
|
||||||
record
|
const index = confirmations.findIndex(({ owner }) => owner === from)
|
||||||
.set('confirmations', fromJS([...tx.confirmations, makeConfirmation({ owner: from })]))
|
return index === -1 ? confirmations.push(makeConfirmation({ owner: from })) : confirmations
|
||||||
.updateIn(['ownersWithPendingActions', toStoreTx.isCancellationTx ? 'reject' : 'confirm'], (previous) =>
|
|
||||||
previous.pop(from),
|
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
safeAddress,
|
safeAddress,
|
||||||
dispatch,
|
dispatch,
|
||||||
|
|
|
@ -34,7 +34,7 @@ import { TypedDataUtils } from 'eth-sig-util'
|
||||||
import { Token } from 'src/logic/tokens/store/model/token'
|
import { Token } from 'src/logic/tokens/store/model/token'
|
||||||
import { ProviderRecord } from 'src/logic/wallets/store/model/provider'
|
import { ProviderRecord } from 'src/logic/wallets/store/model/provider'
|
||||||
import { SafeRecord } from 'src/logic/safe/store/models/safe'
|
import { SafeRecord } from 'src/logic/safe/store/models/safe'
|
||||||
import { DecodedParams } from 'src/routes/safe/store/models/types/transactions.d'
|
import { DataDecoded, DecodedParams } from 'src/routes/safe/store/models/types/transactions.d'
|
||||||
|
|
||||||
export const isEmptyData = (data?: string | null): boolean => {
|
export const isEmptyData = (data?: string | null): boolean => {
|
||||||
return !data || data === EMPTY_DATA
|
return !data || data === EMPTY_DATA
|
||||||
|
@ -316,6 +316,7 @@ export type TxToMock = TxArgs & {
|
||||||
safeTxHash: string
|
safeTxHash: string
|
||||||
value: string
|
value: string
|
||||||
submissionDate: string
|
submissionDate: string
|
||||||
|
dataDecoded: DataDecoded | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mockTransaction = (tx: TxToMock, safeAddress: string, state: AppReduxState): Promise<Transaction> => {
|
export const mockTransaction = (tx: TxToMock, safeAddress: string, state: AppReduxState): Promise<Transaction> => {
|
||||||
|
|
|
@ -142,6 +142,7 @@ const OwnersColumn = ({
|
||||||
displayButtonRow = false
|
displayButtonRow = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: simplify this whole logic around tx status, it's getting hard to maintain and follow
|
||||||
const showConfirmBtn =
|
const showConfirmBtn =
|
||||||
!tx.isExecuted &&
|
!tx.isExecuted &&
|
||||||
tx.status !== 'pending' &&
|
tx.status !== 'pending' &&
|
||||||
|
@ -151,7 +152,8 @@ const OwnersColumn = ({
|
||||||
!currentUserAlreadyConfirmed &&
|
!currentUserAlreadyConfirmed &&
|
||||||
!thresholdReached
|
!thresholdReached
|
||||||
|
|
||||||
const showExecuteBtn = canExecute && !tx.isExecuted && thresholdReached
|
const showExecuteBtn =
|
||||||
|
canExecute && !tx.isExecuted && thresholdReached && tx.status !== 'pending' && cancelTx.status !== 'pending'
|
||||||
|
|
||||||
const showRejectBtn =
|
const showRejectBtn =
|
||||||
!cancelTx.isExecuted &&
|
!cancelTx.isExecuted &&
|
||||||
|
@ -163,7 +165,13 @@ const OwnersColumn = ({
|
||||||
!cancelThresholdReached &&
|
!cancelThresholdReached &&
|
||||||
displayButtonRow
|
displayButtonRow
|
||||||
|
|
||||||
const showExecuteRejectBtn = !cancelTx.isExecuted && !tx.isExecuted && canExecuteCancel && cancelThresholdReached
|
const showExecuteRejectBtn =
|
||||||
|
!cancelTx.isExecuted &&
|
||||||
|
!tx.isExecuted &&
|
||||||
|
canExecuteCancel &&
|
||||||
|
cancelThresholdReached &&
|
||||||
|
tx.status !== 'pending' &&
|
||||||
|
cancelTx.status !== 'pending'
|
||||||
|
|
||||||
const txThreshold = cancelTx.isExecuted ? tx.confirmations.size : threshold
|
const txThreshold = cancelTx.isExecuted ? tx.confirmations.size : threshold
|
||||||
const cancelThreshold = tx.isExecuted ? cancelTx.confirmations.size : threshold
|
const cancelThreshold = tx.isExecuted ? cancelTx.confirmations.size : threshold
|
||||||
|
|
Loading…
Reference in New Issue