Fix source code not displaying for implicit and deterministic accounts#4
Fix source code not displaying for implicit and deterministic accounts#4r-near wants to merge 1 commit intoSourceScan:mainfrom
Conversation
The TLD validation gate rejected any account ID not ending in .near or .testnet, which blocked NEAR implicit (64-char hex), ETH implicit (0x), and deterministic (0s) accounts from ever reaching the data-fetching code path. Verification data exists on-chain for these accounts but the frontend refused to display it. Replace the strict TLD check with isValidNearAccount() which recognises all four NEAR account types defined in near-account-id 2.0.
|
@r-near is attempting to deploy a commit to the 2BeBuilt Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
This PR fixes SourceScan’s /contract/[slug] and /code/[slug] pages rejecting implicit and deterministic NEAR account IDs during upfront validation, allowing those accounts to reach the normal data-fetching/rendering path.
Changes:
- Added implicit/deterministic account pattern detection and broadened address validation to accept those formats.
- Updated
/contract/[slug]and/code/[slug]pages to use the new validation helper and improved the user-facing invalid-address message.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
utils/detectNetwork.ts |
Introduces implicit/deterministic account detection and replaces TLD-only validation with isValidNearAccount. |
pages/contract/[slug].tsx |
Swaps .near/.testnet suffix checks for isValidNearAccount and updates invalid-address UI text. |
pages/code/[slug].tsx |
Swaps .near/.testnet suffix checks for isValidNearAccount in two effects and updates invalid-address messages/UI text. |
Comments suppressed due to low confidence (1)
pages/code/[slug].tsx:459
- The Code page now has two separate effects that both validate
accountIdand perform network detection/switching (one near the top of the component and this one). This duplication makes it easy for behavior to drift (e.g., one effect updated without the other). Consider consolidating validation + network detection into a single effect and derivinginvalidTLD/error state from that result.
useEffect(() => {
if (accountId) {
if (!isValidNearAccount(accountId)) {
console.log(`Code page: Invalid account ID: ${accountId}`)
setLoading(false)
setErrorMessage(
`Invalid contract address: ${accountId}. Must be a named account (.near/.testnet) or an implicit/deterministic account.`
)
setInvalidTLD(true)
return
}
const detectedNetwork = detectNetworkFromAddress(accountId)
if (detectedNetwork && detectedNetwork !== network) {
console.log(
`Code page: Detected ${detectedNetwork} contract, switching networks from ${network}`
)
setNetwork(detectedNetwork)
} else {
// If no network switch needed, mark detection as complete
setNetworkDetected(true)
}
}
}, [accountId]) // Only depend on accountId to avoid re-running when network changes
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** | ||
| * Detects the network type from a contract address based on its TLD. | ||
| * Returns null for implicit/deterministic accounts since they can exist on either network. | ||
| */ | ||
| export const detectNetworkFromAddress = ( | ||
| contractAddress: string | ||
| ): NetworkType | null => { | ||
| if (!contractAddress) return null | ||
|
|
||
| // Check if the address ends with .near (mainnet) or .testnet (testnet) | ||
| if (contractAddress.endsWith('.near')) { | ||
| return 'mainnet' | ||
| } else if (contractAddress.endsWith('.testnet')) { | ||
| return 'testnet' | ||
| } | ||
|
|
||
| // If no specific TLD is found, return null | ||
| // Implicit and deterministic accounts can exist on either network | ||
| return null |
There was a problem hiding this comment.
detectNetworkFromAddress doc says it “Returns null for implicit/deterministic accounts”, but the function also returns null for any non-.near/.testnet named account (e.g. top-level accounts) and for invalid strings. Consider updating the comment to reflect the actual behavior (null when the network can't be inferred from a known suffix).
| /** | ||
| * Checks if a contract address has a valid NEAR TLD (.near or .testnet) | ||
| * @param contractAddress The contract address to check | ||
| * @returns Boolean indicating if the address has a valid TLD | ||
| * Checks if a contract address is a valid NEAR account identifier. | ||
| * Accepts named accounts (.near/.testnet) and implicit/deterministic accounts. | ||
| */ | ||
| export const hasValidTLD = (contractAddress: string): boolean => { | ||
| export const isValidNearAccount = (contractAddress: string): boolean => { | ||
| if (!contractAddress) return false | ||
| return ( | ||
| contractAddress.endsWith('.near') || contractAddress.endsWith('.testnet') | ||
| contractAddress.endsWith('.near') || | ||
| contractAddress.endsWith('.testnet') || | ||
| isImplicitAccount(contractAddress) | ||
| ) |
There was a problem hiding this comment.
isValidNearAccount is documented/named as a full NEAR account identifier validator, but the implementation only checks for .near/.testnet suffixes or implicit/deterministic patterns (so many invalid “*.near” strings would pass, and valid top-level named accounts would fail). Either tighten the validation to match the NEAR account-id rules (or use a dedicated validator lib) or rename/adjust the docstring to reflect that this is a “supported address format” check rather than full validation.
| if (!isValidNearAccount(accountId)) { | ||
| console.log(`Invalid account ID: ${accountId}`) | ||
| setLoading(false) | ||
| setInvalidTLD(true) | ||
| return |
There was a problem hiding this comment.
The state name invalidTLD is now misleading because the check was broadened beyond TLDs (it now validates implicit/deterministic formats too). Consider renaming this state (and related UI copy/console message) to something like invalidAccountId to avoid confusion in future changes.
| // Update the TLD validation to set the invalidTLD state | ||
| useEffect(() => { | ||
| if (accountId) { | ||
| // Check if the TLD is valid (.near or .testnet) | ||
| const isValidTLD = | ||
| accountId.endsWith('.near') || accountId.endsWith('.testnet') | ||
| if (!isValidTLD) { | ||
| console.log(`Code page: Invalid TLD for contract: ${accountId}`) | ||
| if (!isValidNearAccount(accountId)) { | ||
| console.log(`Code page: Invalid account ID: ${accountId}`) | ||
| setLoading(false) | ||
| setErrorMessage( | ||
| `Invalid contract address: ${accountId}. Contract addresses must end with .near or .testnet` | ||
| `Invalid contract address: ${accountId}. Must be a named account (.near/.testnet) or an implicit/deterministic account.` | ||
| ) | ||
| setInvalidTLD(true) | ||
| return |
There was a problem hiding this comment.
In this effect, the variable/comment naming still refers to “TLD” (invalidTLD, “TLD validation”), but the logic now validates the full account ID format (named vs implicit/deterministic). Renaming the state/comment would make the intent clearer and prevent confusion when extending validation further.
| export const isValidNearAccount = (contractAddress: string): boolean => { | ||
| if (!contractAddress) return false | ||
| return ( | ||
| contractAddress.endsWith('.near') || contractAddress.endsWith('.testnet') | ||
| contractAddress.endsWith('.near') || | ||
| contractAddress.endsWith('.testnet') || | ||
| isImplicitAccount(contractAddress) | ||
| ) |
There was a problem hiding this comment.
PR description says isValidNearAccount() “recognizes all four NEAR account types from near-account-id 2.0”, but the implementation here is a custom suffix/regex check and does not implement full NEAR named-account validation rules (nor use the near-account-id package). Either update the PR description to match what’s implemented, or switch the implementation to use the intended library/validation semantics.
Summary
/contract/[slug]and/code/[slug]pages rejects any account ID that doesn't end with.nearor.testnet, which blocks all implicit and deterministic account types from ever reaching the data-fetching code path0sa8247564c6774a33b975a053fc4fbebbd869772dreturns CID, code hash, lang fromget_contract), and the IPFS source files are accessible — the frontend just refuses to show them.near/.testnetsuffix check withisValidNearAccount()which recognizes all four NEAR account types fromnear-account-id2.0: named accounts, NEAR implicit (64-char hex), ETH implicit (0x+ 40 hex), and deterministic (0s+ 40 hex)Context
Reported in this Slack thread — a user verified a global deployer contract at a deterministic account ID but the source code isn't visible on SourceScan.
Test plan
isValidNearAccountaccepts0s+ 40 hex (deterministic),0x+ 40 hex (ETH implicit), 64-char hex (NEAR implicit),.near,.testnetisValidNearAccountrejects garbage strings, short hex, uppercase hex, empty stringsget_contractfor0sa8247564c6774a33b975a053fc4fbebbd869772dvia local proxy → returns valid CID/code_hash/lang/contract/0sa824...and/code/0sa824...pages proceed to loading state instead of showing "Invalid contract address"next buildsucceeds,next linthas no new warnings