(Fix) Transaction not automatically executed (#716)

* feature: action/reducer to UPDATE_SAFE_NONCE

* refactor: when processing txs returned from backend, extract latest tx nonce value and store it in the safe's state

* chore: update `yarn.lock`

* refactor: `UPDATE_SAFE_THRESHOLD` and `UPDATE_SAFE_NONCE` discarded in favor of `UPDATE_SAFE`

* refactor: use `SAFE_REDUCER_ID` constant

* refactor: remove `updateSafeNonce` file
This commit is contained in:
Fernando 2020-04-06 11:30:07 -03:00 committed by GitHub
parent ba49c97fb2
commit 0441ce2ec7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 31 deletions

View File

@ -10,7 +10,7 @@ import { getBalanceInEtherOf, getWeb3 } from '~/logic/wallets/getWeb3'
import addSafe from '~/routes/safe/store/actions/addSafe'
import addSafeOwner from '~/routes/safe/store/actions/addSafeOwner'
import removeSafeOwner from '~/routes/safe/store/actions/removeSafeOwner'
import updateSafeThreshold from '~/routes/safe/store/actions/updateSafeThreshold'
import updateSafe from '~/routes/safe/store/actions/updateSafe'
import { makeOwner } from '~/routes/safe/store/models/owner'
import type { SafeProps } from '~/routes/safe/store/models/safe'
import { type GlobalState } from '~/store/index'
@ -77,7 +77,7 @@ export const checkAndUpdateSafe = (safeAdd: string) => async (dispatch: ReduxDis
localSafe.threshold = remoteThreshold.toNumber()
if (localThreshold !== remoteThreshold.toNumber()) {
dispatch(updateSafeThreshold({ safeAddress, threshold: remoteThreshold.toNumber() }))
dispatch(updateSafe({ address: safeAddress, threshold: remoteThreshold.toNumber() }))
}
// If the remote owners does not contain a local address, we remove that local owner

View File

@ -2,6 +2,7 @@
import axios from 'axios'
import bn from 'bignumber.js'
import { List, Map, type RecordInstance } from 'immutable'
import { batch } from 'react-redux'
import type { Dispatch as ReduxDispatch } from 'redux'
import { addIncomingTransactions } from './addIncomingTransactions'
@ -24,6 +25,7 @@ import { ZERO_ADDRESS, sameAddress } from '~/logic/wallets/ethAddresses'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { addCancellationTransactions } from '~/routes/safe/store/actions/addCancellationTransactions'
import updateSafe from '~/routes/safe/store/actions/updateSafe'
import { makeConfirmation } from '~/routes/safe/store/models/confirmation'
import { type IncomingTransaction, makeIncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
import { makeOwner } from '~/routes/safe/store/models/owner'
@ -347,15 +349,48 @@ export const loadSafeIncomingTransactions = async (safeAddress: string) => {
return Map().set(safeAddress, List(incomingTxsRecord))
}
/**
* Returns nonce from the last tx returned by the server or defaults to 0
* @param outgoingTxs
* @returns {number|*}
*/
const getLastTxNonce = (outgoingTxs) => {
if (!outgoingTxs) {
return 0
}
const mostRecentNonce = outgoingTxs.get(0).nonce
// if nonce is null, then we are in front of the creation-tx
if (mostRecentNonce === null) {
const tx = outgoingTxs.get(1)
if (tx) {
// if there's other tx than the creation one, we return its nonce
return tx.nonce
} else {
return 0
}
}
return mostRecentNonce
}
export default (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
web3 = await getWeb3()
const transactions: SafeTransactionsType | undefined = await loadSafeTransactions(safeAddress)
if (transactions) {
const { cancel, outgoing } = transactions
dispatch(addCancellationTransactions(cancel))
dispatch(addTransactions(outgoing))
const nonce = getLastTxNonce(outgoing && outgoing.get(safeAddress))
batch(() => {
dispatch(addCancellationTransactions(cancel))
dispatch(addTransactions(outgoing))
dispatch(updateSafe({ address: safeAddress, nonce }))
})
}
const incomingTransactions: Map<string, List<IncomingTransaction>> | undefined = await loadSafeIncomingTransactions(
safeAddress,
)

View File

@ -1,8 +0,0 @@
// @flow
import { createAction } from 'redux-actions'
export const UPDATE_SAFE_THRESHOLD = 'UPDATE_SAFE_THRESHOLD'
const updateSafeThreshold = createAction<string, *>(UPDATE_SAFE_THRESHOLD)
export default updateSafeThreshold

View File

@ -13,7 +13,6 @@ import { REPLACE_SAFE_OWNER } from '~/routes/safe/store/actions/replaceSafeOwner
import { SET_DEFAULT_SAFE } from '~/routes/safe/store/actions/setDefaultSafe'
import { SET_LATEST_MASTER_CONTRACT_VERSION } from '~/routes/safe/store/actions/setLatestMasterContractVersion'
import { UPDATE_SAFE } from '~/routes/safe/store/actions/updateSafe'
import { UPDATE_SAFE_THRESHOLD } from '~/routes/safe/store/actions/updateSafeThreshold'
import { makeOwner } from '~/routes/safe/store/models/owner'
import SafeRecord, { type SafeProps } from '~/routes/safe/store/models/safe'
@ -49,21 +48,29 @@ export default handleActions<SafeReducerState, *>(
[UPDATE_SAFE]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState => {
const safe = action.payload
const safeAddress = safe.address
const isNonceUpdate = safe.nonce !== undefined
return state.updateIn(['safes', safeAddress], (prevSafe) => prevSafe.merge(safe))
if (isNonceUpdate && safe.nonce <= state.getIn([SAFE_REDUCER_ID, safeAddress, 'nonce'])) {
// update only when nonce is greater than the one already stored
// this will prevent undesired changes in the safe's state when
// txs pagination is implemented
return state
}
return state.updateIn([SAFE_REDUCER_ID, safeAddress], (prevSafe) => prevSafe.merge(safe))
},
[ACTIVATE_TOKEN_FOR_ALL_SAFES]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState => {
const tokenAddress = action.payload
return state.withMutations((map) => {
map
.get('safes')
.get(SAFE_REDUCER_ID)
.keySeq()
.forEach((safeAddress) => {
const safeActiveTokens = map.getIn(['safes', safeAddress, 'activeTokens'])
const safeActiveTokens = map.getIn([SAFE_REDUCER_ID, safeAddress, 'activeTokens'])
const activeTokens = safeActiveTokens.add(tokenAddress)
map.updateIn(['safes', safeAddress], (prevSafe) => prevSafe.merge({ activeTokens }))
map.updateIn([SAFE_REDUCER_ID, safeAddress], (prevSafe) => prevSafe.merge({ activeTokens }))
})
})
},
@ -74,21 +81,21 @@ export default handleActions<SafeReducerState, *>(
// in case of update it shouldn't, because a record would be initialized
// with initial props and it would overwrite existing ones
if (state.hasIn(['safes', safe.address])) {
return state.updateIn(['safes', safe.address], (prevSafe) => prevSafe.merge(safe))
if (state.hasIn([SAFE_REDUCER_ID, safe.address])) {
return state.updateIn([SAFE_REDUCER_ID, safe.address], (prevSafe) => prevSafe.merge(safe))
}
return state.setIn(['safes', safe.address], SafeRecord(safe))
return state.setIn([SAFE_REDUCER_ID, safe.address], SafeRecord(safe))
},
[REMOVE_SAFE]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState => {
const safeAddress = action.payload
return state.deleteIn(['safes', safeAddress])
return state.deleteIn([SAFE_REDUCER_ID, safeAddress])
},
[ADD_SAFE_OWNER]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState => {
const { ownerAddress, ownerName, safeAddress } = action.payload
return state.updateIn(['safes', safeAddress], (prevSafe) =>
return state.updateIn([SAFE_REDUCER_ID, safeAddress], (prevSafe) =>
prevSafe.merge({
owners: prevSafe.owners.push(makeOwner({ address: ownerAddress, name: ownerName })),
}),
@ -97,7 +104,7 @@ export default handleActions<SafeReducerState, *>(
[REMOVE_SAFE_OWNER]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState => {
const { ownerAddress, safeAddress } = action.payload
return state.updateIn(['safes', safeAddress], (prevSafe) =>
return state.updateIn([SAFE_REDUCER_ID, safeAddress], (prevSafe) =>
prevSafe.merge({
owners: prevSafe.owners.filter((o) => o.address.toLowerCase() !== ownerAddress.toLowerCase()),
}),
@ -106,7 +113,7 @@ export default handleActions<SafeReducerState, *>(
[REPLACE_SAFE_OWNER]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState => {
const { oldOwnerAddress, ownerAddress, ownerName, safeAddress } = action.payload
return state.updateIn(['safes', safeAddress], (prevSafe) =>
return state.updateIn([SAFE_REDUCER_ID, safeAddress], (prevSafe) =>
prevSafe.merge({
owners: prevSafe.owners
.filter((o) => o.address.toLowerCase() !== oldOwnerAddress.toLowerCase())
@ -117,7 +124,7 @@ export default handleActions<SafeReducerState, *>(
[EDIT_SAFE_OWNER]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState => {
const { ownerAddress, ownerName, safeAddress } = action.payload
return state.updateIn(['safes', safeAddress], (prevSafe) => {
return state.updateIn([SAFE_REDUCER_ID, safeAddress], (prevSafe) => {
const ownerToUpdateIndex = prevSafe.owners.findIndex(
(o) => o.address.toLowerCase() === ownerAddress.toLowerCase(),
)
@ -125,11 +132,6 @@ export default handleActions<SafeReducerState, *>(
return prevSafe.merge({ owners: updatedOwners })
})
},
[UPDATE_SAFE_THRESHOLD]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState => {
const { safeAddress, threshold } = action.payload
return state.updateIn(['safes', safeAddress], (prevSafe) => prevSafe.set('threshold', threshold))
},
[SET_DEFAULT_SAFE]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState =>
state.set('defaultSafe', action.payload),
[SET_LATEST_MASTER_CONTRACT_VERSION]: (state: SafeReducerState, action: ActionType<Function>): SafeReducerState =>

View File

@ -18594,7 +18594,6 @@ websocket@1.0.29, "websocket@github:web3-js/WebSocket-Node#polyfill/globalThis":
dependencies:
debug "^2.2.0"
es5-ext "^0.10.50"
gulp "^4.0.2"
nan "^2.14.0"
typedarray-to-buffer "^3.1.5"
yaeti "^0.0.6"