Merge pull request #798 from gnosis/dont-fetch-ownername-in-fetchTransactions
Refactoring: store only an address in transaction confirmation model
This commit is contained in:
commit
dba3148d9c
56
package.json
56
package.json
|
@ -136,27 +136,27 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
|
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
|
||||||
"@gnosis.pm/util-contracts": "2.0.6",
|
|
||||||
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#a057248",
|
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#a057248",
|
||||||
"@ledgerhq/hw-transport-node-hid": "5.12.0",
|
"@gnosis.pm/util-contracts": "2.0.6",
|
||||||
"@material-ui/core": "4.9.10",
|
"@ledgerhq/hw-transport-node-hid": "5.15.0",
|
||||||
|
"@material-ui/core": "4.9.14",
|
||||||
"@material-ui/icons": "4.9.1",
|
"@material-ui/icons": "4.9.1",
|
||||||
"@material-ui/lab": "4.0.0-alpha.39",
|
"@material-ui/lab": "4.0.0-alpha.39",
|
||||||
"@openzeppelin/contracts": "^2.5.0",
|
"@openzeppelin/contracts": "3.0.1",
|
||||||
"@testing-library/jest-dom": "5.5.0",
|
"@testing-library/jest-dom": "5.7.0",
|
||||||
"@welldone-software/why-did-you-render": "4.0.8",
|
"@welldone-software/why-did-you-render": "4.2.1",
|
||||||
"async-sema": "^3.1.0",
|
"async-sema": "^3.1.0",
|
||||||
"axios": "0.19.2",
|
"axios": "0.19.2",
|
||||||
"bignumber.js": "9.0.0",
|
"bignumber.js": "9.0.0",
|
||||||
"bnc-onboard": "1.7.6",
|
"bnc-onboard": "1.9.0",
|
||||||
"connected-react-router": "6.8.0",
|
"connected-react-router": "6.8.0",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
"currency-flags": "^2.1.1",
|
"currency-flags": "2.1.2",
|
||||||
"date-fns": "2.12.0",
|
"date-fns": "2.13.0",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"electron-is-dev": "^1.1.0",
|
"electron-is-dev": "^1.1.0",
|
||||||
"electron-log": "^4.1.1",
|
"electron-log": "4.1.2",
|
||||||
"electron-updater": "4.2.0",
|
"electron-updater": "4.3.1",
|
||||||
"ethereum-ens": "0.8.0",
|
"ethereum-ens": "0.8.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"final-form": "4.19.1",
|
"final-form": "4.19.1",
|
||||||
|
@ -165,13 +165,13 @@
|
||||||
"immutable": "^4.0.0-rc.9",
|
"immutable": "^4.0.0-rc.9",
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"lint-staged": "10.1.3",
|
"lint-staged": "10.2.2",
|
||||||
"material-ui-search-bar": "^1.0.0-beta.13",
|
"material-ui-search-bar": "^1.0.0-beta.13",
|
||||||
"notistack": "https://github.com/gnosis/notistack.git#v0.9.4",
|
"notistack": "https://github.com/gnosis/notistack.git#v0.9.4",
|
||||||
"npm": "^6.14.4",
|
"npm": "6.14.5",
|
||||||
"open": "^7.0.3",
|
"open": "^7.0.3",
|
||||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
"optimize-css-assets-webpack-plugin": "5.0.3",
|
||||||
"polished": "3.5.1",
|
"polished": "3.6.3",
|
||||||
"qrcode.react": "1.0.0",
|
"qrcode.react": "1.0.0",
|
||||||
"query-string": "6.12.1",
|
"query-string": "6.12.1",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
|
@ -180,10 +180,10 @@
|
||||||
"react-final-form": "6.4.0",
|
"react-final-form": "6.4.0",
|
||||||
"react-final-form-listeners": "^1.0.2",
|
"react-final-form-listeners": "^1.0.2",
|
||||||
"react-ga": "^2.7.0",
|
"react-ga": "^2.7.0",
|
||||||
"react-hot-loader": "4.12.20",
|
"react-hot-loader": "4.12.21",
|
||||||
"react-qr-reader": "^2.2.1",
|
"react-qr-reader": "^2.2.1",
|
||||||
"react-redux": "7.2.0",
|
"react-redux": "7.2.0",
|
||||||
"react-router-dom": "5.1.2",
|
"react-router-dom": "5.2.0",
|
||||||
"react-window": "^1.8.5",
|
"react-window": "^1.8.5",
|
||||||
"recompose": "^0.30.0",
|
"recompose": "^0.30.0",
|
||||||
"redux": "4.0.5",
|
"redux": "4.0.5",
|
||||||
|
@ -192,8 +192,8 @@
|
||||||
"reselect": "^4.0.0",
|
"reselect": "^4.0.0",
|
||||||
"semver": "7.3.2",
|
"semver": "7.3.2",
|
||||||
"styled-components": "^5.0.1",
|
"styled-components": "^5.0.1",
|
||||||
"wait-on": "^4.0.1",
|
"wait-on": "5.0.0",
|
||||||
"web3": "1.2.6"
|
"web3": "1.2.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "7.8.4",
|
"@babel/cli": "7.8.4",
|
||||||
|
@ -220,13 +220,13 @@
|
||||||
"@babel/preset-env": "7.9.5",
|
"@babel/preset-env": "7.9.5",
|
||||||
"@babel/preset-flow": "7.9.0",
|
"@babel/preset-flow": "7.9.0",
|
||||||
"@babel/preset-react": "7.9.4",
|
"@babel/preset-react": "7.9.4",
|
||||||
"@testing-library/react": "10.0.2",
|
"@testing-library/react": "10.0.3",
|
||||||
"autoprefixer": "9.7.6",
|
"autoprefixer": "9.7.6",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"babel-eslint": "10.1.0",
|
"babel-eslint": "10.1.0",
|
||||||
"babel-jest": "25.3.0",
|
"babel-jest": "25.4.0",
|
||||||
"babel-loader": "8.1.0",
|
"babel-loader": "8.1.0",
|
||||||
"babel-plugin-dynamic-import-node": "^2.3.0",
|
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||||
"babel-plugin-transform-es3-member-expression-literals": "^6.22.0",
|
"babel-plugin-transform-es3-member-expression-literals": "^6.22.0",
|
||||||
"babel-plugin-transform-es3-property-literals": "^6.22.0",
|
"babel-plugin-transform-es3-property-literals": "^6.22.0",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
|
@ -239,37 +239,37 @@
|
||||||
"electron-builder": "22.2.0",
|
"electron-builder": "22.2.0",
|
||||||
"electron-notarize": "^0.2.1",
|
"electron-notarize": "^0.2.1",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-config-prettier": "6.10.1",
|
"eslint-config-prettier": "6.11.0",
|
||||||
"eslint-plugin-flowtype": "4.7.0",
|
"eslint-plugin-flowtype": "4.7.0",
|
||||||
"eslint-plugin-import": "2.20.2",
|
"eslint-plugin-import": "2.20.2",
|
||||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||||
"eslint-plugin-prettier": "^3.1.2",
|
"eslint-plugin-prettier": "^3.1.2",
|
||||||
"eslint-plugin-react": "^7.18.3",
|
"eslint-plugin-react": "^7.18.3",
|
||||||
"eslint-plugin-sort-destructure-keys": "^1.3.3",
|
"eslint-plugin-sort-destructure-keys": "1.3.4",
|
||||||
"ethereumjs-abi": "0.6.8",
|
"ethereumjs-abi": "0.6.8",
|
||||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||||
"file-loader": "6.0.0",
|
"file-loader": "6.0.0",
|
||||||
"flow-bin": "0.122.0",
|
"flow-bin": "0.123.0",
|
||||||
"fs-extra": "9.0.0",
|
"fs-extra": "9.0.0",
|
||||||
"html-loader": "1.1.0",
|
"html-loader": "1.1.0",
|
||||||
"html-webpack-plugin": "4.2.0",
|
"html-webpack-plugin": "4.2.0",
|
||||||
"husky": "^4.2.2",
|
"husky": "^4.2.2",
|
||||||
"jest": "25.3.0",
|
"jest": "25.4.0",
|
||||||
"jest-dom": "4.0.0",
|
"jest-dom": "4.0.0",
|
||||||
"json-loader": "^0.5.7",
|
"json-loader": "^0.5.7",
|
||||||
"mini-css-extract-plugin": "0.9.0",
|
"mini-css-extract-plugin": "0.9.0",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
"postcss-mixins": "6.2.3",
|
"postcss-mixins": "6.2.3",
|
||||||
"postcss-simple-vars": "^5.0.2",
|
"postcss-simple-vars": "^5.0.2",
|
||||||
"prettier": "2.0.4",
|
"prettier": "2.0.5",
|
||||||
"run-with-testrpc": "0.3.1",
|
"run-with-testrpc": "0.3.1",
|
||||||
"style-loader": "1.1.4",
|
"style-loader": "1.1.4",
|
||||||
"terser-webpack-plugin": "2.3.5",
|
"terser-webpack-plugin": "2.3.5",
|
||||||
"truffle": "5.1.21",
|
"truffle": "5.1.23",
|
||||||
"truffle-contract": "4.0.31",
|
"truffle-contract": "4.0.31",
|
||||||
"truffle-solidity-loader": "0.1.32",
|
"truffle-solidity-loader": "0.1.32",
|
||||||
"url-loader": "4.1.0",
|
"url-loader": "4.1.0",
|
||||||
"webpack": "4.42.1",
|
"webpack": "4.43.0",
|
||||||
"webpack-bundle-analyzer": "3.7.0",
|
"webpack-bundle-analyzer": "3.7.0",
|
||||||
"webpack-cli": "3.3.11",
|
"webpack-cli": "3.3.11",
|
||||||
"webpack-dev-server": "3.10.3",
|
"webpack-dev-server": "3.10.3",
|
||||||
|
|
|
@ -34,3 +34,16 @@ export const getAddressBookListSelector: Selector<GlobalState, {}, List<AddressB
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const getNameFromAddressBook = createSelector(
|
||||||
|
getAddressBookListSelector,
|
||||||
|
(_, address) => address,
|
||||||
|
(addressBook: Map<string, AddressBook>, address: string) => {
|
||||||
|
const adbkEntry = addressBook.find((addressBookItem) => addressBookItem.address === address)
|
||||||
|
if (adbkEntry) {
|
||||||
|
return adbkEntry.name
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'UNKNOWN'
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { useSelector } from 'react-redux'
|
|
||||||
|
|
||||||
import type { AddressBook, AddressBookProps } from '~/logic/addressBook/model/addressBook'
|
import type { AddressBook, AddressBookProps } from '~/logic/addressBook/model/addressBook'
|
||||||
import { getAddressBook } from '~/logic/addressBook/store/selectors'
|
|
||||||
import type { Owner } from '~/routes/safe/store/models/owner'
|
import type { Owner } from '~/routes/safe/store/models/owner'
|
||||||
import { loadFromStorage, saveToStorage } from '~/utils/storage'
|
import { loadFromStorage, saveToStorage } from '~/utils/storage'
|
||||||
|
|
||||||
|
@ -33,14 +30,6 @@ export const getNameFromAdbk = (addressBook: AddressBook, userAddress: string):
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getNameFromAddressBook = (userAddress: string): string | null => {
|
|
||||||
if (!userAddress) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
const addressBook = useSelector(getAddressBook)
|
|
||||||
return addressBook ? getNameFromAdbk(addressBook, userAddress) : null
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getOwnersWithNameFromAddressBook = (addressBook: AddressBook, ownerList: List<Owner>) => {
|
export const getOwnersWithNameFromAddressBook = (addressBook: AddressBook, ownerList: List<Owner>) => {
|
||||||
if (!ownerList) {
|
if (!ownerList) {
|
||||||
return []
|
return []
|
||||||
|
|
|
@ -12,7 +12,7 @@ export const generateSignaturesFromTxConfirmations = (
|
||||||
// The constant parts need to be sorted so that the recovered signers are sorted ascending
|
// The constant parts need to be sorted so that the recovered signers are sorted ascending
|
||||||
// (natural order) by address (not checksummed).
|
// (natural order) by address (not checksummed).
|
||||||
const confirmationsMap = confirmations.reduce((map, obj) => {
|
const confirmationsMap = confirmations.reduce((map, obj) => {
|
||||||
map[obj.owner.address.toLowerCase()] = obj // eslint-disable-line no-param-reassign
|
map[obj.owner.toLowerCase()] = obj // eslint-disable-line no-param-reassign
|
||||||
return map
|
return map
|
||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,7 @@ export const getAwaitingTransactions = (
|
||||||
if (!transaction.executionTxHash && !isTransactionCancelled) {
|
if (!transaction.executionTxHash && !isTransactionCancelled) {
|
||||||
// Then we check if the waiting confirmations are not from the current user, otherwise, filters this
|
// Then we check if the waiting confirmations are not from the current user, otherwise, filters this
|
||||||
// transaction
|
// transaction
|
||||||
const transactionWaitingUser = transaction.confirmations.filter(
|
const transactionWaitingUser = transaction.confirmations.filter(({ owner }) => owner !== userAccount)
|
||||||
(confirmation) => confirmation.owner && confirmation.owner.address !== userAccount,
|
|
||||||
)
|
|
||||||
|
|
||||||
return transactionWaitingUser.size > 0
|
return transactionWaitingUser.size > 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
import EtherscanLink from '~/components/EtherscanLink'
|
import EtherscanLink from '~/components/EtherscanLink'
|
||||||
import Block from '~/components/layout/Block'
|
import Block from '~/components/layout/Block'
|
||||||
import Bold from '~/components/layout/Bold'
|
import Bold from '~/components/layout/Bold'
|
||||||
import { getNameFromAddressBook } from '~/logic/addressBook/utils'
|
import { getNameFromAddressBook } from '~/logic/addressBook/store/selectors'
|
||||||
import OwnerAddressTableCell from '~/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell'
|
import OwnerAddressTableCell from '~/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell'
|
||||||
import { getIncomingTxAmount } from '~/routes/safe/components/Transactions/TxsTable/columns'
|
import { getIncomingTxAmount } from '~/routes/safe/components/Transactions/TxsTable/columns'
|
||||||
import type { IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
import type { IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
||||||
|
@ -46,7 +47,7 @@ const TransferDescription = ({ from, txFromName, value = '' }: TransferDescProps
|
||||||
|
|
||||||
const IncomingTxDescription = ({ tx }: Props) => {
|
const IncomingTxDescription = ({ tx }: Props) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const txFromName = getNameFromAddressBook(tx.from)
|
const txFromName = useSelector((state) => getNameFromAddressBook(state, tx.from))
|
||||||
return (
|
return (
|
||||||
<Block className={classes.txDataContainer}>
|
<Block className={classes.txDataContainer}>
|
||||||
<TransferDescription from={tx.from} txFromName={txFromName} value={getIncomingTxAmount(tx, false)} />
|
<TransferDescription from={tx.from} txFromName={txFromName} value={getIncomingTxAmount(tx, false)} />
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { withStyles } from '@material-ui/core/styles'
|
import { withStyles } from '@material-ui/core/styles'
|
||||||
import cn from 'classnames'
|
import cn from 'classnames'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
import CancelSmallFilledCircle from './assets/cancel-small-filled.svg'
|
import CancelSmallFilledCircle from './assets/cancel-small-filled.svg'
|
||||||
import ConfirmSmallFilledCircle from './assets/confirm-small-filled.svg'
|
import ConfirmSmallFilledCircle from './assets/confirm-small-filled.svg'
|
||||||
|
@ -16,8 +17,7 @@ import Block from '~/components/layout/Block'
|
||||||
import Button from '~/components/layout/Button'
|
import Button from '~/components/layout/Button'
|
||||||
import Img from '~/components/layout/Img'
|
import Img from '~/components/layout/Img'
|
||||||
import Paragraph from '~/components/layout/Paragraph'
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
import { getNameFromAddressBook } from '~/logic/addressBook/utils'
|
import { getNameFromAddressBook } from '~/logic/addressBook/store/selectors'
|
||||||
import { type Owner } from '~/routes/safe/store/models/owner'
|
|
||||||
|
|
||||||
export const CONFIRM_TX_BTN_TEST_ID = 'confirm-btn'
|
export const CONFIRM_TX_BTN_TEST_ID = 'confirm-btn'
|
||||||
export const EXECUTE_TX_BTN_TEST_ID = 'execute-btn'
|
export const EXECUTE_TX_BTN_TEST_ID = 'execute-btn'
|
||||||
|
@ -32,7 +32,7 @@ type OwnerProps = {
|
||||||
onTxReject?: Function,
|
onTxReject?: Function,
|
||||||
onTxConfirm: Function,
|
onTxConfirm: Function,
|
||||||
onTxExecute: Function,
|
onTxExecute: Function,
|
||||||
owner: Owner,
|
owner: string,
|
||||||
showRejectBtn: boolean,
|
showRejectBtn: boolean,
|
||||||
showExecuteRejectBtn: boolean,
|
showExecuteRejectBtn: boolean,
|
||||||
showConfirmBtn: boolean,
|
showConfirmBtn: boolean,
|
||||||
|
@ -57,8 +57,7 @@ const OwnerComponent = ({
|
||||||
thresholdReached,
|
thresholdReached,
|
||||||
userAddress,
|
userAddress,
|
||||||
}: OwnerProps) => {
|
}: OwnerProps) => {
|
||||||
const nameInAdbk = getNameFromAddressBook(owner.address)
|
const nameInAdbk = useSelector((state) => getNameFromAddressBook(state, owner))
|
||||||
const ownerName = nameInAdbk || owner.name
|
|
||||||
const [imgCircle, setImgCircle] = React.useState(ConfirmSmallGreyCircle)
|
const [imgCircle, setImgCircle] = React.useState(ConfirmSmallGreyCircle)
|
||||||
|
|
||||||
React.useMemo(() => {
|
React.useMemo(() => {
|
||||||
|
@ -77,15 +76,15 @@ const OwnerComponent = ({
|
||||||
<div className={classes.circleState}>
|
<div className={classes.circleState}>
|
||||||
<Img alt="" src={imgCircle} />
|
<Img alt="" src={imgCircle} />
|
||||||
</div>
|
</div>
|
||||||
<Identicon address={owner.address} className={classes.icon} diameter={32} />
|
<Identicon address={owner} className={classes.icon} diameter={32} />
|
||||||
<Block>
|
<Block>
|
||||||
<Paragraph className={classes.name} noMargin>
|
<Paragraph className={classes.name} noMargin>
|
||||||
{ownerName}
|
{nameInAdbk}
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
<EtherscanLink className={classes.address} cut={4} type="address" value={owner.address} />
|
<EtherscanLink className={classes.address} cut={4} type="address" value={owner} />
|
||||||
</Block>
|
</Block>
|
||||||
<Block className={classes.spacer} />
|
<Block className={classes.spacer} />
|
||||||
{owner.address === userAddress && (
|
{owner === userAddress && (
|
||||||
<Block>
|
<Block>
|
||||||
{isCancelTx ? (
|
{isCancelTx ? (
|
||||||
<>
|
<>
|
||||||
|
@ -140,7 +139,7 @@ const OwnerComponent = ({
|
||||||
)}
|
)}
|
||||||
</Block>
|
</Block>
|
||||||
)}
|
)}
|
||||||
{owner.address === executor && <Block className={classes.executor}>Executor</Block>}
|
{owner === executor && <Block className={classes.executor}>Executor</Block>}
|
||||||
</Block>
|
</Block>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ const OwnersList = ({
|
||||||
confirmed
|
confirmed
|
||||||
executor={executor}
|
executor={executor}
|
||||||
isCancelTx={isCancelTx}
|
isCancelTx={isCancelTx}
|
||||||
key={owner.address}
|
key={owner}
|
||||||
onTxExecute={onTxExecute}
|
onTxExecute={onTxExecute}
|
||||||
onTxReject={onTxReject}
|
onTxReject={onTxReject}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
|
@ -64,7 +64,7 @@ const OwnersList = ({
|
||||||
classes={classes}
|
classes={classes}
|
||||||
executor={executor}
|
executor={executor}
|
||||||
isCancelTx={isCancelTx}
|
isCancelTx={isCancelTx}
|
||||||
key={owner.address}
|
key={owner}
|
||||||
onTxConfirm={onTxConfirm}
|
onTxConfirm={onTxConfirm}
|
||||||
onTxExecute={onTxExecute}
|
onTxExecute={onTxExecute}
|
||||||
onTxReject={onTxReject}
|
onTxReject={onTxReject}
|
||||||
|
|
|
@ -39,7 +39,7 @@ function getOwnersConfirmations(tx, userAddress) {
|
||||||
let currentUserAlreadyConfirmed = false
|
let currentUserAlreadyConfirmed = false
|
||||||
|
|
||||||
tx.confirmations.forEach((conf) => {
|
tx.confirmations.forEach((conf) => {
|
||||||
if (conf.owner.address === userAddress) {
|
if (conf.owner === userAddress) {
|
||||||
currentUserAlreadyConfirmed = true
|
currentUserAlreadyConfirmed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,18 +52,20 @@ function getOwnersConfirmations(tx, userAddress) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPendingOwnersConfirmations(owners, tx, userAddress) {
|
function getPendingOwnersConfirmations(owners, tx, userAddress) {
|
||||||
const ownersUnconfirmed = owners.filter(
|
const ownersNotConfirmed = []
|
||||||
(owner) => tx.confirmations.findIndex((conf) => conf.owner.address === owner.address) === -1,
|
let currentUserNotConfirmed = true
|
||||||
)
|
|
||||||
|
|
||||||
let userIsUnconfirmedOwner = false
|
owners.forEach((owner) => {
|
||||||
|
const confirmationsEntry = tx.confirmations.find((conf) => conf.owner === owner.address)
|
||||||
ownersUnconfirmed.some((owner) => {
|
if (!confirmationsEntry) {
|
||||||
userIsUnconfirmedOwner = owner.address === userAddress
|
ownersNotConfirmed.push(owner.address)
|
||||||
return userIsUnconfirmedOwner
|
}
|
||||||
|
if (confirmationsEntry && confirmationsEntry.owner === userAddress) {
|
||||||
|
currentUserNotConfirmed = false
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return [ownersUnconfirmed, userIsUnconfirmedOwner]
|
return [ownersNotConfirmed, currentUserNotConfirmed]
|
||||||
}
|
}
|
||||||
|
|
||||||
const OwnersColumn = ({
|
const OwnersColumn = ({
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { withStyles } from '@material-ui/core/styles'
|
import { withStyles } from '@material-ui/core/styles'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
import { getTxData } from './utils'
|
import { getTxData } from './utils'
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ import Block from '~/components/layout/Block'
|
||||||
import Bold from '~/components/layout/Bold'
|
import Bold from '~/components/layout/Bold'
|
||||||
import LinkWithRef from '~/components/layout/Link'
|
import LinkWithRef from '~/components/layout/Link'
|
||||||
import Paragraph from '~/components/layout/Paragraph'
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
import { getNameFromAddressBook } from '~/logic/addressBook/utils'
|
import { getNameFromAddressBook } from '~/logic/addressBook/store/selectors'
|
||||||
import { SAFE_METHODS_NAMES } from '~/logic/contracts/methodIds'
|
import { SAFE_METHODS_NAMES } from '~/logic/contracts/methodIds'
|
||||||
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
|
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
|
||||||
import OwnerAddressTableCell from '~/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell'
|
import OwnerAddressTableCell from '~/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell'
|
||||||
|
@ -68,7 +69,7 @@ type CustomDescProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const TransferDescription = ({ amount = '', recipient }: TransferDescProps) => {
|
const TransferDescription = ({ amount = '', recipient }: TransferDescProps) => {
|
||||||
const recipientName = getNameFromAddressBook(recipient)
|
const recipientName = useSelector((state) => getNameFromAddressBook(state, recipient))
|
||||||
return (
|
return (
|
||||||
<Block data-testid={TRANSACTIONS_DESC_SEND_TEST_ID}>
|
<Block data-testid={TRANSACTIONS_DESC_SEND_TEST_ID}>
|
||||||
<Bold>Send {amount} to:</Bold>
|
<Bold>Send {amount} to:</Bold>
|
||||||
|
@ -82,7 +83,7 @@ const TransferDescription = ({ amount = '', recipient }: TransferDescProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const RemovedOwner = ({ removedOwner }: { removedOwner: string }) => {
|
const RemovedOwner = ({ removedOwner }: { removedOwner: string }) => {
|
||||||
const ownerChangedName = getNameFromAddressBook(removedOwner)
|
const ownerChangedName = useSelector((state) => getNameFromAddressBook(state, removedOwner))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Block data-testid={TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID}>
|
<Block data-testid={TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID}>
|
||||||
|
@ -97,7 +98,7 @@ const RemovedOwner = ({ removedOwner }: { removedOwner: string }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddedOwner = ({ addedOwner }: { addedOwner: string }) => {
|
const AddedOwner = ({ addedOwner }: { addedOwner: string }) => {
|
||||||
const ownerChangedName = getNameFromAddressBook(addedOwner)
|
const ownerChangedName = useSelector((state) => getNameFromAddressBook(state, addedOwner))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Block data-testid={TRANSACTIONS_DESC_ADD_OWNER_TEST_ID}>
|
<Block data-testid={TRANSACTIONS_DESC_ADD_OWNER_TEST_ID}>
|
||||||
|
@ -161,7 +162,7 @@ const SettingsDescription = ({ action, addedOwner, newThreshold, removedOwner }:
|
||||||
|
|
||||||
const CustomDescription = ({ amount = 0, classes, data, recipient }: CustomDescProps) => {
|
const CustomDescription = ({ amount = 0, classes, data, recipient }: CustomDescProps) => {
|
||||||
const [showTxData, setShowTxData] = useState(false)
|
const [showTxData, setShowTxData] = useState(false)
|
||||||
const recipientName = getNameFromAddressBook(recipient)
|
const recipientName = useSelector((state) => getNameFromAddressBook(state, recipient))
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Block data-testid={TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID}>
|
<Block data-testid={TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID}>
|
||||||
|
|
|
@ -34,7 +34,7 @@ const getTxStatus = (tx: Transaction, userAddress: string, safe: Safe): Transact
|
||||||
} else if (!tx.confirmations.size) {
|
} else if (!tx.confirmations.size) {
|
||||||
txStatus = 'pending'
|
txStatus = 'pending'
|
||||||
} else {
|
} else {
|
||||||
const userConfirmed = tx.confirmations.filter((conf) => conf.owner.address === userAddress).size === 1
|
const userConfirmed = tx.confirmations.filter((conf) => conf.owner === userAddress).size === 1
|
||||||
const userIsSafeOwner = safe.owners.filter((owner) => owner.address === userAddress).size === 1
|
const userIsSafeOwner = safe.owners.filter((owner) => owner.address === userAddress).size === 1
|
||||||
txStatus = !userConfirmed && userIsSafeOwner ? 'awaiting_your_confirmation' : 'awaiting_confirmations'
|
txStatus = !userConfirmed && userIsSafeOwner ? 'awaiting_your_confirmation' : 'awaiting_confirmations'
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import generateBatchRequests from '~/logic/contracts/generateBatchRequests'
|
||||||
import { decodeParamsFromSafeMethod } from '~/logic/contracts/methodIds'
|
import { decodeParamsFromSafeMethod } from '~/logic/contracts/methodIds'
|
||||||
import { buildIncomingTxServiceUrl } from '~/logic/safe/transactions/incomingTxHistory'
|
import { buildIncomingTxServiceUrl } from '~/logic/safe/transactions/incomingTxHistory'
|
||||||
import { type TxServiceType, buildTxServiceUrl } from '~/logic/safe/transactions/txHistory'
|
import { type TxServiceType, buildTxServiceUrl } from '~/logic/safe/transactions/txHistory'
|
||||||
import { getLocalSafe } from '~/logic/safe/utils'
|
|
||||||
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 { ALTERNATIVE_TOKEN_ABI } from '~/logic/tokens/utils/alternativeAbi'
|
||||||
import {
|
import {
|
||||||
|
@ -28,7 +27,6 @@ import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { addCancellationTransactions } from '~/routes/safe/store/actions/addCancellationTransactions'
|
import { addCancellationTransactions } from '~/routes/safe/store/actions/addCancellationTransactions'
|
||||||
import { makeConfirmation } from '~/routes/safe/store/models/confirmation'
|
import { makeConfirmation } from '~/routes/safe/store/models/confirmation'
|
||||||
import { type IncomingTransaction, makeIncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
import { type IncomingTransaction, makeIncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
||||||
import { makeOwner } from '~/routes/safe/store/models/owner'
|
|
||||||
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'
|
||||||
import { type GlobalState } from '~/store'
|
import { type GlobalState } from '~/store'
|
||||||
|
@ -83,27 +81,15 @@ export const buildTransactionFrom = async (
|
||||||
txTokenName,
|
txTokenName,
|
||||||
txTokenSymbol,
|
txTokenSymbol,
|
||||||
): Promise<Transaction> => {
|
): Promise<Transaction> => {
|
||||||
const localSafe = await getLocalSafe(safeAddress)
|
|
||||||
|
|
||||||
const confirmations = List(
|
const confirmations = List(
|
||||||
tx.confirmations.map((conf: ConfirmationServiceModel) => {
|
tx.confirmations.map((conf: ConfirmationServiceModel) =>
|
||||||
let ownerName = 'UNKNOWN'
|
makeConfirmation({
|
||||||
|
owner: conf.owner,
|
||||||
if (localSafe && localSafe.owners) {
|
|
||||||
const storedOwner = localSafe.owners.find((owner) => sameAddress(conf.owner, owner.address))
|
|
||||||
|
|
||||||
if (storedOwner) {
|
|
||||||
ownerName = storedOwner.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return makeConfirmation({
|
|
||||||
owner: makeOwner({ address: conf.owner, name: ownerName }),
|
|
||||||
type: ((conf.confirmationType.toLowerCase(): any): TxServiceType),
|
type: ((conf.confirmationType.toLowerCase(): any): TxServiceType),
|
||||||
hash: conf.transactionHash,
|
hash: conf.transactionHash,
|
||||||
signature: conf.signature,
|
signature: conf.signature,
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
const modifySettingsTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !!tx.data
|
const modifySettingsTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !!tx.data
|
||||||
const cancellationTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !tx.data
|
const cancellationTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !tx.data
|
||||||
|
|
|
@ -3,17 +3,16 @@ import { Record } from 'immutable'
|
||||||
import type { RecordFactory, RecordOf } from 'immutable'
|
import type { RecordFactory, RecordOf } from 'immutable'
|
||||||
|
|
||||||
import { type TxServiceType } from '~/logic/safe/transactions/txHistory'
|
import { type TxServiceType } from '~/logic/safe/transactions/txHistory'
|
||||||
import { type Owner, makeOwner } from '~/routes/safe/store/models/owner'
|
|
||||||
|
|
||||||
export type ConfirmationProps = {
|
export type ConfirmationProps = {
|
||||||
owner: Owner,
|
owner: string,
|
||||||
type: TxServiceType,
|
type: TxServiceType,
|
||||||
hash: string,
|
hash: string,
|
||||||
signature?: string,
|
signature?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makeConfirmation: RecordFactory<ConfirmationProps> = Record({
|
export const makeConfirmation: RecordFactory<ConfirmationProps> = Record({
|
||||||
owner: makeOwner(),
|
owner: '',
|
||||||
type: 'initialised',
|
type: 'initialised',
|
||||||
hash: '',
|
hash: '',
|
||||||
signature: null,
|
signature: null,
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { type OutputSelector, createSelector } from 'reselect'
|
||||||
|
|
||||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { SAFELIST_ADDRESS, SAFE_PARAM_ADDRESS } from '~/routes/routes'
|
import { SAFELIST_ADDRESS, SAFE_PARAM_ADDRESS } from '~/routes/routes'
|
||||||
import { type Confirmation } from '~/routes/safe/store/models/confirmation'
|
|
||||||
import type { IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
import type { IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
||||||
import { type Safe } from '~/routes/safe/store/models/safe'
|
import { type Safe } from '~/routes/safe/store/models/safe'
|
||||||
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||||
|
@ -25,8 +24,8 @@ export type RouterProps = {
|
||||||
match: Match,
|
match: Match,
|
||||||
}
|
}
|
||||||
|
|
||||||
type TransactionProps = {
|
export type SafeProps = {
|
||||||
transaction: Transaction,
|
safeAddress: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const safesStateSelector = (state: GlobalState): Map<string, *> => state[SAFE_REDUCER_ID]
|
const safesStateSelector = (state: GlobalState): Map<string, *> => state[SAFE_REDUCER_ID]
|
||||||
|
@ -64,8 +63,6 @@ const cancellationTransactionsSelector = (state: GlobalState): CancelTransaction
|
||||||
const incomingTransactionsSelector = (state: GlobalState): IncomingTransactionsState =>
|
const incomingTransactionsSelector = (state: GlobalState): IncomingTransactionsState =>
|
||||||
state[INCOMING_TRANSACTIONS_REDUCER_ID]
|
state[INCOMING_TRANSACTIONS_REDUCER_ID]
|
||||||
|
|
||||||
const oneTransactionSelector = (state: GlobalState, props: TransactionProps) => props.transaction
|
|
||||||
|
|
||||||
export const safeParamAddressFromStateSelector = (state: GlobalState): string | null => {
|
export const safeParamAddressFromStateSelector = (state: GlobalState): string | null => {
|
||||||
const match = matchPath(state.router.location.pathname, { path: `${SAFELIST_ADDRESS}/:safeAddress` })
|
const match = matchPath(state.router.location.pathname, { path: `${SAFELIST_ADDRESS}/:safeAddress` })
|
||||||
|
|
||||||
|
@ -144,22 +141,6 @@ export const safeIncomingTransactionsSelector: IncomingTxSelectorType = createSe
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
export const confirmationsTransactionSelector: OutputSelector<GlobalState, TransactionProps, number> = createSelector(
|
|
||||||
oneTransactionSelector,
|
|
||||||
(tx: Transaction) => {
|
|
||||||
if (!tx) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmations: List<Confirmation> = tx.get('confirmations')
|
|
||||||
if (!confirmations) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return confirmations.filter((confirmation: Confirmation) => confirmation.get('type') === 'confirmation').count()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
export type SafeSelectorProps = Safe | typeof undefined
|
export type SafeSelectorProps = Safe | typeof undefined
|
||||||
|
|
||||||
export const safeSelector: OutputSelector<GlobalState, RouterProps, SafeSelectorProps> = createSelector(
|
export const safeSelector: OutputSelector<GlobalState, RouterProps, SafeSelectorProps> = createSelector(
|
||||||
|
|
Loading…
Reference in New Issue