mirror of
https://github.com/logos-messaging/OpChan.git
synced 2026-01-02 12:53:10 +00:00
fix: message signing
This commit is contained in:
parent
0ad1cce551
commit
367cb72834
@ -3,7 +3,6 @@ import { Link, useLocation } from 'react-router-dom';
|
||||
import { useAuth, useForum, useNetwork } from '@/hooks';
|
||||
import { EVerificationStatus } from '@opchan/core';
|
||||
import { localDatabase } from '@opchan/core';
|
||||
import { DelegationFullStatus } from '@opchan/core';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
@ -49,9 +48,7 @@ import { WalletWizard } from '@/components/ui/wallet-wizard';
|
||||
import { WakuHealthDot } from '@/components/ui/waku-health-indicator';
|
||||
|
||||
const Header = () => {
|
||||
const { currentUser, delegationStatus } = useAuth();
|
||||
const [delegationInfo, setDelegationInfo] =
|
||||
useState<DelegationFullStatus | null>(null);
|
||||
const { currentUser, delegationInfo } = useAuth();
|
||||
const {statusMessage} = useNetwork();
|
||||
|
||||
const location = useLocation()
|
||||
@ -76,13 +73,6 @@ const Header = () => {
|
||||
const [walletWizardOpen, setWalletWizardOpen] = useState(false);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
|
||||
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
delegationStatus().then(setDelegationInfo).catch(console.error);
|
||||
}, [delegationStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log({currentUser})
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { Button } from './button';
|
||||
import { useAuth } from '@opchan/react';
|
||||
import { CheckCircle, AlertCircle, Trash2 } from 'lucide-react';
|
||||
import { DelegationDuration, DelegationFullStatus } from '@opchan/core';
|
||||
import { DelegationDuration } from '@opchan/core';
|
||||
|
||||
interface DelegationStepProps {
|
||||
onComplete: () => void;
|
||||
@ -17,15 +17,7 @@ export function DelegationStep({
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
}: DelegationStepProps) {
|
||||
const { currentUser, isAuthenticating, getDelegationStatus } = useAuth();
|
||||
const [delegationInfo, setDelegationInfo] =
|
||||
useState<DelegationFullStatus | null>(null);
|
||||
const { delegateKey, clearDelegation } = useAuth();
|
||||
|
||||
// Load delegation status
|
||||
useEffect(() => {
|
||||
getDelegationStatus().then(setDelegationInfo).catch(console.error);
|
||||
}, [getDelegationStatus]);
|
||||
const { currentUser, delegationInfo, delegate, clearDelegation } = useAuth();
|
||||
|
||||
const [selectedDuration, setSelectedDuration] =
|
||||
React.useState<DelegationDuration>('7days');
|
||||
@ -42,11 +34,11 @@ export function DelegationStep({
|
||||
setDelegationResult(null);
|
||||
|
||||
try {
|
||||
const success = await delegateKey(selectedDuration);
|
||||
const success = await delegate(selectedDuration);
|
||||
|
||||
if (success) {
|
||||
const expiryDate = currentUser.delegationExpiry
|
||||
? new Date(currentUser.delegationExpiry).toLocaleString()
|
||||
const expiryDate = delegationInfo?.expiresAt
|
||||
? delegationInfo.expiresAt.toLocaleString()
|
||||
: `${selectedDuration === '7days' ? '1 week' : '30 days'} from now`;
|
||||
|
||||
setDelegationResult({
|
||||
@ -211,13 +203,7 @@ export function DelegationStep({
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
onClick={async () => {
|
||||
const ok = await clearDelegation();
|
||||
if (ok) {
|
||||
// Refresh status so UI immediately reflects cleared state
|
||||
getDelegationStatus()
|
||||
.then(setDelegationInfo)
|
||||
.catch(console.error);
|
||||
}
|
||||
await clearDelegation();
|
||||
}}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@ -245,7 +231,7 @@ export function DelegationStep({
|
||||
<Button
|
||||
onClick={handleDelegate}
|
||||
className="w-full bg-blue-600 hover:bg-blue-700 text-white"
|
||||
disabled={isLoading || isAuthenticating}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? 'Delegating...' : 'Delegate Key'}
|
||||
</Button>
|
||||
|
||||
@ -40,7 +40,7 @@ export default function ProfilePage() {
|
||||
const { toast } = useToast();
|
||||
|
||||
// Get current user from auth context for the address
|
||||
const { currentUser, delegation } = useAuth();
|
||||
const { currentUser, delegationInfo } = useAuth();
|
||||
const address = currentUser?.address;
|
||||
|
||||
// Debug current user ENS info
|
||||
@ -461,7 +461,7 @@ export default function ProfilePage() {
|
||||
<Shield className="h-5 w-5 text-cyber-accent" />
|
||||
Security
|
||||
</div>
|
||||
{delegation.hasDelegation && (
|
||||
{delegationInfo.hasDelegation && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@ -469,7 +469,7 @@ export default function ProfilePage() {
|
||||
className="border-cyber-muted/30 text-cyber-neutral hover:bg-cyber-muted/30"
|
||||
>
|
||||
<Settings className="w-4 h-4 mr-2" />
|
||||
{delegation.isValid ? 'Renew' : 'Setup'}
|
||||
{delegationInfo.isValid ? 'Renew' : 'Setup'}
|
||||
</Button>
|
||||
)}
|
||||
</CardTitle>
|
||||
@ -482,25 +482,25 @@ export default function ProfilePage() {
|
||||
Delegation
|
||||
</span>
|
||||
<Badge
|
||||
variant={delegation.isValid ? 'default' : 'secondary'}
|
||||
variant={delegationInfo.isValid ? 'default' : 'secondary'}
|
||||
className={
|
||||
delegation.isValid
|
||||
delegationInfo.isValid
|
||||
? 'bg-green-500/20 text-green-400 border-green-500/30'
|
||||
: 'bg-red-500/20 text-red-400 border-red-500/30'
|
||||
}
|
||||
>
|
||||
{delegation.isValid ? 'Active' : 'Inactive'}
|
||||
{delegationInfo.isValid ? 'Active' : 'Inactive'}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{/* Expiry Date */}
|
||||
{delegation.expiresAt && (
|
||||
{delegationInfo.expiresAt && (
|
||||
<div className="space-y-1">
|
||||
<span className="text-xs text-cyber-neutral">
|
||||
Valid until
|
||||
</span>
|
||||
<div className="text-sm font-mono text-cyber-light">
|
||||
{delegation.expiresAt.toLocaleDateString()}
|
||||
{delegationInfo.expiresAt.toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -513,12 +513,12 @@ export default function ProfilePage() {
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={
|
||||
delegation.isValid
|
||||
delegationInfo.isValid
|
||||
? 'text-green-400 border-green-500/30 bg-green-500/10'
|
||||
: 'text-red-400 border-red-500/30 bg-red-500/10'
|
||||
}
|
||||
>
|
||||
{delegation.isValid ? 'Valid' : 'Not signed'}
|
||||
{delegationInfo.isValid ? 'Valid' : 'Not signed'}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
@ -530,17 +530,17 @@ export default function ProfilePage() {
|
||||
</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1 font-mono text-xs bg-cyber-dark/50 border border-cyber-muted/30 px-2 py-1 rounded text-cyber-light">
|
||||
{delegation.publicKey
|
||||
? `${delegation.publicKey.slice(0, 12)}...${delegation.publicKey.slice(-8)}`
|
||||
{delegationInfo.publicKey
|
||||
? `${delegationInfo.publicKey.slice(0, 12)}...${delegationInfo.publicKey.slice(-8)}`
|
||||
: 'Not delegated'}
|
||||
</div>
|
||||
{delegation.publicKey && (
|
||||
{delegationInfo.publicKey && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
copyToClipboard(
|
||||
delegation.publicKey!,
|
||||
delegationInfo.publicKey!,
|
||||
'Public Key'
|
||||
)
|
||||
}
|
||||
@ -553,7 +553,7 @@ export default function ProfilePage() {
|
||||
</div>
|
||||
|
||||
{/* Warning for expired delegation */}
|
||||
{(!delegation.isValid && delegation.hasDelegation) && (
|
||||
{(!delegationInfo.isValid && delegationInfo.hasDelegation) && (
|
||||
<div className="p-3 bg-orange-500/10 border border-orange-500/30 rounded-md">
|
||||
<div className="flex items-center gap-2 text-orange-400">
|
||||
<AlertTriangle className="w-4 h-4" />
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import * as React from 'react';
|
||||
import { OpChanProvider, type WalletAdapter, type WalletAdapterAccount } from '@opchan/react';
|
||||
import { useAppKitAccount } from '@reown/appkit/react';
|
||||
import { useAppKitAccount, modal } from '@reown/appkit/react';
|
||||
import { AppKit } from '@reown/appkit';
|
||||
import type { OpChanClientConfig } from '@opchan/core';
|
||||
import { walletManager } from '@opchan/core';
|
||||
|
||||
interface Props { config: OpChanClientConfig; children: React.ReactNode }
|
||||
|
||||
@ -23,16 +25,31 @@ export const OpchanWithAppKit: React.FC<Props> = ({ config, children }) => {
|
||||
listenersRef.current.add(cb);
|
||||
return () => { listenersRef.current.delete(cb); };
|
||||
},
|
||||
}), [getCurrent]);
|
||||
}), [getCurrent]);
|
||||
|
||||
// Notify listeners when AppKit account changes
|
||||
React.useEffect(() => {
|
||||
const account = getCurrent();
|
||||
listenersRef.current.forEach(cb => {
|
||||
try { cb(account); } catch (e) { /* ignore */ }
|
||||
try { cb(account); } catch { /* ignore */ }
|
||||
});
|
||||
}, [getCurrent]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!modal) return;
|
||||
try {
|
||||
const hasBtc = btc.isConnected && !!btc.address;
|
||||
const hasEth = eth.isConnected && !!eth.address;
|
||||
if (hasBtc || hasEth) {
|
||||
walletManager.create(modal as AppKit, btc, eth);
|
||||
} else if (walletManager.hasInstance()) {
|
||||
walletManager.clear();
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('WalletManager initialization error', err);
|
||||
}
|
||||
}, [btc, btc.isConnected, btc.address, eth, eth.isConnected, eth.address]);
|
||||
|
||||
return (
|
||||
<OpChanProvider config={config} walletAdapter={adapter}>
|
||||
{children}
|
||||
|
||||
@ -10,7 +10,6 @@ import { config } from './config';
|
||||
import { Provider } from '@reown/appkit-controllers';
|
||||
import { WalletInfo, ActiveWallet } from './types';
|
||||
import { Inscription } from 'ordiscan';
|
||||
import { environment } from '../utils/environment';
|
||||
export class WalletManager {
|
||||
private static instance: WalletManager | null = null;
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
EVerificationStatus,
|
||||
DelegationDuration,
|
||||
EDisplayPreference,
|
||||
walletManager,
|
||||
} from '@opchan/core';
|
||||
import type { DelegationFullStatus } from '@opchan/core';
|
||||
|
||||
@ -101,17 +102,17 @@ export function useAuth() {
|
||||
}, [client, currentUser]);
|
||||
|
||||
const delegate = React.useCallback(async (
|
||||
signFunction: (message: string) => Promise<string>,
|
||||
duration: DelegationDuration = '7days',
|
||||
): Promise<boolean> => {
|
||||
const user = currentUser;
|
||||
if (!user) return false;
|
||||
try {
|
||||
const signer = ((message: string) => walletManager.getInstance().signMessage(message));
|
||||
const ok = await client.delegation.delegate(
|
||||
user.address,
|
||||
user.walletType,
|
||||
duration,
|
||||
signFunction,
|
||||
signer,
|
||||
);
|
||||
|
||||
const status = await client.delegation.getStatus(user.address, user.walletType);
|
||||
@ -132,12 +133,18 @@ export function useAuth() {
|
||||
return client.delegation.getStatus(user.address, user.walletType);
|
||||
}, [client, currentUser]);
|
||||
|
||||
const clearDelegation = React.useCallback(async () => {
|
||||
await client.delegation.clear();
|
||||
setOpchanState(prev => ({
|
||||
...prev,
|
||||
session: { ...prev.session, delegation: null },
|
||||
}));
|
||||
const clearDelegation = React.useCallback(async (): Promise<boolean> => {
|
||||
try {
|
||||
await client.delegation.clear();
|
||||
setOpchanState(prev => ({
|
||||
...prev,
|
||||
session: { ...prev.session, delegation: null },
|
||||
}));
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('clearDelegation failed', e);
|
||||
return false;
|
||||
}
|
||||
}, [client]);
|
||||
|
||||
const updateProfile = React.useCallback(async (updates: { callSign?: string; displayPreference?: EDisplayPreference }): Promise<boolean> => {
|
||||
@ -167,19 +174,20 @@ export function useAuth() {
|
||||
}
|
||||
}, [client, currentUser]);
|
||||
|
||||
const delegationInfo = React.useMemo<DelegationFullStatus & { expiresAt?: Date }>(() => {
|
||||
const base: DelegationFullStatus =
|
||||
delegation ?? ({ hasDelegation: false, isValid: false } as const);
|
||||
const expiresAt = base?.proof?.expiryTimestamp
|
||||
? new Date(base.proof.expiryTimestamp)
|
||||
: undefined;
|
||||
return { ...base, expiresAt };
|
||||
}, [delegation]);
|
||||
|
||||
return {
|
||||
currentUser,
|
||||
verificationStatus,
|
||||
isAuthenticated: currentUser !== null,
|
||||
// Provide a stable, non-null delegation object for UI safety
|
||||
delegation: ((): DelegationFullStatus & { expiresAt?: Date } => {
|
||||
const base: DelegationFullStatus =
|
||||
delegation ?? ({ hasDelegation: false, isValid: false } as const);
|
||||
const expiresAt = base?.proof?.expiryTimestamp
|
||||
? new Date(base.proof.expiryTimestamp)
|
||||
: undefined;
|
||||
return { ...base, expiresAt };
|
||||
})(),
|
||||
delegationInfo,
|
||||
connect,
|
||||
disconnect,
|
||||
verifyOwnership,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user