β—† CIP-???? Reference Implementation Β· On-Chain Resolution

Handle Provider Resolver

A live demonstration of CIP-???? on-chain handle resolution. No provider API involved β€” handles resolve directly from the Cardano blockchain via Koios, with zero trust in any provider infrastructure.

πŸ”’
On-chain resolution only. This demo queries the Cardano blockchain directly via Koios. The provider's API server is never contacted. The NFT holder address IS the resolved address β€” enforced by Cardano itself.
STEP 1
Load Registry
registry.json
STEP 2
Detect Namespace
string match
STEP 3
Query Blockchain
Koios RPC
STEP 4
Show Result
address + policy
πŸ“‹ Step 1 β€” Registry
The wallet loads registry.json once. All providers and their Policy IDs discovered automatically. No API keys needed β€” Policy IDs are public.
Loading registry…
⛓️ Steps 2–4 β€” Detect Namespace β†’ Query Blockchain β†’ Resolve
Enter a handle minted on GetMyID. The algorithm detects the namespace, constructs the Cardano asset ID, and queries the blockchain directly for the NFT holder.
// On-chain resolution trace will appear here
// Type a handle above and click Resolve On-Chain
πŸ’» Complete Implementation
The full on-chain resolver in ~50 lines. This is all a wallet needs β€” no provider API, no trust in any server, pure blockchain query.
// Step 1: Load registry once at startup const registry = await fetch('registry.json').then(r => r.json()); // Step 2: Namespace detection (pure string ops, no network) function detectProviders(input, registry) { const EXCLUDED = /[?&%"'<>()\[\]{},\^`\s]/; const norm = input.trim().toLowerCase(); const candidates = []; // Check prefix providers for (const p of registry.filter(r => r.namespace_type === 'prefix')) if (norm.startsWith(p.namespace)) candidates.push(p); // Find suffix from last non-excluded delimiter const stripped = candidates[0] ? norm.slice(candidates[0].namespace.length) : norm; let lastDelim = -1; for (let i = stripped.length-1; i >= 0; i--) { if (!stripped[i].match(/[a-z0-9]/) && !EXCLUDED.test(stripped[i])) { lastDelim = i; break; } } if (lastDelim > -1) { const suffix = stripped.slice(lastDelim); for (const p of registry.filter(r => r.namespace_type === 'suffix' && r.namespace === suffix)) candidates.push(p); } // Always add bare namespace providers as fallback candidates.push(...registry.filter(r => r.namespace_type === 'bare')); return [...new Set(candidates)]; } // Step 3: On-chain resolution via Koios (no API key needed) async function resolveOnChain(handle, policyId, network) { const assetHex = [...handle].map(c => c.charCodeAt(0).toString(16).padStart(2,'0')).join(''); const base = network === 'mainnet' ? 'https://api.koios.rest/api/v1' : 'https://preprod.koios.rest/api/v1'; const resp = await fetch( `${base}/asset_addresses?_asset_policy=${policyId}&_asset_name=${assetHex}`, { headers: { Accept: 'application/json' } } ); const data = await resp.json(); return data?.find(e => parseInt(e.quantity) > 0)?.payment_address || null; } // Step 4: Display address + provider to user showResult(address, provider.provider, provider.policy_ids[network]);