diff --git a/.env.example b/.env.example index 77a7b1b..30c3437 100644 --- a/.env.example +++ b/.env.example @@ -2,5 +2,9 @@ AI_API_KEY= AI_BASE_URL= AI_MODEL= XLAYER_RPC_URL=https://testrpc.xlayer.tech/terigon +XLAYER_MAINNET_RPC_URL=https://rpc.xlayer.tech +OKX_API_KEY= +OKX_SECRET_KEY= +OKX_API_PASSPHRASE= NEXT_PUBLIC_RISK_REGISTRY_ADDRESS= DEPLOYER_PRIVATE_KEY= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a0f7bc..68e1d35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [main, enhancement-v2, final-judge-upgrade, final-polish, v3-competition] + branches: [main, enhancement-v2, final-judge-upgrade, final-polish, v3-competition, codex/v4-okx-simulation] pull_request: branches: [main] @@ -35,3 +35,5 @@ jobs: - run: pnpm run pipeline:test - run: pnpm run token-standard:test - run: pnpm run security-benchmark:test + - run: pnpm run simulation:test + - run: pnpm run presentation:test diff --git a/README.md b/README.md index 546beda..9e0f3b2 100644 --- a/README.md +++ b/README.md @@ -1,191 +1,114 @@ # XGuard AI -> **The explainable pre-sign security layer for X Layer.** +> **Know what a transaction does before you sign.** -XGuard AI decodes transaction behavior, explains the deterministic consequences of signing, compares those consequences with the user's optional stated intent, inspects real X Layer on-chain context, and fuses deterministic security rules with AI explanation. AI may raise risk, but it cannot reduce known deterministic security signals. Users remain in control of every wallet action. +XGuard AI is an explainable pre-sign security layer for X Layer. It decodes calldata, applies deterministic security rules, inspects live X Layer RPC facts, compares user intent with observed behavior, and uses AI only as an advisory evidence interpreter. On X Layer Mainnet, V4 can add read-only OKX OnchainOS Transaction Simulation evidence. No provider is treated as a safety oracle, and nothing connects, signs, or broadcasts automatically. -**Live Demo:** https://xguard-ai-six.vercel.app · **GitHub:** https://github.com/leafwithered/xguard-ai · **Final Judge Demo Video:** https://github.com/leafwithered/xguard-ai/blob/main/demo/xguard-ai-build-x-demo.mp4 +**Production:** [xguard-ai-six.vercel.app](https://xguard-ai-six.vercel.app) · **Source:** [github.com/leafwithered/xguard-ai](https://github.com/leafwithered/xguard-ai) · **Demo:** [xguard-ai-build-x-demo.mp4](https://github.com/leafwithered/xguard-ai/blob/main/demo/xguard-ai-build-x-demo.mp4) -**Project X:** https://x.com/AevrynHQ · **Build X Post:** https://x.com/AevrynHQ/status/2090382549205873099 +**X account:** [@AevrynHQ](https://x.com/AevrynHQ) · **Build X post:** [View post](https://x.com/AevrynHQ/status/2090382549205873099) -![XGuard AI Final Judge interface](docs/assets/xguard-v2-hero.png) +![XGuard AI interface](docs/assets/xguard-v2-hero.png) -**Demo asset:** `demo/xguard-ai-build-x-demo.mp4` (1920×1080 H.264, approximately 1:34). It was composed from verified screenshots of the canonical Production deployment and demonstrates Judge Mode, Hybrid Analysis, Risk Fusion, real X Layer RPC intelligence, and the existing confirmed receipt without connecting a wallet or creating a transaction. +## What judges can verify -## 60–90 Second Judge Path (V3.1 candidate) +1. **Safe Transfer** — `8 LOW`, an explainable deterministic baseline. +2. **Ambiguous Approval** — deterministic `20 LOW`, `LOW` confidence, `UNDETERMINED`; `approve(address,uint256)` is not forced into ERC20 semantics without token-standard evidence. +3. **Suspicious Airdrop** — deterministic `78 HIGH`, `MISMATCH`; claim intent conflicts with `setApprovalForAll(true)`. +4. **Live OKX Mainnet Simulation** — a public historical approval fixture can be loaded explicitly for real, read-only provider evidence on Chain `196`. +5. **Existing receipt** — a real, user-signed RiskRegistry receipt is verifiable on X Layer Testnet (`1952`). -1. Open the V3.1 Preview and select **⚡ Try Judge Demo**. -2. Load **Safe Transfer**, then explicitly click **Analyze risk** to see the LOW baseline. -3. Load **Ambiguous Approval** to see `approve(address,uint256)` remain LOW-confidence and `UNDETERMINED`: the uint256 may be an ERC20 allowance or an ERC721 token ID, so a low heuristic score is not confirmation of safety. -4. Load **Suspicious Airdrop** to see a CLAIM intent conflict with `setApprovalForAll(true)`, producing a deterministic HIGH `MISMATCH` because the transaction grants contract-wide operator permission. -5. Select **Load Verified X Layer Receipt** to inspect the existing confirmed RiskRegistry transaction from real X Layer RPC data. +Judge Mode only loads examples and navigates. The user must explicitly select **Analyze risk**. It never connects a wallet, signs, records, or broadcasts. -Judge Mode only loads examples, navigates, and explains. It never auto-analyzes, connects a wallet, signs, records an assessment, or broadcasts a transaction. +## V4 Preview status -## Why XGuard Is Different +`codex/v4-okx-simulation` is a Preview-only candidate based on frozen V3 Stable commit `04575cc764163c7cb99b948c050e974e4cd20a2e` (`v3.1.1-stable`). It has not been merged into `main` and has not changed the canonical Production deployment. -- **Deterministic first:** known security rules and decoded permissions establish an inspectable floor. -- **Transaction consequences:** a deterministic engine answers “What happens if I sign this?” with source-labeled facts and no invented token metadata. -- **Intent vs Reality:** optional user intent is normalized, then compared against decoded behavior; deterministic mismatches may raise risk and cannot be downgraded by AI. -- **Transparent AI fusion:** `Final Risk = max(Deterministic Floor, AI Assessment)` is shown in the product. -- **Real X Layer intelligence:** `eth_getCode`, EIP-1967 inspection, `eth_call`, and `eth_estimateGas` provide live context with isolated timeouts. -- **Explainable evidence:** risk signals are labeled `RULE`, `DECODER`, `ON-CHAIN`, or `AI`; unavailable data is never fabricated. -- **User-controlled signing:** analysis and receipt recording are advisory and require explicit user actions. +- Testnet `1952` retains the V3 RPC/preflight path and never calls the Mainnet simulator. +- Mainnet `196` adds optional OKX OnchainOS simulation with `chainIndex: "196"`. +- A Live Provider badge appears only for normalized `AVAILABLE` evidence with HTTP `200` and business code `0` on Mainnet `196`. +- RPC and OKX simulation remain separate evidence sources; disagreement is surfaced and lowers confidence. +- Missing credentials, timeout, rate limiting, malformed responses, and provider errors never disable deterministic analysis. +- Empty provider risk entries mean only that no entries were returned—not that a transaction is safe. -## Stable Production Baseline +See [V4 evidence and live verification](docs/V4_OKX_SIMULATION.md), [integration guide](docs/INTEGRATION.md), and [75–90 second demo](docs/DEMO.md). -The verified Production baseline is commit `8f37ee568ee02cb7affa51069eac618c3adb9363` and remains live on the canonical Vercel Production URL. Production Hybrid Analysis is verified through the provider-neutral adapter; the upstream provider is selected only through server-side environment variables and is not asserted by the public client. The V1 RiskRegistry evidence and every public URL remain unchanged. +## Evidence hierarchy -- Safe Transfer: `8 LOW`, Hybrid Analysis -- Unlimited Approval: `72 HIGH`, decoded ERC20 `approve`, spender and `Amount: Unlimited` visible -- Suspicious Airdrop: `100 HIGH`, deterministic safety floor preserved through AI enrichment -- Clear Analysis, wallet connection, X Layer Testnet switching, and explicit user confirmation are included -- Contract V2 is documented as a proposal only; no new contract or chain transaction was introduced +XGuard reports these layers separately: -### V3 Preview Candidate - -The `v3-competition` branch adds an evidence-first analysis pipeline, deterministic Transaction Consequence Engine, optional Intent vs Reality comparison, selector-ambiguity hardening, and a reproducible 57-case security benchmark (34 corpus cases, 11 pipeline invariants, and 12 semantic/adversarial cases). It is developed and deployed as a Preview candidate only until explicit approval; it does not alter the existing Production deployment, RiskRegistry contract, or verified receipt. - -### V3.1 semantic correctness - -`approve(address,uint256)` and `transferFrom(address,address,uint256)` are shared by ERC20 and ERC721. V3.1 therefore decodes their signature-level facts first and leaves the uint256 meaning explicitly unresolved unless bounded ERC165 evidence positively identifies ERC721. A negative ERC721/ERC1155 result never proves ERC20. In particular, `maxUint256` is not called an unlimited ERC20 allowance without separately trusted ERC20 semantics. - -For smart contracts, XGuard checks `supportsInterface(0x80ac58cd)` and `supportsInterface(0xd9b67a26)` with bounded RPC calls. Positive results may establish ERC721 or ERC1155; unavailable, false, or inconsistent evidence remains `UNKNOWN`. `setApprovalForAll` is described as contract-wide NFT/multi-token operator permission without inventing a standard or collection identity. - -Empty calldata with native value is also target-aware: an EOA is described as an externally owned account, while a smart-contract target warns that `receive()` or `fallback()` logic may execute. XGuard never claims what that logic does. - -## Project Overview - -The application supports wallet connection, X Layer Testnet detection and switching, transaction decoding, real RPC intelligence, bounded preflight checks, provider-neutral AI analysis, deterministic fallback analysis, post-hoc transaction inspection, Judge Mode, user confirmation, and an optional on-chain risk receipt. - -### V3.1 Candidate Product - -- Hybrid Analysis returns structured risk analysis through an OpenAI-compatible Responses API without allowing AI to weaken deterministic signals. -- Local Analysis keeps the product usable when the configured AI provider is unavailable or returns invalid output. -- Every V3 report separates known-risk severity, analysis confidence, verdict, and current execution status, with plain-language reasons and a recommendation. -- Calldata decoding exposes signature-level approval/transfer facts, confirmed token-standard evidence, transfer recipients, raw uint256 values, and contract-wide operator permissions without forcing ERC20 semantics onto shared selectors. -- Demo presets make Safe Transfer, Ambiguous Approval, and Suspicious Airdrop paths reproducible without auto-analyzing or signing. -- Recording is optional and only starts after explicit user review and wallet confirmation. -- The UI waits for a successful X Layer receipt before displaying `Confirmed`. -- `RiskRegistry` is deployed on X Layer Testnet, and a real user-signed interaction is publicly verified below. -- The production deployment has been verified with a provider-backed Hybrid Analysis response. - -## Problem +| Layer | Meaning | +| --- | --- | +| Final Risk Score | `max(Deterministic Known Risk, AI Advisory)` | +| Deterministic Known Risk | Rule- and decoder-backed heuristic severity | +| AI Advisory | Evidence-grounded score/explanation; may raise but never lower the deterministic floor | +| Confidence / Verdict / Execution | Whether evidence is sufficient, whether the case is assessed, and current-state preflight outcome | +| Consequences / Intent | What signing does and whether that matches the user’s stated goal | +| X Layer RPC | Bytecode, scoped EIP-1967 implementation-slot check, `eth_call`, and `eth_estimateGas` | +| OKX Simulation | Additional Mainnet provider evidence: intention, changes, gas, failure reason, and risk entries | -Wallet confirmation screens expose raw addresses, values, and calldata that many users cannot interpret. Malicious approvals, unknown selectors, zero-address transfers, and social-engineering prompts can look similar to normal transactions. +The primary score is never labeled “known risk” when AI raised it. For example, an Ambiguous Approval may show deterministic `20 LOW`, AI `75 HIGH`, and final `75 HIGH` while remaining `LOW` confidence and `UNDETERMINED`. -## Solution +## Deterministic Safety Invariant -XGuard AI converts transaction fields into a `0–100` heuristic severity score, a `LOW / MEDIUM / HIGH` known-risk level, concise reasons, and an actionable recommendation. V3 separately reports `Analysis Confidence`, `Verdict`, and `Execution Status`, so a low score for unsupported behavior cannot look like confirmed safety. The app never signs automatically; users retain final control. +`Final Risk = max(Deterministic Known Risk, AI Advisory)` -The score is a deterministic heuristic severity score. It is not a probability of maliciousness, a statistically calibrated fraud probability, an audit result, or a safety guarantee; for example, `72` does not mean “72% malicious.” +AI can explain evidence or raise final risk, but it cannot reduce deterministic known-risk signals, rewrite RPC/simulation facts, change the deterministic verdict, or turn missing evidence into proof of safety. If the AI provider is missing, unavailable, slow, or malformed, XGuard falls back to Local Analysis. -The hybrid design combines a deterministic Risk Engine with a configurable OpenAI-compatible explanation layer. Production Hybrid Analysis is verified, while the public repository remains neutral about the server-configured upstream provider. If that provider is unavailable, Local Analysis remains fully demoable. +## Why X Layer and OKX -## How XGuard AI Works +X Layer is where transaction intent, contract behavior, and user confirmation meet. XGuard uses X Layer RPC for chain-specific bytecode and bounded preflight evidence on both supported networks. The existing `RiskRegistry` creates a compact, public proof that a user reviewed an assessment on Testnet without executing the analyzed transaction. -1. Connect an EVM wallet. -2. Detect or switch to X Layer Testnet (`1952`). -3. Enter `from`, `to`, value, calldata, and an optional plain-language expectation. -4. Decode supported calldata and run the deterministic Local Risk Engine. -5. Inspect the target through real X Layer RPC calls and run bounded `eth_call` / `eth_estimateGas` preflight checks—not a full state-diff simulation. -6. Build sanitized, normalized evidence containing decoded behavior, deterministic signals, consequences, contract facts, and execution facts. -7. Derive confidence, verdict, and execution state deterministically, then call the optional AI adapter once with that evidence. -8. Compare optional stated intent with decoded reality, enforce deterministic mismatch floors, and fuse AI advisory risk without allowing it to lower the floor. -9. Review consequences, Intent vs Reality, known-risk severity, confidence, execution, source-labeled signals, intelligence, reasons, and recommendation before signing. -10. Optionally confirm explicitly and record the assessment hash and score through `RiskRegistry`. +On X Layer Mainnet, OKX OnchainOS adds an independent read-only simulation view. That evidence improves consequence visibility but is deliberately bounded: provider evidence is not a safety verdict, and Testnet `1952` is never sent to the Mainnet-only simulation endpoint. ## Architecture ```mermaid flowchart TD - U[User Transaction] --> D[Transaction Decoder] - D --> L[Deterministic Risk Engine] - L --> CI[On-chain Contract Intelligence] - CI --> P[Transaction Preflight] - P --> C[Deterministic Consequences] - C --> E[Normalized Evidence] - E --> V[Confidence / Verdict / Execution] - E --> A[One AI Advisory Call] - I[Optional User Intent] --> M[Intent vs Reality] - A --> M - C --> M - M --> S[Deterministic Safety Floor] - S --> F[Risk Fusion] + U[User transaction + optional intent] --> D[Deterministic decoder and rules] + D --> R[X Layer RPC intelligence and preflight] + R --> O{Mainnet 196?} + O -->|yes| S[OKX read-only simulation] + O -->|no: Testnet 1952| E[Normalized evidence] + S --> E + E --> C[Consequences + confidence + verdict] + E --> A[One optional AI advisory call] + C --> F[Deterministic safety invariant] A --> F - A -. unavailable or invalid .-> S - V --> R[Final Evidence Report] - F --> R - R --> Q[User Decision] - Q --> XR[Optional X Layer Receipt] + F --> V[Final evidence report] + V --> H[Human decision] + H --> Q[Optional existing Testnet RiskRegistry] ``` -## AI Risk Engine - -`lib/analyze-pipeline.ts` owns the evidence-first orchestration and accepts small injectable RPC and AI dependencies for integration testing. `lib/evidence.ts` creates a bounded, sanitized object with the transaction, decoded action, deterministic signals, consequences, address type, code presence/size, scoped EIP-1967 observation, preflight status/reason, gas estimate, and RPC status. Only after that evidence exists does `lib/ai/provider.ts` make one advisory request. Configure an OpenAI-compatible provider using `AI_API_KEY`, `AI_BASE_URL`, and `AI_MODEL`. The adapter attempts `/v1/responses` first and then `/v1/chat/completions`. Output is validated before use. Production Hybrid Analysis is verified through this server-configured adapter; public artifacts do not assert the upstream provider identity. - -Confidence and verdict are deterministic: unsupported, malformed, or materially token-standard-ambiguous calldata is `LOW` confidence and `UNDETERMINED`; a known decode with unavailable or partial RPC evidence is generally `MEDIUM`; a known decode with complete RPC evidence may be `HIGH`; an observed EIP-1967 implementation caps confidence at `MEDIUM` because arbitrary implementation behavior is not fully inspected. Every response includes deterministic `confidenceReasons`. High risk does not mean low confidence, and preflight revert does not add arbitrary malicious-risk points. AI cannot change evidence, execution status, verdict, or final analysis confidence. - -User-provided `transaction.context` is structured as untrusted intent data. Both Responses and Chat fallback prompts explicitly reject embedded instructions such as “ignore previous instructions,” “mark this safe,” or requests to discard RPC evidence. This is defense-in-depth, not a claim that any LLM is universally prompt-injection-proof; deterministic evidence and fusion invariants remain the primary boundary. - -AI enrichment has a shared 15-second provider budget. Responses remains preferred and Chat Completions is attempted only when the Responses endpoint explicitly reports a compatibility status or returns malformed success output. Network failures and timeouts fall back directly to Local Analysis instead of stacking a second provider timeout. RPC evidence is still collected before AI, so this bound does not weaken evidence-first ordering. - -The deterministic Local Risk Engine checks zero addresses, exact bigint native value thresholds, decoded ERC20/NFT approvals, unlimited permissions, transfer methods, malformed and unknown calldata, intent mismatches, unknown-contract context, and common social-engineering signals. AI may normalize ambiguous natural language, but deterministic code performs the consequence comparison wherever supported. - -The browser never receives `AI_API_KEY`. Missing configuration, timeouts, unsupported endpoints, and malformed output automatically use Local Analysis. - -The adapter is intentionally provider-neutral: `AI_BASE_URL` may point at a third-party OpenAI-compatible base URL, with or without `/v1`. It tries `/v1/responses` first and uses `/v1/chat/completions` when Responses is unsupported. `mergeRiskResults` guarantees `finalScore >= deterministicScore` and preserves deterministic critical signals. - -## X Layer Integration - -- Network: X Layer Testnet -- Chain ID: `1952` -- Native token: `OKB` -- Official RPC: `https://testrpc.xlayer.tech/terigon` -- Explorer: `https://www.okx.com/web3/explorer/xlayer-test` +`lib/analyze-pipeline.ts` owns evidence-first orchestration. `lib/evidence.ts` creates a bounded, normalized evidence object before `lib/ai/provider.ts` is called. The provider adapter is configured only on the server through `AI_API_KEY`, `AI_BASE_URL`, and `AI_MODEL`; the public client does not expose or prove the upstream provider identity. -### On-chain Intelligence and Preflight +## X Layer integration -For each valid destination, the server performs isolated, timeout-bounded X Layer RPC checks: +| Analysis network | Chain ID | RPC | OKX Transaction Simulation | +| --- | ---: | --- | --- | +| X Layer Testnet | `1952` | `https://testrpc.xlayer.tech/terigon` | Unsupported; never called | +| X Layer Mainnet | `196` | `https://rpc.xlayer.tech` | V4 Preview, `chainIndex: "196"` | -- `eth_getCode` distinguishes an EOA from a smart contract and reports actual bytecode size. -- `eth_getStorageAt` inspects the EIP-1967 implementation slot without claiming trust, verification, or audit status. -- `eth_call` reports whether the proposed call succeeds or reverts and decodes standard `Error(string)` and `Panic(uint256)` data when available. -- `eth_estimateGas` reports an estimate when the RPC can produce one. +RPC checks are isolated and timeout-bounded: -RPC failure never blocks deterministic analysis. Unavailable results are labeled `Unavailable`; XGuard does not invent contract reputation or simulation output. The Transaction Analyzer can also load a real X Layer transaction and receipt for clearly labeled **post-hoc** analysis. +- `eth_getCode` identifies EOA versus contract and reports bytecode size. +- `eth_getStorageAt` checks only the EIP-1967 implementation slot; it does not exclude every proxy type. +- `eth_call` records current-state success/revert evidence. +- `eth_estimateGas` reports an estimate when available. -## Smart Contract +These are bounded preflight checks, not an audit or full trace/state-diff guarantee. -`contracts/RiskRegistry.sol` stores an assessment by `analysisHash` with the submitting user, risk score, and timestamp. It holds no funds and creates no token. - -```solidity -recordAssessment(bytes32 analysisHash, uint8 riskScore) -``` - -Deployed testnet contract: `0xf4505A4e8dEca4659b8A2054555788Ddc1f5AcE5` -Deployment transaction: `0xf4169572833b69bb7a5cb234d092f7ab1b27e15d2520e6544591c2358533c75b` -[Open in X Layer Testnet Explorer](https://www.okx.com/web3/explorer/xlayer-test/address/0xf4505A4e8dEca4659b8A2054555788Ddc1f5AcE5) - -### Verified user interaction +## Verified on-chain evidence - Network: X Layer Testnet (`1952`) -- Contract: `0xf4505A4e8dEca4659b8A2054555788Ddc1f5AcE5` -- Method: `recordAssessment(bytes32,uint8)` -- User interaction transaction: `0x1492bc179e98fe5fe79add3528f8f1f26990ab37e189a98d4c4a052d6fd11bcb` -- Receipt status: success (`0x1`) -- Event: `RiskAssessmentRecorded` emitted with risk score `12` -- Explorer: [View transaction](https://www.okx.com/web3/explorer/xlayer-test/tx/0x1492bc179e98fe5fe79add3528f8f1f26990ab37e189a98d4c4a052d6fd11bcb) - -## Tech Stack +- RiskRegistry: [`0xf4505A4e8dEca4659b8A2054555788Ddc1f5AcE5`](https://www.okx.com/web3/explorer/xlayer-test/address/0xf4505A4e8dEca4659b8A2054555788Ddc1f5AcE5) +- Deployment transaction: `0xf4169572833b69bb7a5cb234d092f7ab1b27e15d2520e6544591c2358533c75b` +- Verified user transaction: [`0x1492bc179e98fe5fe79add3528f8f1f26990ab37e189a98d4c4a052d6fd11bcb`](https://www.okx.com/web3/explorer/xlayer-test/tx/0x1492bc179e98fe5fe79add3528f8f1f26990ab37e189a98d4c4a052d6fd11bcb) +- Receipt: success; `RiskAssessmentRecorded` emitted with score `12` -- Next.js 14, React, TypeScript -- viem and injected EVM wallets -- Configurable OpenAI-compatible provider adapter -- Solidity 0.8.24, Hardhat, ethers -- X Layer Testnet +The deployed V1 contract holds no funds and creates no token. Contract V2 remains a proposal only; V4 deploys no contract and creates no transaction. -## Local Development +## Local development ```bash pnpm install --frozen-lockfile @@ -193,36 +116,28 @@ copy .env.example .env.local pnpm run dev ``` -Open `http://localhost:3000`. The app works without AI credentials using Local Analysis. +Open `http://localhost:3000`. Without AI or OKX credentials, deterministic Local Analysis and the Testnet RPC path remain usable. -The public production deployment is available at https://xguard-ai-six.vercel.app. - -## Environment Variables +### Server-side configuration | Variable | Purpose | | --- | --- | -| `AI_API_KEY` | AI provider key; server-side only | -| `AI_BASE_URL` | OpenAI-compatible provider base URL, with or without `/v1` | -| `AI_MODEL` | Provider-specific model identifier | -| `XLAYER_RPC_URL` | X Layer Testnet deployment RPC | -| `NEXT_PUBLIC_RISK_REGISTRY_ADDRESS` | Deployed registry address used by the browser | -| `DEPLOYER_PRIVATE_KEY` | Deployment wallet key; never commit | - -## Contract Deployment - -```bash -pnpm run contract:compile -pnpm run contract:test -pnpm run contract:deploy -``` +| `AI_API_KEY` | AI provider key | +| `AI_BASE_URL` | OpenAI-compatible base URL | +| `AI_MODEL` | Provider model identifier | +| `XLAYER_RPC_URL` | Testnet RPC | +| `XLAYER_MAINNET_RPC_URL` | Mainnet RPC | +| `OKX_API_KEY` | OKX API key | +| `OKX_SECRET_KEY` | OKX signing secret | +| `OKX_API_PASSPHRASE` | OKX passphrase | +| `NEXT_PUBLIC_RISK_REGISTRY_ADDRESS` | Public deployed Testnet registry address | -Deployment requires a user-controlled private key and testnet OKB. Never commit `.env.local` or expose a private key to the browser. +`DEPLOYER_PRIVATE_KEY` is needed only for explicitly authorized contract deployment and must never be configured in the browser or committed. V4 does not use it. -## Testing +## Verification ```bash pnpm run build -pnpm run contract:compile pnpm run contract:test pnpm run risk:test pnpm run ai:test @@ -237,44 +152,24 @@ pnpm run intent:test pnpm run pipeline:test pnpm run token-standard:test pnpm run security-benchmark:test +pnpm run simulation:test +pnpm run presentation:test ``` -The full 57-case V3.1 benchmark and its invariants are documented in [docs/SECURITY_BENCHMARK.md](docs/SECURITY_BENCHMARK.md). - -The browser smoke path is documented in [docs/DEMO.md](docs/DEMO.md). The API returns `400` for invalid transaction input and keeps Local Analysis available when the configured provider fails. - -`npm run contract:deploy` is intentionally not part of the automated test run because it requires a user-controlled deployer key and testnet OKB. - -## Demo Flow - -Use the 60–90 second path in [docs/DEMO.md](docs/DEMO.md) to demonstrate Safe Transfer, Ambiguous Approval, Suspicious Airdrop, Risk Fusion, and Contract Intelligence without connecting a wallet or creating a new transaction. Finish with the existing verified X Layer receipt as optional public evidence. - -## Security Disclaimer - -XGuard AI is an advisory prototype, not an audit, wallet firewall, or guarantee of transaction safety. AI and deterministic rules can miss malicious behavior or produce false positives. Verify contracts, permissions, amounts, and destinations independently before signing. +The V3.1 security corpus contains 57 adversarial and invariant cases. V4 adds authentication, network-boundary, normalization, failure-isolation, evidence-immutability, live-badge eligibility, and score-semantics regression coverage. ## Limitations -- Transaction Preflight uses `eth_call` and `eth_estimateGas`; it is not a full state-diff simulation and does not prove contract safety. -- Contract reputation and verified source metadata are not yet integrated. -- The on-chain registry stores the submitting address, score, hash, and timestamp only; it does not execute or protect transactions. -- AI provider behavior depends on the configured service and its OpenAI-compatible endpoint behavior. - -## Roadmap +- Scores are heuristic severity, not calibrated fraud probabilities. +- RPC preflight and OKX simulation are current-state, bounded evidence—not proof of safety. +- Contract reputation and verified-source provenance are not yet integrated. +- AI and deterministic rules can miss malicious behavior or create false positives. +- This prototype has a basic in-memory API rate limit and no availability SLA. -- Wallet SDK/API integration for other X Layer applications. -- Browser extension and wallet-native pre-sign delivery after the web prototype. -- Verified source metadata and bytecode provenance from authoritative sources. -- Full state-diff simulation with explicit trace provenance. -- Evidence-backed phishing intelligence without fabricated reputation scores. -- X Layer mainnet deployment only after the required testnet phase and a separate security review. +## Historical evidence note -The append-only registry design is documented in [docs/CONTRACT_V2.md](docs/CONTRACT_V2.md). It is a proposal only; the deployed V1 contract and verified evidence remain unchanged. +The unchanged public video captures the earlier stable Production Judge path, including the historical Unlimited Approval result `72 HIGH`. It is retained as stable Production evidence, not as the current V4 Preview Judge semantics. The current Preview path uses selector-hardened Ambiguous Approval instead. ## License -Released under the [MIT License](LICENSE). - -## Submission - -See [docs/SUBMISSION.md](docs/SUBMISSION.md) for the complete public evidence checklist and final submission fields. Contact email is intentionally omitted from the public repository and provided only in the official form. +Released under the [MIT License](LICENSE). Submission fields are in [docs/SUBMISSION.md](docs/SUBMISSION.md); contact email remains only in the official form. diff --git a/app/globals.css b/app/globals.css index f639f3e..4badc09 100644 --- a/app/globals.css +++ b/app/globals.css @@ -41,12 +41,12 @@ h1 { font-size: clamp(44px, 7vw, 78px); line-height: .94; margin: 16px 0 18px; m .signal strong { color: var(--text); text-align: right; } .workspace { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); gap: 22px; align-items: start; } .workspace > .panel { min-width: 0; } -.capability-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; margin: 0 0 22px; overflow: hidden; border: 1px solid var(--line); border-radius: 14px; background: var(--line); } +.capability-strip { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1px; margin: 0 0 22px; overflow: hidden; border: 1px solid var(--line); border-radius: 14px; background: var(--line); } .capability-strip span { padding: 13px; text-align: center; background: rgba(16,22,33,.96); color: var(--muted); font-size: 12px; } .judge-mode { margin-bottom: 22px; padding: 24px; border: 1px solid rgba(119,242,194,.3); border-radius: 22px; background: linear-gradient(145deg, rgba(16,22,33,.96), rgba(16,40,40,.82)); } .judge-mode h2 { margin: 8px 0; } .judge-mode .panel-heading p { margin: 0; } -.judge-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 20px; } +.judge-steps { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; margin-top: 20px; } .judge-steps article { display: flex; flex-direction: column; align-items: flex-start; min-width: 0; padding: 15px; border: 1px solid var(--line); border-radius: 14px; background: rgba(8,11,18,.52); } .judge-steps article > b { color: var(--accent); font-size: 11px; } .judge-steps article > span { margin-top: 12px; font-weight: 800; } @@ -65,8 +65,9 @@ h1 { font-size: clamp(44px, 7vw, 78px); line-height: .94; margin: 16px 0 18px; m .presets strong, .presets span { display: block; } .presets span { color: var(--muted); font-size: 11px; line-height: 1.35; margin-top: 6px; } label { display: block; color: var(--muted); font-size: 13px; margin: 18px 0 8px; } -textarea, input { width: 100%; background: var(--panel-soft); border: 1px solid var(--line); border-radius: 12px; color: var(--text); padding: 13px; outline: none; } -textarea:focus, input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(119,242,194,.08); } +textarea, input, select { width: 100%; background: var(--panel-soft); border: 1px solid var(--line); border-radius: 12px; color: var(--text); padding: 13px; outline: none; } +textarea:focus, input:focus, select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(119,242,194,.08); } +select { color-scheme: dark; } textarea { min-height: 110px; resize: vertical; } .field-note { margin-top: 7px; color: var(--muted); font-size: 11px; line-height: 1.4; } .row { display: grid; grid-template-columns: .7fr 1.3fr; gap: 12px; } @@ -88,20 +89,48 @@ textarea { min-height: 110px; resize: vertical; } .score-copy strong { font-size: 20px; margin: 5px 0; } .score-copy small { color: var(--muted); } .analysis-mode { display: inline-block; border: 1px solid rgba(119,242,194,.3); border-radius: 999px; padding: 6px 10px; color: var(--accent); font-size: 12px; } +.score-breakdown { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 0 0 12px; } +.score-breakdown > div { display: grid; gap: 5px; padding: 11px; border: 1px solid var(--line); border-radius: 10px; background: rgba(8,11,18,.45); } +.score-breakdown span { color: var(--muted); font-size: 10px; } +.score-breakdown strong { font-size: 13px; } .assessment-dimensions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 12px; } .assessment-dimensions > div { display: grid; gap: 5px; padding: 11px; border: 1px solid var(--line); border-radius: 10px; background: rgba(8,11,18,.45); } .assessment-dimensions span { color: var(--muted); font-size: 9px; letter-spacing: .06em; text-transform: uppercase; } .assessment-dimensions strong { font-size: 12px; word-break: break-word; } .assessment-dimensions.verdict-undetermined { border-left: 3px solid var(--warning); padding-left: 8px; } .confidence-reasons { margin: 10px 0 0; padding-left: 18px; color: var(--muted); font-size: 11px; line-height: 1.55; } -.decoded-card, .intelligence-card, .fusion-card, .consequence-card, .intent-card, .explanation, .record-card { margin-top: 18px; background: var(--panel-soft); border: 1px solid var(--line); border-radius: 14px; padding: 16px; } -.decoded-card h3, .intelligence-card h3, .fusion-card h3, .consequence-card h3, .intent-card h3, .signal-section h3, .explanation h3 { margin: 0 0 10px; font-size: 14px; } +.decoded-card, .intelligence-card, .simulation-card, .timing-card, .fusion-card, .consequence-card, .intent-card, .explanation, .record-card { margin-top: 18px; background: var(--panel-soft); border: 1px solid var(--line); border-radius: 14px; padding: 16px; } +.decoded-card h3, .intelligence-card h3, .simulation-card h3, .timing-card h3, .fusion-card h3, .consequence-card h3, .intent-card h3, .signal-section h3, .explanation h3 { margin: 0 0 10px; font-size: 14px; } .decoded-grid { display: grid; grid-template-columns: 96px minmax(0,1fr); gap: 8px 12px; font-size: 12px; } .decoded-grid span { color: var(--muted); } .decoded-grid strong { word-break: break-all; } .decoded-card p, .intelligence-card p, .fusion-card p, .explanation p { margin-bottom: 0; font-size: 13px; } .intelligence-card { border-color: rgba(119,242,194,.18); } .intelligence-card code { color: var(--accent); } +.simulation-card { border-color: rgba(181,166,255,.3); } +.simulation-card > p { color: var(--muted); font-size: 12px; line-height: 1.5; } +.simulation-status { border: 1px solid var(--line); border-radius: 999px; padding: 5px 8px; color: var(--muted); font-size: 10px; } +.simulation-badges { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 7px; } +.live-provider-badge { display: inline-flex; align-items: center; gap: 6px; border: 1px solid rgba(119,242,194,.45); border-radius: 999px; padding: 5px 8px; color: var(--accent); font-size: 9px; font-weight: 800; letter-spacing: .04em; } +.simulation-available { border-color: rgba(181,166,255,.45); color: #b5a6ff; } +.simulation-error { border-color: rgba(255,124,139,.45); color: var(--danger); } +.simulation-detail { padding: 10px; border-radius: 9px; background: rgba(8,11,18,.45); } +.simulation-subsection { margin-top: 14px; display: grid; gap: 8px; } +.simulation-subsection > strong { font-size: 12px; } +.simulation-subsection > p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.45; } +.simulation-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; } +.simulation-list li { display: grid; gap: 5px; padding: 10px; border-radius: 9px; background: rgba(8,11,18,.45); } +.simulation-list li > div { display: flex; justify-content: space-between; gap: 8px; color: var(--muted); font-size: 10px; } +.simulation-list p, .simulation-list code, .simulation-list small { margin: 0; overflow-wrap: anywhere; } +.simulation-list p { font-size: 12px; } +.simulation-list code, .simulation-list small { color: var(--muted); font-size: 10px; } +.evidence-inconsistency { margin-top: 14px; padding: 11px; border-left: 3px solid var(--warning); border-radius: 9px; background: rgba(249,198,107,.08); } +.evidence-inconsistency strong { color: var(--warning); font-size: 12px; } +.evidence-inconsistency ul { margin: 7px 0 0; padding-left: 18px; color: var(--muted); font-size: 11px; } +.timing-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: 8px; } +.timing-grid div { display: grid; gap: 4px; padding: 10px; border-radius: 9px; background: rgba(8,11,18,.45); } +.timing-grid span { color: var(--muted); font-size: 9px; text-transform: uppercase; } +.timing-grid strong { font-size: 12px; } .card-title { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; } .card-title .eyebrow { display: block; margin-bottom: 7px; font-size: 10px; } .rpc-status { border: 1px solid var(--line); border-radius: 999px; padding: 5px 8px; color: var(--muted); font-size: 10px; } @@ -142,6 +171,7 @@ textarea { min-height: 110px; resize: vertical; } .source-rule { color: var(--danger); background: rgba(255,124,139,.1); } .source-decoder { color: var(--warning); background: rgba(249,198,107,.1); } .source-on-chain { color: var(--accent); background: rgba(119,242,194,.1); } +.source-okx { color: #b5a6ff; background: rgba(181,166,255,.1); } .safety-guarantee { display: grid; gap: 8px; margin-top: 18px; border: 1px solid rgba(119,242,194,.24); border-radius: 14px; padding: 15px; background: rgba(119,242,194,.06); } .safety-guarantee strong { font-size: 13px; line-height: 1.45; } .recommendation { background: rgba(119,242,194,.07); border: 1px solid rgba(119,242,194,.18); border-radius: 12px; padding: 14px; } @@ -170,6 +200,7 @@ textarea { min-height: 110px; resize: vertical; } .topbar { margin-bottom: 34px; } .result-panel { min-height: 0; } .judge-steps { grid-template-columns: repeat(2, 1fr); } + .capability-strip { grid-template-columns: repeat(3, 1fr); } } @media (max-width: 620px) { @@ -183,7 +214,7 @@ textarea { min-height: 110px; resize: vertical; } .panel-heading > button { width: 100%; } .presets, .row, .why-xlayer, .tx-search, .judge-steps { grid-template-columns: 1fr; } .capability-strip { grid-template-columns: repeat(2, 1fr); } - .fusion-grid, .assessment-dimensions { grid-template-columns: 1fr; } + .fusion-grid, .assessment-dimensions, .timing-grid, .score-breakdown { grid-template-columns: 1fr; } .presets button { min-height: 0; } .score { width: 88px; height: 88px; flex-basis: 88px; } .record-card > div:first-child { display: grid; } diff --git a/app/page.tsx b/app/page.tsx index 4c80ef1..bbeace2 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,17 +1,20 @@ "use client"; import { useEffect, useLayoutEffect, useMemo, useReducer, useState } from "react"; -import { createPublicClient, createWalletClient, custom, http, isAddress, keccak256, toHex, type Address } from "viem"; +import { createPublicClient, createWalletClient, custom, formatUnits, http, isAddress, keccak256, toHex, type Address } from "viem"; import { riskRegistryAbi, xLayerTestnet } from "../lib/xlayer"; import type { RiskInput, RiskResult } from "../lib/risk"; import type { ContractIntelligence } from "../lib/chain/intelligence"; import type { TransactionConsequence } from "../lib/consequence"; import type { IntentComparison } from "../lib/intent"; import type { AnalysisConfidence, AnalysisVerdict, ExecutionStatus } from "../lib/evidence"; +import { getAnalysisNetworkConfig, type AnalysisNetwork } from "../lib/network"; +import type { SimulationEvidence } from "../lib/okx/simulation"; import type { XLayerTransaction } from "../lib/chain/transaction-analyzer"; -import { judgePresets as presets } from "../lib/presets"; +import { judgePresets as presets, publicMainnetSimulationFixture } from "../lib/presets"; import { currentAnalysisResult, invalidateStaleAnalysis } from "../lib/analysis-state"; import { initialRecordState, isRecordPending, reduceRecordState } from "../lib/transaction-state"; +import { buildRiskScorePresentation, isLiveOkxProviderEvidence } from "../lib/presentation"; import type { WalletProvider } from "../types/ethereum"; const registryAddress = process.env.NEXT_PUBLIC_RISK_REGISTRY_ADDRESS as Address | undefined; @@ -29,15 +32,25 @@ type AnalysisResult = RiskResult & { contractIntelligence: ContractIntelligence; consequences: TransactionConsequence[]; intentComparison: IntentComparison; + analysisTimings: { rpcMs: number; simulationMs: number; aiMs: number; totalMs: number }; + simulationEvidence: SimulationEvidence; + evidenceConsistency: { status: "CONSISTENT" | "INCONSISTENT" | "NOT_COMPARABLE"; reasons: string[] }; }; const shortAddress = (value: string) => value ? `${value.slice(0, 6)}…${value.slice(-4)}` : ""; -const signalSources = new Set(["RULE", "DECODER", "ON-CHAIN", "AI"]); -const consequenceSources = new Set(["DECODER", "VALUE", "ON_CHAIN"]); +const signalSources = new Set(["RULE", "DECODER", "ON-CHAIN", "OKX", "AI"]); +const consequenceSources = new Set(["DECODER", "VALUE", "ON_CHAIN", "SIMULATION"]); const intentStatuses = new Set(["MATCH", "PARTIAL", "MISMATCH", "UNKNOWN"]); const analysisConfidences = new Set(["HIGH", "MEDIUM", "LOW"]); const analysisVerdicts = new Set(["ASSESSED", "UNDETERMINED"]); const executionStatuses = new Set(["SUCCEEDED", "REVERTED", "UNAVAILABLE"]); +const simulationStatuses = new Set(["AVAILABLE", "UNAVAILABLE", "UNSUPPORTED", "ERROR"]); +const consistencyStatuses = new Set(["CONSISTENT", "INCONSISTENT", "NOT_COMPARABLE"]); + +function formatSimulationAmount(asset: SimulationEvidence["assetChanges"][number]) { + if ((asset.assetType !== "NATIVE" && asset.assetType !== "ERC20") || !Number.isInteger(asset.decimals) || asset.decimals === null || asset.decimals < 0 || asset.decimals > 36) return null; + try { return formatUnits(BigInt(asset.rawValue), asset.decimals); } catch { return null; } +} function isCurrentAnalysisResult(value: unknown): value is AnalysisResult { if (!value || typeof value !== "object") return false; @@ -45,6 +58,15 @@ function isCurrentAnalysisResult(value: unknown): value is AnalysisResult { const validSignals = (signals: unknown) => Array.isArray(signals) && signals.every((item) => item && typeof item === "object" && signalSources.has(String((item as { source?: unknown }).source))); const validConsequences = Array.isArray(candidate.consequences) && candidate.consequences.every((item) => item && typeof item === "object" && consequenceSources.has(String((item as { evidenceSource?: unknown }).evidenceSource))); const validIntent = Boolean(candidate.intentComparison && intentStatuses.has(String(candidate.intentComparison.status))); + const validTimings = Boolean(candidate.analysisTimings && [candidate.analysisTimings.rpcMs, candidate.analysisTimings.simulationMs, candidate.analysisTimings.aiMs, candidate.analysisTimings.totalMs].every((duration) => typeof duration === "number" && Number.isFinite(duration) && duration >= 0)); + const validSimulation = Boolean(candidate.simulationEvidence + && simulationStatuses.has(String(candidate.simulationEvidence.status)) + && Array.isArray(candidate.simulationEvidence.assetChanges) + && Array.isArray(candidate.simulationEvidence.risks)); + const validConsistency = Boolean(candidate.evidenceConsistency + && consistencyStatuses.has(String(candidate.evidenceConsistency.status)) + && Array.isArray(candidate.evidenceConsistency.reasons) + && candidate.evidenceConsistency.reasons.every((reason) => typeof reason === "string")); return typeof candidate.finalScore === "number" && typeof candidate.deterministicScore === "number" && analysisConfidences.has(String(candidate.analysisConfidence)) @@ -56,7 +78,10 @@ function isCurrentAnalysisResult(value: unknown): value is AnalysisResult { && validSignals(candidate.advisorySignals) && Boolean(candidate.contractIntelligence) && validConsequences - && validIntent; + && validIntent + && validTimings + && validSimulation + && validConsistency; } export default function Home() { @@ -69,6 +94,7 @@ export default function Home() { const [value, setValue] = useState("0"); const [data, setData] = useState("0x"); const [context, setContext] = useState(""); + const [analysisNetwork, setAnalysisNetwork] = useState("XLAYER_TESTNET"); const [result, setResult] = useState(null); const [lastInput, setLastInput] = useState(null); const [analyzing, setAnalyzing] = useState(false); @@ -80,10 +106,12 @@ export default function Home() { const [transactionLoading, setTransactionLoading] = useState(false); const [transactionError, setTransactionError] = useState(""); const [judgeModeOpen, setJudgeModeOpen] = useState(false); - const networkName = chainId === null ? "Not connected" : chainId === 1952 ? "X Layer Testnet" : `Wrong network · ${chainId}`; + const walletNetworkName = chainId === null ? "Wallet not connected" : chainId === 1952 ? "Wallet on X Layer Testnet" : `Wallet network · ${chainId}`; + const analysisNetworkConfig = getAnalysisNetworkConfig(analysisNetwork); + const networkName = analysisNetworkConfig.name; const isCorrectNetwork = chainId === 1952; const recordPending = isRecordPending(recordState); - const currentTransactionInput: RiskInput = { from, to, value, data, context }; + const currentTransactionInput: RiskInput = { from, to, value, data, context, analysisNetwork }; const activeResult = currentAnalysisResult({ result, lastInput, reviewed }, currentTransactionInput); const analysisHash = useMemo(() => lastInput && activeResult ? keccak256(toHex(JSON.stringify({ input: lastInput, result: activeResult }))) : null, [lastInput, activeResult]); @@ -101,13 +129,14 @@ export default function Home() { setValue(parsed.input.value); setData(parsed.input.data); setContext(parsed.input.context); + setAnalysisNetwork(parsed.input.analysisNetwork ?? "XLAYER_TESTNET"); } catch { window.sessionStorage.removeItem("xguard-session-result"); } }, []); useLayoutEffect(() => { - const currentInput: RiskInput = { from, to, value, data, context }; + const currentInput: RiskInput = { from, to, value, data, context, analysisNetwork }; const freshness = invalidateStaleAnalysis({ result, lastInput, reviewed }, currentInput); if (!freshness.invalidated) return; setResult(freshness.snapshot.result); @@ -116,7 +145,7 @@ export default function Home() { dispatchRecord({ type: "RESET" }); window.sessionStorage.removeItem("xguard-session-result"); setMessage(freshness.notice); - }, [from, to, value, data, context, result, lastInput, reviewed]); + }, [from, to, value, data, context, analysisNetwork, result, lastInput, reviewed]); useEffect(() => { const discovered = new Map(); @@ -198,6 +227,7 @@ export default function Home() { setValue(input.value); setData(input.data); setContext(input.context); + setAnalysisNetwork(input.analysisNetwork ?? "XLAYER_TESTNET"); } function clearAnalysis(clearFields = true) { @@ -212,7 +242,7 @@ export default function Home() { async function analyze() { setMessage(""); setReviewed(false); dispatchRecord({ type: "RESET" }); - const input: RiskInput = { from, to, value, data, context }; + const input: RiskInput = { from, to, value, data, context, analysisNetwork }; if (!isAddress(to)) { setMessage("Enter a valid recipient contract address."); return; } setAnalyzing(true); try { @@ -230,7 +260,7 @@ export default function Home() { } async function recordOnchain() { - if (!registryAddress || !analysisHash || !walletProvider || !address || !activeResult || !isCorrectNetwork || !reviewed || recordPending) return; + if (!registryAddress || !analysisHash || !walletProvider || !address || !activeResult || analysisNetwork !== "XLAYER_TESTNET" || !isCorrectNetwork || !reviewed || recordPending) return; setMessage(""); dispatchRecord({ type: "SIGNATURE_REQUESTED" }); try { @@ -283,25 +313,29 @@ export default function Home() { const recordLabel = recordState.phase === "awaiting-signature" ? "Awaiting wallet signature" : recordState.phase === "submitted" ? "Submitted" : recordState.phase === "confirming" ? "Confirming on X Layer" : recordState.phase === "confirmed" ? "Confirmed on X Layer" : recordState.phase === "reverted" ? "Transaction reverted" : recordState.phase === "error" ? "Confirmation error" : "Ready after review"; const decoded = activeResult?.decodedAction; const intelligence = activeResult?.contractIntelligence; + const simulation = activeResult?.simulationEvidence; + const scorePresentation = activeResult ? buildRiskScorePresentation(activeResult) : null; + const liveOkxEvidence = isLiveOkxProviderEvidence(simulation); return
XXGuard AI
-
{isCorrectNetwork && }{networkName} · Chain 1952
+
Analysis: {networkName} · Chain {analysisNetworkConfig.chainId}
-
Explainable pre-sign intelligence

The pre-sign security layer for X Layer.

Decode transactions, inspect on-chain context, apply deterministic safety rules, and use AI without allowing AI to override known security signals.

-

What happens if I sign this?

Network{networkName}
Analysis{modeLabel}
Safety floorDeterministic
SigningAlways user-confirmed
+
Evidence-grounded pre-sign intelligence

Know what a transaction does before you sign.

XGuard combines deterministic decoding, X Layer RPC facts, optional OKX Mainnet simulation, Intent vs Reality, and evidence-grounded AI—without treating any provider as a safety oracle.

+

What happens if I sign this?

Analysis Network{networkName}
Wallet{walletNetworkName}
Analysis{modeLabel}
Safety floorDeterministic
SigningAlways user-confirmed
-
Transaction DecoderOn-chain IntelligenceDeterministic Safety FloorAI Risk Analysis
+
Deterministic DecoderX Layer RPCOKX Simulation EvidenceIntent vs RealityEvidence-grounded AI
{judgeModeOpen &&
60-Second Judge Path

See why XGuard is more than an AI wrapper.

Each action is explicit. Nothing connects, signs, records, or broadcasts automatically.

01Safe TransferExpected: LOW

Baseline deterministic analysis plus optional AI enrichment.

02Ambiguous ApprovalExpected: UNDETERMINED

The shared approve() selector stays ambiguous unless token-standard evidence resolves it.

03Suspicious AirdropExpected: HIGH + MISMATCH

Claim intent contradicts contract-wide operator permission; deterministic evidence is not weakened by AI.

-
04Verified X Layer EvidenceReceipt: Confirmed

Real user-signed RiskRegistry receipt on Chain 1952.

+
04Live OKX Mainnet SimulationExpected: PROVIDER EVIDENCE

Loads a public historical approval fixture. Analysis remains explicit and read-only.

+
05Verified X Layer EvidenceReceipt: Confirmed

Real user-signed RiskRegistry receipt on Chain 1952.

✓ Human-readable calldata✓ Deterministic safety floor✓ AI enrichment✓ X Layer intelligence✓ User-controlled signing✓ Verified on-chain receipt
} @@ -309,18 +343,24 @@ export default function Home() {

1. Prepare transaction

Start with a preset or inspect a transaction manually.

{presets.map((preset) => )}
+ +
Testnet never uses the Mainnet simulator. Mainnet simulation is read-only evidence and requires a sender address.
setFrom(event.target.value)} /> setTo(event.target.value)} />
setValue(event.target.value)} />
setData(event.target.value)} />