diff --git a/src/components/EtherscanLink/index.tsx b/src/components/EtherscanLink/index.tsx index ea4dec04..9a6d70f9 100644 --- a/src/components/EtherscanLink/index.tsx +++ b/src/components/EtherscanLink/index.tsx @@ -8,7 +8,7 @@ import CopyBtn from 'src/components/CopyBtn' import Block from 'src/components/layout/Block' import Span from 'src/components/layout/Span' import { shortVersionOf } from 'src/logic/wallets/ethAddresses' -import EllipsisTransactionDetails from 'src/routes/safe/components/AddressBook/EllipsisTransactionDetails' +import { EllipsisTransactionDetails } from 'src/routes/safe/components/AddressBook/EllipsisTransactionDetails' import { ExplorerButton } from '@gnosis.pm/safe-react-components' import { getExplorerInfo } from 'src/config' @@ -19,9 +19,16 @@ interface EtherscanLinkProps { cut?: number knownAddress?: boolean value: string + sendModalOpenHandler?: () => void } -export const EtherscanLink = ({ className, cut, knownAddress, value }: EtherscanLinkProps): React.ReactElement => { +export const EtherscanLink = ({ + className, + cut, + knownAddress, + value, + sendModalOpenHandler, +}: EtherscanLinkProps): React.ReactElement => { const classes = useStyles() return ( @@ -31,7 +38,13 @@ export const EtherscanLink = ({ className, cut, knownAddress, value }: Etherscan - {knownAddress !== undefined ? : null} + {knownAddress !== undefined ? ( + + ) : null} ) } diff --git a/src/routes/safe/components/AddressBook/EllipsisTransactionDetails/index.tsx b/src/routes/safe/components/AddressBook/EllipsisTransactionDetails/index.tsx index 3d7cfa44..783b0f52 100644 --- a/src/routes/safe/components/AddressBook/EllipsisTransactionDetails/index.tsx +++ b/src/routes/safe/components/AddressBook/EllipsisTransactionDetails/index.tsx @@ -1,4 +1,4 @@ -import { ClickAwayListener, Divider } from '@material-ui/core' +import { ClickAwayListener, createStyles, Divider } from '@material-ui/core' import Menu from '@material-ui/core/Menu' import MenuItem from '@material-ui/core/MenuItem' import { makeStyles } from '@material-ui/core/styles' @@ -11,26 +11,38 @@ import { SAFELIST_ADDRESS } from 'src/routes/routes' import { safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors' import { xs } from 'src/theme/variables' -const useStyles = makeStyles({ - container: { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - cursor: 'pointer', - margin: `0 ${xs}`, - borderRadius: '50%', - transition: 'background-color .2s ease-in-out', - '&:hover': { - backgroundColor: '#F0EFEE', +const useStyles = makeStyles( + createStyles({ + container: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + cursor: 'pointer', + margin: `0 ${xs}`, + borderRadius: '50%', + transition: 'background-color .2s ease-in-out', + '&:hover': { + backgroundColor: '#F0EFEE', + }, + outline: 'none', }, - outline: 'none', - }, - increasedPopperZindex: { - zIndex: 2001, - }, -}) + increasedPopperZindex: { + zIndex: 2001, + }, + }), +) -const EllipsisTransactionDetails = ({ address, knownAddress }) => { +type EllipsisTransactionDetailsProps = { + address: string + knownAddress?: boolean + sendModalOpenHandler?: () => void +} + +export const EllipsisTransactionDetails = ({ + address, + knownAddress, + sendModalOpenHandler, +}: EllipsisTransactionDetailsProps): React.ReactElement => { const classes = useStyles() const [anchorEl, setAnchorEl] = React.useState(null) @@ -51,10 +63,12 @@ const EllipsisTransactionDetails = ({ address, knownAddress }) => {
- - Send Again - - + {sendModalOpenHandler ? ( + <> + Send Again + + + ) : null} {knownAddress ? ( Edit Address book Entry ) : ( @@ -65,5 +79,3 @@ const EllipsisTransactionDetails = ({ address, knownAddress }) => { ) } - -export default EllipsisTransactionDetails diff --git a/src/routes/safe/components/Balances/SendModal/index.tsx b/src/routes/safe/components/Balances/SendModal/index.tsx index 5cdb7eb0..a10b046f 100644 --- a/src/routes/safe/components/Balances/SendModal/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/index.tsx @@ -6,7 +6,6 @@ import React, { Suspense, useEffect, useState } from 'react' import Modal from 'src/components/Modal' import { CollectibleTx } from './screens/ReviewCollectible' import { CustomTx } from './screens/ContractInteraction/ReviewCustomTx' -import { SendFundsTx } from './screens/SendFunds' import { ContractInteractionTx } from './screens/ContractInteraction' import { CustomTxProps } from './screens/ContractInteraction/SendCustomTx' import { ReviewTxProp } from './screens/ReviewTx' @@ -53,6 +52,7 @@ type Props = { onClose: () => void recipientAddress?: string selectedToken?: string | NFTToken + tokenAmount?: string } const SendModal = ({ @@ -61,6 +61,7 @@ const SendModal = ({ onClose, recipientAddress, selectedToken, + tokenAmount, }: Props): React.ReactElement => { const classes = useStyles() const [activeScreen, setActiveScreen] = useState(activeScreenType || 'chooseTxType') @@ -119,11 +120,11 @@ const SendModal = ({ )} {activeScreen === 'sendFunds' && ( )} {activeScreen === 'reviewTx' && ( diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.tsx index 0d85e87a..4fa961ab 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.tsx @@ -48,44 +48,36 @@ const formMutators = { const useStyles = makeStyles(styles) -export type SendFundsTx = { - amount?: string - recipientAddress?: string - token?: string -} - type SendFundsProps = { - initialValues: SendFundsTx onClose: () => void onNext: (txInfo: unknown) => void recipientAddress?: string selectedToken?: string + amount?: string } const { nativeCoin } = getNetworkInfo() const SendFunds = ({ - initialValues, onClose, onNext, recipientAddress, selectedToken = '', + amount, }: SendFundsProps): React.ReactElement => { const classes = useStyles() const tokens = useSelector(extendedSafeTokensSelector) const addressBook = useSelector(addressBookSelector) const [selectedEntry, setSelectedEntry] = useState<{ address: string; name: string } | null>(() => { - const defaultEntry = { address: '', name: '' } + const defaultEntry = { address: recipientAddress || '', name: '' } // if there's nothing to lookup for, we return the default entry - if (!initialValues?.recipientAddress && !recipientAddress) { + if (!recipientAddress) { return defaultEntry } - // if there's something to lookup for, `initialValues` has precedence over `recipientAddress` - const predefinedAddress = initialValues?.recipientAddress ?? recipientAddress const addressBookEntry = addressBook.find(({ address }) => { - return sameAddress(predefinedAddress, address) + return sameAddress(recipientAddress, address) }) // if found in the Address Book, then we return the entry @@ -126,7 +118,11 @@ const SendFunds = ({ - + {(...args) => { const formState = args[2] const mutators = args[3] diff --git a/src/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell/index.tsx b/src/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell/index.tsx index 39220c64..f626aabe 100644 --- a/src/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell/index.tsx @@ -13,10 +13,11 @@ type OwnerAddressTableCellProps = { knownAddress?: boolean showLinks: boolean userName?: string + sendModalOpenHandler?: () => void } const OwnerAddressTableCell = (props: OwnerAddressTableCellProps): React.ReactElement => { - const { address, knownAddress, showLinks, userName } = props + const { address, knownAddress, showLinks, userName, sendModalOpenHandler } = props const [cut, setCut] = useState(0) const { width } = useWindowDimensions() @@ -36,7 +37,12 @@ const OwnerAddressTableCell = (props: OwnerAddressTableCellProps): React.ReactEl {showLinks ? (
{userName && getValidAddressBookName(userName)} - +
) : ( {address} diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/TransferDescription.tsx b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/TransferDescription.tsx index 7d589d84..2cdbab12 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/TransferDescription.tsx +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/TransferDescription.tsx @@ -7,23 +7,59 @@ import { getNameFromAddressBookSelector } from 'src/logic/addressBook/store/sele import OwnerAddressTableCell from 'src/routes/safe/components/Settings/ManageOwners/OwnerAddressTableCell' import { TRANSACTIONS_DESC_SEND_TEST_ID } from './index' +import SendModal from 'src/routes/safe/components/Balances/SendModal' interface TransferDescriptionProps { - amount: string + amountWithSymbol: string recipient: string + tokenAddress?: string + rawAmount?: string + isTokenTransfer: boolean } -const TransferDescription = ({ amount = '', recipient }: TransferDescriptionProps): React.ReactElement => { +const TransferDescription = ({ + amountWithSymbol = '', + recipient, + tokenAddress, + rawAmount, + isTokenTransfer, +}: TransferDescriptionProps): React.ReactElement => { const recipientName = useSelector((state) => getNameFromAddressBookSelector(state, recipient)) + const [sendModalOpen, setSendModalOpen] = React.useState(false) + + const sendModalOpenHandler = () => { + setSendModalOpen(true) + } + return ( - - Send {amount} to: - {recipientName ? ( - - ) : ( - - )} - + <> + + Send {amountWithSymbol} to: + {recipientName ? ( + + ) : ( + + )} + + setSendModalOpen(false)} + recipientAddress={recipient} + selectedToken={tokenAddress} + tokenAmount={rawAmount} + /> + ) } diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.tsx b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.tsx index 5a99fbb5..cf7cd433 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.tsx +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.tsx @@ -7,7 +7,7 @@ import SettingsDescription from './SettingsDescription' import CustomDescription from './CustomDescription' import TransferDescription from './TransferDescription' -import { getTxAmount } from 'src/routes/safe/components/Transactions/TxsTable/columns' +import { getRawTxAmount, getTxAmount } from 'src/routes/safe/components/Transactions/TxsTable/columns' import Block from 'src/components/layout/Block' import { Transaction } from 'src/logic/safe/store/models/types/transaction' @@ -30,8 +30,12 @@ const TxDescription = ({ tx }: { tx: Transaction }): React.ReactElement => { recipient, removedOwner, upgradeTx, + tokenAddress, + isTokenTransfer, }: any = getTxData(tx) - const amount = getTxAmount(tx, false) + + const amountWithSymbol = getTxAmount(tx, false) + const amount = getRawTxAmount(tx) return ( {modifySettingsTx && action && ( @@ -43,10 +47,18 @@ const TxDescription = ({ tx }: { tx: Transaction }): React.ReactElement => { module={module} /> )} - {!upgradeTx && customTx && } + {!upgradeTx && customTx && ( + + )} {upgradeTx &&
{data}
} {!cancellationTx && !modifySettingsTx && !customTx && !creationTx && !upgradeTx && ( - + )}
) diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.ts b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.ts index 2ba34f22..08d8ec47 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.ts +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.ts @@ -1,5 +1,7 @@ import { Transaction } from 'src/logic/safe/store/models/types/transaction' import { SAFE_METHODS_NAMES } from 'src/routes/safe/store/models/types/transactions.d' +import { sameString } from 'src/utils/strings' +import { getNetworkInfo } from 'src/config' const getSafeVersion = (data) => { const contractAddress = data.substr(340, 40).toLowerCase() @@ -27,6 +29,7 @@ interface TxData { cancellationTx?: boolean creationTx?: boolean upgradeTx?: boolean + tokenAddress?: string } const getTxDataForModifySettingsTxs = (tx: Transaction): TxData => { @@ -97,6 +100,7 @@ const getTxDataForTxsWithDecodedParams = (tx: Transaction): TxData => { const { to } = tx.decodedParams.transfer || {} txData.recipient = to txData.isTokenTransfer = true + txData.tokenAddress = tx.recipient return txData } @@ -133,6 +137,12 @@ const getTxDataForTxsWithDecodedParams = (tx: Transaction): TxData => { export const getTxData = (tx: Transaction): TxData => { const txData: TxData = {} + const { nativeCoin } = getNetworkInfo() + if (sameString(tx.type, 'outgoing') && tx.symbol && sameString(tx.symbol, nativeCoin.symbol)) { + txData.isTokenTransfer = true + txData.tokenAddress = nativeCoin.address + } + if (tx.decodedParams) { return getTxDataForTxsWithDecodedParams(tx) } diff --git a/src/routes/safe/components/Transactions/TxsTable/columns.tsx b/src/routes/safe/components/Transactions/TxsTable/columns.tsx index 39eca8d5..db364e72 100644 --- a/src/routes/safe/components/Transactions/TxsTable/columns.tsx +++ b/src/routes/safe/components/Transactions/TxsTable/columns.tsx @@ -13,6 +13,7 @@ import { formatAmount } from 'src/logic/tokens/utils/formatAmount' import { INCOMING_TX_TYPES } from 'src/logic/safe/store/models/incomingTransaction' import { Transaction } from 'src/logic/safe/store/models/types/transaction' import { CancellationTransactions } from 'src/logic/safe/store/reducer/cancellationTransactions' +import { getNetworkInfo } from 'src/config' export const TX_TABLE_ID = 'id' export const TX_TABLE_TYPE_ID = 'type' @@ -71,6 +72,25 @@ export const getTxAmount = (tx: Transaction, formatted = true): string => { return getAmountWithSymbol({ decimals: decimals as string, symbol: symbol as string, value }, formatted) } +export const getRawTxAmount = (tx: Transaction): string => { + const { decimals, decodedParams, isTokenTransfer } = tx + const { nativeCoin } = getNetworkInfo() + const { value } = isTokenTransfer && !!decodedParams?.transfer ? decodedParams.transfer : tx + + if (tx.isCollectibleTransfer) { + return '1' + } + + if (!isTokenTransfer && !(Number(value) > 0)) { + return NOT_AVAILABLE + } + + const tokenDecimals = decimals ?? nativeCoin.decimals + const finalValue = new BigNumber(value).times(`1e-${tokenDecimals}`).toFixed() + + return finalValue === 'NaN' ? NOT_AVAILABLE : finalValue +} + export interface TableData { amount: string cancelTx?: Transaction