Epic: #1229 · Spec: §3.1, §6.3 · Type: CODE · Estimate: 0.3 day · Depends on: T2.1
Scope
(0) Install siwe npm package (RE1 round-23 — not yet in package.json)
- Verify
siwe appears in package.json dependencies + package-lock.json updated
- Spec uses EIP-4361 + ENS resolution from
siwe@2.x (compatible with viem@2.x / wagmi@2.x / next@16 confirmed by main-app risk audit)
- Lockfile change committed
(1) Build lib/airdrop/siwe-verify.ts
Create the lib using the installed siwe package. This is the auth foundation for ALL signed airdrop endpoints (activation + referral mutation).
```ts
export async function verifySiweRequest(
message: string,
signature: string
): Promise<
| { ok: true; address: string }
| { ok: false; error: string }
```
Validates the FULL EIP-4361 envelope:
- Signature recovers to claimed address
- Domain matches
SIWE_DOMAIN (plotlink.xyz)
- URI matches
SIWE_URI (https://plotlink.xyz/airdrop)
- Chain ID matches
SIWE_CHAIN_ID (8453)
- Statement matches
SIWE_STATEMENT (PlotLink Buy-Back Sprint activation)
expirationTime has not passed
issuedAt is within SIGNATURE_FRESHNESS_MIN (10 min) of server time
Uses SiweMessage(message).verify({ signature, domain, ... }) per the siwe package API.
Replaces v1's lib/airdrop/verify-wallet.ts (verifyWalletOwnership) for ALL signed v5 endpoints (activation 5 + referral 2). v1 file is NOT modified — kept for legacy/deprecated endpoint compat until post-launch cleanup PR.
Acceptance
Dependencies
T2.1 (config provides SIWE_DOMAIN/SIWE_URI/etc.)
Epic: #1229 · Spec: §3.1, §6.3 · Type: CODE · Estimate: 0.3 day · Depends on: T2.1
Scope
(0) Install
siwenpm package (RE1 round-23 — not yet in package.json)siweappears inpackage.jsondependencies +package-lock.jsonupdatedsiwe@2.x(compatible with viem@2.x / wagmi@2.x / next@16 confirmed by main-app risk audit)(1) Build
lib/airdrop/siwe-verify.tsCreate the lib using the installed
siwepackage. This is the auth foundation for ALL signed airdrop endpoints (activation + referral mutation).```ts
export async function verifySiweRequest(
message: string,
signature: string
): Promise<
| { ok: true; address: string }
| { ok: false; error: string }
```
Validates the FULL EIP-4361 envelope:
SIWE_DOMAIN(plotlink.xyz)SIWE_URI(https://plotlink.xyz/airdrop)SIWE_CHAIN_ID(8453)SIWE_STATEMENT(PlotLink Buy-Back Sprint activation)expirationTimehas not passedissuedAtis withinSIGNATURE_FRESHNESS_MIN(10 min) of server timeUses
SiweMessage(message).verify({ signature, domain, ... })per thesiwepackage API.Replaces v1's
lib/airdrop/verify-wallet.ts(verifyWalletOwnership) for ALL signed v5 endpoints (activation 5 + referral 2). v1 file is NOT modified — kept for legacy/deprecated endpoint compat until post-launch cleanup PR.Acceptance
{ ok: true, address }{ ok: false, error: 'expired' }{ ok: false, error: '...' }{ ok: false, error: 'invalid_signature' }siwepackage (new SiweMessage(...).verify(...))siweinpackage.jsondependencies + lockfile committednpm run typecheckpasses (siwe types resolve)Dependencies
T2.1 (config provides
SIWE_DOMAIN/SIWE_URI/etc.)