fetch transactions refactoring wip
This commit is contained in:
parent
ec9e7f9fb8
commit
a533f576c3
|
@ -6,8 +6,6 @@ import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
|
|
||||||
export const CALL = 0
|
export const CALL = 0
|
||||||
export const DELEGATE_CALL = 1
|
export const DELEGATE_CALL = 1
|
||||||
export const TX_TYPE_EXECUTION = 'execution'
|
|
||||||
export const TX_TYPE_CONFIRMATION = 'confirmation'
|
|
||||||
|
|
||||||
type Transaction = {
|
type Transaction = {
|
||||||
safeInstance: any,
|
safeInstance: any,
|
||||||
|
|
|
@ -4,7 +4,6 @@ import axios from 'axios'
|
||||||
import { getTxServiceHost, getTxServiceUriFrom } from '~/config'
|
import { getTxServiceHost, getTxServiceUriFrom } from '~/config'
|
||||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
|
|
||||||
export type TxServiceType = 'confirmation' | 'execution' | 'initialised'
|
|
||||||
export type Operation = 0 | 1 | 2
|
export type Operation = 0 | 1 | 2
|
||||||
|
|
||||||
const calculateBodyFrom = async (
|
const calculateBodyFrom = async (
|
||||||
|
|
|
@ -16,7 +16,6 @@ import Block from '~/components/layout/Block'
|
||||||
import Col from '~/components/layout/Col'
|
import Col from '~/components/layout/Col'
|
||||||
import Img from '~/components/layout/Img'
|
import Img from '~/components/layout/Img'
|
||||||
import Paragraph from '~/components/layout/Paragraph/index'
|
import Paragraph from '~/components/layout/Paragraph/index'
|
||||||
import { TX_TYPE_CONFIRMATION } from '~/logic/safe/transactions/send'
|
|
||||||
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
import { type Transaction, makeTransaction } from '~/routes/safe/store/models/transaction'
|
import { type Transaction, makeTransaction } from '~/routes/safe/store/models/transaction'
|
||||||
import { safeOwnersSelector, safeThresholdSelector } from '~/routes/safe/store/selectors'
|
import { safeOwnersSelector, safeThresholdSelector } from '~/routes/safe/store/selectors'
|
||||||
|
@ -43,9 +42,7 @@ 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,34 +0,0 @@
|
||||||
// @flow
|
|
||||||
import type { Dispatch as ReduxDispatch } from 'redux'
|
|
||||||
|
|
||||||
import { type GlobalState } from '~/store'
|
|
||||||
|
|
||||||
const getMockCreationTx = (safeAddress: string) => ({
|
|
||||||
blockNumber: null,
|
|
||||||
baseGas: 0,
|
|
||||||
confirmations: [],
|
|
||||||
data: null,
|
|
||||||
executionDate: null,
|
|
||||||
gasPrice: 0,
|
|
||||||
gasToken: '0x0000000000000000000000000000000000000000',
|
|
||||||
isExecuted: true,
|
|
||||||
nonce: null,
|
|
||||||
operation: 0,
|
|
||||||
refundReceiver: '0x0000000000000000000000000000000000000000',
|
|
||||||
safe: safeAddress,
|
|
||||||
safeTxGas: 0,
|
|
||||||
safeTxHash: '',
|
|
||||||
signatures: null,
|
|
||||||
submissionDate: null,
|
|
||||||
executor: '',
|
|
||||||
to: '',
|
|
||||||
transactionHash: null,
|
|
||||||
value: 0,
|
|
||||||
creationTx: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
const addMockSafeCreationTx = (safeAddress: string) => (dispatch: ReduxDispatch<GlobalState>) => {
|
|
||||||
dispatch(addTransaction(getMockCreationTx(safeAddress)))
|
|
||||||
}
|
|
||||||
|
|
||||||
export default addMockSafeCreationTx
|
|
|
@ -6,12 +6,12 @@ import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
import { addIncomingTransactions } from '../addIncomingTransactions'
|
import { addIncomingTransactions } from '../addIncomingTransactions'
|
||||||
import { addTransactions } from '../addTransactions'
|
import { addTransactions } from '../addTransactions'
|
||||||
|
|
||||||
|
import { loadIncomingTransactions } from './loadIncomingTransactions'
|
||||||
import { type SafeTransactionsType, loadOutgoingTransactions } from './loadOutgoingTransactions'
|
import { type SafeTransactionsType, loadOutgoingTransactions } from './loadOutgoingTransactions'
|
||||||
|
|
||||||
import { addCancellationTransactions } from '~/routes/safe/store/actions/transactions/addCancellationTransactions'
|
import { addCancellationTransactions } from '~/routes/safe/store/actions/transactions/addCancellationTransactions'
|
||||||
import { type IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
import { type IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
||||||
import { type GlobalState } from '~/store'
|
import { type GlobalState } from '~/store'
|
||||||
|
|
||||||
export default (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>, getState: GetState) => {
|
export default (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>, getState: GetState) => {
|
||||||
const transactions: SafeTransactionsType | typeof undefined = await loadOutgoingTransactions(safeAddress, getState)
|
const transactions: SafeTransactionsType | typeof undefined = await loadOutgoingTransactions(safeAddress, getState)
|
||||||
if (transactions) {
|
if (transactions) {
|
||||||
|
@ -25,7 +25,7 @@ export default (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalSta
|
||||||
|
|
||||||
const incomingTransactions:
|
const incomingTransactions:
|
||||||
| Map<string, List<IncomingTransaction>>
|
| Map<string, List<IncomingTransaction>>
|
||||||
| typeof undefined = await loadSafeIncomingTransactions(safeAddress)
|
| typeof undefined = await loadIncomingTransactions(safeAddress)
|
||||||
|
|
||||||
if (incomingTransactions) {
|
if (incomingTransactions) {
|
||||||
dispatch(addIncomingTransactions(incomingTransactions))
|
dispatch(addIncomingTransactions(incomingTransactions))
|
||||||
|
|
|
@ -71,7 +71,7 @@ const batchIncomingTxsTokenDataRequest = (txs: IncomingTxServiceModel[]) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let prevIncomingTxsEtag = null
|
let prevIncomingTxsEtag = null
|
||||||
export const loadSafeIncomingTransactions = async (safeAddress: string) => {
|
export const loadIncomingTransactions = async (safeAddress: string) => {
|
||||||
let incomingTransactions: IncomingTxServiceModel[] = []
|
let incomingTransactions: IncomingTxServiceModel[] = []
|
||||||
try {
|
try {
|
||||||
const config = prevIncomingTxsEtag
|
const config = prevIncomingTxsEtag
|
||||||
|
|
|
@ -3,9 +3,12 @@ import ERC20Detailed from '@openzeppelin/contracts/build/contracts/ERC20Detailed
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { List, Map, type RecordInstance } from 'immutable'
|
import { List, Map, type RecordInstance } from 'immutable'
|
||||||
|
|
||||||
|
import addMockSafeCreationTx from '../utils/addMockSafeCreationTx'
|
||||||
|
|
||||||
import generateBatchRequests from '~/logic/contracts/generateBatchRequests'
|
import generateBatchRequests from '~/logic/contracts/generateBatchRequests'
|
||||||
import { decodeParamsFromSafeMethod } from '~/logic/contracts/methodIds'
|
import { decodeParamsFromSafeMethod } from '~/logic/contracts/methodIds'
|
||||||
import { type TxServiceType, buildTxServiceUrl } from '~/logic/safe/transactions/txHistory'
|
import { buildTxServiceUrl } from '~/logic/safe/transactions/txHistory'
|
||||||
|
import { getTokenInfos } from '~/logic/tokens/store/actions/fetchTokens'
|
||||||
import { TOKEN_REDUCER_ID } from '~/logic/tokens/store/reducer/tokens'
|
import { TOKEN_REDUCER_ID } from '~/logic/tokens/store/reducer/tokens'
|
||||||
import {
|
import {
|
||||||
SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH,
|
SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH,
|
||||||
|
@ -19,10 +22,11 @@ import { web3ReadOnly } from '~/logic/wallets/getWeb3'
|
||||||
import { makeConfirmation } from '~/routes/safe/store/models/confirmation'
|
import { makeConfirmation } from '~/routes/safe/store/models/confirmation'
|
||||||
import type { TransactionProps } from '~/routes/safe/store/models/transaction'
|
import type { TransactionProps } from '~/routes/safe/store/models/transaction'
|
||||||
import { type Transaction, makeTransaction } from '~/routes/safe/store/models/transaction'
|
import { type Transaction, makeTransaction } from '~/routes/safe/store/models/transaction'
|
||||||
|
|
||||||
type ConfirmationServiceModel = {
|
type ConfirmationServiceModel = {
|
||||||
owner: string,
|
owner: string,
|
||||||
submissionDate: Date,
|
submissionDate: Date,
|
||||||
confirmationType: string,
|
signature: string,
|
||||||
transactionHash: string,
|
transactionHash: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,16 +62,12 @@ export const buildTransactionFrom = async (
|
||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
tx: TxServiceModel,
|
tx: TxServiceModel,
|
||||||
knownTokens,
|
knownTokens,
|
||||||
txTokenDecimals,
|
|
||||||
txTokenSymbol,
|
|
||||||
txTokenName,
|
|
||||||
code,
|
code,
|
||||||
): Promise<Transaction> => {
|
): Promise<Transaction> => {
|
||||||
const confirmations = List(
|
const confirmations = List(
|
||||||
tx.confirmations.map((conf: ConfirmationServiceModel) =>
|
tx.confirmations.map((conf: ConfirmationServiceModel) =>
|
||||||
makeConfirmation({
|
makeConfirmation({
|
||||||
owner: conf.owner,
|
owner: conf.owner,
|
||||||
type: ((conf.confirmationType.toLowerCase(): any): TxServiceType),
|
|
||||||
hash: conf.transactionHash,
|
hash: conf.transactionHash,
|
||||||
signature: conf.signature,
|
signature: conf.signature,
|
||||||
}),
|
}),
|
||||||
|
@ -77,7 +77,7 @@ export const buildTransactionFrom = async (
|
||||||
const cancellationTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !tx.data
|
const cancellationTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !tx.data
|
||||||
const isERC721Token =
|
const isERC721Token =
|
||||||
(code && code.includes(SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH)) ||
|
(code && code.includes(SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH)) ||
|
||||||
(isTokenTransfer(tx.data, Number(tx.value)) && !knownTokens.get(tx.to) && txTokenDecimals !== null)
|
(isTokenTransfer(tx.data, Number(tx.value)) && !knownTokens.get(tx.to))
|
||||||
let isSendTokenTx = !isERC721Token && isTokenTransfer(tx.data, Number(tx.value))
|
let isSendTokenTx = !isERC721Token && isTokenTransfer(tx.data, Number(tx.value))
|
||||||
const isMultiSendTx = isMultisendTransaction(tx.data, Number(tx.value))
|
const isMultiSendTx = isMultisendTransaction(tx.data, Number(tx.value))
|
||||||
const isUpgradeTx = isMultiSendTx && isUpgradeTransaction(tx.data)
|
const isUpgradeTx = isMultiSendTx && isUpgradeTransaction(tx.data)
|
||||||
|
@ -85,11 +85,16 @@ export const buildTransactionFrom = async (
|
||||||
|
|
||||||
let refundParams = null
|
let refundParams = null
|
||||||
if (tx.gasPrice > 0) {
|
if (tx.gasPrice > 0) {
|
||||||
const refundSymbol = txTokenSymbol || 'ETH'
|
let refundSymbol = 'ETH'
|
||||||
const decimals = txTokenName || 18
|
let refundDecimals = 18
|
||||||
const feeString = (tx.gasPrice * (tx.baseGas + tx.safeTxGas)).toString().padStart(decimals, 0)
|
if (tx.gasToken !== ZERO_ADDRESS) {
|
||||||
const whole = feeString.slice(0, feeString.length - decimals) || '0'
|
const gasToken = await getTokenInfos(tx.gasToken)
|
||||||
const fraction = feeString.slice(feeString.length - decimals)
|
refundSymbol = gasToken.symbol
|
||||||
|
refundDecimals = gasToken.decimals
|
||||||
|
}
|
||||||
|
const feeString = (tx.gasPrice * (tx.baseGas + tx.safeTxGas)).toString().padStart(refundDecimals, 0)
|
||||||
|
const whole = feeString.slice(0, feeString.length - refundDecimals) || '0'
|
||||||
|
const fraction = feeString.slice(feeString.length - refundDecimals)
|
||||||
|
|
||||||
const formattedFee = `${whole}.${fraction}`
|
const formattedFee = `${whole}.${fraction}`
|
||||||
refundParams = {
|
refundParams = {
|
||||||
|
@ -98,11 +103,16 @@ export const buildTransactionFrom = async (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let symbol = txTokenSymbol || 'ETH'
|
let symbol = 'ETH'
|
||||||
let decimals = txTokenDecimals || 18
|
let decimals = 18
|
||||||
let decodedParams
|
let decodedParams
|
||||||
if (isSendTokenTx) {
|
if (isSendTokenTx) {
|
||||||
if (txTokenSymbol === null || txTokenDecimals === null) {
|
try {
|
||||||
|
const token = await getTokenInfos(tx.to)
|
||||||
|
|
||||||
|
symbol = token.symbol
|
||||||
|
decimals = token.decimals
|
||||||
|
} catch (e) {
|
||||||
try {
|
try {
|
||||||
const [tokenSymbol, tokenDecimals] = await Promise.all(
|
const [tokenSymbol, tokenDecimals] = await Promise.all(
|
||||||
generateBatchRequests({
|
generateBatchRequests({
|
||||||
|
@ -114,7 +124,7 @@ export const buildTransactionFrom = async (
|
||||||
|
|
||||||
symbol = tokenSymbol
|
symbol = tokenSymbol
|
||||||
decimals = tokenDecimals
|
decimals = tokenDecimals
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
// some contracts may implement the same methods as in ERC20 standard
|
// some contracts may implement the same methods as in ERC20 standard
|
||||||
// we may falsely treat them as tokens, so in case we get any errors when getting token info
|
// we may falsely treat them as tokens, so in case we get any errors when getting token info
|
||||||
// we fallback to displaying custom transaction
|
// we fallback to displaying custom transaction
|
||||||
|
@ -123,7 +133,7 @@ export const buildTransactionFrom = async (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = web3.eth.abi.decodeParameters(['address', 'uint256'], tx.data.slice(10))
|
const params = web3ReadOnly.eth.abi.decodeParameters(['address', 'uint256'], tx.data.slice(10))
|
||||||
decodedParams = {
|
decodedParams = {
|
||||||
recipient: params[0],
|
recipient: params[0],
|
||||||
value: params[1],
|
value: params[1],
|
||||||
|
@ -173,7 +183,7 @@ const batchTxTokenRequest = (txs: any[]) => {
|
||||||
const batch = new web3ReadOnly.BatchRequest()
|
const batch = new web3ReadOnly.BatchRequest()
|
||||||
|
|
||||||
const whenTxsValues = txs.map((tx) => {
|
const whenTxsValues = txs.map((tx) => {
|
||||||
const methods = ['decimals', { method: 'getCode', type: 'eth', args: [tx.to] }, 'symbol', 'name']
|
const methods = [{ method: 'getCode', type: 'eth', args: [tx.to] }]
|
||||||
return generateBatchRequests({
|
return generateBatchRequests({
|
||||||
abi: ERC20Detailed.abi,
|
abi: ERC20Detailed.abi,
|
||||||
address: tx.to,
|
address: tx.to,
|
||||||
|
@ -229,9 +239,7 @@ export const loadOutgoingTransactions = async (
|
||||||
const txsWithData = await batchTxTokenRequest(transactions)
|
const txsWithData = await batchTxTokenRequest(transactions)
|
||||||
// In case that the etags don't match, we parse the new transactions and save them to the cache
|
// In case that the etags don't match, we parse the new transactions and save them to the cache
|
||||||
const txsRecord: Array<RecordInstance<TransactionProps>> = await Promise.all(
|
const txsRecord: Array<RecordInstance<TransactionProps>> = await Promise.all(
|
||||||
txsWithData.map(([tx: TxServiceModel, decimals, code, symbol, name]) =>
|
txsWithData.map(([tx: TxServiceModel, code]) => buildTransactionFrom(safeAddress, tx, knownTokens, code)),
|
||||||
buildTransactionFrom(safeAddress, tx, knownTokens, decimals, symbol, name, code),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const groupedTxs = List(txsRecord).groupBy((tx) => (tx.get('cancellationTx') ? 'cancel' : 'outgoing'))
|
const groupedTxs = List(txsRecord).groupBy((tx) => (tx.get('cancellationTx') ? 'cancel' : 'outgoing'))
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
const addMockSafeCreationTx = (safeAddress: string) => [
|
||||||
|
{
|
||||||
|
blockNumber: null,
|
||||||
|
baseGas: 0,
|
||||||
|
confirmations: [],
|
||||||
|
data: null,
|
||||||
|
executionDate: null,
|
||||||
|
gasPrice: 0,
|
||||||
|
gasToken: '0x0000000000000000000000000000000000000000',
|
||||||
|
isExecuted: true,
|
||||||
|
nonce: null,
|
||||||
|
operation: 0,
|
||||||
|
refundReceiver: '0x0000000000000000000000000000000000000000',
|
||||||
|
safe: safeAddress,
|
||||||
|
safeTxGas: 0,
|
||||||
|
safeTxHash: '',
|
||||||
|
signatures: null,
|
||||||
|
submissionDate: null,
|
||||||
|
executor: '',
|
||||||
|
to: '',
|
||||||
|
transactionHash: null,
|
||||||
|
value: 0,
|
||||||
|
creationTx: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export default addMockSafeCreationTx
|
|
@ -2,18 +2,14 @@
|
||||||
import { Record } from 'immutable'
|
import { Record } from 'immutable'
|
||||||
import type { RecordFactory, RecordOf } from 'immutable'
|
import type { RecordFactory, RecordOf } from 'immutable'
|
||||||
|
|
||||||
import { type TxServiceType } from '~/logic/safe/transactions/txHistory'
|
|
||||||
|
|
||||||
export type ConfirmationProps = {
|
export type ConfirmationProps = {
|
||||||
owner: string,
|
owner: string,
|
||||||
type: TxServiceType,
|
|
||||||
hash: string,
|
hash: string,
|
||||||
signature?: string,
|
signature?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeConfirmation: RecordFactory<ConfirmationProps> = Record({
|
export const makeConfirmation: RecordFactory<ConfirmationProps> = Record({
|
||||||
owner: '',
|
owner: '',
|
||||||
type: 'initialised',
|
|
||||||
hash: '',
|
hash: '',
|
||||||
signature: null,
|
signature: null,
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
// @flow
|
||||||
|
import { List, Map } from 'immutable'
|
||||||
|
import { type Selector, createSelector } from 'reselect'
|
||||||
|
|
||||||
|
import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
|
import type { IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
||||||
|
import { type Safe } from '~/routes/safe/store/models/safe'
|
||||||
|
import { type Transaction, type TransactionStatus } from '~/routes/safe/store/models/transaction'
|
||||||
|
import {
|
||||||
|
type RouterProps,
|
||||||
|
safeCancellationTransactionsSelector,
|
||||||
|
safeIncomingTransactionsSelector,
|
||||||
|
safeSelector,
|
||||||
|
safeTransactionsSelector,
|
||||||
|
} from '~/routes/safe/store/selectors'
|
||||||
|
import { type GlobalState } from '~/store'
|
||||||
|
|
||||||
|
const getTxStatus = (tx: Transaction, userAddress: string, safe: Safe): TransactionStatus => {
|
||||||
|
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: Selector<
|
||||||
|
GlobalState,
|
||||||
|
RouterProps,
|
||||||
|
List<Transaction | IncomingTransaction>,
|
||||||
|
> = 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: Transaction) =>
|
||||||
|
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