feat: anonymous interactions

This commit is contained in:
Danish Arora 2025-08-18 14:07:01 +05:30
parent dd13ef6b2e
commit 88012154d3
No known key found for this signature in database
GPG Key ID: 1C6EF37CDAE1426E
14 changed files with 239 additions and 82 deletions

View File

@ -44,8 +44,10 @@ const FeedSidebar: React.FC = () => {
// Ethereum wallet with ENS
if (currentUser.walletType === 'ethereum') {
if (currentUser.ensName && verificationStatus === 'verified-owner') {
if (currentUser.ensName && (verificationStatus === 'verified-owner' || currentUser.ensOwnership)) {
return <Badge className="bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"> Owns ENS: {currentUser.ensName}</Badge>;
} else if (verificationStatus === 'verified-basic') {
return <Badge className="bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200"> Connected Wallet</Badge>;
} else {
return <Badge variant="outline">Read-only (No ENS detected)</Badge>;
}
@ -53,8 +55,10 @@ const FeedSidebar: React.FC = () => {
// Bitcoin wallet with Ordinal
if (currentUser.walletType === 'bitcoin') {
if (verificationStatus === 'verified-owner') {
if (verificationStatus === 'verified-owner' || currentUser.ordinalOwnership) {
return <Badge className="bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"> Owns Ordinal</Badge>;
} else if (verificationStatus === 'verified-basic') {
return <Badge className="bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200"> Connected Wallet</Badge>;
} else {
return <Badge variant="outline">Read-only (No Ordinal detected)</Badge>;
}
@ -62,6 +66,8 @@ const FeedSidebar: React.FC = () => {
// Fallback cases
switch (verificationStatus) {
case 'verified-basic':
return <Badge className="bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200"> Connected Wallet</Badge>;
case 'verified-none':
return <Badge variant="outline">Read Only</Badge>;
case 'verifying':

View File

@ -18,8 +18,7 @@ const Header = () => {
verifyOwnership,
delegateKey,
isDelegationValid,
delegationTimeRemaining,
isWalletAvailable
delegationTimeRemaining
} = useAuth();
const { isNetworkConnected, isRefreshing } = useForum();
const location = useLocation();
@ -85,8 +84,10 @@ const Header = () => {
return 'Verifying...';
case 'verified-none':
return 'Read-Only Access';
case 'verified-owner':
case 'verified-basic':
return isDelegationValid() ? 'Full Access' : 'Setup Key';
case 'verified-owner':
return isDelegationValid() ? 'Premium Access' : 'Setup Key';
default:
return 'Setup Account';
}
@ -100,6 +101,8 @@ const Header = () => {
return <RefreshCw className="w-3 h-3 animate-spin" />;
case 'verified-none':
return <CircleSlash className="w-3 h-3" />;
case 'verified-basic':
return isDelegationValid() ? <CheckCircle className="w-3 h-3" /> : <Key className="w-3 h-3" />;
case 'verified-owner':
return isDelegationValid() ? <CheckCircle className="w-3 h-3" /> : <Key className="w-3 h-3" />;
default:
@ -115,6 +118,8 @@ const Header = () => {
return 'outline';
case 'verified-none':
return 'secondary';
case 'verified-basic':
return isDelegationValid() ? 'default' : 'outline';
case 'verified-owner':
return isDelegationValid() ? 'default' : 'outline';
default:

View File

@ -84,12 +84,12 @@ const PostDetail = () => {
};
const handleVotePost = async (isUpvote: boolean) => {
if (verificationStatus !== 'verified-owner') return;
if (verificationStatus !== 'verified-owner' && verificationStatus !== 'verified-basic' && !currentUser?.ensOwnership && !currentUser?.ordinalOwnership) return;
await votePost(post.id, isUpvote);
};
const handleVoteComment = async (commentId: string, isUpvote: boolean) => {
if (verificationStatus !== 'verified-owner') return;
if (verificationStatus !== 'verified-owner' && verificationStatus !== 'verified-basic' && !currentUser?.ensOwnership && !currentUser?.ordinalOwnership) return;
await voteComment(commentId, isUpvote);
};
@ -185,7 +185,7 @@ const PostDetail = () => {
</div>
</div>
{verificationStatus === 'verified-owner' ? (
{(verificationStatus === 'verified-owner' || verificationStatus === 'verified-basic' || currentUser?.ensOwnership || currentUser?.ordinalOwnership) ? (
<div className="mb-8">
<form onSubmit={handleCreateComment}>
<div className="flex gap-2">
@ -219,7 +219,7 @@ const PostDetail = () => {
</div>
) : (
<div className="mb-8 p-3 border border-muted rounded-sm bg-secondary/30 text-center">
<p className="text-sm mb-2">Connect wallet and verify Ordinal ownership to comment</p>
<p className="text-sm mb-2">Connect wallet and verify ownership to comment</p>
<Button asChild size="sm">
<Link to="/">Go to Home</Link>
</Button>

View File

@ -4,6 +4,7 @@ import { Shield, Crown } from 'lucide-react';
import { UserVerificationStatus } from '@/lib/forum/types';
import { getEnsName } from '@wagmi/core';
import { config } from '@/lib/identity/wallets/appkit';
import { OrdinalAPI } from '@/lib/identity/ordinal';
interface AuthorDisplayProps {
address: string;
@ -20,20 +21,52 @@ export function AuthorDisplay({
}: AuthorDisplayProps) {
const userStatus = userVerificationStatus?.[address];
const [resolvedEns, setResolvedEns] = React.useState<string | undefined>(undefined);
const [resolvedOrdinal, setResolvedOrdinal] = React.useState<boolean | undefined>(undefined);
// Heuristics for address types
const isEthereumAddress = address.startsWith('0x') && address.length === 42;
const isBitcoinAddress = !isEthereumAddress; // simple heuristic for our context
// Lazily resolve ENS name for Ethereum addresses if not provided
React.useEffect(() => {
const isEthereumAddress = address.startsWith('0x') && address.length === 42;
let cancelled = false;
if (!userStatus?.ensName && isEthereumAddress) {
getEnsName(config, { address: address as `0x${string}` })
.then((name) => setResolvedEns(name || undefined))
.catch(() => setResolvedEns(undefined));
.then((name) => { if (!cancelled) setResolvedEns(name || undefined); })
.catch(() => { if (!cancelled) setResolvedEns(undefined); });
} else {
setResolvedEns(userStatus?.ensName);
}
return () => { cancelled = true; };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [address]);
}, [address, isEthereumAddress, userStatus?.ensName]);
const hasENS = userStatus?.hasENS || Boolean(resolvedEns) || Boolean(userStatus?.ensName);
const hasOrdinal = userStatus?.hasOrdinal || false;
// Lazily check Ordinal ownership for Bitcoin addresses if not provided
React.useEffect(() => {
let cancelled = false;
const run = async () => {
console.log({
isBitcoinAddress, userStatus
})
if (isBitcoinAddress) {
try {
const api = new OrdinalAPI();
const res = await api.getOperatorDetails(address);
if (!cancelled) setResolvedOrdinal(Boolean(res?.has_operators));
} catch {
if (!cancelled) setResolvedOrdinal(undefined);
}
} else {
setResolvedOrdinal(userStatus?.hasOrdinal);
}
};
run();
return () => { cancelled = true; };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [address, isBitcoinAddress, userStatus?.hasOrdinal]);
const hasENS = Boolean(userStatus?.hasENS) || Boolean(resolvedEns) || Boolean(userStatus?.ensName);
const hasOrdinal = Boolean(userStatus?.hasOrdinal) || Boolean(resolvedOrdinal);
// Only show a badge if the author has ENS or Ordinal ownership (not for basic verification)
const shouldShowBadge = showBadge && (hasENS || hasOrdinal);

View File

@ -36,7 +36,7 @@ export function VerificationStep({
const [verificationResult, setVerificationResult] = React.useState<{
success: boolean;
message: string;
details?: any;
details?: { ensName?: string; ensAvatar?: string } | boolean | { id: string; details: string };
} | null>(null);
const handleVerify = async () => {
@ -62,8 +62,8 @@ export function VerificationStep({
setVerificationResult({
success: false,
message: walletType === 'bitcoin'
? "No Ordinal ownership found. You'll have read-only access."
: "No ENS ownership found. You'll have read-only access."
? "No Ordinal ownership found. You can still participate in the forum with your connected wallet!"
: "No ENS ownership found. You can still participate in the forum with your connected wallet!"
});
}
} catch (error) {
@ -81,7 +81,7 @@ export function VerificationStep({
};
const getVerificationType = () => {
return walletType === 'bitcoin' ? 'Bitcoin Ordinal' : 'ENS Domain';
return walletType === 'bitcoin' ? 'Bitcoin Ordinal' : 'Ethereum ENS';
};
const getVerificationIcon = () => {
@ -94,9 +94,9 @@ export function VerificationStep({
const getVerificationDescription = () => {
if (walletType === 'bitcoin') {
return "Verify that you own Bitcoin Ordinals to get full posting and voting access.";
return "Verify your Bitcoin Ordinal ownership to unlock premium features. If you don't own any Ordinals, you can still participate in the forum with your connected wallet.";
} else {
return "Verify that you own an ENS domain to get full posting and voting access.";
return "Verify your Ethereum ENS ownership to unlock premium features. If you don't own any ENS, you can still participate in the forum with your connected wallet.";
}
};
@ -128,9 +128,9 @@ export function VerificationStep({
{verificationResult.details && (
<div className="text-xs text-neutral-400">
{walletType === 'bitcoin' ? (
<p>Ordinal ID: {verificationResult.details.id}</p>
<p>Ordinal ID: {typeof verificationResult.details === 'object' && 'id' in verificationResult.details ? verificationResult.details.id : 'Verified'}</p>
) : (
<p>ENS Name: {verificationResult.details.ensName}</p>
<p>ENS Name: {typeof verificationResult.details === 'object' && 'ensName' in verificationResult.details ? verificationResult.details.ensName : 'Verified'}</p>
)}
</div>
)}

View File

@ -39,7 +39,7 @@ export function WalletWizard({
setCurrentStep(1); // Start at connection step if not authenticated
} else if (isAuthenticated && (verificationStatus === 'unverified' || verificationStatus === 'verifying')) {
setCurrentStep(2); // Start at verification step if authenticated but not verified
} else if (isAuthenticated && (verificationStatus === 'verified-owner' || verificationStatus === 'verified-none') && !isDelegationValid()) {
} else if (isAuthenticated && (verificationStatus === 'verified-owner' || verificationStatus === 'verified-basic' || verificationStatus === 'verified-none') && !isDelegationValid()) {
setCurrentStep(3); // Start at delegation step if verified but no valid delegation
} else {
setCurrentStep(3); // Default to step 3 if everything is complete
@ -66,34 +66,25 @@ export function WalletWizard({
};
const getStepStatus = (step: WizardStep) => {
// Step 1: Wallet connection - completed when authenticated
if (step === 1) {
if (isAuthenticated) return "completed";
if (currentStep === step) return "current";
return "pending";
return isAuthenticated ? 'complete' : 'current';
} else if (step === 2) {
if (!isAuthenticated) return 'disabled';
if (verificationStatus === 'unverified' || verificationStatus === 'verifying') return 'current';
if (verificationStatus === 'verified-owner' || verificationStatus === 'verified-basic' || verificationStatus === 'verified-none') return 'complete';
return 'disabled';
} else if (step === 3) {
if (!isAuthenticated || (verificationStatus !== 'verified-owner' && verificationStatus !== 'verified-basic' && verificationStatus !== 'verified-none')) return 'disabled';
if (isDelegationValid()) return 'complete';
return 'current';
}
// Step 2: Verification - completed when verified (either owner or none)
if (step === 2) {
if (verificationStatus === 'verified-owner' || verificationStatus === 'verified-none') return "completed";
if (currentStep === step) return "current";
return "pending";
}
// Step 3: Key delegation - completed when delegation is valid AND authenticated
if (step === 3) {
if (isAuthenticated && isDelegationValid()) return "completed";
if (currentStep === step) return "current";
return "pending";
}
return "pending";
return 'disabled';
};
const renderStepIcon = (step: WizardStep) => {
const status = getStepStatus(step);
if (status === "completed") {
if (status === "complete") {
return <CheckCircle className="h-5 w-5 text-green-500" />;
} else if (status === "current") {
return <Loader2 className="h-5 w-5 text-blue-500 animate-spin" />;
@ -130,7 +121,7 @@ export function WalletWizard({
<span className={`text-sm ${
getStepStatus(step as WizardStep) === "current"
? "text-blue-500 font-medium"
: getStepStatus(step as WizardStep) === "completed"
: getStepStatus(step as WizardStep) === "complete"
? "text-green-500"
: "text-gray-400"
}`}>
@ -139,7 +130,7 @@ export function WalletWizard({
</div>
{step < 3 && (
<div className={`w-8 h-px mx-2 ${
getStepStatus(step as WizardStep) === "completed"
getStepStatus(step as WizardStep) === "complete"
? "bg-green-500"
: "bg-gray-600"
}`} />

View File

@ -6,7 +6,7 @@ import { OpchanMessage } from '@/types';
import { useAppKitAccount, useDisconnect, modal } from '@reown/appkit/react';
import { DelegationDuration } from '@/lib/identity/signatures/key-delegation';
export type VerificationStatus = 'unverified' | 'verified-none' | 'verified-owner' | 'verifying';
export type VerificationStatus = 'unverified' | 'verified-none' | 'verified-basic' | 'verified-owner' | 'verifying';
interface AuthContextType {
currentUser: User | null;
@ -76,13 +76,39 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const newUser: User = {
address,
walletType: isBitcoinConnected ? 'bitcoin' : 'ethereum',
verificationStatus: 'unverified',
verificationStatus: 'verified-basic', // Connected wallets get basic verification by default
lastChecked: Date.now(),
};
setCurrentUser(newUser);
setVerificationStatus('unverified');
authServiceRef.current.saveUser(newUser);
// For Ethereum wallets, try to check ENS ownership immediately
if (isEthereumConnected) {
authServiceRef.current.getWalletInfo().then((walletInfo) => {
if (walletInfo?.ensName) {
const updatedUser = {
...newUser,
ensOwnership: true,
ensName: walletInfo.ensName,
verificationStatus: 'verified-owner' as const,
};
setCurrentUser(updatedUser);
setVerificationStatus('verified-owner');
authServiceRef.current.saveUser(updatedUser);
} else {
setCurrentUser(newUser);
setVerificationStatus('verified-basic');
authServiceRef.current.saveUser(newUser);
}
}).catch(() => {
// Fallback to basic verification if ENS check fails
setCurrentUser(newUser);
setVerificationStatus('verified-basic');
authServiceRef.current.saveUser(newUser);
});
} else {
setCurrentUser(newUser);
setVerificationStatus('verified-basic');
authServiceRef.current.saveUser(newUser);
}
const chainName = isBitcoinConnected ? 'Bitcoin' : 'Ethereum';
const displayName = `${address.slice(0, 6)}...${address.slice(-4)}`;
@ -95,7 +121,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const verificationType = isBitcoinConnected ? 'Ordinal ownership' : 'ENS ownership';
toast({
title: "Action Required",
description: `Please verify your ${verificationType} and delegate a signing key for better UX.`,
description: `You can participate in the forum now! Verify your ${verificationType} for premium features and delegate a signing key for better UX.`,
});
}
} else {
@ -126,9 +152,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const getVerificationStatus = (user: User): VerificationStatus => {
if (user.walletType === 'bitcoin') {
return user.ordinalOwnership ? 'verified-owner' : 'verified-none';
return user.ordinalOwnership ? 'verified-owner' : 'verified-basic';
} else if (user.walletType === 'ethereum') {
return user.ensOwnership ? 'verified-owner' : 'verified-none';
return user.ensOwnership ? 'verified-owner' : 'verified-basic';
}
return 'unverified';
};
@ -169,18 +195,18 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
if (updatedUser.walletType === 'bitcoin' && updatedUser.ordinalOwnership) {
toast({
title: "Ordinal Verified",
description: "You now have full access. We recommend delegating a key for better UX.",
description: "You now have premium access with higher relevance bonuses. We recommend delegating a key for better UX.",
});
} else if (updatedUser.walletType === 'ethereum' && updatedUser.ensOwnership) {
toast({
title: "ENS Verified",
description: "You now have full access. We recommend delegating a key for better UX.",
description: "You now have premium access with higher relevance bonuses. We recommend delegating a key for better UX.",
});
} else {
const verificationType = updatedUser.walletType === 'bitcoin' ? 'Ordinal Operators' : 'ENS domain';
toast({
title: "Read-Only Access",
description: `No ${verificationType} found. You have read-only access.`,
title: "Basic Access Granted",
description: `No ${verificationType} found, but you can still participate in the forum with your connected wallet.`,
variant: "default",
});
}

View File

@ -21,6 +21,8 @@ import { getDataFromCache } from '@/lib/forum/transformers';
import { RelevanceCalculator } from '@/lib/forum/relevance';
import { UserVerificationStatus } from '@/lib/forum/types';
import { AuthService } from '@/lib/identity/services/AuthService';
import { getEnsName } from '@wagmi/core';
import { config } from '@/lib/identity/wallets/appkit';
interface ForumContextType {
cells: Cell[];
@ -138,21 +140,55 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
// Create generic user object for other addresses
allUsers.push({
address,
walletType: 'bitcoin', // Default, will be updated if we have more info
walletType: address.startsWith('0x') ? 'ethereum' : 'bitcoin',
verificationStatus: 'unverified'
});
}
});
const userVerificationStatus = relevanceCalculator.buildUserVerificationStatus(allUsers);
const initialStatus = relevanceCalculator.buildUserVerificationStatus(allUsers);
// Transform data with relevance calculation
const { cells, posts, comments } = getDataFromCache(verifyFn, userVerificationStatus);
// Transform data with relevance calculation (initial pass)
const { cells, posts, comments } = getDataFromCache(verifyFn, initialStatus);
setCells(cells);
setPosts(posts);
setComments(comments);
setUserVerificationStatus(userVerificationStatus);
setUserVerificationStatus(initialStatus);
// Enrich: resolve ENS for ethereum addresses asynchronously and update
(async () => {
const targets = allUsers.filter(u => u.walletType === 'ethereum' && !u.ensOwnership);
if (targets.length === 0) return;
const lookups = await Promise.all(targets.map(async (u) => {
try {
const name = await getEnsName(config, { address: u.address as `0x${string}` });
return { address: u.address, ensName: name || undefined };
} catch {
return { address: u.address, ensName: undefined };
}
}));
const ensByAddress = new Map<string, string | undefined>(lookups.map(l => [l.address, l.ensName]));
const enrichedUsers: User[] = allUsers.map(u => {
const ensName = ensByAddress.get(u.address);
if (ensName) {
return {
...u,
walletType: 'ethereum',
ensOwnership: true,
ensName,
verificationStatus: 'verified-owner'
} as User;
}
return u;
});
const enrichedStatus = relevanceCalculator.buildUserVerificationStatus(enrichedUsers);
const transformed = getDataFromCache(verifyFn, enrichedStatus);
setCells(transformed.cells);
setPosts(transformed.posts);
setComments(transformed.comments);
setUserVerificationStatus(enrichedStatus);
})();
}, [authService, isAuthenticated, currentUser]);
const handleRefreshData = async () => {

View File

@ -35,7 +35,22 @@ export const createPost = async (
if (!isAuthenticated || !currentUser) {
toast({
title: 'Authentication Required',
description: 'You need to verify Ordinal ownership to post.',
description: 'You need to connect your wallet to post.',
variant: 'destructive',
});
return null;
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(currentUser.ensOwnership || currentUser.ordinalOwnership);
const isVerified = currentUser.verificationStatus === 'verified-owner' ||
currentUser.verificationStatus === 'verified-basic' ||
hasENSOrOrdinal;
if (!isVerified && (currentUser.verificationStatus === 'unverified' || currentUser.verificationStatus === 'verifying')) {
toast({
title: 'Verification Required',
description: 'Please complete wallet verification to post.',
variant: 'destructive',
});
return null;
@ -92,7 +107,22 @@ export const createComment = async (
if (!isAuthenticated || !currentUser) {
toast({
title: 'Authentication Required',
description: 'You need to verify Ordinal ownership to comment.',
description: 'You need to connect your wallet to comment.',
variant: 'destructive',
});
return null;
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(currentUser.ensOwnership || currentUser.ordinalOwnership);
const isVerified = currentUser.verificationStatus === 'verified-owner' ||
currentUser.verificationStatus === 'verified-basic' ||
hasENSOrOrdinal;
if (!isVerified && (currentUser.verificationStatus === 'unverified' || currentUser.verificationStatus === 'verifying')) {
toast({
title: 'Verification Required',
description: 'Please complete wallet verification to comment.',
variant: 'destructive',
});
return null;
@ -210,7 +240,22 @@ export const vote = async (
if (!isAuthenticated || !currentUser) {
toast({
title: 'Authentication Required',
description: 'You need to verify Ordinal ownership to vote.',
description: 'You need to connect your wallet to vote.',
variant: 'destructive',
});
return false;
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(currentUser.ensOwnership || currentUser.ordinalOwnership);
const isVerified = currentUser.verificationStatus === 'verified-owner' ||
currentUser.verificationStatus === 'verified-basic' ||
hasENSOrOrdinal;
if (!isVerified && (currentUser.verificationStatus === 'unverified' || currentUser.verificationStatus === 'verifying')) {
toast({
title: 'Verification Required',
description: 'Please complete wallet verification to vote.',
variant: 'destructive',
});
return false;

View File

@ -14,7 +14,8 @@ export class RelevanceCalculator {
COMMENT: 0.5
};
private static readonly VERIFICATION_BONUS = 1.25; // 25% increase
private static readonly VERIFICATION_BONUS = 1.25; // 25% increase for ENS/Ordinal owners
private static readonly BASIC_VERIFICATION_BONUS = 1.1; // 10% increase for basic verified users
private static readonly VERIFIED_UPVOTE_BONUS = 0.1;
private static readonly VERIFIED_COMMENTER_BONUS = 0.05;
@ -201,10 +202,10 @@ export class RelevanceCalculator {
/**
* Check if a user is verified (has ENS or ordinal ownership)
* Check if a user is verified (has ENS or ordinal ownership, or basic verification)
*/
isUserVerified(user: User): boolean {
return !!(user.ensOwnership || user.ordinalOwnership);
return !!(user.ensOwnership || user.ordinalOwnership || user.verificationStatus === 'verified-basic');
}
/**
@ -218,7 +219,8 @@ export class RelevanceCalculator {
isVerified: this.isUserVerified(user),
hasENS: !!user.ensOwnership,
hasOrdinal: !!user.ordinalOwnership,
ensName: user.ensName
ensName: user.ensName,
verificationStatus: user.verificationStatus
};
});
@ -245,22 +247,31 @@ export class RelevanceCalculator {
}
/**
* Apply author verification bonus
* Apply verification bonus for verified authors
*/
private applyAuthorVerificationBonus(
score: number,
authorAddress: string,
score: number,
authorAddress: string,
userVerificationStatus: UserVerificationStatus
): { bonus: number; isVerified: boolean } {
const authorStatus = userVerificationStatus[authorAddress];
const isVerified = authorStatus?.isVerified || false;
if (isVerified) {
const bonus = score * (RelevanceCalculator.VERIFICATION_BONUS - 1);
return { bonus, isVerified };
if (!isVerified) {
return { bonus: 0, isVerified: false };
}
return { bonus: 0, isVerified };
// Apply different bonuses based on verification level
let bonus = 0;
if (authorStatus?.verificationStatus === 'verified-owner') {
// Full bonus for ENS/Ordinal owners
bonus = score * (RelevanceCalculator.VERIFICATION_BONUS - 1);
} else if (authorStatus?.verificationStatus === 'verified-basic') {
// Lower bonus for basic verified users
bonus = score * (RelevanceCalculator.BASIC_VERIFICATION_BONUS - 1);
}
return { bonus, isVerified: true };
}
/**

View File

@ -22,5 +22,6 @@ export interface RelevanceScoreDetails {
hasENS: boolean;
hasOrdinal: boolean;
ensName?: string;
verificationStatus?: 'unverified' | 'verified-none' | 'verified-basic' | 'verified-owner' | 'verifying';
};
}

View File

@ -9,7 +9,7 @@ export class OrdinalAPI {
* @returns A promise that resolves with the API response.
*/
async getOperatorDetails(address: string): Promise<OrdinalApiResponse> {
if (import.meta.env.VITE_OPCHAN_MOCK_ORDINAL_CHECK === 'true') {
console.log(`[DEV] Bypassing ordinal verification for address: ${address}`);
return {

View File

@ -182,6 +182,7 @@ export class AuthService {
const updatedUser = {
...user,
ordinalOwnership: hasOperators,
verificationStatus: hasOperators ? 'verified-owner' : 'verified-basic',
lastChecked: Date.now(),
};
@ -206,6 +207,7 @@ export class AuthService {
...user,
ensOwnership: hasENS,
ensName: ensName,
verificationStatus: hasENS ? 'verified-owner' : 'verified-basic',
lastChecked: Date.now(),
};
@ -216,11 +218,12 @@ export class AuthService {
} catch (error) {
console.error('Error verifying ENS ownership:', error);
// Fall back to no ENS ownership on error
// Fall back to basic verification on error
const updatedUser = {
...user,
ensOwnership: false,
ensName: undefined,
verificationStatus: 'verified-basic',
lastChecked: Date.now(),
};

View File

@ -15,7 +15,7 @@ export interface User {
ensAvatar?: string;
ensOwnership?: boolean;
verificationStatus: 'unverified' | 'verified-none' | 'verified-owner' | 'verifying';
verificationStatus: 'unverified' | 'verified-none' | 'verified-basic' | 'verified-owner' | 'verifying';
signature?: string;
lastChecked?: number;