diff --git a/contracts-periphery/foundry.toml b/contracts-periphery/foundry.toml index 93566dd48..47fa588e2 100644 --- a/contracts-periphery/foundry.toml +++ b/contracts-periphery/foundry.toml @@ -1,8 +1,10 @@ [profile.default] verbosity = 3 +fs_permissions = [{ access = "read", path = "./"}] [profile.ci] fuzz_runs = 10000 +fs_permissions = [{ access = "read", path = "./"}] # See more config options https://github.com/gakonst/foundry/tree/master/config [rpc_endpoints] diff --git a/frontend/src/components/AccountReceiveTable.vue b/frontend/src/components/AccountReceiveTable.vue index 60928aba7..a0fc8931e 100644 --- a/frontend/src/components/AccountReceiveTable.vue +++ b/frontend/src/components/AccountReceiveTable.vue @@ -116,7 +116,7 @@
- {{ formatAddress(props.row.receiver) }} + {{ formatNameOrAddress(props.row.receiver) }}
@@ -233,7 +233,7 @@
- {{ col.value }} + {{ formatNameOrAddress(props.row.formattedFrom) }}
@@ -241,7 +241,7 @@
- {{ formatAddress(col.value) }} + {{ formatNameOrAddress(col.value) }}
@@ -272,7 +272,17 @@ if (advancedMode) expanded = expanded[0] === props.key ? [] : [props.key]; " > - {{ $t('AccountReceiveTable.withdrawn') }} + +
+ {{ $t('AccountReceiveTable.withdrawn') }} + +
{ isLoading.value = true; if (!provider.value) throw new Error(vm.$i18n.tc('AccountReceiveTable.wallet-not-connected')); // Format addresses to use ENS, CNS, or formatted address const fromAddresses = announcements.map((announcement) => announcement.from); - const formattedAddresses = await lookupOrFormatAddresses(fromAddresses, MAINNET_PROVIDER as Web3Provider); + const formattedAddresses = await lookupOrReturnAddresses(fromAddresses, MAINNET_PROVIDER as Web3Provider); formattedAnnouncements.value.forEach((announcement, index) => { - announcement.from = formattedAddresses[index]; + announcement.formattedFrom = formattedAddresses[index]; + announcement.from = fromAddresses[index]; }); // Find announcements that have been withdrawn @@ -505,6 +526,13 @@ function useReceivedFundsTable(announcements: UserAnnouncement[], spendingKeyPai window.open(getEtherscanUrl(row.txHash, chainId)); } + function getSenderOrReceiverEtherscanUrl(address: string) { + if (!provider.value) throw new Error(vm.$i18n.tc('AccountReceiveTable.wallet-not-connected')); + // Assume mainnet if we don't have a provider with a valid chainId + const chainId = provider.value.network.chainId || 1; + return getEtherscanUrl(address, chainId); + } + /** * @notice Initialize the withdraw process * @param announcement Announcement to withdraw @@ -634,7 +662,7 @@ function useReceivedFundsTable(announcements: UserAnnouncement[], spendingKeyPai destinationAddress, executeWithdraw, expanded, - formatAddress, + formatNameOrAddress, formatAmount, formatDate, formattedAnnouncements, @@ -650,6 +678,7 @@ function useReceivedFundsTable(announcements: UserAnnouncement[], spendingKeyPai isWithdrawInProgress, mainTableColumns, openInEtherscan, + getSenderOrReceiverEtherscanUrl, paginationConfig, privacyModalAddressWarnings, showConfirmationModal, diff --git a/frontend/src/components/AccountReceiveTableWithdrawConfirmation.vue b/frontend/src/components/AccountReceiveTableWithdrawConfirmation.vue index 97b4e819c..d0c885815 100644 --- a/frontend/src/components/AccountReceiveTableWithdrawConfirmation.vue +++ b/frontend/src/components/AccountReceiveTableWithdrawConfirmation.vue @@ -8,7 +8,7 @@
{{ $t('AccountReceiveTableWithdrawConfirmation.to') }}
-
{{ $q.screen.xs ? formatAddress(destinationAddress) : destinationAddress }}
+
{{ $q.screen.xs ? formatNameOrAddress(destinationAddress) : destinationAddress }}
{{ $t('AccountReceiveTableWithdrawConfirmation.amount') }}
@@ -120,7 +120,7 @@ import { computed, defineComponent, onMounted, PropType, ref } from '@vue/composition-api'; import { utils as umbraUtils, UserAnnouncement } from '@umbra/umbra-js'; import { FeeEstimate } from 'components/models'; -import { formatAddress, toAddress } from 'src/utils/address'; +import { formatNameOrAddress, toAddress } from 'src/utils/address'; import { BigNumber, formatUnits } from 'src/utils/ethers'; import { getEtherscanUrl, getGasPrice, humanizeTokenAmount, humanizeArithmeticResult } from 'src/utils/utils'; import useWalletStore from 'src/store/wallet'; @@ -282,7 +282,7 @@ export default defineComponent({ context, confirmationOptions, etherscanUrl, - formatAddress, + formatNameOrAddress, formattedAmount, formattedAmountReceived, formattedDefaultTxCost, diff --git a/frontend/src/components/models.ts b/frontend/src/components/models.ts index fc92b097c..bb288dbc4 100644 --- a/frontend/src/components/models.ts +++ b/frontend/src/components/models.ts @@ -80,7 +80,7 @@ export const supportedChains: Array = [ logoURI: ETH_NETWORK_LOGO, }, rpcUrls: ['https://mainnet.optimism.io', `https://optimism-mainnet.infura.io/v3/${String(process.env.INFURA_ID)}`], - blockExplorerUrls: ['https://optimistic.etherscan.io/'], + blockExplorerUrls: ['https://optimistic.etherscan.io'], iconUrls: ['/networks/optimism.svg'], logoURI: '/networks/optimism.svg', }, @@ -110,7 +110,7 @@ export const supportedChains: Array = [ logoURI: ETH_NETWORK_LOGO, }, rpcUrls: ['https://arb1.arbitrum.io/rpc', `https://arbitrum-mainnet.infura.io/v3/${String(process.env.INFURA_ID)}`], - blockExplorerUrls: ['https://arbiscan.io/'], + blockExplorerUrls: ['https://arbiscan.io'], iconUrls: ['/networks/arbitrum.svg'], logoURI: '/networks/arbitrum.svg', }, diff --git a/frontend/src/store/wallet.ts b/frontend/src/store/wallet.ts index a2b4ec8d8..b0c5cda08 100644 --- a/frontend/src/store/wallet.ts +++ b/frontend/src/store/wallet.ts @@ -14,7 +14,7 @@ import { SupportedChainId, TokenInfoExtended, } from 'components/models'; -import { formatAddress, lookupEnsName, lookupCnsName } from 'src/utils/address'; +import { formatNameOrAddress, lookupEnsName, lookupCnsName } from 'src/utils/address'; import { ERC20_ABI, MAINNET_PROVIDER, MAINNET_RPC_URL, MULTICALL_ABI, MULTICALL_ADDRESSES } from 'src/utils/constants'; import { BigNumber, Contract, getAddress, Web3Provider, parseUnits } from 'src/utils/ethers'; import { UmbraApi } from 'src/utils/umbra-api'; @@ -424,7 +424,7 @@ export default function useWalletStore() { const userDisplayName = computed(() => { if (userEns.value) return userEns.value; if (userCns.value) return userCns.value; - return userAddress.value ? formatAddress(userAddress.value) : undefined; + return userAddress.value ? formatNameOrAddress(userAddress.value) : undefined; }); const keysMatch = computed(() => { diff --git a/frontend/src/utils/address.ts b/frontend/src/utils/address.ts index d0c63c26a..93d7319ef 100644 --- a/frontend/src/utils/address.ts +++ b/frontend/src/utils/address.ts @@ -5,13 +5,15 @@ import { CnsQueryResponse, Provider } from 'components/models'; import { utils } from '@umbra/umbra-js'; import { MAINNET_PROVIDER } from 'src/utils/constants'; -import { getAddress, Web3Provider } from 'src/utils/ethers'; +import { getAddress, Web3Provider, isHexString } from 'src/utils/ethers'; import { getChainById } from 'src/utils/utils'; import { i18n } from '../boot/i18n'; // ================================================== Address Helpers ================================================== // Returns an address with the following format: 0x1234...abcd -export const formatAddress = (address: string) => `${address.slice(0, 6)}...${address.slice(38)}`; +export const formatNameOrAddress = (nameOrAddress: string) => { + return isHexString(nameOrAddress) ? `${nameOrAddress.slice(0, 6)}...${nameOrAddress.slice(38)}` : nameOrAddress; +}; // Returns an ENS or CNS name if found, otherwise returns the address export const lookupAddress = async (address: string, provider: Provider) => { @@ -19,10 +21,10 @@ export const lookupAddress = async (address: string, provider: Provider) => { return domainName ? domainName : address; }; -// Returns an ENS or CNS name if found, otherwise returns a formatted version of the address -export const lookupOrFormatAddress = async (address: string, provider: Provider) => { +// Returns an ENS or CNS name if found, otherwise returns the address +export const lookupOrReturnAddress = async (address: string, provider: Provider) => { const domainName = await lookupAddress(address, provider); - return domainName !== address ? domainName : formatAddress(address); + return domainName !== address ? domainName : address; }; // Returns ENS name that address resolves to, or null if not found @@ -80,15 +82,15 @@ export const toAddress = utils.toAddress; // =============================================== Bulk Address Helpers ================================================ // Duplicates of the above methods for operating on multiple addresses in parallel -export const formatAddresses = (addresses: string[]) => addresses.map(formatAddress); +export const formatAddresses = (addresses: string[]) => addresses.map(formatNameOrAddress); export const lookupAddresses = async (addresses: string[], provider: Provider) => { const promises = addresses.map((address) => lookupAddress(address, provider)); return Promise.all(promises); }; -export const lookupOrFormatAddresses = async (addresses: string[], provider: Provider) => { - const promises = addresses.map((address) => lookupOrFormatAddress(address, provider)); +export const lookupOrReturnAddresses = async (addresses: string[], provider: Provider) => { + const promises = addresses.map((address) => lookupOrReturnAddress(address, provider)); return Promise.all(promises); }; diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index 9d1a072c4..bd2ae8162 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -1,14 +1,17 @@ import { supportedChains, TokenInfo } from 'src/components/models'; -import { BigNumber, BigNumberish, hexValue, parseUnits, formatUnits } from './ethers'; - +import { BigNumber, BigNumberish, hexValue, parseUnits, formatUnits, isHexString } from './ethers'; /** * @notice Generates the Etherscan URL based on the given `txHash` or `address and `chainId` */ export const getEtherscanUrl = (txHashOrAddress: string, chainId: number) => { - const group = txHashOrAddress.length === 42 ? 'address' : 'tx'; + const group = isHexString(txHashOrAddress) ? (txHashOrAddress.length === 42 ? 'address' : 'tx') : 'ens'; const chain = getChainById(chainId); const networkPrefix = chain?.blockExplorerUrls?.length ? chain?.blockExplorerUrls[0] : 'https://etherscan.io'; - return `${networkPrefix}/${group}/${txHashOrAddress}`; + if (group === 'ens') { + return `${networkPrefix}/enslookup-search?search=${txHashOrAddress}`; + } else { + return `${networkPrefix}/${group}/${txHashOrAddress}`; + } }; /**