Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import { sameString } from 'src/utils/strings'
interface AddressInfoProps {
address: string
title?: string
name?: string
logoUri?: string
}

const AddressInfo = ({ address, title }: AddressInfoProps): ReactElement => {
const name = useSelector((state) => addressBookEntryName(state, { address }))
const AddressInfo = ({ address, title, name, logoUri }: AddressInfoProps): ReactElement => {
const addessBookName = useSelector((state) => addressBookEntryName(state, { address }))

return (
<>
Expand All @@ -25,11 +27,12 @@ const AddressInfo = ({ address, title }: AddressInfoProps): ReactElement => {
)}
<PrefixedEthHashInfo
hash={address}
name={sameString(name, ADDRESS_BOOK_DEFAULT_NAME) ? undefined : name}
name={sameString(addessBookName, ADDRESS_BOOK_DEFAULT_NAME) ? name : addessBookName}
showCopyBtn
showAvatar
textSize="lg"
explorerUrl={getExplorerInfo(address)}
customAvatar={logoUri || undefined}
/>
</>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Props = EthHashInfoRestProps & {
}

export const AddressInfo = ({ address, name, avatarUrl, ...rest }: Props): ReactElement | null => {
const toInfo = useKnownAddress(address, { name, image: avatarUrl })
const toInfo = useKnownAddress({ value: address, name: name || null, logoUri: avatarUrl || null })

if (address === '') {
return null
Expand All @@ -25,9 +25,9 @@ export const AddressInfo = ({ address, name, avatarUrl, ...rest }: Props): React
return (
<PrefixedEthHashInfo
hash={address}
name={toInfo.name}
name={toInfo.name || undefined}
showAvatar
customAvatar={toInfo.image}
customAvatar={toInfo.logoUri || undefined}
showCopyBtn
explorerUrl={getExplorerInfo(address)}
{...rest}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { sameString } from 'src/utils/strings'
import { fromTokenUnit } from 'src/logic/tokens/utils/humanReadableValue'
import { getResetTimeOptions } from 'src/routes/safe/components/Settings/SpendingLimit/FormFields/ResetTime'
import { AddressInfo, ResetTimeInfo, TokenInfo } from 'src/routes/safe/components/Settings/SpendingLimit/InfoDisplay'
import { DataDecoded } from '@gnosis.pm/safe-react-gateway-sdk'
import { TransactionData, TransactionInfo } from '@gnosis.pm/safe-react-gateway-sdk'
import { getTxTo } from './utils'

const SET_ALLOWANCE = 'setAllowance'
const DELETE_ALLOWANCE = 'deleteAllowance'
Expand All @@ -28,10 +29,16 @@ const SpendingLimitRow = styled.div`
margin-bottom: 16px;
`

export const ModifySpendingLimitDetails = ({ data }: { data: DataDecoded }): React.ReactElement => {
type SpendingLimitProps = {
txData: TransactionData
txInfo: TransactionInfo
}

export const ModifySpendingLimitDetails = ({ txData, txInfo }: SpendingLimitProps): React.ReactElement => {
const { dataDecoded } = txData
const [beneficiary, tokenAddress, amount, resetTimeMin] = useMemo(
() => data.parameters?.map(({ value }) => value) ?? [],
[data.parameters],
() => dataDecoded?.parameters?.map(({ value }) => value) ?? [],
[dataDecoded?.parameters],
)

const resetTimeLabel = useMemo(
Expand All @@ -40,6 +47,7 @@ export const ModifySpendingLimitDetails = ({ data }: { data: DataDecoded }): Rea
)

const tokenInfo = useTokenInfo(tokenAddress as string)
const txTo = getTxTo({ txInfo })

return (
<>
Expand All @@ -49,7 +57,12 @@ export const ModifySpendingLimitDetails = ({ data }: { data: DataDecoded }): Rea
</Text>
</SpendingLimitRow>
<SpendingLimitRow>
<AddressInfo title="Beneficiary" address={beneficiary as string} />
<AddressInfo
title="Beneficiary"
address={(beneficiary as string) || txTo?.value || '0x'}
name={txTo?.name || undefined}
logoUri={txTo?.logoUri || undefined}
/>
</SpendingLimitRow>
<SpendingLimitRow>
{tokenInfo && (
Expand All @@ -63,9 +76,14 @@ export const ModifySpendingLimitDetails = ({ data }: { data: DataDecoded }): Rea
)
}

export const DeleteSpendingLimitDetails = ({ data }: { data: DataDecoded }): React.ReactElement => {
const [beneficiary, tokenAddress] = useMemo(() => data.parameters?.map(({ value }) => value) ?? [], [data.parameters])
export const DeleteSpendingLimitDetails = ({ txData, txInfo }: SpendingLimitProps): React.ReactElement => {
const { dataDecoded } = txData
const [beneficiary, tokenAddress] = useMemo(
() => dataDecoded?.parameters?.map(({ value }) => value) ?? [],
[dataDecoded?.parameters],
)
const tokenInfo = useTokenInfo(tokenAddress as string)
const txTo = getTxTo({ txInfo })

return (
<>
Expand All @@ -75,7 +93,12 @@ export const DeleteSpendingLimitDetails = ({ data }: { data: DataDecoded }): Rea
</Text>
</SpendingLimitRow>
<SpendingLimitRow>
<AddressInfo title="Beneficiary" address={beneficiary as string} />
<AddressInfo
title="Beneficiary"
address={(beneficiary as string) || txTo?.value || '0x'}
name={txTo?.name || undefined}
logoUri={txTo?.logoUri || undefined}
/>
</SpendingLimitRow>
<SpendingLimitRow>{tokenInfo && <TokenInfo amount="" title="Token" token={tokenInfo} />}</SpendingLimitRow>
</>
Expand Down
22 changes: 12 additions & 10 deletions src/routes/safe/components/Transactions/TxList/TxCollapsed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
} from 'src/logic/safe/store/models/types/gateway.d'
import { TxCollapsedActions } from './TxCollapsedActions'
import { formatDateTime, formatTime, formatTimeInWords } from 'src/utils/date'
import { KNOWN_MODULES } from 'src/utils/constants'
import { sameString } from 'src/utils/strings'
import { AssetInfo, isTokenTransferAsset } from './hooks/useAssetInfo'
import { TransactionActions } from './hooks/useTransactionActions'
Expand All @@ -24,17 +23,18 @@ import { TxsInfiniteScrollContext } from './TxsInfiniteScroll'
import { TxLocationContext } from './TxLocationProvider'
import { CalculatedVotes } from './TxQueueCollapsed'
import { getTxTo, isCancelTxDetails } from './utils'
import { SettingsChange, DisableModule, MultiSend, Custom } from '@gnosis.pm/safe-react-gateway-sdk'
import { MultiSend, Custom } from '@gnosis.pm/safe-react-gateway-sdk'
import { useKnownAddress } from './hooks/useKnownAddress'

const TxInfo = ({ info }: { info: AssetInfo }) => {
const TxInfo = ({ info, name }: { info: AssetInfo; name?: string }) => {
if (isTokenTransferAsset(info)) {
return <TokenTransferAmount assetInfo={info} />
}

if (isSettingsChangeTxInfo(info)) {
if (isSettingsChangeTxInfo(info) && !isCustomTxInfo(info)) {
const UNKNOWN_MODULE = 'Unknown module'

switch ((info as SettingsChange).settingsInfo?.type) {
switch (info.settingsInfo?.type) {
case 'SET_FALLBACK_HANDLER':
case 'ADD_OWNER':
case 'REMOVE_OWNER':
Expand All @@ -44,10 +44,9 @@ const TxInfo = ({ info }: { info: AssetInfo }) => {
break
case 'ENABLE_MODULE':
case 'DISABLE_MODULE':
const disableInfo = (info as SettingsChange).settingsInfo as DisableModule
return (
<Text size="xl" as="span">
{KNOWN_MODULES[disableInfo.module.value] ?? UNKNOWN_MODULE}
{name || UNKNOWN_MODULE}
</Text>
)
}
Expand Down Expand Up @@ -117,6 +116,7 @@ export const TxCollapsed = ({
const { txLocation } = useContext(TxLocationContext)
const { ref, lastItemId } = useContext(TxsInfiniteScrollContext)
const toAddress = getTxTo(transaction)
const toInfo = useKnownAddress(toAddress)

const willBeReplaced = transaction?.txStatus === 'WILL_BE_REPLACED' ? ' will-be-replaced' : ''
const onChainRejection =
Expand All @@ -132,14 +132,16 @@ export const TxCollapsed = ({
<div className={'tx-type' + willBeReplaced + onChainRejection}>
<CustomIconText
address={toAddress?.value || '0x'}
iconUrl={type.icon}
iconUrl={type.icon || toInfo?.logoUri || undefined}
iconUrlFallback={type.fallbackIcon}
text={type.text}
text={type.text || toInfo?.name || undefined}
/>
</div>
)

const txCollapsedInfo = <div className={'tx-info' + willBeReplaced}>{info && <TxInfo info={info} />}</div>
const txCollapsedInfo = (
<div className={'tx-info' + willBeReplaced}>{info && <TxInfo info={info} name={toInfo?.name || undefined} />}</div>
)

const timestamp = useRef<HTMLDivElement | null>(null)

Expand Down
4 changes: 2 additions & 2 deletions src/routes/safe/components/Transactions/TxList/TxData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ export const TxData = ({ txData, txInfo }: TxDataProps): ReactElement | null =>

// FixMe: this way won't scale well
if (isSetAllowance(txData.dataDecoded.method)) {
return <ModifySpendingLimitDetails data={txData.dataDecoded} />
return <ModifySpendingLimitDetails txData={txData} txInfo={txInfo} />
}

// FixMe: this way won't scale well
if (isDeleteAllowance(txData.dataDecoded.method)) {
return <DeleteSpendingLimitDetails data={txData.dataDecoded} />
return <DeleteSpendingLimitDetails txData={txData} txInfo={txInfo} />
}

// we render the decoded data
Expand Down
27 changes: 9 additions & 18 deletions src/routes/safe/components/Transactions/TxList/TxInfoCreation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,9 @@ export const TxInfoCreation = ({ transaction }: { transaction: Transaction }): R
const txInfo = transaction.txInfo as Creation
const timestamp = transaction.timestamp

const creator = useKnownAddress(txInfo.creator.value, {
name: txInfo.creator?.name,
image: txInfo.creator?.logoUri,
})
const factory = useKnownAddress(txInfo.factory?.value, {
name: txInfo.factory?.name,
image: txInfo.factory?.logoUri,
})
const implementation = useKnownAddress(txInfo.implementation?.value, {
name: txInfo.implementation?.name,
image: txInfo.implementation?.logoUri,
})
const creator = useKnownAddress(txInfo.creator)
const factory = useKnownAddress(txInfo.factory)
const implementation = useKnownAddress(txInfo.implementation)
Comment on lines +17 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!


return (
<TxDetailsContainer>
Expand Down Expand Up @@ -61,8 +52,8 @@ export const TxInfoCreation = ({ transaction }: { transaction: Transaction }): R
hash={txInfo.creator.value}
showCopyBtn
explorerUrl={getExplorerInfo(txInfo.creator.value)}
name={creator.name}
customAvatar={creator.image}
name={creator.name || undefined}
customAvatar={creator.logoUri || undefined}
showAvatar
/>
</div>
Expand All @@ -76,8 +67,8 @@ export const TxInfoCreation = ({ transaction }: { transaction: Transaction }): R
hash={txInfo.factory.value}
showCopyBtn
explorerUrl={getExplorerInfo(txInfo.factory.value)}
name={factory.name}
customAvatar={factory.image}
name={factory?.name || undefined}
customAvatar={factory?.logoUri || undefined}
showAvatar
/>
) : (
Expand All @@ -96,8 +87,8 @@ export const TxInfoCreation = ({ transaction }: { transaction: Transaction }): R
hash={txInfo.implementation.value}
showCopyBtn
explorerUrl={getExplorerInfo(txInfo.implementation.value)}
name={implementation.name}
customAvatar={implementation.image}
name={implementation?.name || undefined}
customAvatar={implementation?.logoUri || undefined}
showAvatar
/>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,31 @@ import { useSelector } from 'react-redux'
import { sameString } from 'src/utils/strings'
import { ADDRESS_BOOK_DEFAULT_NAME } from 'src/logic/addressBook/model/addressBook'
import { addressBookEntryName } from 'src/logic/addressBook/store/selectors'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { AddressEx } from '@gnosis.pm/safe-react-gateway-sdk'

type AddressExName = AddressEx['name']
type AddressExImage = AddressEx['logoUri']
type AddressInfo = { name: AddressExName | undefined; image: AddressExImage | undefined }
const DEFAULT_PROPS: AddressEx = {
value: '',
name: null,
logoUri: null,
}
export const useKnownAddress = (props: AddressEx | null = DEFAULT_PROPS): AddressEx & { isInAddressBook: boolean } => {
const recipientName = useSelector((state) => addressBookEntryName(state, { address: props?.value || '' }))

type UseKnownAddressResponse = { name: string | undefined; image: string | undefined; isAddressBook: boolean }
// Undefined known address
if (!props) {
return {
...DEFAULT_PROPS,
isInAddressBook: false,
}
}

export const useKnownAddress = (address = ZERO_ADDRESS, { name, image }: AddressInfo): UseKnownAddressResponse => {
const recipientName = useSelector((state) => addressBookEntryName(state, { address }))
// We have to check that the name returned is not UNKNOWN
const isInAddressBook = !sameString(recipientName, ADDRESS_BOOK_DEFAULT_NAME)
const name = isInAddressBook && recipientName ? recipientName : props?.name

return isInAddressBook
? {
name: recipientName,
image: undefined,
isAddressBook: true,
}
: { name: name || undefined, image: image || undefined, isAddressBook: false }
return {
...props,
name,
isInAddressBook,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@ export const useTransactionType = (tx: Transaction): TxTypeProps => {
const [type, setType] = useState<TxTypeProps>({ icon: CustomTxIcon, text: 'Contract interaction' })
const safeAddress = extractSafeAddress()
const toAddress = getTxTo(tx)
// Fixed casting because known address only works for Custom tx
const knownAddressBookAddress = useKnownAddress(toAddress?.value, {
name: toAddress?.name,
image: toAddress?.logoUri,
})
const knownAddressBookAddress = useKnownAddress(toAddress)

useEffect(() => {
switch (tx.txInfo.type) {
Expand Down Expand Up @@ -62,10 +58,10 @@ export const useTransactionType = (tx: Transaction): TxTypeProps => {
}

setType({
icon: knownAddressBookAddress.isAddressBook
icon: knownAddressBookAddress.isInAddressBook
? CustomTxIcon
: knownAddressBookAddress.image || toAddress?.logoUri || CustomTxIcon,
fallbackIcon: knownAddressBookAddress.isAddressBook ? undefined : CustomTxIcon,
: knownAddressBookAddress.logoUri || toAddress?.logoUri || CustomTxIcon,
fallbackIcon: knownAddressBookAddress.isInAddressBook ? undefined : CustomTxIcon,
text: knownAddressBookAddress.name || toAddress?.name || 'Contract interaction',
})
break
Expand All @@ -75,8 +71,8 @@ export const useTransactionType = (tx: Transaction): TxTypeProps => {
tx,
safeAddress,
knownAddressBookAddress.name,
knownAddressBookAddress.image,
knownAddressBookAddress.isAddressBook,
knownAddressBookAddress.logoUri,
knownAddressBookAddress.isInAddressBook,
toAddress?.logoUri,
toAddress?.name,
])
Expand Down
10 changes: 5 additions & 5 deletions src/routes/safe/components/Transactions/TxList/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,19 @@ export const addressInList =
(address: string): boolean =>
list.some((ownerAddress) => sameAddress(ownerAddress.value, address))

export const getTxTo = (tx: Transaction): AddressEx | undefined => {
switch (tx.txInfo.type) {
export const getTxTo = ({ txInfo }: Pick<Transaction, 'txInfo'>): AddressEx | undefined => {
switch (txInfo.type) {
case 'Transfer': {
return tx.txInfo.recipient
return txInfo.recipient
}
case 'SettingsChange': {
return undefined
}
case 'Custom': {
return tx.txInfo.to
return txInfo.to
}
case 'Creation': {
return tx.txInfo.factory || undefined
return txInfo.factory || undefined
}
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,4 @@ export const GATEWAY_URL = IS_PRODUCTION
export const IPFS_GATEWAY = process.env.REACT_APP_IPFS_GATEWAY
export const SPENDING_LIMIT_MODULE_ADDRESS =
process.env.REACT_APP_SPENDING_LIMIT_MODULE_ADDRESS || '0xCFbFaC74C26F8647cBDb8c5caf80BB5b32E43134'
export const GNOSISDAO_SAFESNAP_MODULE_ADDRESS =
process.env.GNOSISDAO_SAFESNAP_MODULE_ADDRESS || '0x0eBaC21F7f6A6599B5fa5f57Baaa974ADFEC4613'
export const KNOWN_MODULES = {
[SPENDING_LIMIT_MODULE_ADDRESS]: 'Spending limit',
[GNOSISDAO_SAFESNAP_MODULE_ADDRESS]: 'GnosisDAO SafeSnap',
}
// TODO: Remove GNOSISDAO_SAFESNAP_MODULE_ADDRESS from GitHub secrets