From 97f66152b64fe784ee498a19752a6f6cb80153ac Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Fri, 19 Jun 2026 21:12:21 +0100 Subject: [PATCH 01/14] docs: fix relative documentation links to prevent broken paths on forks --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2ef20cb..067dbfd 100644 --- a/README.md +++ b/README.md @@ -307,12 +307,12 @@ Users can delete their own airdrop claim: For more detailed information, see the `/docs` folder: -- **[Getting Started](/docs/index.md)** - Quick overview and contact information -- **[Core Concepts](/docs/core-concepts.md)** - Understanding providers, traits, tokens, and Sybil resistance -- **[Integration Guide](/docs/integration.md)** - Complete implementation walkthrough with code examples -- **[Trait Catalog](/docs/traits.md)** - All available traits for X, Coinbase, Instagram, and TikTok -- **[API Reference](/docs/api.md)** - Complete API endpoint documentation -- **[Security & Privacy](/docs/security.md)** - Security best practices and data handling +- **[Getting Started](docs/index.md)** - Quick overview and contact information +- **[Core Concepts](docs/core-concepts.md)** - Understanding providers, traits, tokens, and Sybil resistance +- **[Integration Guide](docs/integration.md)** - Complete implementation walkthrough with code examples +- **[Trait Catalog](docs/traits.md)** - All available traits for X, Coinbase, Instagram, and TikTok +- **[API Reference](docs/api.md)** - Complete API endpoint documentation +- **[Security & Privacy](docs/security.md)** - Security best practices and data handling --- From cea8a1b17518302b140e7645444b9a38b59f89fc Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Fri, 19 Jun 2026 23:59:23 +0100 Subject: [PATCH 02/14] docs: update outdated 2025 example placeholders to 2026 --- docs/core-concepts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core-concepts.md b/docs/core-concepts.md index d3072db..c4c06bf 100644 --- a/docs/core-concepts.md +++ b/docs/core-concepts.md @@ -63,7 +63,7 @@ The action is returned in the API response: **Use Cases:** - **Multiple campaigns**: Run separate airdrops without interference - **Feature gating**: Different tokens for different premium features -- **Time-based events**: New action per event (e.g., `raffle_jan_2025`, `raffle_feb_2025`) +- **Time-based events**: New action per event (e.g., `raffle_jan_2026`, `raffle_feb_2026`) ### Choosing Action Names From ff92f7f235def0a9ab76acdea2cdfa31d61fcaf4 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 00:19:05 +0100 Subject: [PATCH 03/14] docs: fix missing comma typo in integration guide --- docs/integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integration.md b/docs/integration.md index 1d77de1..525ac2b 100644 --- a/docs/integration.md +++ b/docs/integration.md @@ -14,7 +14,7 @@ Even if a wallet has few transactions, Base Verify reveals if the user is high-v **Example Use Cases:** - Token-gated airdrops or daily rewards -- Exclusive content access (e.g. creator coins) +- Exclusive content access (e.g., creator coins) - Identity-based rewards and loyalty programs --- From a9deb869c3e8f8a3bc0e7fb22a6e0edcf83a1d6e Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 00:35:35 +0100 Subject: [PATCH 04/14] docs: adjust signature verification comment phrasing in backend code --- docs/integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integration.md b/docs/integration.md index 525ac2b..b759f9d 100644 --- a/docs/integration.md +++ b/docs/integration.md @@ -256,7 +256,7 @@ export default async function handler(req, res) { }); } - // Now safe to verify signature with Base Verify API + // Now safe to check signature with Base Verify API const response = await fetch('https://verify.base.dev/v1/base_verify_token', { method: 'POST', headers: { From b2860abd9c1f6d133e909e92fed5d909297a66a7 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 01:03:34 +0100 Subject: [PATCH 05/14] docs: correct nonce status logic in replay attack section --- docs/security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/security.md b/docs/security.md index 7472e99..bbc797e 100644 --- a/docs/security.md +++ b/docs/security.md @@ -85,7 +85,7 @@ The user signs this message, proving they control the wallet and agree to check Users can delete their verifications at any time: - Removes all stored provider data - Invalidates future token generation -- Your app's stored tokens become meaningless (user can't re-verify with same account) +- Your app's stored tokens become completely invalid (user can't re-verify with same account) --- From 2e8e53c358c7b7f96ef47ad45645e6f7bd75dfd1 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 01:12:48 +0100 Subject: [PATCH 06/14] docs: correct description for coinbase_one_active trait in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 067dbfd..20cf771 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Traits are specific attributes of provider accounts you can verify. Examples: **Coinbase:** - `coinbase_one_active:eq:true` - Active Coinbase One subscription -- `coinbase_one_billed:eq:true` - User has been billed for Coinbase One +- `coinbase_one_billed:eq:true` - User has an active Coinbase One subscription **Instagram:** - `followers_count:gte:5000` - 5000+ followers From c076f2c3c5825313e5714b075629bac22b51bbdb Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 01:22:52 +0100 Subject: [PATCH 07/14] docs: rename frontend publisher key variable to public key in env.example --- env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env.example b/env.example index ffef3b0..d2b8ad4 100644 --- a/env.example +++ b/env.example @@ -12,7 +12,7 @@ NEXT_PUBLIC_ONCHAINKIT_API_KEY="your_onchainkit_api_key_here" NEXT_PUBLIC_BASE_VERIFY_API_URL="https://verify.base.dev/v1" NEXT_PUBLIC_BASE_VERIFY_WEBAPP_URL="https://verify.base.dev" BASE_VERIFY_SECRET_KEY="sk_live_your_secret_key_here_64_character_hex_string" -NEXT_PUBLIC_BASE_VERIFY_PUBLISHER_KEY="pk_live_your_publisher_key_here_64_character_hex_string" +NEXT_PUBLIC_BASE_VERIFY_PUBLIC_KEY="pk_live_your_publisher_key_here_64_character_hex_string" # Your application's URL NEXT_PUBLIC_APP_URL="https://baseverifydemo.com" From d91bb1ad131a6da1223db695ea52f000baf6d269 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 01:42:14 +0100 Subject: [PATCH 08/14] fix: update baseVerifyPublicKey variable mappings in config logic --- lib/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config.ts b/lib/config.ts index d112421..c991fed 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -10,7 +10,7 @@ export const config = { baseVerifySecretKey: process.env.BASE_VERIFY_SECRET_KEY, // Publisher key for client-side API calls (public, requires origin validation) - baseVerifyPublisherKey: process.env.NEXT_PUBLIC_BASE_VERIFY_PUBLISHER_KEY, + baseVerifyPublicKey: process.env.NEXT_PUBLIC_BASE_VERIFY_PUBLIC_KEY, // Current app URL for redirects appUrl: process.env.NEXT_PUBLIC_APP_URL || 'https://baseverifydemo.com', From 5495197d0da843e565f496ab3beca0165f675b3e Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 01:59:13 +0100 Subject: [PATCH 09/14] fix: dynamically extract provider from trait URNs in validator logic --- lib/trait-validator.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/trait-validator.ts b/lib/trait-validator.ts index 2f03871..ad4a603 100644 --- a/lib/trait-validator.ts +++ b/lib/trait-validator.ts @@ -36,13 +36,13 @@ function parseTraitsFromMessage(message: string): { provider: string; traits: Tr .map(line => line.replace(/^- /, '').trim()) .filter(line => line.length > 0); - // Find provider URN - const providerUrn = resources.find(r => r.match(/^urn:verify:provider:[^:]+$/)); - if (!providerUrn) { + // Find the first trait URN to extract the provider + const traitUrn = resources.find(r => r.startsWith('urn:verify:provider:')); + if (!traitUrn) { return null; } - const providerMatch = providerUrn.match(/^urn:verify:provider:([^:]+)$/); + const providerMatch = traitUrn.match(/^urn:verify:provider:([^:]+):/); if (!providerMatch) { return null; } @@ -50,6 +50,7 @@ function parseTraitsFromMessage(message: string): { provider: string; traits: Tr const provider = providerMatch[1]; const traits: TraitRequirement = {}; + // Parse trait URNs for this provider const traitPattern = new RegExp(`^urn:verify:provider:${provider}:([^:]+):([^:]+):(.+)$`); From ff3b2f4a878e4254b46967d3f193d000096b8eb4 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 02:09:47 +0100 Subject: [PATCH 10/14] fix: dynamically resolve chainId from config in SIWE message builder --- lib/signature-generator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/signature-generator.ts b/lib/signature-generator.ts index 59a76eb..f23dbf7 100644 --- a/lib/signature-generator.ts +++ b/lib/signature-generator.ts @@ -20,7 +20,7 @@ function buildSIWEMessage(options: SIWEOptions): { message: string; nonce: strin domain = new URL(config.appUrl).hostname, address, uri = config.appUrl, - chainId = 8453, // Base chain + chainId = config.claimChainId || 84532, action, provider, traits = {}, From 86b0ab8b11072aab7b8b00ce72c25b14a968d615 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 12:25:54 +0100 Subject: [PATCH 11/14] fix: normalize extracted wallet address string to lowercase for DB safety --- pages/api/verify-token.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/verify-token.ts b/pages/api/verify-token.ts index 008b770..7dd6823 100644 --- a/pages/api/verify-token.ts +++ b/pages/api/verify-token.ts @@ -103,7 +103,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) try { // Extract user data from verification response const addressMatch = message.match(/0x[a-fA-F0-9]{40}/); - const walletAddress = addressMatch ? addressMatch[0] : ''; + const walletAddress = addressMatch ? addressMatch[0].toLowerCase() : ''; console.log('Extracted wallet address:', walletAddress); From 84fa6c426bd58eca8917b826379634c6515f2753 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 12:40:52 +0100 Subject: [PATCH 12/14] fix: explicit pass of OAuth code parameters to prevent router query wipe race condition --- pages/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/index.tsx b/pages/index.tsx index 7e0ea92..fd1c43d 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -62,7 +62,7 @@ export default function Home({ initialUsers, error }: Props) { if (success === 'true' && address && isConnected && !isVerifying && !verificationResult) { console.log('Auto-verifying after successful redirect...'); setIsAutoVerification(true); - handleVerify(true); + handleVerify(true, router.query.code as string, router.query.state as string); // Clean up the URL to remove the success parameter const { success: _, code: __, state: ___, ...cleanQuery } = router.query; @@ -219,7 +219,7 @@ export default function Home({ initialUsers, error }: Props) { setShowVerifyModal(true); } - const handleVerify = async (isAutoVerifyFromSuccess = false) => { + const handleVerify = async (isAutoVerifyFromSuccess = false, passedCode?: string, passedState?: string) => { if (!address || !signMessage) { setVerificationError('Please connect your wallet to claim') return @@ -262,7 +262,7 @@ export default function Home({ initialUsers, error }: Props) { verifySignatureCache.set(signature); } - const { code, state } = router.query; + const code = passedCode || router.query.code; const state = passedState || router.query.state; const storedCodeVerifier = sessionStorage.getItem('pkce_code_verifier'); const storedState = sessionStorage.getItem('pkce_state'); From c0cd0478212d29ecde33d3d619a44d996bc51ff2 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 12:47:20 +0100 Subject: [PATCH 13/14] fix: sync hardcoded action string with main claim page identifier --- pages/onchain.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/onchain.tsx b/pages/onchain.tsx index b2ca07c..a6f925c 100644 --- a/pages/onchain.tsx +++ b/pages/onchain.tsx @@ -56,7 +56,7 @@ type OnchainToken = { signature: string } -const ACTION = 'my_app_airdrop_2026' +const ACTION = 'claim_demo_x_airdrop' // Read-only client for the dedup pre-check. const publicClient = createPublicClient({ chain: baseSepolia, transport: http() }) From 327f657d9d42b8ed68888799dac1c2c1f6dd7417 Mon Sep 17 00:00:00 2001 From: shinobi133 Date: Sat, 20 Jun 2026 13:18:09 +0100 Subject: [PATCH 14/14] fix: adjust cache eviction to match unified action signature --- pages/onchain.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/onchain.tsx b/pages/onchain.tsx index a6f925c..d1bd4f6 100644 --- a/pages/onchain.tsx +++ b/pages/onchain.tsx @@ -96,8 +96,7 @@ export default function OnchainPage() { if (cachedSignature) { if (cachedSignature.address.toLowerCase() !== address.toLowerCase()) { verifySignatureCache.clear() - } else if (!cachedSignature.message.includes('urn:verify:provider:coinbase') || - !cachedSignature.message.includes(`urn:verify:action:${ACTION}`)) { + } else if (!cachedSignature.message.includes(`urn:verify:action:${ACTION}`)) { verifySignatureCache.clear() } }