import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import styles from './Create.module.css'; interface Share { id: string; walletName: string; publicKey: string; threshold: { t: number; n: number }; createdAt: string; } interface CreateCoSignResult { success: boolean; sessionId?: string; inviteCode?: string; error?: string; } export default function CoSignCreate() { const navigate = useNavigate(); const [shares, setShares] = useState([]); const [selectedShareId, setSelectedShareId] = useState(''); const [sharePassword, setSharePassword] = useState(''); const [messageHash, setMessageHash] = useState(''); const [participantName, setParticipantName] = useState(''); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [result, setResult] = useState(null); const [step, setStep] = useState<'config' | 'creating' | 'created'>('config'); // 加载本地 shares useEffect(() => { const loadShares = async () => { try { const result = await window.electronAPI.storage.listShares(); // 兼容不同返回格式 const shareList = Array.isArray(result) ? result : ((result as any)?.data || []); setShares(shareList); if (shareList.length > 0) { setSelectedShareId(shareList[0].id); } } catch (err) { console.error('Failed to load shares:', err); } }; loadShares(); }, []); const handleCreateSession = async () => { if (!selectedShareId) { setError('请选择一个钱包'); return; } if (!messageHash.trim()) { setError('请输入待签名的消息哈希'); return; } if (!/^[0-9a-fA-F]{64}$/.test(messageHash.trim())) { setError('消息哈希必须是 64 位十六进制字符串 (32 字节)'); return; } if (!participantName.trim()) { setParticipantName('发起者'); } setStep('creating'); setIsLoading(true); setError(null); try { const createResult = await window.electronAPI.cosign.createSession({ shareId: selectedShareId, sharePassword: sharePassword, messageHash: messageHash.trim().toLowerCase(), initiatorName: participantName.trim() || '发起者', }); if (createResult.success) { setResult(createResult); setStep('created'); } else { setError(createResult.error || '创建签名会话失败'); setStep('config'); } } catch (err) { setError('创建签名会话失败,请检查网络连接'); setStep('config'); } finally { setIsLoading(false); } }; const handleCopyInviteCode = async () => { if (result?.inviteCode) { try { await navigator.clipboard.writeText(result.inviteCode); } catch (err) { console.error('Failed to copy:', err); } } }; const handleGoToSession = () => { if (result?.sessionId) { navigate(`/cosign/session/${result.sessionId}`); } }; const selectedShare = shares.find(s => s.id === selectedShareId); return (

发起多方签名

选择钱包并输入待签名的消息哈希

{step === 'config' && (
{/* 签名说明 */}
i
多方协作签名说明
  • 选择钱包: 使用已创建的共管钱包进行签名
  • 消息哈希: 待签名数据的 SHA256 哈希值
  • 阈值签名: 需要足够数量的参与方共同完成
  • 安全性: 私钥份额永不离开本地设备
{/* 选择钱包 */}
{shares.length === 0 ? (

暂无可用钱包,请先创建或加入共管钱包

) : ( )} {selectedShare && (

公钥: {selectedShare.publicKey.substring(0, 16)}...

)}
{/* 钱包密码 */}
setSharePassword(e.target.value)} placeholder="如果设置了密码,请输入" className={styles.input} disabled={isLoading} />
{/* 消息哈希 */}
setMessageHash(e.target.value)} placeholder="64位十六进制字符串,如: a1b2c3d4..." className={styles.input} disabled={isLoading} />

待签名数据的 SHA256 哈希值 (32 字节 = 64 个十六进制字符)

{/* 参与者名称 */}
setParticipantName(e.target.value)} placeholder="输入您的名称(其他参与者可见)" className={styles.input} disabled={isLoading} />
{error &&
{error}
}
)} {step === 'creating' && (

正在创建签名会话...

)} {step === 'created' && result && (
OK

签名会话创建成功

{result.inviteCode}

将此邀请码分享给其他参与方,他们可以使用此码加入签名

)}
); }