feature: WIP - add mocked tx to the list

This commit is contained in:
fernandomg 2020-05-12 00:40:49 -03:00
parent be4caa1baf
commit 141e05c2e8
7 changed files with 149 additions and 28 deletions

View File

@ -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)

View File

@ -0,0 +1,6 @@
// @flow
import { createAction } from 'redux-actions'
export const ADD_TRANSACTION = 'ADD_TRANSACTION'
export const addTransaction = createAction<string, *>(ADD_TRANSACTION)

View File

@ -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)

View File

@ -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) => {

View File

@ -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)

View File

@ -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(),
) )

View File

@ -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