Skip to content
Open
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
23 changes: 9 additions & 14 deletions pages/code/[slug].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import FileSelectionDrawer from '@/components/Code/FileSelectionDrawer'
import PageHead from '@/components/Common/PageHead'
import { useNetwork } from '@/contexts/NetworkContext'
import { detectNetworkFromAddress } from '@/utils/detectNetwork'
import { detectNetworkFromAddress, isValidNearAccount } from '@/utils/detectNetwork'
import { ascii_to_str } from '@/utils/near/ascii_converter'
import { useRpcUrl } from '@/utils/near/rpc'
import { bg, color } from '@/utils/theme'
Expand Down Expand Up @@ -39,14 +39,11 @@ export default function Code() {
// Step 1: Detect network from contract address and switch if necessary
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.`
)
return
}
Expand Down Expand Up @@ -438,14 +435,11 @@ export default function Code() {
// 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
Comment on lines 435 to 445
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Expand Down Expand Up @@ -491,7 +485,8 @@ export default function Code() {
textAlign="center"
maxW="600px"
>
Contract addresses must end with .near or .testnet
Must be a named account (.near/.testnet) or an
implicit/deterministic account.
</Text>
</Flex>
) : loading ? (
Expand Down
12 changes: 5 additions & 7 deletions pages/contract/[slug].tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GithubDto } from '@/Interfaces/github/github.dto'
import { useNetwork } from '@/contexts/NetworkContext'
import { detectNetworkFromAddress } from '@/utils/detectNetwork'
import { detectNetworkFromAddress, isValidNearAccount } from '@/utils/detectNetwork'
import { extractGitHubDetails } from '@/utils/extractGithub'
import { ascii_to_str } from '@/utils/near/ascii_converter'
import { useRpcUrl } from '@/utils/near/rpc'
Expand Down Expand Up @@ -248,11 +248,8 @@ export default function Contract() {
// Step 1: Detect network from contract address and switch if necessary
useEffect(() => {
if (accountId) {
// Check if the TLD is valid (.near or .testnet)
const isValidTLD =
accountId.endsWith('.near') || accountId.endsWith('.testnet')
if (!isValidTLD) {
console.log(`Invalid TLD for contract: ${accountId}`)
if (!isValidNearAccount(accountId)) {
console.log(`Invalid account ID: ${accountId}`)
setLoading(false)
setInvalidTLD(true)
return
Comment on lines +251 to 255
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Expand Down Expand Up @@ -282,7 +279,8 @@ export default function Contract() {
Invalid contract address: {accountId}
</Text>
<Text color="gray.500">
Contract addresses must end with .near or .testnet
Must be a named account (.near/.testnet) or an
implicit/deterministic account.
</Text>
</Stack>
) : data ? (
Expand Down
34 changes: 24 additions & 10 deletions utils/detectNetwork.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,48 @@
import { NetworkType } from '@/contexts/NetworkContext'

/**
* Detects the network type from a contract address based on its TLD
* @param contractAddress The contract address to analyze
* @returns The detected network type or null if can't be determined
* Checks whether an address is a valid NEAR implicit-style account:
* - NEAR implicit account: 64 lowercase hex characters
* - ETH implicit account: 0x + 40 lowercase hex characters
* - NEAR deterministic account: 0s + 40 lowercase hex characters
*/
export const isImplicitAccount = (address: string): boolean => {
if (!address) return false
return (
/^[0-9a-f]{64}$/.test(address) ||
/^0x[0-9a-f]{40}$/.test(address) ||
/^0s[0-9a-f]{40}$/.test(address)
)
}

/**
* 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
Comment on lines +18 to 34
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

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).

Copilot uses AI. Check for mistakes.
}

/**
* 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)
)
Comment on lines 37 to 47
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to 47
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
}
Loading