Refactor create/confirm transactions
This commit is contained in:
parent
560301f981
commit
9259d79f61
|
@ -1,24 +1,14 @@
|
||||||
// @flow
|
// @flow
|
||||||
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
|
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
|
||||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchTokens'
|
import { type Operation } from '~/logic/safe/transactions'
|
||||||
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
|
||||||
import { isEther } from '~/logic/tokens/utils/tokenHelpers'
|
|
||||||
import { type Token } from '~/logic/tokens/store/model/token'
|
|
||||||
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
|
||||||
import { type Operation, saveTxToHistory } from '~/logic/safe/transactions'
|
|
||||||
import { type NotificationsQueue } from '~/logic/notifications'
|
|
||||||
import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
|
import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
|
||||||
import { getErrorMessage } from '~/test/utils/ethereumErrors'
|
|
||||||
|
|
||||||
export const CALL = 0
|
export const CALL = 0
|
||||||
export const TX_TYPE_EXECUTION = 'execution'
|
export const TX_TYPE_EXECUTION = 'execution'
|
||||||
export const TX_TYPE_CONFIRMATION = 'confirmation'
|
export const TX_TYPE_CONFIRMATION = 'confirmation'
|
||||||
|
|
||||||
export const approveTransaction = async (
|
export const getApprovalTransaction = async (
|
||||||
notiQueue: NotificationsQueue,
|
|
||||||
enqueueSnackbar: Function,
|
|
||||||
closeSnackbar: Function,
|
|
||||||
safeInstance: any,
|
safeInstance: any,
|
||||||
to: string,
|
to: string,
|
||||||
valueInWei: number | string,
|
valueInWei: number | string,
|
||||||
|
@ -43,62 +33,19 @@ export const approveTransaction = async (
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
const beforeExecutionKey = enqueueSnackbar(notiQueue.beforeExecution.message, notiQueue.beforeExecution.options)
|
|
||||||
let pendingExecutionKey
|
|
||||||
try {
|
try {
|
||||||
const web3 = getWeb3()
|
const web3 = getWeb3()
|
||||||
const contract = new web3.eth.Contract(GnosisSafeSol.abi, safeInstance.address)
|
const contract = new web3.eth.Contract(GnosisSafeSol.abi, safeInstance.address)
|
||||||
|
|
||||||
const transactionHash = await contract.methods
|
return contract.methods.approveHash(txHash)
|
||||||
.approveHash(txHash)
|
} catch (err) {
|
||||||
.send({
|
console.error(`Error while approving transaction: ${err}`)
|
||||||
from: sender,
|
|
||||||
})
|
|
||||||
.once('transactionHash', () => {
|
|
||||||
closeSnackbar(beforeExecutionKey)
|
|
||||||
pendingExecutionKey = enqueueSnackbar(
|
|
||||||
notiQueue.pendingExecution.single.message,
|
|
||||||
notiQueue.pendingExecution.single.options,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.on('error', (error) => {
|
|
||||||
console.error('Tx error:', error)
|
|
||||||
})
|
|
||||||
.then(async (receipt) => {
|
|
||||||
closeSnackbar(pendingExecutionKey)
|
|
||||||
await saveTxToHistory(
|
|
||||||
safeInstance,
|
|
||||||
to,
|
|
||||||
valueInWei,
|
|
||||||
data,
|
|
||||||
operation,
|
|
||||||
nonce,
|
|
||||||
receipt.transactionHash,
|
|
||||||
sender,
|
|
||||||
TX_TYPE_CONFIRMATION,
|
|
||||||
)
|
|
||||||
enqueueSnackbar(notiQueue.afterExecution.message, notiQueue.afterExecution.options)
|
|
||||||
return receipt.transactionHash
|
|
||||||
})
|
|
||||||
|
|
||||||
return transactionHash
|
throw err
|
||||||
} catch (error) {
|
|
||||||
closeSnackbar(beforeExecutionKey)
|
|
||||||
closeSnackbar(pendingExecutionKey)
|
|
||||||
enqueueSnackbar(notiQueue.afterExecutionError.message, notiQueue.afterExecutionError.options)
|
|
||||||
|
|
||||||
const executeData = safeInstance.contract.methods.approveHash(txHash).encodeABI()
|
|
||||||
const errMsg = await getErrorMessage(safeInstance.address, 0, executeData, sender)
|
|
||||||
console.error(`Error executing the TX: ${errMsg}`)
|
|
||||||
|
|
||||||
throw error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const executeTransaction = async (
|
export const getExecutionTransaction = async (
|
||||||
notiQueue: NotificationsQueue,
|
|
||||||
enqueueSnackbar: Function,
|
|
||||||
closeSnackbar: Function,
|
|
||||||
safeInstance: any,
|
safeInstance: any,
|
||||||
to: string,
|
to: string,
|
||||||
valueInWei: number | string,
|
valueInWei: number | string,
|
||||||
|
@ -106,95 +53,16 @@ export const executeTransaction = async (
|
||||||
operation: Operation,
|
operation: Operation,
|
||||||
nonce: string | number,
|
nonce: string | number,
|
||||||
sender: string,
|
sender: string,
|
||||||
signatures?: string,
|
sigs: string,
|
||||||
) => {
|
) => {
|
||||||
let sigs = signatures
|
|
||||||
|
|
||||||
// https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures
|
|
||||||
if (!sigs) {
|
|
||||||
sigs = `0x000000000000000000000000${sender.replace(
|
|
||||||
'0x',
|
|
||||||
'',
|
|
||||||
)}000000000000000000000000000000000000000000000000000000000000000001`
|
|
||||||
}
|
|
||||||
|
|
||||||
const beforeExecutionKey = enqueueSnackbar(notiQueue.beforeExecution.message, notiQueue.beforeExecution.options)
|
|
||||||
let pendingExecutionKey
|
|
||||||
try {
|
try {
|
||||||
const web3 = getWeb3()
|
const web3 = getWeb3()
|
||||||
const contract = new web3.eth.Contract(GnosisSafeSol.abi, safeInstance.address)
|
const contract = new web3.eth.Contract(GnosisSafeSol.abi, safeInstance.address)
|
||||||
|
|
||||||
const transactionHash = await contract.methods
|
return contract.methods.execTransaction(to, valueInWei, data, operation, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, sigs)
|
||||||
.execTransaction(to, valueInWei, data, operation, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, sigs)
|
} catch (err) {
|
||||||
.send({
|
console.error(`Error while creating transaction: ${err}`)
|
||||||
from: sender,
|
|
||||||
})
|
|
||||||
.once('transactionHash', () => {
|
|
||||||
closeSnackbar(beforeExecutionKey)
|
|
||||||
pendingExecutionKey = enqueueSnackbar(
|
|
||||||
notiQueue.pendingExecution.single.message,
|
|
||||||
notiQueue.pendingExecution.single.options,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.on('error', (error) => {
|
|
||||||
console.error('Tx error:', error)
|
|
||||||
})
|
|
||||||
.then(async (receipt) => {
|
|
||||||
closeSnackbar(pendingExecutionKey)
|
|
||||||
await saveTxToHistory(
|
|
||||||
safeInstance,
|
|
||||||
to,
|
|
||||||
valueInWei,
|
|
||||||
data,
|
|
||||||
operation,
|
|
||||||
nonce,
|
|
||||||
receipt.transactionHash,
|
|
||||||
sender,
|
|
||||||
TX_TYPE_EXECUTION,
|
|
||||||
)
|
|
||||||
enqueueSnackbar(notiQueue.afterExecution.message, notiQueue.afterExecution.options)
|
|
||||||
return receipt.transactionHash
|
|
||||||
})
|
|
||||||
|
|
||||||
return transactionHash
|
throw err
|
||||||
} catch (error) {
|
|
||||||
closeSnackbar(beforeExecutionKey)
|
|
||||||
closeSnackbar(pendingExecutionKey)
|
|
||||||
enqueueSnackbar(notiQueue.afterExecutionError.message, notiQueue.afterExecutionError.options)
|
|
||||||
|
|
||||||
const executeDataUsedSignatures = safeInstance.contract.methods
|
|
||||||
.execTransaction(to, valueInWei, data, operation, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, sigs)
|
|
||||||
.encodeABI()
|
|
||||||
const errMsg = await getErrorMessage(safeInstance.address, 0, executeDataUsedSignatures, sender)
|
|
||||||
console.error(`Error executing the TX: ${errMsg}`)
|
|
||||||
|
|
||||||
throw error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createTransaction = async (safeAddress: string, to: string, valueInEth: string, token: Token) => {
|
|
||||||
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
|
|
||||||
const web3 = getWeb3()
|
|
||||||
const from = web3.currentProvider.selectedAddress
|
|
||||||
const threshold = await safeInstance.getThreshold()
|
|
||||||
const nonce = (await safeInstance.nonce()).toString()
|
|
||||||
const valueInWei = web3.utils.toWei(valueInEth, 'ether')
|
|
||||||
const isExecution = threshold.toNumber() === 1
|
|
||||||
|
|
||||||
let txData = EMPTY_DATA
|
|
||||||
if (!isEther(token.symbol)) {
|
|
||||||
const StandardToken = await getStandardTokenContract()
|
|
||||||
const sendToken = await StandardToken.at(token.address)
|
|
||||||
|
|
||||||
txData = sendToken.contract.transfer(to, valueInWei).encodeABI()
|
|
||||||
}
|
|
||||||
|
|
||||||
let txHash
|
|
||||||
if (isExecution) {
|
|
||||||
txHash = await executeTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from)
|
|
||||||
} else {
|
|
||||||
// txHash = await approveTransaction(safeAddress, to, valueInWei, txData, CALL, nonce)
|
|
||||||
}
|
|
||||||
|
|
||||||
return txHash
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,9 +6,17 @@ import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
||||||
import { type GlobalState } from '~/store'
|
import { type GlobalState } from '~/store'
|
||||||
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
||||||
import {
|
import {
|
||||||
type NotifiedTransaction, approveTransaction, executeTransaction, CALL,
|
getApprovalTransaction,
|
||||||
|
getExecutionTransaction,
|
||||||
|
CALL,
|
||||||
|
type NotifiedTransaction,
|
||||||
|
TX_TYPE_CONFIRMATION,
|
||||||
|
TX_TYPE_EXECUTION,
|
||||||
|
saveTxToHistory,
|
||||||
} from '~/logic/safe/transactions'
|
} from '~/logic/safe/transactions'
|
||||||
import { getNofiticationsFromTxType } from '~/logic/notifications'
|
import { getNofiticationsFromTxType, type NotificationsQueue } from '~/logic/notifications'
|
||||||
|
import { getErrorMessage } from '~/test/utils/ethereumErrors'
|
||||||
|
import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
|
||||||
|
|
||||||
const createTransaction = (
|
const createTransaction = (
|
||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
|
@ -28,39 +36,78 @@ const createTransaction = (
|
||||||
const nonce = (await safeInstance.nonce()).toString()
|
const nonce = (await safeInstance.nonce()).toString()
|
||||||
const isExecution = threshold.toNumber() === 1 || shouldExecute
|
const isExecution = threshold.toNumber() === 1 || shouldExecute
|
||||||
|
|
||||||
const notificationsQueue = getNofiticationsFromTxType(notifiedTransaction)
|
// https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures
|
||||||
|
const sigs = `0x000000000000000000000000${from.replace(
|
||||||
|
'0x',
|
||||||
|
'',
|
||||||
|
)}000000000000000000000000000000000000000000000000000000000000000001`
|
||||||
|
|
||||||
|
const notificationsQueue: NotificationsQueue = getNofiticationsFromTxType(notifiedTransaction)
|
||||||
|
const beforeExecutionKey = enqueueSnackbar(
|
||||||
|
notificationsQueue.beforeExecution.message,
|
||||||
|
notificationsQueue.beforeExecution.options,
|
||||||
|
)
|
||||||
|
let pendingExecutionKey
|
||||||
|
|
||||||
let txHash
|
let txHash
|
||||||
|
let tx
|
||||||
try {
|
try {
|
||||||
if (isExecution) {
|
if (isExecution) {
|
||||||
txHash = await executeTransaction(
|
tx = await getExecutionTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from, sigs)
|
||||||
notificationsQueue,
|
|
||||||
enqueueSnackbar,
|
|
||||||
closeSnackbar,
|
|
||||||
safeInstance,
|
|
||||||
to,
|
|
||||||
valueInWei,
|
|
||||||
txData,
|
|
||||||
CALL,
|
|
||||||
nonce,
|
|
||||||
from,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
txHash = await approveTransaction(
|
tx = await getApprovalTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from)
|
||||||
notificationsQueue,
|
|
||||||
enqueueSnackbar,
|
|
||||||
closeSnackbar,
|
|
||||||
safeInstance,
|
|
||||||
to,
|
|
||||||
valueInWei,
|
|
||||||
txData,
|
|
||||||
CALL,
|
|
||||||
nonce,
|
|
||||||
from,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sendParams = { from }
|
||||||
|
// if not set owner management tests will fail on ganache
|
||||||
|
if (process.env.NODE_ENV === 'test') {
|
||||||
|
sendParams.gas = '7000000'
|
||||||
|
}
|
||||||
|
|
||||||
|
await tx
|
||||||
|
.send(sendParams)
|
||||||
|
.once('transactionHash', (hash) => {
|
||||||
|
txHash = hash
|
||||||
|
closeSnackbar(beforeExecutionKey)
|
||||||
|
pendingExecutionKey = enqueueSnackbar(
|
||||||
|
(shouldExecute)
|
||||||
|
? notificationsQueue.pendingExecution.single.message
|
||||||
|
: notificationsQueue.pendingExecution.multiple.message,
|
||||||
|
notificationsQueue.pendingExecution.single.options,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.on('error', (error) => {
|
||||||
|
console.error('Tx error: ', error)
|
||||||
|
})
|
||||||
|
.then(async (receipt) => {
|
||||||
|
closeSnackbar(pendingExecutionKey)
|
||||||
|
await saveTxToHistory(
|
||||||
|
safeInstance,
|
||||||
|
to,
|
||||||
|
valueInWei,
|
||||||
|
txData,
|
||||||
|
CALL,
|
||||||
|
nonce,
|
||||||
|
receipt.transactionHash,
|
||||||
|
from,
|
||||||
|
isExecution ? TX_TYPE_EXECUTION : TX_TYPE_CONFIRMATION,
|
||||||
|
)
|
||||||
|
if (isExecution) {
|
||||||
|
enqueueSnackbar(notificationsQueue.afterExecution.message, notificationsQueue.afterExecution.options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return receipt.transactionHash
|
||||||
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`Error while creating transaction: ${err}`)
|
closeSnackbar(beforeExecutionKey)
|
||||||
|
closeSnackbar(pendingExecutionKey)
|
||||||
|
enqueueSnackbar(notificationsQueue.afterExecutionError.message, notificationsQueue.afterExecutionError.options)
|
||||||
|
|
||||||
|
const executeDataUsedSignatures = safeInstance.contract.methods
|
||||||
|
.execTransaction(to, valueInWei, txData, CALL, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, sigs)
|
||||||
|
.encodeABI()
|
||||||
|
const errMsg = await getErrorMessage(safeInstance.address, 0, executeDataUsedSignatures, from)
|
||||||
|
console.error(`Error executing the TX: ${errMsg}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(fetchTransactions(safeAddress))
|
dispatch(fetchTransactions(safeAddress))
|
||||||
|
|
|
@ -5,8 +5,17 @@ import { userAccountSelector } from '~/logic/wallets/store/selectors'
|
||||||
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
||||||
import { type GlobalState } from '~/store'
|
import { type GlobalState } from '~/store'
|
||||||
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
||||||
import { approveTransaction, executeTransaction, CALL } from '~/logic/safe/transactions'
|
import {
|
||||||
|
type NotificationsQueue,
|
||||||
|
getApprovalTransaction,
|
||||||
|
getExecutionTransaction,
|
||||||
|
CALL,
|
||||||
|
saveTxToHistory,
|
||||||
|
TX_TYPE_EXECUTION,
|
||||||
|
TX_TYPE_CONFIRMATION,
|
||||||
|
} from '~/logic/safe/transactions'
|
||||||
import { getNofiticationsFromTxType } from '~/logic/notifications'
|
import { getNofiticationsFromTxType } from '~/logic/notifications'
|
||||||
|
import { getErrorMessage } from '~/test/utils/ethereumErrors'
|
||||||
|
|
||||||
// https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures
|
// https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures
|
||||||
// https://github.com/gnosis/safe-contracts/blob/master/test/gnosisSafeTeamEdition.js#L26
|
// https://github.com/gnosis/safe-contracts/blob/master/test/gnosisSafeTeamEdition.js#L26
|
||||||
|
@ -45,38 +54,85 @@ const processTransaction = (
|
||||||
const nonce = (await safeInstance.nonce()).toString()
|
const nonce = (await safeInstance.nonce()).toString()
|
||||||
const threshold = (await safeInstance.getThreshold()).toNumber()
|
const threshold = (await safeInstance.getThreshold()).toNumber()
|
||||||
const shouldExecute = threshold === tx.confirmations.size || approveAndExecute
|
const shouldExecute = threshold === tx.confirmations.size || approveAndExecute
|
||||||
const sigs = generateSignaturesFromTxConfirmations(tx, approveAndExecute && userAddress)
|
|
||||||
|
|
||||||
const notificationsQueue = getNofiticationsFromTxType(notifiedTransaction)
|
let sigs = generateSignaturesFromTxConfirmations(tx, approveAndExecute && userAddress)
|
||||||
|
// https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures
|
||||||
|
if (!sigs) {
|
||||||
|
sigs = `0x000000000000000000000000${from.replace(
|
||||||
|
'0x',
|
||||||
|
'',
|
||||||
|
)}000000000000000000000000000000000000000000000000000000000000000001`
|
||||||
|
}
|
||||||
|
|
||||||
|
const notificationsQueue: NotificationsQueue = getNofiticationsFromTxType(notifiedTransaction)
|
||||||
|
const beforeExecutionKey = enqueueSnackbar(
|
||||||
|
notificationsQueue.beforeExecution.message,
|
||||||
|
notificationsQueue.beforeExecution.options,
|
||||||
|
)
|
||||||
|
let pendingExecutionKey
|
||||||
|
|
||||||
let txHash
|
let txHash
|
||||||
if (shouldExecute) {
|
let transaction
|
||||||
txHash = await executeTransaction(
|
try {
|
||||||
notificationsQueue,
|
if (shouldExecute) {
|
||||||
enqueueSnackbar,
|
transaction = await getExecutionTransaction(
|
||||||
closeSnackbar,
|
safeInstance,
|
||||||
safeInstance,
|
tx.recipient,
|
||||||
tx.recipient,
|
tx.value,
|
||||||
tx.value,
|
tx.data,
|
||||||
tx.data,
|
CALL,
|
||||||
CALL,
|
nonce,
|
||||||
nonce,
|
from,
|
||||||
from,
|
sigs,
|
||||||
sigs,
|
)
|
||||||
)
|
} else {
|
||||||
} else {
|
transaction = await getApprovalTransaction(safeInstance, tx.recipient, tx.value, tx.data, CALL, nonce, from)
|
||||||
txHash = await approveTransaction(
|
}
|
||||||
notificationsQueue,
|
|
||||||
enqueueSnackbar,
|
const sendParams = { from }
|
||||||
closeSnackbar,
|
// if not set owner management tests will fail on ganache
|
||||||
safeInstance,
|
if (process.env.NODE_ENV === 'test') {
|
||||||
tx.recipient,
|
sendParams.gas = '7000000'
|
||||||
tx.value,
|
}
|
||||||
tx.data,
|
|
||||||
CALL,
|
await transaction
|
||||||
nonce,
|
.send(sendParams)
|
||||||
from,
|
.once('transactionHash', (hash) => {
|
||||||
)
|
txHash = hash
|
||||||
|
closeSnackbar(beforeExecutionKey)
|
||||||
|
pendingExecutionKey = enqueueSnackbar(
|
||||||
|
notificationsQueue.pendingExecution.single.message,
|
||||||
|
notificationsQueue.pendingExecution.single.options,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.on('error', (error) => {
|
||||||
|
console.error('Processing transaction error: ', error)
|
||||||
|
})
|
||||||
|
.then(async (receipt) => {
|
||||||
|
closeSnackbar(pendingExecutionKey)
|
||||||
|
await saveTxToHistory(
|
||||||
|
safeInstance,
|
||||||
|
tx.recipient,
|
||||||
|
tx.value,
|
||||||
|
tx.data,
|
||||||
|
CALL,
|
||||||
|
nonce,
|
||||||
|
receipt.transactionHash,
|
||||||
|
from,
|
||||||
|
shouldExecute ? TX_TYPE_EXECUTION : TX_TYPE_CONFIRMATION,
|
||||||
|
)
|
||||||
|
enqueueSnackbar(notificationsQueue.afterExecution.message, notificationsQueue.afterExecution.options)
|
||||||
|
|
||||||
|
return receipt.transactionHash
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
closeSnackbar(beforeExecutionKey)
|
||||||
|
closeSnackbar(pendingExecutionKey)
|
||||||
|
enqueueSnackbar(notificationsQueue.afterExecutionError.message, notificationsQueue.afterExecutionError.options)
|
||||||
|
|
||||||
|
const executeData = safeInstance.contract.methods.approveHash(txHash).encodeABI()
|
||||||
|
const errMsg = await getErrorMessage(safeInstance.address, 0, executeData, from)
|
||||||
|
console.error(`Error executing the TX: ${errMsg}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(fetchTransactions(safeAddress))
|
dispatch(fetchTransactions(safeAddress))
|
||||||
|
|
Loading…
Reference in New Issue