diff --git a/.changelog/1492.feature.md b/.changelog/1492.feature.md new file mode 100644 index 000000000..da5384496 --- /dev/null +++ b/.changelog/1492.feature.md @@ -0,0 +1 @@ +Link to ABI playground from verified contracts diff --git a/playwright/tests/accounts.spec.ts b/playwright/tests/accounts.spec.ts index da156b3cc..d92ccf873 100644 --- a/playwright/tests/accounts.spec.ts +++ b/playwright/tests/accounts.spec.ts @@ -8,12 +8,12 @@ async function setup(page: Page) { // Don't respond }, ) - await page.route('**/v1/', route => { - // Don't respond - }) - await page.route('**/v1/sapphire/status', route => { - // Don't respond - }) + await page.route( + url => url.href.includes('.oasis.io/v1/'), + route => { + // Don't respond + }, + ) await page.route( '**/v1/sapphire/transactions?limit=10&offset=0&rel=oasis1qq2v39p9fqk997vk6742axrzqyu9v2ncyuqt8uek', route => { diff --git a/playwright/tests/analytics.spec.ts b/playwright/tests/analytics.spec.ts index fc1d603c6..a3a8cbc92 100644 --- a/playwright/tests/analytics.spec.ts +++ b/playwright/tests/analytics.spec.ts @@ -2,9 +2,12 @@ import '../../src/types/global.d.ts' import { Page, expect, test } from '@playwright/test' async function setup(page: Page, mode: 'allow-matomo-lib' | 'block-matomo-lib') { - await page.route('**/v1/', route => { - // Don't respond - }) + await page.route( + url => url.href.includes('.oasis.io/v1/'), + route => { + // Don't respond + }, + ) await page.route('https://matomo.oasis.io/matomo.php?**', route => { // Don't send tracked events }) @@ -41,12 +44,12 @@ test.describe('analytics', () => { await page.getByRole('button', { name: 'Privacy Settings' }).click() await page.getByRole('button', { name: 'Accept' }).click() - await page.waitForTimeout(1) + await page.waitForTimeout(100) expect(getMatomoRequests()).toHaveLength(2) // Tracked await page.getByRole('link', { name: 'Blocks' }).first().click() await page.waitForRequest('https://matomo.oasis.io/matomo.php?**') // Debounced - await page.waitForTimeout(1) + await page.waitForTimeout(100) expect(getMatomoRequests()).toHaveLength(3) // Tracked }) @@ -78,7 +81,7 @@ test.describe('analytics', () => { await test.step('consent', async () => { expect(getMatomoRequests()).toHaveLength(1) // Loaded library await page.getByRole('button', { name: 'Accept' }).click() - await page.waitForTimeout(1) + await page.waitForTimeout(100) expect(getMatomoRequests()).toHaveLength(2) // Tracked }) diff --git a/playwright/tests/getPreciseNumberFormat.spec.ts b/playwright/tests/getPreciseNumberFormat.spec.ts index 5130a6b67..d051ee601 100644 --- a/playwright/tests/getPreciseNumberFormat.spec.ts +++ b/playwright/tests/getPreciseNumberFormat.spec.ts @@ -8,12 +8,12 @@ async function setup(page: Page, balance: string, decimals: number) { // Don't respond }, ) - await page.route('**/v1/', route => { - // Don't respond - }) - await page.route('**/v1/sapphire/status', route => { - // Don't respond - }) + await page.route( + url => url.href.includes('.oasis.io/v1/'), + route => { + // Don't respond + }, + ) await page.route('**/v1/sapphire/accounts/oasis1qq2v39p9fqk997vk6742axrzqyu9v2ncyuqt8uek', route => { route.fulfill({ diff --git a/src/app/components/ContractVerificationIcon/index.tsx b/src/app/components/ContractVerificationIcon/index.tsx index e21962864..8033ba18f 100644 --- a/src/app/components/ContractVerificationIcon/index.tsx +++ b/src/app/components/ContractVerificationIcon/index.tsx @@ -8,7 +8,10 @@ import { COLORS } from '../../../styles/theme/colors' import Link from '@mui/material/Link' import Typography from '@mui/material/Typography' import Skeleton from '@mui/material/Skeleton' -import { RuntimeAccount } from '../../../oasis-nexus/api' +import { Layer, RuntimeAccount } from '../../../oasis-nexus/api' +import { SearchScope } from '../../../types/searchScope' +import { Network } from '../../../types/network' +import * as externalLinks from '../../utils/externalLinks' type VerificationStatus = 'verified' | 'unverified' @@ -52,7 +55,7 @@ const StyledPill = styled(Box, { }) type ContractVerificationIconProps = { - account: Pick | undefined + account: Pick | undefined noLink?: boolean } @@ -71,14 +74,15 @@ export const ContractVerificationIcon: FC = ({ ac const verified = !!account.evm_contract?.verification const address_eth = account.address_eth! - return + return } -export const VerificationIcon: FC<{ address_eth: string; verified: boolean; noLink?: boolean }> = ({ - address_eth, - verified, - noLink = false, -}) => { +export const VerificationIcon: FC<{ + address_eth: string + scope: SearchScope + verified: boolean + noLink?: boolean +}> = ({ address_eth, scope, verified, noLink = false }) => { const { t } = useTranslation() const [explainDelay, setExplainDelay] = useState(false) @@ -87,15 +91,32 @@ export const VerificationIcon: FC<{ address_eth: string; verified: boolean; noLi verified: t('contract.verification.isVerified'), unverified: t('contract.verification.isNotVerified'), } - const linkProps = { - href: `https://sourcify.dev/#/lookup/${address_eth}`, + const sourcifyLinkProps = { + href: `${externalLinks.dapps.sourcifyRoot}#/lookup/${address_eth}`, rel: 'noopener noreferrer', target: '_blank', sx: { fontWeight: 400, color: 'inherit', textDecoration: 'underline' }, onClick: verified ? undefined : () => setExplainDelay(true), } const Component = noLink ? Box : Link - const componentProps = noLink ? {} : linkProps + const componentProps = noLink ? {} : sourcifyLinkProps + + const scopeToPlaygroundURL: Record>> = { + [Network.mainnet]: { + [Layer.emerald]: `${externalLinks.dapps.abiPlayground}?network=42262&contractAddress=${address_eth}`, + [Layer.sapphire]: `${externalLinks.dapps.abiPlayground}?network=23294&contractAddress=${address_eth}`, + }, + [Network.testnet]: { + [Layer.emerald]: `${externalLinks.dapps.abiPlayground}?network=42261&contractAddress=${address_eth}`, + [Layer.sapphire]: `${externalLinks.dapps.abiPlayground}?network=23295&contractAddress=${address_eth}`, + }, + } + const abiPlaygroundLinkProps = { + href: scopeToPlaygroundURL[scope.network]?.[scope.layer], + rel: 'noopener noreferrer', + target: '_blank', + sx: { fontWeight: 400, color: 'inherit', textDecoration: 'underline' }, + } return ( <> @@ -105,20 +126,41 @@ export const VerificationIcon: FC<{ address_eth: string; verified: boolean; noLi {statusIcon[status]}     - {!noLink && ( - - , - }} - />{' '} - {explainDelay && t('contract.verification.explainVerificationDelay')} - - )} + {!noLink && + (verified ? ( + + , + }} + /> + {abiPlaygroundLinkProps.href && ( + + {' | '} + , + }} + /> + + )} + + ) : ( + + , + }} + />{' '} + {explainDelay && t('contract.verification.explainVerificationDelay')} + + ))} ) } diff --git a/src/app/components/Tokens/TokenDetails.tsx b/src/app/components/Tokens/TokenDetails.tsx index e888c9d34..a272bda50 100644 --- a/src/app/components/Tokens/TokenDetails.tsx +++ b/src/app/components/Tokens/TokenDetails.tsx @@ -65,7 +65,7 @@ export const TokenDetails: FC<{
{t('contract.verification.title')}
- +
{t(isMobile ? 'tokens.holders' : 'tokens.holdersCount')}
diff --git a/src/app/components/Tokens/TokenList.tsx b/src/app/components/Tokens/TokenList.tsx index ec2e0bea4..b45633033 100644 --- a/src/app/components/Tokens/TokenList.tsx +++ b/src/app/components/Tokens/TokenList.tsx @@ -127,7 +127,12 @@ export const TokenList = (props: TokensProps) => { width: '100%', }} > - + ), }, diff --git a/src/app/pages/NFTInstanceDashboardPage/InstanceDetailsCard.tsx b/src/app/pages/NFTInstanceDashboardPage/InstanceDetailsCard.tsx index 6b9e715d0..c9a58dfc9 100644 --- a/src/app/pages/NFTInstanceDashboardPage/InstanceDetailsCard.tsx +++ b/src/app/pages/NFTInstanceDashboardPage/InstanceDetailsCard.tsx @@ -85,7 +85,11 @@ export const InstanceDetailsCard: FC = ({
{t('contract.verification.title')}
- +
)} diff --git a/src/app/pages/NFTInstanceDashboardPage/InstanceTitleCard.tsx b/src/app/pages/NFTInstanceDashboardPage/InstanceTitleCard.tsx index beb512b66..8c3141132 100644 --- a/src/app/pages/NFTInstanceDashboardPage/InstanceTitleCard.tsx +++ b/src/app/pages/NFTInstanceDashboardPage/InstanceTitleCard.tsx @@ -65,7 +65,12 @@ export const InstanceTitleCard: FC = ({ isFetched, isLoa alignItems: 'center', }} > - + diff --git a/src/app/pages/TokenDashboardPage/TokenDetailsCard.tsx b/src/app/pages/TokenDashboardPage/TokenDetailsCard.tsx index 5fd211da1..d586c7089 100644 --- a/src/app/pages/TokenDashboardPage/TokenDetailsCard.tsx +++ b/src/app/pages/TokenDashboardPage/TokenDetailsCard.tsx @@ -59,7 +59,11 @@ export const TokenDetailsCard: FC<{ scope: SearchScope; address: string; searchT
{t('contract.verification.title')}
- +
{t('common.type')}
diff --git a/src/app/pages/TokenDashboardPage/TokenTitleCard.tsx b/src/app/pages/TokenDashboardPage/TokenTitleCard.tsx index fdfb5ab8a..892edcb95 100644 --- a/src/app/pages/TokenDashboardPage/TokenTitleCard.tsx +++ b/src/app/pages/TokenDashboardPage/TokenTitleCard.tsx @@ -24,7 +24,12 @@ export const TokenTitleCard: FC<{ scope: SearchScope; address: string; searchTer <> {token && ( <> - + ABI Playground", "openInSourcify": "Open in Sourcify", "verifyInSourcify": "Verify through Sourcify", "explainVerificationDelay": "If you have just verified a contract, it should take a few minutes to update here."