Skip to content

Commit

Permalink
feat: fetch contract info for contract interactions (#3652)
Browse files Browse the repository at this point in the history
* feat: fetch contract info for contract interactions
  • Loading branch information
schmanu authored May 6, 2024
1 parent 4ed007f commit 7130d87
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 19 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"@safe-global/safe-core-sdk": "^3.3.5",
"@safe-global/safe-core-sdk-utils": "^1.7.4",
"@safe-global/safe-ethers-lib": "^1.9.4",
"@safe-global/safe-gateway-typescript-sdk": "3.21.0-alpha.3",
"@safe-global/safe-gateway-typescript-sdk": "3.21.1",
"@safe-global/safe-modules-deployments": "^1.2.0",
"@sentry/react": "^7.91.0",
"@spindl-xyz/attribution-lite": "^1.4.0",
Expand Down
67 changes: 67 additions & 0 deletions src/components/common/NamedAddressInfo/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { render, waitFor } from '@/tests/test-utils'
import NamedAddressInfo from '.'
import { faker } from '@faker-js/faker'
import { getContract, type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'

const mockChainInfo = {
chainId: '4',
shortName: 'tst',
blockExplorerUriTemplate: {
address: 'https://test.scan.eth/{address}',
api: 'https://test.scan.eth/',
txHash: 'https://test.scan.eth/{txHash}',
},
} as ChainInfo

jest.mock('@safe-global/safe-gateway-typescript-sdk', () => ({
...jest.requireActual('@safe-global/safe-gateway-typescript-sdk'),
getContract: jest.fn(),
__esModule: true,
}))

describe('NamedAddressInfo', () => {
const getContractMock = getContract as jest.Mock
it('should not fetch contract info if name / logo is given', async () => {
const result = render(
<NamedAddressInfo
address={faker.finance.ethereumAddress()}
name="TestAddressName"
customAvatar="https://img.test.safe.global"
/>,
{
initialReduxState: {
chains: {
loading: false,
data: [mockChainInfo],
},
},
},
)

expect(result.getByText('TestAddressName')).toBeVisible()
expect(getContractMock).not.toHaveBeenCalled()
})

it('should fetch contract info if name / logo is not given', async () => {
const address = faker.finance.ethereumAddress()
getContractMock.mockResolvedValue({
displayName: 'Resolved Test Name',
name: 'ResolvedTestName',
logoUri: 'https://img-resolved.test.safe.global',
})
const result = render(<NamedAddressInfo address={address} />, {
initialReduxState: {
chains: {
loading: false,
data: [mockChainInfo],
},
},
})

await waitFor(() => {
expect(result.getByText('Resolved Test Name')).toBeVisible()
})

expect(getContractMock).toHaveBeenCalledWith('4', address)
})
})
24 changes: 24 additions & 0 deletions src/components/common/NamedAddressInfo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import useAsync from '@/hooks/useAsync'
import useChainId from '@/hooks/useChainId'
import { getContract } from '@safe-global/safe-gateway-typescript-sdk'
import EthHashInfo from '../EthHashInfo'
import type { EthHashInfoProps } from '../EthHashInfo/SrcEthHashInfo'

const NamedAddressInfo = ({ address, name, customAvatar, ...props }: EthHashInfoProps) => {
const chainId = useChainId()
const [contract] = useAsync(
() => (!name && !customAvatar ? getContract(chainId, address) : undefined),
[address, chainId, name, customAvatar],
)

return (
<EthHashInfo
address={address}
name={name || contract?.displayName || contract?.name}
customAvatar={customAvatar || contract?.logoUri}
{...props}
/>
)
}

export default NamedAddressInfo
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import accordionCss from '@/styles/accordion.module.css'
import CodeIcon from '@mui/icons-material/Code'
import { DelegateCallWarning } from '@/components/transactions/Warning'
import { InfoDetails } from '@/components/transactions/InfoDetails'
import EthHashInfo from '@/components/common/EthHashInfo'
import NamedAddressInfo from '@/components/common/NamedAddressInfo'

type SingleTxDecodedProps = {
tx: InternalTransaction
Expand Down Expand Up @@ -74,7 +74,7 @@ export const SingleTxDecoded = ({
{isDelegateCall && <DelegateCallWarning showWarning={!txData.trustedDelegateCallTarget} />}
{!isSpendingLimitMethod && (
<InfoDetails title={title}>
<EthHashInfo
<NamedAddressInfo
address={tx.to}
name={name}
customAvatar={avatarUrl}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import type { ReactElement } from 'react'
import type { TransactionDetails } from '@safe-global/safe-gateway-typescript-sdk'
import { isCustomTxInfo } from '@/utils/transaction-guards'
import { InfoDetails } from '@/components/transactions/InfoDetails'
import EthHashInfo from '@/components/common/EthHashInfo'
import { HexEncodedData } from '@/components/transactions/HexEncodedData'
import { MethodDetails } from '@/components/transactions/TxDetails/TxData/DecodedData/MethodDetails'
import NamedAddressInfo from '@/components/common/NamedAddressInfo'

interface Props {
txData: TransactionDetails['txData']
Expand All @@ -29,7 +29,7 @@ export const DecodedData = ({ txData, txInfo }: Props): ReactElement | null => {
return (
<>
<InfoDetails title="Interact with:">
<EthHashInfo
<NamedAddressInfo
address={txData.to.value}
name={isCustomTxInfo(txInfo) ? txInfo.to.name : undefined}
customAvatar={isCustomTxInfo(txInfo) ? txInfo.to.logoUri : undefined}
Expand Down
12 changes: 2 additions & 10 deletions src/features/swap/components/SwapOrderConfirmationView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import type { CowSwapConfirmationView } from '@safe-global/safe-gateway-typescri
import SwapTokens from '@/features/swap/components/SwapTokens'
import AlertIcon from '@/public/images/common/alert.svg'
import EthHashInfo from '@/components/common/EthHashInfo'
import CowLogo from '@/public/images/swaps/cow-logo.png'
import css from './styles.module.css'
import NamedAddress from '@/components/common/NamedAddressInfo'

type SwapOrderProps = {
order: CowSwapConfirmationView
Expand Down Expand Up @@ -109,15 +109,7 @@ export const SwapOrderConfirmationView = ({ order, settlementContract }: SwapOrd
<OrderId orderId={uid} href={explorerUrl} />
</DataRow>,
<DataRow key="Interact with" title="Interact with">
<EthHashInfo
address={settlementContract}
name="Cow Protocol"
customAvatar={CowLogo.src}
avatarSize={24}
shortAddress={false}
hasExplorer
onlyName
/>
<NamedAddress address={settlementContract} onlyName hasExplorer shortAddress={false} avatarSize={24} />
</DataRow>,
receiver && owner !== receiver ? (
<>
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4336,10 +4336,10 @@
"@safe-global/safe-core-sdk-utils" "^1.7.4"
ethers "5.7.2"

"@safe-global/[email protected].0-alpha.3":
version "3.21.0-alpha.3"
resolved "https://registry.yarnpkg.com/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.21.0-alpha.3.tgz#21e0f01e9fbc6cff504fa9c7f957c27877b3f982"
integrity sha512-31xjB8VYUMsJ9akBd30YqHt4mreAwF5Kwbfa0LO0lE5L/DvfIwYiK/VB9uMse3LF/gVKKVOu9TIxKkaTsh9Y5w==
"@safe-global/[email protected].1":
version "3.21.1"
resolved "https://registry.yarnpkg.com/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.21.1.tgz#984ec2d3d4211caf6a96786ab922b39909093538"
integrity sha512-7nakIjcRSs6781LkizYpIfXh1DYlkUDqyALciqz/BjFU/S97sVjZdL4cuKsG9NEarytE+f6p0Qbq2Bo1aocVUA==

"@safe-global/safe-gateway-typescript-sdk@^3.5.3":
version "3.19.0"
Expand Down

0 comments on commit 7130d87

Please sign in to comment.