{"path":"DEVIN_KNOWLEDGE.md","size":19426,"locked":false,"binary":false,"truncated":false,"content":"# Mappers Protocol — Devin AI Knowledge Base\n## Production-Grade Engineering Reference\n\n> Read this entire document before touching any file in this repo.\n> This is the authoritative source of truth for all architectural decisions.\n\n---\n\n## 1. Project Identity\n\n**What Mappers Is**\nA decentralized freelance settlement protocol on Solana. Clients lock SOL in an on-chain escrow vault. When a freelancer submits work, an autonomous AI oracle dispatches the deliverable to Gemini and Claude in parallel. Only when both models independently agree the work meets acceptance criteria does the oracle sign and execute the on-chain payment release. No platform fees. No human approval required for standard settlements.\n\n**What Mappers Is Not**\n- Not a token project — all settlement is native SOL, no protocol token\n- Not a DAO — no governance contracts\n- Not a lending protocol — funds are locked, not invested\n- Not a general-purpose oracle — the oracle is purpose-built for freelance deliverable verification\n\n**Live Program (Devnet)**\n```\nProgram ID: 52yt1gCbPeiKP4JYjUVKmMJSgBMMcUx8xRGqozMKX2Mu\nNetwork: Solana Devnet\nFramework: Anchor 0.30.1\n```\n\n**Repo**\n```\nhttps://github.com/mrphatom/mappers_contract\n```\n\n---\n\n## 2. Monorepo Structure\n\n```\nmappers_contract/\n├── programs/project_mappers/src/lib.rs   ← Anchor smart contract (HANDLE WITH CARE)\n├── tests/\n│   ├── project_mappers.ts                ← Anchor integration tests\n│   └── helpers.ts                        ← createEscrow(), expectAnchorError(), airdrop()\n├── oracle/\n│   ├── src/\n│   │   ├── index.ts                      ← Entry point: HTTP server + gRPC listener boot\n│   │   ├── listener.ts                   ← Helius gRPC subscription + account decoder\n│   │   ├── verification.ts               ← Gemini + Claude parallel verification engine\n│   │   ├── chain.ts                      ← On-chain transaction builder and signer\n│   │   ├── store.ts                      ← In-memory pending job registry\n│   │   ├── config.ts                     ← Env var loader and validator\n│   │   ├── types.ts                      ← Shared TypeScript interfaces\n│   │   └── utils.ts                      ← Shared utility functions\n│   ├── src/__tests__/                    ← Oracle unit tests (Vitest)\n│   │   ├── config.test.ts\n│   │   ├── index.test.ts\n│   │   ├── listener.test.ts\n│   │   ├── store.test.ts\n│   │   └── verification.test.ts\n│   ├── idl.json                          ← Copy of compiled program IDL\n│   ├── package.json\n│   ├── tsconfig.json\n│   └── vitest.config.ts\n├── apps/\n│   ├── dashboard/                        ← React 18 + Vite + shadcn/ui frontend\n│   │   ├── src/pages/                    ← create-job, jobs, job-detail, oracle, dashboard\n│   │   ├── src/components/               ← job-card, status-badge, wallet-button, wallet-provider\n│   │   └── src/hooks/use-mappers-client.ts ← Bridge between UI and on-chain program\n│   └── api-server/                       ← Express API server\n│       ├── src/app.ts\n│       ├── src/routes/jobs.ts\n│       └── src/routes/health.ts\n├── lib/\n│   ├── sdk/                              ← @mappers-protocol/sdk\n│   │   ├── client.ts                     ← MappersEscrowClient\n│   │   ├── oracle.ts                     ← MappersOracleClient\n│   │   ├── pda.ts                        ← PDA derivation utilities\n│   │   ├── types.ts                      ← Shared types\n│   │   ├── constants.ts                  ← Program ID, seeds, thresholds\n│   │   └── index.ts                      ← Public exports\n│   ├── api-spec/openapi.yaml             ← OpenAPI 3.0 spec (source of truth for API)\n│   ├── api-client-react/generated/       ← Auto-generated from OpenAPI spec (DO NOT EDIT MANUALLY)\n│   ├── api-zod/                          ← Auto-generated Zod schemas (DO NOT EDIT MANUALLY)\n│   └── db/\n│       ├── drizzle.config.ts\n│       └── schema/jobs.ts                ← Drizzle ORM jobs table\n├── scripts/\n│   └── e2e-devnet.ts                     ← End-to-end devnet test script\n├── shared/pda.ts                         ← Shared PDA derivation (used by tests + scripts)\n├── docs/wiki/                            ← 11 documentation files\n├── idl.json                              ← Root IDL (copy from oracle/idl.json after builds)\n├── Anchor.toml\n├── Cargo.toml\n├── package.json                          ← Root: ts-mocha test runner\n├── tsconfig.json                         ← Root TypeScript config\n└── Makefile                              ← Build/test shortcuts\n```\n\n---\n\n## 3. Smart Contract — Critical Rules\n\n### 3.1 DO NOT modify lib.rs without explicit instruction from the project lead.\n\nThe contract is deployed on devnet. Unauthorized changes require redeployment, IDL regeneration, and updates across oracle/idl.json, root idl.json, apps/dashboard, and lib/sdk. A botched deployment can brick the live program.\n\n### 3.2 Account Architecture — The Dual PDA Pattern\n\nEvery job creates two separate PDAs:\n\n**GigEscrow PDA** (stores state):\n```rust\nseeds = [b\"gig-escrow\", client_pubkey, job_id_bytes]\n```\n\n**Vault PDA** (holds SOL lamports):\n```rust\nseeds = [b\"vault\", client_pubkey, job_id_bytes]\n```\n\n**Why two PDAs?** The Vault must be owned by the System Program for native SOL transfer CPIs to work. If merged into one account, Anchor's ownership model conflicts with System Program signer authority. This is the correct pattern — do not suggest merging them.\n\n### 3.3 GigEscrow State Schema\n\n```rust\npub struct GigEscrow {\n    pub client:      Pubkey,    // 32 bytes\n    pub freelancer:  Pubkey,    // 32 bytes\n    pub oracle:      Pubkey,    // 32 bytes\n    pub amount:      u64,       // 8 bytes\n    pub job_id:      String,    // 4 + 32 bytes (max 32 char ID)\n    pub status:      JobStatus, // 1 byte (Pending/Completed/Cancelled)\n    pub escrow_bump: u8,        // 1 byte — GigEscrow PDA canonical bump\n    pub vault_bump:  u8,        // 1 byte — Vault PDA canonical bump\n}\n// MAXIMUM_SPACE = 151 bytes (8 discriminator + fields above)\n```\n\n**Critical:** Both `escrow_bump` AND `vault_bump` are stored separately at initialization. Using `escrow_bump` to sign for the vault is a CRITICAL bug that causes every settlement to revert at runtime. Always use `vault_bump` when signing for vault transfers.\n\n### 3.4 Job Lifecycle — State Machine\n\n```\nPENDING ──── oracle.releasePayment() ────▶ COMPLETED\nPENDING ──── oracle.cancelJob()      ────▶ CANCELLED\n```\n\nBoth `releasePayment` and `cancelJob` carry `close = client` which atomically closes the `GigEscrow` account and returns rent to the client. This is a constraint, not optional logic — do not remove it.\n\n### 3.5 Error Codes\n\n| Code | Name | Condition |\n|---|---|---|\n| 6000 | JobIdTooLong | job_id.len() > 32 |\n| 6001 | InvalidAmount | amount == 0 |\n| 6002 | AmountBelowRentExemption | amount < ~890,880 lamports |\n| 6003 | JobNotPending | status != Pending |\n| 6004 | UnauthorizedExecution | signer ≠ client and signer ≠ oracle |\n| 6005 | InvalidFreelancerTarget | passed freelancer ≠ stored freelancer |\n| 6006 | InvalidOracleAuthority | signer ≠ stored oracle |\n| 6007 | InvalidClientAuthority | passed client ≠ stored client |\n\n### 3.6 Instructions\n\n**initialize_job(job_id: String, amount: u64)**\n- Validates job_id ≤ 32 chars, amount > 0, amount ≥ rent-exempt minimum\n- Stores both bumps at initialization\n- Transfers SOL from client to vault via System Program CPI\n- Sets status = Pending\n\n**release_payment()**\n- Authority can be client OR oracle (hybrid approval model)\n- Reads and caches all state before any mutable borrow (reentrancy mitigation)\n- Uses stored vault_bump to sign vault transfer\n- Sets status = Completed\n- Escrow account closed via close = client constraint\n\n**cancel_job()**\n- Only oracle can sign\n- Refunds vault balance to client\n- Sets status = Cancelled\n- Escrow account closed via close = client constraint\n\n---\n\n## 4. Oracle Middleware — Architecture\n\n### 4.1 Boot Sequence (index.ts)\n1. Validate all env vars via config.ts\n2. Start Helius gRPC listener (listener.ts) — non-blocking background loop\n3. Start Express HTTP server on PORT (default 3001)\n4. Register graceful shutdown on SIGTERM/SIGINT\n\n### 4.2 gRPC Listener (listener.ts)\n- Uses `@triton-one/yellowstone-grpc` v2.x\n- Subscribes to ALL accounts owned by the program ID\n- Decodes each account update using BorshCoder from `@coral-xyz/anchor`\n- If decoded as GigEscrow with status Pending → upsert to store\n- If status Completed or Cancelled → remove from store\n- Reconnects with exponential backoff on stream drop (base 2s, max 60s)\n\n### 4.3 Verification Pipeline (verification.ts)\n\n```\nSubmission arrives\n       │\n       ▼\nbuildSystemPrompt() + buildUserPrompt(description, criteria, deliverable)\n       │\n       ├──▶ callGemini() ──────────────────────────────────┐\n       │    [gemini-2.5-flash via REST API]                 │\n       │                                                    ▼\n       └──▶ callClaude() ──────────────────────── ► determineOutcome()\n            [claude-sonnet-4-6 via Anthropic SDK]          │\n                                                            ▼\n                                              RELEASE / REFUND / ESCALATE\n```\n\n**Prompt injection defense:** All deliverable content is wrapped in XML delimiters (`<deliverable>`) and models are instructed to treat that content as data only, never as instructions.\n\n**Confidence thresholds:**\n- Approval requires ≥ 0.80 confidence from both models\n- Rejection requires ≥ 0.75 confidence from both models\n- Sub-threshold from either model → ESCALATE regardless of verdict\n\n**Response schema (both models must return):**\n```json\n{\n  \"work_approved\": boolean,\n  \"confidence_score\": float,\n  \"reasoning_summary\": \"string\"\n}\n```\n\n### 4.4 HTTP Endpoints\n\n| Method | Path | Description |\n|---|---|---|\n| GET | /health | Liveness check + pending job count |\n| GET | /jobs/:jobId | Fetch tracked job from in-memory store |\n| POST | /submit | Trigger AI verification for a deliverable |\n\n**POST /submit body:**\n```typescript\n{\n  jobId: string;\n  description: string;\n  acceptanceCriteria: string[];\n  deliverable: string;\n  deliverableType: \"url\" | \"text\" | \"json\" | \"ipfs\";\n}\n```\n\n### 4.5 Chain Interaction (chain.ts)\n- Loads oracle keypair from `ORACLE_PRIVATE_KEY` env var (base58 encoded)\n- Injects `PROGRAM_ID` into IDL at runtime (IDL address field override)\n- Uses `@coral-xyz/anchor` Program instance for all instruction calls\n- Derives Vault PDA using `PublicKey.findProgramAddressSync` at call time\n- Signs all transactions with oracle keypair\n\n---\n\n## 5. Environment Variables\n\n### Oracle (.env)\n```bash\n# Required — Solana\nSOLANA_RPC_URL=             # Helius devnet endpoint\nPROGRAM_ID=52yt1gCbPeiKP4JYjUVKmMJSgBMMcUx8xRGqozMKX2Mu\nORACLE_PRIVATE_KEY=         # Base58 private key of oracle signer\n\n# Required — Helius gRPC\nHELIUS_GRPC_ENDPOINT=       # Format: your-endpoint.helius-rpc.com:2053\nHELIUS_API_KEY=             # From Helius dashboard\n\n# Required — AI APIs\nGEMINI_API_KEY=\nANTHROPIC_API_KEY=\nGEMINI_MODEL=gemini-2.5-flash           # DO NOT use gemini-1.5-pro — deprecated\nANTHROPIC_MODEL=claude-sonnet-4-6       # Current Sonnet model\n\n# Confidence thresholds\nAPPROVAL_CONFIDENCE_THRESHOLD=0.80\nREJECTION_CONFIDENCE_THRESHOLD=0.75\n\n# Server\nPORT=3001\nNODE_ENV=development\n\n# Optional\nSENTRY_DSN=\n```\n\n---\n\n## 6. PDA Derivation — Source of Truth\n\nAlways derive PDAs exactly as follows. Any deviation breaks account validation:\n\n```typescript\n// GigEscrow PDA\nconst [escrowPda] = PublicKey.findProgramAddressSync(\n  [\n    Buffer.from(\"gig-escrow\"),\n    clientPublicKey.toBuffer(),\n    Buffer.from(jobId),       // jobId must be UTF-8 string, max 32 chars\n  ],\n  programId\n);\n\n// Vault PDA\nconst [vaultPda] = PublicKey.findProgramAddressSync(\n  [\n    Buffer.from(\"vault\"),\n    clientPublicKey.toBuffer(),\n    Buffer.from(jobId),\n  ],\n  programId\n);\n```\n\nSeeds are in `shared/pda.ts` and `lib/sdk/pda.ts` — use those functions, do not re-derive inline.\n\n---\n\n## 7. Tech Stack — Exact Versions\n\n| Layer | Technology | Version |\n|---|---|---|\n| Smart Contract | Rust + Anchor Framework | 0.30.1 |\n| Solana Runtime | Solana CLI | 1.18.x |\n| Oracle | Node.js | 18+ |\n| Oracle | TypeScript | 5.5.x |\n| Oracle | @coral-xyz/anchor | 0.30.0 |\n| Oracle | @solana/web3.js | 1.95.x |\n| Oracle | @triton-one/yellowstone-grpc | 2.x |\n| Oracle | @anthropic-ai/sdk | 0.27.x |\n| Oracle | @google/generative-ai | 0.15.x |\n| Oracle Test Runner | Vitest | latest |\n| Dashboard | React | 18 |\n| Dashboard | Vite | latest |\n| Dashboard | Tailwind CSS | 3.x |\n| Dashboard | shadcn/ui | latest |\n| API Server | Express | 4.19.x |\n| ORM | Drizzle ORM | latest |\n| API Spec | OpenAPI | 3.0 |\n| Code Generator | Orval | latest |\n| Package Manager | pnpm (workspace) | latest |\n| Anchor Tests | ts-mocha | 10.x |\n| Error Tracking | Sentry | 8.x |\n\n---\n\n## 8. Security Requirements — Non-Negotiable\n\nThese come from an independent security audit. Do not regress on any of these:\n\n### 8.1 Oracle Authority\n- The oracle keypair is currently a single hot signer (devnet only)\n- For mainnet: oracle authority MUST be replaced with a threshold-signature or multisig\n- Add emergency pause and key rotation controls before mainnet\n- Never hardcode or log the oracle private key\n\n### 8.2 AI Output Validation\n- Every model response must be validated against the strict JSON schema\n- Non-conforming responses must be rejected — never passed through with partial data\n- Log the full prompt, model version, artifact hash, and model verdict for every call\n- Confidence below threshold = ESCALATE, regardless of verdict\n\n### 8.3 Artifact Integrity\n- Currently accepting raw URLs — this is a known gap\n- Upcoming: require SHA-256 hash or IPFS CID in submission, verify before consensus\n- Never pass unvalidated deliverable content to the on-chain program\n\n### 8.4 API Mutations\n- PATCH /jobs/:jobId must be restricted to oracle/admin auth only\n- Database state must never override chain state — chain is the source of truth\n- Add chain-to-DB reconciliation\n\n### 8.5 Never Do These\n- Never remove `close = client` from ReleasePayment or CancelJob structs\n- Never use `escrow_bump` to sign for vault transfers (use `vault_bump`)\n- Never commit a `.env` file to the repository\n- Never log private keys, API keys, or seed phrases\n- Never change PDA seeds without updating ALL downstream consumers\n\n---\n\n## 9. Testing Commands\n\n```bash\n# Root — Anchor integration tests (requires local validator or devnet)\nanchor test                           # localnet\nanchor test --provider.cluster devnet # devnet\n\n# Oracle unit tests\ncd oracle && npx vitest               # run all\ncd oracle && npx vitest store         # run specific file\n\n# End-to-end devnet (requires oracle running in separate terminal)\ncd oracle && npm run dev              # terminal 1\nts-node scripts/e2e-devnet.ts        # terminal 2\n\n# Makefile shortcuts\nmake test          # anchor test localnet\nmake oracle-dev    # start oracle\nmake e2e           # run e2e script\nmake setup         # install all dependencies\n```\n\n---\n\n## 10. API-Generated Files — DO NOT Edit Manually\n\nThese files are auto-generated from `lib/api-spec/openapi.yaml` using Orval:\n- `lib/api-client-react/generated/` — entire directory\n- `lib/api-zod/` — entire directory\n\nIf you need to change the API shape, edit `openapi.yaml` first, then regenerate:\n```bash\ncd lib/api-spec && npx orval\n```\n\n---\n\n## 11. IDL Synchronization\n\nThe IDL file must be kept in sync across three locations:\n1. `idl.json` (repo root) — source after `anchor build`\n2. `oracle/idl.json` — oracle runtime reads this\n3. `lib/sdk/idl.ts` — SDK embeds the IDL\n\nAfter any contract change and rebuild, copy the new IDL to all three locations. The oracle cannot start with a stale IDL.\n\n---\n\n## 12. What Devin Can Work On Freely\n\n✅ `apps/dashboard/` — all React/TypeScript frontend work\n✅ `apps/api-server/` — Express routes, middleware, Drizzle schema\n✅ `oracle/src/` — TypeScript oracle source (with security rules above)\n✅ `oracle/src/__tests__/` — Vitest unit tests\n✅ `tests/` — Anchor integration tests\n✅ `lib/sdk/` — SDK TypeScript source\n✅ `lib/api-spec/openapi.yaml` — API spec (then regenerate clients)\n✅ `scripts/` — utility scripts\n✅ `docs/wiki/` — documentation markdown\n\n## 13. What Devin Must NOT Change Without Explicit Instruction\n\n🚫 `programs/project_mappers/src/lib.rs` — smart contract\n🚫 `idl.json` (all three copies) — only updated after anchor build\n🚫 `lib/api-client-react/generated/` — auto-generated, use orval\n🚫 `lib/api-zod/` — auto-generated, use orval\n🚫 `.env` files — never create, never commit\n🚫 PDA seed strings (`\"gig-escrow\"`, `\"vault\"`) — changing these breaks all existing accounts\n🚫 `MAXIMUM_SPACE = 151` calculation — changing this causes deserialization panics\n🚫 The dual bump storage pattern — removing vault_bump is a critical regression\n\n---\n\n## 14. Wallet Connect Pattern\n\nThe dashboard and scripts use `window.solana` directly — not the full `@solana/wallet-adapter` package suite. This is intentional to avoid package installation timeouts in the AI Studio build environment.\n\n```typescript\nconst sol = window.solana;\nif (!sol) { window.open(\"https://phantom.app\", \"_blank\"); return; }\nconst res = await sol.connect();\nconst pubkey = res.publicKey.toString();\n```\n\nDo not refactor this to use wallet-adapter unless explicitly asked.\n\n---\n\n## 15. Consensus Engine Reference\n\nThe core consensus logic lives in `oracle/src/verification.ts`:\n\n| Gemini | Claude | Outcome |\n|---|---|---|\n| APPROVED (≥0.80) | APPROVED (≥0.80) | `releasePayment` → freelancer |\n| REJECTED (≥0.75) | REJECTED (≥0.75) | `cancelJob` → refund client |\n| Divergent | — | `ESCALATE` → human arbitration |\n| Sub-threshold | — | `ESCALATE` → human arbitration |\n\nHuman arbitration cases: oracle stores the job in an escalation queue and does NOT execute any on-chain instruction. Funds remain locked in Pending state until a human manually resolves.\n\n---\n\n## 16. Key Links\n\n| Resource | URL |\n|---|---|\n| GitHub | https://github.com/mrphatom/mappers_contract |\n| Live Demo | https://mappers-contract--godtimebenson4.replit.app/ |\n| Landing Page | https://mappersio.vercel.app |\n| Solana Explorer (Devnet) | https://explorer.solana.com/address/52yt1gCbPeiKP4JYjUVKmMJSgBMMcUx8xRGqozMKX2Mu?cluster=devnet |\n| Whitepaper | mappers_whitepaper.md (repo root) |\n| Helius Docs | https://docs.helius.dev |\n| Anchor Docs | https://www.anchor-lang.com/docs |\n\n---\n\n*Mappers Protocol — Production Knowledge Base v1.0*\n*Last updated: June 2026*\n*License: MIT*\n"}