feature: WIP - add mocked tx to the list
This commit is contained in:
parent
be4caa1baf
commit
141e05c2e8
|
@ -0,0 +1,6 @@
|
||||||
|
// @flow
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
|
||||||
|
export const ADD_CANCELLATION_TRANSACTION = 'ADD_CANCELLATION_TRANSACTION'
|
||||||
|
|
||||||
|
export const addCancellationTransaction = createAction<string, *>(ADD_CANCELLATION_TRANSACTION)
|
|
@ -0,0 +1,6 @@
|
||||||
|
// @flow
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
|
||||||
|
export const ADD_TRANSACTION = 'ADD_TRANSACTION'
|
||||||
|
|
||||||
|
export const addTransaction = createAction<string, *>(ADD_TRANSACTION)
|
|
@ -1,8 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { push } from 'connected-react-router'
|
import { push } from 'connected-react-router'
|
||||||
|
import type { RecordInstance } from 'immutable'
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import type { GetState, Dispatch as ReduxDispatch } from 'redux'
|
import type { GetState, Dispatch as ReduxDispatch } from 'redux'
|
||||||
import semverSatisfies from 'semver/functions/satisfies'
|
// import semverSatisfies from 'semver/functions/satisfies'
|
||||||
|
|
||||||
import { makeConfirmation } from '../../models/confirmation'
|
import { makeConfirmation } from '../../models/confirmation'
|
||||||
|
|
||||||
|
@ -20,13 +21,22 @@ import {
|
||||||
saveTxToHistory,
|
saveTxToHistory,
|
||||||
} from '~/logic/safe/transactions'
|
} from '~/logic/safe/transactions'
|
||||||
import { estimateSafeTxGas } from '~/logic/safe/transactions/gasNew'
|
import { estimateSafeTxGas } from '~/logic/safe/transactions/gasNew'
|
||||||
import { SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES, tryOffchainSigning } from '~/logic/safe/transactions/offchainSigner'
|
// import { SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES, tryOffchainSigning } from '~/logic/safe/transactions/offchainSigner'
|
||||||
import { getCurrentSafeVersion } from '~/logic/safe/utils/safeVersion'
|
// import { getCurrentSafeVersion } from '~/logic/safe/utils/safeVersion'
|
||||||
import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
|
import { TOKEN_REDUCER_ID } from '~/logic/tokens/store/reducer/tokens'
|
||||||
|
import { ZERO_ADDRESS, sameAddress } from '~/logic/wallets/ethAddresses'
|
||||||
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
import { providerSelector } from '~/logic/wallets/store/selectors'
|
import { providerSelector } from '~/logic/wallets/store/selectors'
|
||||||
import { SAFELIST_ADDRESS } from '~/routes/routes'
|
import { SAFELIST_ADDRESS } from '~/routes/routes'
|
||||||
|
import { addCancellationTransaction } from '~/routes/safe/store/actions/transactions/addCancellationTransaction'
|
||||||
|
import { addTransaction } from '~/routes/safe/store/actions/transactions/addTransaction'
|
||||||
|
import type { TxServiceModel } from '~/routes/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions'
|
||||||
|
import { buildTransactionFrom } from '~/routes/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions'
|
||||||
|
import { updateCancellationTransaction } from '~/routes/safe/store/actions/transactions/updateCancellationTransaction'
|
||||||
import { getLastTx, getNewTxNonce, shouldExecuteTransaction } from '~/routes/safe/store/actions/utils'
|
import { getLastTx, getNewTxNonce, shouldExecuteTransaction } from '~/routes/safe/store/actions/utils'
|
||||||
|
import type { TransactionProps } from '~/routes/safe/store/models/transaction'
|
||||||
|
import { CANCELLATION_TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/cancellationTransactions'
|
||||||
|
import { TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
||||||
import { type GlobalState } from '~/store'
|
import { type GlobalState } from '~/store'
|
||||||
import { getErrorMessage } from '~/test/utils/ethereumErrors'
|
import { getErrorMessage } from '~/test/utils/ethereumErrors'
|
||||||
|
|
||||||
|
@ -44,6 +54,49 @@ export type CreateTransactionArgs = {
|
||||||
origin?: string | null,
|
origin?: string | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function mockMyTransaction(safeAddress: string, state, tx: {}) {
|
||||||
|
const submissionDate = new Date().toISOString()
|
||||||
|
const knownTokens = state[TOKEN_REDUCER_ID]
|
||||||
|
const cancellationTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !tx.data
|
||||||
|
const existentTx: TransactionProps =
|
||||||
|
state[cancellationTx ? CANCELLATION_TRANSACTIONS_REDUCER_ID : TRANSACTIONS_REDUCER_ID]
|
||||||
|
.get(safeAddress)
|
||||||
|
.find(({ nonce }) => nonce === tx.nonce) || null
|
||||||
|
|
||||||
|
const transactionStructure: TxServiceModel = {
|
||||||
|
...tx,
|
||||||
|
value: tx.valueInWei,
|
||||||
|
blockNumber: null,
|
||||||
|
confirmations: [], // this is used to determine if a tx is pending or not. See `getTxStatus` selector
|
||||||
|
confirmationsRequired: null,
|
||||||
|
dataDecoded: {},
|
||||||
|
ethGasPrice: null,
|
||||||
|
executionDate: null,
|
||||||
|
executor: null,
|
||||||
|
fee: null,
|
||||||
|
gasUsed: null,
|
||||||
|
isExecuted: false,
|
||||||
|
isSuccessful: null,
|
||||||
|
origin: null,
|
||||||
|
safeTxHash: null,
|
||||||
|
signatures: null,
|
||||||
|
transactionHash: null,
|
||||||
|
...existentTx,
|
||||||
|
modified: submissionDate,
|
||||||
|
submissionDate,
|
||||||
|
safe: safeAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockedTransaction: RecordInstance<TransactionProps> = await buildTransactionFrom(
|
||||||
|
safeAddress,
|
||||||
|
transactionStructure,
|
||||||
|
knownTokens,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
|
return { cancellationTx, existentTx, mockedTransaction }
|
||||||
|
}
|
||||||
|
|
||||||
const createTransaction = ({
|
const createTransaction = ({
|
||||||
safeAddress,
|
safeAddress,
|
||||||
to,
|
to,
|
||||||
|
@ -66,12 +119,12 @@ const createTransaction = ({
|
||||||
const ready = await onboardUser()
|
const ready = await onboardUser()
|
||||||
if (!ready) return
|
if (!ready) return
|
||||||
|
|
||||||
const { account: from, hardwareWallet, smartContractWallet } = providerSelector(state)
|
const { account: from /*, hardwareWallet, smartContractWallet*/ } = providerSelector(state)
|
||||||
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
|
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
|
||||||
const lastTx = await getLastTx(safeAddress)
|
const lastTx = await getLastTx(safeAddress)
|
||||||
const nonce = await getNewTxNonce(txNonce, lastTx, safeInstance)
|
const nonce = await getNewTxNonce(txNonce, lastTx, safeInstance)
|
||||||
const isExecution = await shouldExecuteTransaction(safeInstance, nonce, lastTx)
|
const isExecution = await shouldExecuteTransaction(safeInstance, nonce, lastTx)
|
||||||
const safeVersion = await getCurrentSafeVersion(safeInstance)
|
// const safeVersion = await getCurrentSafeVersion(safeInstance)
|
||||||
const safeTxGas = await estimateSafeTxGas(safeInstance, safeAddress, txData, to, valueInWei, operation)
|
const safeTxGas = await estimateSafeTxGas(safeInstance, safeAddress, txData, to, valueInWei, operation)
|
||||||
|
|
||||||
// https://docs.gnosis.io/safe/docs/docs5/#pre-validated-signatures
|
// https://docs.gnosis.io/safe/docs/docs5/#pre-validated-signatures
|
||||||
|
@ -105,25 +158,26 @@ const createTransaction = ({
|
||||||
try {
|
try {
|
||||||
// Here we're checking that safe contract version is greater or equal 1.1.1, but
|
// Here we're checking that safe contract version is greater or equal 1.1.1, but
|
||||||
// theoretically EIP712 should also work for 1.0.0 contracts
|
// theoretically EIP712 should also work for 1.0.0 contracts
|
||||||
const canTryOffchainSigning =
|
// TODO: revert this
|
||||||
!isExecution && !smartContractWallet && semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES)
|
// const canTryOffchainSigning =
|
||||||
if (false) {
|
// !isExecution && !smartContractWallet && semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES)
|
||||||
const signature = await tryOffchainSigning({ ...txArgs, safeAddress }, hardwareWallet)
|
// if (canTryOffchainSigning) {
|
||||||
|
// const signature = await tryOffchainSigning({ ...txArgs, safeAddress }, hardwareWallet)
|
||||||
if (signature) {
|
//
|
||||||
closeSnackbar(beforeExecutionKey)
|
// if (signature) {
|
||||||
|
// closeSnackbar(beforeExecutionKey)
|
||||||
await saveTxToHistory({
|
//
|
||||||
...txArgs,
|
// await saveTxToHistory({
|
||||||
signature,
|
// ...txArgs,
|
||||||
origin,
|
// signature,
|
||||||
})
|
// origin,
|
||||||
showSnackbar(notificationsQueue.afterExecution.moreConfirmationsNeeded, enqueueSnackbar, closeSnackbar)
|
// })
|
||||||
|
// showSnackbar(notificationsQueue.afterExecution.moreConfirmationsNeeded, enqueueSnackbar, closeSnackbar)
|
||||||
dispatch(fetchTransactions(safeAddress))
|
//
|
||||||
return
|
// dispatch(fetchTransactions(safeAddress))
|
||||||
}
|
// return
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
tx = isExecution ? await getExecutionTransaction(txArgs) : await getApprovalTransaction(txArgs)
|
tx = isExecution ? await getExecutionTransaction(txArgs) : await getApprovalTransaction(txArgs)
|
||||||
|
|
||||||
|
@ -143,11 +197,26 @@ const createTransaction = ({
|
||||||
pendingExecutionKey = showSnackbar(notificationsQueue.pendingExecution, enqueueSnackbar, closeSnackbar)
|
pendingExecutionKey = showSnackbar(notificationsQueue.pendingExecution, enqueueSnackbar, closeSnackbar)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await saveTxToHistory({
|
// TODO: let's mock the tx
|
||||||
|
const { cancellationTx, existentTx, mockedTransaction } = await mockMyTransaction(safeAddress, state, {
|
||||||
...txArgs,
|
...txArgs,
|
||||||
txHash,
|
txHash,
|
||||||
origin,
|
|
||||||
})
|
})
|
||||||
|
if (cancellationTx) {
|
||||||
|
if (existentTx) {
|
||||||
|
dispatch(updateCancellationTransaction({ safeAddress, transaction: mockedTransaction }))
|
||||||
|
} else {
|
||||||
|
dispatch(addCancellationTransaction({ safeAddress, transaction: mockedTransaction }))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (existentTx) {
|
||||||
|
dispatch(updateTransaction({ safeAddress, transaction: mockedTransaction }))
|
||||||
|
} else {
|
||||||
|
dispatch(addTransaction({ safeAddress, transaction: mockedTransaction }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await saveTxToHistory({ ...txArgs, txHash, origin })
|
||||||
await dispatch(fetchTransactions(safeAddress))
|
await dispatch(fetchTransactions(safeAddress))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { decodeParamsFromSafeMethod } from '~/logic/contracts/methodIds'
|
||||||
import { buildTxServiceUrl } from '~/logic/safe/transactions/txHistory'
|
import { buildTxServiceUrl } from '~/logic/safe/transactions/txHistory'
|
||||||
import { getTokenInfos } from '~/logic/tokens/store/actions/fetchTokens'
|
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 { ALTERNATIVE_TOKEN_ABI } from '~/logic/tokens/utils/alternativeAbi'
|
||||||
import {
|
import {
|
||||||
SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH,
|
SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH,
|
||||||
isMultisendTransaction,
|
isMultisendTransaction,
|
||||||
|
@ -179,7 +180,7 @@ export const buildTransactionFrom = async (
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const batchTxTokenRequest = (txs: any[]) => {
|
export const batchTxTokenRequest = (txs: any[]) => {
|
||||||
const batch = new web3ReadOnly.BatchRequest()
|
const batch = new web3ReadOnly.BatchRequest()
|
||||||
|
|
||||||
const whenTxsValues = txs.map((tx) => {
|
const whenTxsValues = txs.map((tx) => {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
// @flow
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
|
||||||
|
export const UPDATE_CANCELLATION_TRANSACTION = 'UPDATE_CANCELLATION_TRANSACTION'
|
||||||
|
|
||||||
|
export const updateCancellationTransaction = createAction<string, *>(UPDATE_CANCELLATION_TRANSACTION)
|
|
@ -2,7 +2,9 @@
|
||||||
import { List, Map } from 'immutable'
|
import { List, Map } from 'immutable'
|
||||||
import { type ActionType, handleActions } from 'redux-actions'
|
import { type ActionType, handleActions } from 'redux-actions'
|
||||||
|
|
||||||
|
import { ADD_CANCELLATION_TRANSACTION } from '~/routes/safe/store/actions/transactions/addCancellationTransaction'
|
||||||
import { ADD_CANCELLATION_TRANSACTIONS } from '~/routes/safe/store/actions/transactions/addCancellationTransactions'
|
import { ADD_CANCELLATION_TRANSACTIONS } from '~/routes/safe/store/actions/transactions/addCancellationTransactions'
|
||||||
|
import { UPDATE_CANCELLATION_TRANSACTION } from '~/routes/safe/store/actions/transactions/updateCancellationTransaction'
|
||||||
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||||
|
|
||||||
export const CANCELLATION_TRANSACTIONS_REDUCER_ID = 'cancellationTransactions'
|
export const CANCELLATION_TRANSACTIONS_REDUCER_ID = 'cancellationTransactions'
|
||||||
|
@ -11,7 +13,32 @@ export type CancelState = Map<string, List<Transaction>>
|
||||||
|
|
||||||
export default handleActions<CancelState, *>(
|
export default handleActions<CancelState, *>(
|
||||||
{
|
{
|
||||||
|
[ADD_CANCELLATION_TRANSACTION]: (state: CancelState, action: ActionType<Function>): CancelState => {
|
||||||
|
const { safeAddress, transaction } = action.payload
|
||||||
|
const transactionList = state.get(safeAddress)
|
||||||
|
return state.set(safeAddress, transactionList.push(transaction))
|
||||||
|
},
|
||||||
[ADD_CANCELLATION_TRANSACTIONS]: (state: CancelState, action: ActionType<Function>): CancelState => action.payload,
|
[ADD_CANCELLATION_TRANSACTIONS]: (state: CancelState, action: ActionType<Function>): CancelState => action.payload,
|
||||||
|
[UPDATE_CANCELLATION_TRANSACTION]: (state: CancelState, action: ActionType<Function>): CancelState => {
|
||||||
|
const { safeAddress, transaction } = action.payload
|
||||||
|
|
||||||
|
const transactionList = state.get(safeAddress)
|
||||||
|
|
||||||
|
if (!transaction) {
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
const storedTransactionIndex = transactionList.findIndex((tx) => tx.safeTxHash === transaction.safeTxHash)
|
||||||
|
|
||||||
|
if (storedTransactionIndex === -1) {
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.set(
|
||||||
|
safeAddress,
|
||||||
|
transactionList.update(storedTransactionIndex, (tx) => tx.merge(transaction)),
|
||||||
|
)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Map(),
|
Map(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { List, Map } from 'immutable'
|
import { List, Map } from 'immutable'
|
||||||
import { type ActionType, handleActions } from 'redux-actions'
|
import { type ActionType, handleActions } from 'redux-actions'
|
||||||
|
|
||||||
|
import { ADD_TRANSACTION } from '~/routes/safe/store/actions/transactions/addTransaction'
|
||||||
import { ADD_TRANSACTIONS } from '~/routes/safe/store/actions/transactions/addTransactions'
|
import { ADD_TRANSACTIONS } from '~/routes/safe/store/actions/transactions/addTransactions'
|
||||||
import { UPDATE_TRANSACTION } from '~/routes/safe/store/actions/transactions/updateTransaction'
|
import { UPDATE_TRANSACTION } from '~/routes/safe/store/actions/transactions/updateTransaction'
|
||||||
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||||
|
@ -12,6 +13,11 @@ export type State = Map<string, List<Transaction>>
|
||||||
|
|
||||||
export default handleActions<State, *>(
|
export default handleActions<State, *>(
|
||||||
{
|
{
|
||||||
|
[ADD_TRANSACTION]: (state: State, action: ActionType<Function>): State => {
|
||||||
|
const { safeAddress, transaction } = action.payload
|
||||||
|
const transactionList = state.get(safeAddress)
|
||||||
|
return state.set(safeAddress, transactionList.push(transaction))
|
||||||
|
},
|
||||||
[ADD_TRANSACTIONS]: (state: State, action: ActionType<Function>): State => action.payload,
|
[ADD_TRANSACTIONS]: (state: State, action: ActionType<Function>): State => action.payload,
|
||||||
[UPDATE_TRANSACTION]: (state: State, action: ActionType<Function>): State => {
|
[UPDATE_TRANSACTION]: (state: State, action: ActionType<Function>): State => {
|
||||||
const { safeAddress, transaction } = action.payload
|
const { safeAddress, transaction } = action.payload
|
||||||
|
|
Loading…
Reference in New Issue