feat: single-asset auth, UI improvements

- Auth flow now uses single signature from user's chosen coin
- Update SmirkSignResult types to match extension API
- Add Creepster font for branding
- Better error messages from API responses
- Update docs to reflect single-asset auth is working
This commit is contained in:
jwinterm
2026-01-25 12:40:57 -05:00
parent 9ccc962514
commit e7b459f5bd
7 changed files with 58 additions and 39 deletions
+18
View File
@@ -1,5 +1,13 @@
@import "tailwindcss";
@font-face {
font-family: 'Creepster';
src: url('/fonts/Creepster-Regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
font-display: swap;
}
:root {
--background: #0a0a0a;
--foreground: #ededed;
@@ -73,3 +81,13 @@ body {
font-weight: 500;
text-transform: uppercase;
}
/* Creepster text styling */
.creepster-text {
font-family: 'Creepster', cursive;
color: #fbeb0a;
text-shadow:
0 0 10px rgba(251, 235, 10, 0.6),
0 0 20px rgba(251, 235, 10, 0.4),
0 0 30px rgba(251, 235, 10, 0.2);
}
+18 -11
View File
@@ -60,14 +60,17 @@ export default function Home() {
const challenge = await getChallenge(window.location.origin);
// Sign with the selected coin
const signatures = await window.smirk.signMessage(challenge.challenge);
const sig = signatures[coin];
const result = await window.smirk.signMessage(challenge.challenge);
const sig = result.signatures.find((s) => s.asset === coin);
if (!sig) {
throw new Error(`No signature found for ${coin}`);
}
// Verify with backend
const auth = await verifySignature(challenge.challenge_id, {
asset: coin,
signature: sig.signature,
public_key: sig.public_key,
public_key: sig.publicKey,
});
// Store token and show logged in
@@ -101,14 +104,18 @@ export default function Home() {
return (
<div className="min-h-screen flex flex-col items-center justify-center p-8">
{/* Logo */}
<div className="mb-12 logo-glow">
<Image
src="/logo_w_creepytext.svg"
alt="Smirk Wallet"
width={220}
height={200}
priority
/>
<div className="mb-12 flex flex-col items-center">
<h1 className="creepster-text text-4xl mb-4">SMIRK WALLET</h1>
<div className="logo-glow">
<Image
src="/logo.svg"
alt="Smirk"
width={160}
height={160}
priority
/>
</div>
<p className="creepster-text text-2xl mt-4">smirk.ca$h</p>
</div>
{/* Initial state - Connect button */}
+4 -4
View File
@@ -34,8 +34,8 @@ export async function getChallenge(origin: string): Promise<ChallengeResponse> {
});
if (!res.ok) {
const error = await res.json().catch(() => ({ message: 'Request failed' }));
throw new Error(error.message || 'Failed to get challenge');
const data = await res.json().catch(() => ({}));
throw new Error(data.error || data.message || 'Failed to get challenge');
}
return res.json();
@@ -55,8 +55,8 @@ export async function verifySignature(
});
if (!res.ok) {
const error = await res.json().catch(() => ({ message: 'Request failed' }));
throw new Error(error.message || 'Failed to verify signature');
const data = await res.json().catch(() => ({}));
throw new Error(data.error || data.message || 'Failed to verify signature');
}
return res.json();
+7 -9
View File
@@ -9,25 +9,23 @@ interface SmirkPublicKeys {
}
interface SmirkSignature {
asset: string;
asset: 'btc' | 'ltc' | 'xmr' | 'wow' | 'grin';
signature: string;
public_key: string;
publicKey: string;
}
interface SmirkSignatures {
btc: SmirkSignature;
ltc: SmirkSignature;
xmr: SmirkSignature;
wow: SmirkSignature;
grin: SmirkSignature;
interface SmirkSignResult {
message: string;
signatures: SmirkSignature[];
}
interface SmirkAPI {
isSmirk: boolean;
connect(): Promise<SmirkPublicKeys>;
disconnect(): Promise<void>;
isConnected(): Promise<boolean>;
getPublicKeys(): Promise<SmirkPublicKeys | null>;
signMessage(message: string): Promise<SmirkSignatures>;
signMessage(message: string): Promise<SmirkSignResult>;
}
interface Window {