Changelog: Polkadot anchor integration now documented as part of the complete extended workflow—see agent-workplan.md for full technical direction including Google Drive upload, codex preloading, and multi-anchor workflow.
Extend Lockb0x Codex Forge to: 1. Use Google Drive for payload storage (unchanged). 2. Add a Polkadot-based anchor (anchorPolkadot()). 3. Record both Google and Polkadot identities in the Codex Entry.
⸻
🧠 Architecture Additions
Layer Description File Anchor Adapter anchorPolkadot(entry, polkadotAccount) — creates a Polkadot transaction embedding entry.storage.integrity_proof lib/protocol.js Identity Merge Extend createdBy to include both Google and Polkadot info popup.js Workflow Update If anchorType = polkadot, call anchorPolkadot() in addition to (or instead of) anchorGoogle() background.js / codex-workflow.js
⸻
⚙️ Step-by-Step Integration Plan
- Add Polkadot anchor adapter
Append this to the bottom of lib/protocol.js (after anchorGoogle()):
// Polkadot Anchor Adapter export async function anchorPolkadot(entry, polkadotAccount) { // Example uses Polkadot.js HTTP RPC endpoint const payloadHash = entry.storage?.integrity_proof; const timestamp = new Date().toISOString();
// Post to your relay or public endpoint
const res = await fetch("https://polkadot.api.subscan.io/api/scan/extrinsic", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
hash: payloadHash,
note: Lockb0x anchor for ${entry.id},
account: polkadotAccount?.address || "unknown",
time: timestamp,
}),
});
if (!res.ok) throw new Error([Polkadot Anchor] ${res.status}: ${await res.text()});
// Minimal result
return {
chain: "polkadot:relay",
tx: mock-tx-${Date.now()},
url: "https://polkadot.js.org/apps/#/explorer",
hash_alg: "sha-256",
timestamp,
};
}
Later you can swap the mock POST for @polkadot/api extrinsic submission.
⸻
- Extend popup anchor type options
In popup.html, add to the : Polkadot Anchor ⸻ Add Polkadot identity capture In popup.js, where createdBy is assembled (around L~850): Replace: let createdBy = { type: "mock" }; With: let createdBy = { type: "mock" }; if (anchorType && anchorType.value === "google" && googleAuthToken) { createdBy = await new Promise((resolve) => { chrome.storage.local.get(["googleUserProfile"], (result) => { if (result.googleUserProfile) { resolve({ type: "google", ...result.googleUserProfile }); } else resolve({ type: "google", email: "unknown" }); }); }); } else if (anchorType && anchorType.value === "polkadot") { // Retrieve Polkadot account from localStorage (set earlier via extension) const polkadotProfile = await chrome.storage.local.get(["polkadotProfile"]); createdBy = { type: "polkadot", address: polkadotProfile?.polkadotProfile?.address || "unknown", name: polkadotProfile?.polkadotProfile?.name || "Anonymous", }; } Later, a lightweight popup component can allow the user to paste or connect their Polkadot address and store it in chrome.storage.local.set({ polkadotProfile }). ⸻ Integrate into background.js workflow In background.js, import the new function: import { anchorPolkadot } from "./lib/protocol.js"; Then, right before calling processCodexEntryAndArchive(...), inject the Polkadot anchor logic: if (msg.payload.anchorType === "polkadot") { try { console.log("[background] Performing Polkadot anchoring..."); const polkadotAnchor = await anchorPolkadot(result.entry, msg.payload.createdBy); result.entry.anchor = polkadotAnchor; } catch (err) { console.error("[background] Polkadot anchoring failed:", err); } } Do this in both small-file (CREATE_CODEX_FROM_FILE) and large-file (END_LARGE_FILE_UPLOAD) paths. ⸻ Update Codex Entry builder Record both anchors (Google + Polkadot), modify updateCodexEntryWithStorage() in lib/codex-utils.js to allow entry.anchors[] array. ⸻ UI Feedback In popup.js, extend updateAuthUI() to show Polkadot address when anchorType.value === "polkadot". Example: if (anchorType.value === "polkadot") { googleSignInBtn.style.display = "none"; googleLogOutBtn.style.display = "none"; const { polkadotProfile } = await chrome.storage.local.get(["polkadotProfile"]); authStatus.textContent = polkadotProfile?.address ? Polkadot Connected: ${polkadotProfile.address.slice(0, 8)}... : "No Polkadot account configured"; authStatus.style.color = polkadotProfile?.address ? "#00796b" : "#c62828"; return; } ⸻ ✅ Summary of What Changes Area Change File Anchor Add anchorPolkadot() protocol.js Identity Capture Polkadot profile popup.js Background workflow Call anchorPolkadot() background.js UI Add “Polkadot” option + status display popup.html, popup.js ⸻ ✅ Implementation Status (Updated - PAPI Integration) All planned features have been successfully implemented with modern Polkadot API (PAPI): ✅ Anchor Adapter - PAPI Implementation - anchorPolkadot() in protocol.js and polkadot-utils.js Modern Implementation: Uses Polkadot API (PAPI) v1.20.1 with Smoldot light client v2.0.39 Decentralized: Connects to real Polkadot relay chain via light client (no RPC servers required) Real Data: Retrieves actual finalized block hash and block number from the blockchain Graceful Fallback: Falls back to deterministic mock mode when offline or connection times out Timeout Handling: 2 seconds in test mode, 8 seconds in production mode Returns all required schema fields: chain, tx, hash_alg, timestamp, blockHash, blockNumber, url Accepts both string addresses and account objects Anchor Payload: Prepared for future system.remark extrinsic submission with signing ✅ Identity Merge - createdBy extended in popup.js to include Polkadot profile Uses getPolkadotProfile() from polkadot-utils.js Falls back to default mock address if no profile configured ✅ Background Workflow - File handlers call anchorPolkadot() when anchorType === "polkadot" Implemented in both small-file-handler.js and large-file-handler.js No changes needed to background.js (delegates to handlers) ✅ UI Components - Complete Polkadot connection UI added "Polkadot Anchor" option in anchor type selector "Connect Polkadot Account" button with pink/magenta styling Connection status display showing connected address Prompts for address and optional name Address validation (47-48 character substrate format) ✅ Storage - Polkadot profile persistence via chrome.storage.local setPolkadotProfile() saves profile with address and name getPolkadotProfile() retrieves stored profile Full test coverage ✅ Testing - All tests passing with PAPI integration protocol.test.js validates anchorPolkadot return fields including url polkadot-utils.test.js validates profile storage functions and PAPI anchoring Tests verify both string and object account inputs Tests validate graceful fallback when PAPI connection times out Smoldot light client initialization verified in test output ✅ Documentation - README.md and docs updated with PAPI usage instructions Step-by-step guide for connecting Polkadot account Explanation of anchor fields and explorer links Detailed PAPI implementation notes Notes about light client, timeout handling, and fallback behavior Future roadmap for extrinsic signing PAPI Technical Details: Library: polkadot-api@1.20.1 with @polkadot-api/descriptors Light Client: Smoldot v2.0.39 (embedded WebAssembly) Chain: Polkadot relay chain (polkadot) Connection: Decentralized light client sync (no centralized RPC required) Fallback Strategy: Attempts PAPI connection first, falls back to deterministic mock on timeout/error Cleanup: Properly terminates Smoldot instance after use or on error Next Steps for Full On-Chain Anchoring: Add wallet integration (e.g., Polkadot.js extension, Talisman, SubWallet) Implement transaction signing with user's private key Submit signed system.remark extrinsic with anchor payload Wait for transaction inclusion and finalization Return real transaction hash in anchor.tx field The Polkadot anchor integration now uses modern PAPI with real blockchain connectivity! For complete workflow documentation, QA criteria, and agent collaboration patterns, see agent-workplan.md.