diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8afb6d..2a0f7bc 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] + branches: [main, enhancement-v2, final-judge-upgrade, final-polish, v3-competition] pull_request: branches: [main] @@ -30,3 +30,8 @@ jobs: - run: pnpm run transaction-analyzer:test - run: pnpm run judge:test - run: pnpm run analysis-state:test + - run: pnpm run consequence:test + - run: pnpm run intent:test + - run: pnpm run pipeline:test + - run: pnpm run token-standard:test + - run: pnpm run security-benchmark:test diff --git a/README.md b/README.md index 4e14053..546beda 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > **The explainable pre-sign security layer for X Layer.** -XGuard AI decodes transaction intent, inspects real X Layer on-chain context, runs a transaction preflight, 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 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. **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 @@ -12,12 +12,12 @@ XGuard AI decodes transaction intent, inspects real X Layer on-chain context, ru **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. -## 60–90 Second Judge Path +## 60–90 Second Judge Path (V3.1 candidate) -1. Open the Live Demo and select **⚡ Try Judge Demo**. +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 **Unlimited Approval** to inspect `approve(address,uint256)`, the spender, and `Amount: Unlimited`. -4. Load **Suspicious Airdrop** to see the deterministic safety floor remain at `100 HIGH` through AI enrichment. +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, navigates, and explains. It never auto-analyzes, connects a wallet, signs, records an assessment, or broadcasts a transaction. @@ -25,6 +25,8 @@ Judge Mode only loads examples, navigates, and explains. It never auto-analyzes, ## Why XGuard Is Different - **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. @@ -32,7 +34,7 @@ Judge Mode only loads examples, navigates, and explains. It never auto-analyzes, ## Stable Production Baseline -The Final Judge Upgrade core application baseline is commit `409aa73c211a6b350af757d130c3f41ac8cfe962` and is 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. +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. - Safe Transfer: `8 LOW`, Hybrid Analysis - Unlimited Approval: `72 HIGH`, decoded ERC20 `approve`, spender and `Amount: Unlimited` visible @@ -40,17 +42,29 @@ The Final Judge Upgrade core application baseline is commit `409aa73c211a6b350af - 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 +### 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. -### Verified Production Product +### 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 report includes a `0–100` Risk Score, plain-language reasons, and a recommendation. -- Calldata decoding exposes approval spenders, transfer recipients, token amounts, unlimited approvals, and NFT operator permissions. -- Demo presets make Safe Transfer, Unlimited Approval, and Suspicious Airdrop paths reproducible without auto-analyzing or signing. +- 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. @@ -62,7 +76,9 @@ Wallet confirmation screens expose raw addresses, values, and calldata that many ## Solution -XGuard AI converts transaction fields into a `0–100` risk score, a `LOW / MEDIUM / HIGH` level, concise reasons, and an actionable recommendation. The app never signs automatically; users retain final control. +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. + +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.” 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. @@ -70,36 +86,51 @@ The hybrid design combines a deterministic Risk Engine with a configurable OpenA 1. Connect an EVM wallet. 2. Detect or switch to X Layer Testnet (`1952`). -3. Enter `from`, `to`, value, calldata, and context. -4. Decode supported calldata and inspect the target through real X Layer RPC calls. -5. Run bounded `eth_call` and `eth_estimateGas` preflight checks—not a full state-diff simulation. -6. Run the deterministic Local Risk Engine and merge optional AI enrichment above its safety floor. -7. Review the score, source-labeled signals, intelligence, reasons, and recommendation before signing. -8. Optionally confirm explicitly and record the assessment hash and score through `RiskRegistry`. +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`. ## Architecture ```mermaid flowchart TD U[User Transaction] --> D[Transaction Decoder] - D --> C[On-chain Contract Intelligence] - C --> P[Transaction Preflight] - P --> L[Deterministic Risk Engine] - L --> S[Security Floor] - L --> A[AI Enrichment] + 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] A --> F A -. unavailable or invalid .-> S - F --> R[Final Risk and Explanation] + V --> R[Final Evidence Report] + F --> R R --> Q[User Decision] - Q --> O[Optional X Layer Receipt] + Q --> XR[Optional X Layer Receipt] ``` ## AI Risk Engine -`lib/ai/provider.ts` isolates provider-specific behavior. 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. +`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. -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, unknown-contract context, and common social-engineering signals. +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. @@ -201,15 +232,22 @@ pnpm run intelligence:test pnpm run transaction-analyzer:test pnpm run judge:test pnpm run analysis-state:test +pnpm run consequence:test +pnpm run intent:test +pnpm run pipeline:test +pnpm run token-standard:test +pnpm run security-benchmark: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, Unlimited Approval, Risk Fusion, Contract Intelligence, and Suspicious Airdrop without connecting a wallet or creating a new transaction. Finish with the existing verified X Layer receipt as optional public evidence. +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 diff --git a/app/api/analyze/route.ts b/app/api/analyze/route.ts index d6c9d42..6c7fdf1 100644 --- a/app/api/analyze/route.ts +++ b/app/api/analyze/route.ts @@ -1,9 +1,7 @@ import { NextResponse } from "next/server"; -import { analyzeTransaction } from "../../../lib/ai/provider"; -import { localRiskAnalysis, validateRiskInput, type RiskInput } from "../../../lib/risk"; -import { mergeRiskResults } from "../../../lib/risk-fusion"; +import { runAnalysisPipeline } from "../../../lib/analyze-pipeline"; +import { validateRiskInput, type RiskInput } from "../../../lib/risk"; import { consumeAnalyzeRateLimit } from "../../../lib/api-rate-limit"; -import { inspectContract, signalsFromIntelligence } from "../../../lib/chain/intelligence"; export async function POST(request: Request) { const forwardedFor = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim(); @@ -22,11 +20,5 @@ export async function POST(request: Request) { } const errors = validateRiskInput(input); if (errors.length) return NextResponse.json({ error: errors.join(". "), code: "INVALID_INPUT" }, { status: 400 }); - const fallback = localRiskAnalysis(input); - const [aiResult, contractIntelligence] = await Promise.all([ - analyzeTransaction(input, fallback), - inspectContract(input) - ]); - const riskResult = aiResult ? mergeRiskResults(fallback, aiResult) : fallback; - return NextResponse.json({ ...riskResult, advisorySignals: [...riskResult.advisorySignals, ...signalsFromIntelligence(contractIntelligence)], contractIntelligence }); + return NextResponse.json(await runAnalysisPipeline(input)); } diff --git a/app/globals.css b/app/globals.css index 5850b85..f639f3e 100644 --- a/app/globals.css +++ b/app/globals.css @@ -40,6 +40,7 @@ h1 { font-size: clamp(44px, 7vw, 78px); line-height: .94; margin: 16px 0 18px; m .signal { display: flex; justify-content: space-between; gap: 18px; padding: 12px 0; border-top: 1px solid var(--line); color: var(--muted); font-size: 14px; } .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 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)); } @@ -67,6 +68,7 @@ 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 { 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; } .actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; } .primary, .secondary { border-radius: 12px; padding: 12px 16px; border: 1px solid transparent; font-weight: 700; } @@ -80,13 +82,20 @@ textarea { min-height: 110px; resize: vertical; } .score { flex: 0 0 106px; width: 106px; height: 106px; border-radius: 50%; display: grid; place-items: center; border: 8px solid var(--accent); font-size: 34px; font-weight: 800; } .score-medium { border-color: var(--warning); } .score-high { border-color: var(--danger); } +.score-undetermined { border-color: var(--warning); box-shadow: 0 0 0 3px rgba(249,198,107,.1); } .score-copy span, .score-copy strong, .score-copy small { display: block; } .score-copy span { color: var(--muted); font-size: 12px; } .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; } -.decoded-card, .intelligence-card, .fusion-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, .signal-section h3, .explanation h3 { margin: 0 0 10px; font-size: 14px; } +.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-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; } @@ -104,6 +113,23 @@ textarea { min-height: 110px; resize: vertical; } .fusion-grid div { display: grid; gap: 5px; padding: 12px; background: rgba(8,11,18,.45); border-radius: 10px; } .fusion-grid span { color: var(--muted); font-size: 10px; } .fusion-grid strong { font-size: 21px; } +.consequence-card { border-color: rgba(119,242,194,.22); } +.consequence-list { display: grid; gap: 9px; margin: 0; padding: 0; list-style: none; } +.consequence-list li { display: grid; gap: 6px; padding: 12px; border-left: 3px solid var(--accent); border-radius: 10px; background: rgba(8,11,18,.45); } +.consequence-list li.consequence-caution { border-left-color: var(--warning); } +.consequence-list li.consequence-critical { border-left-color: var(--danger); } +.consequence-list li > div { display: flex; justify-content: space-between; color: var(--muted); font-size: 9px; letter-spacing: .06em; } +.consequence-list li > strong { font-size: 13px; } +.consequence-list li > p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.45; } +.intent-card { border-color: rgba(249,198,107,.3); } +.intent-card.intent-match { border-color: rgba(119,242,194,.4); } +.intent-card.intent-mismatch { border-color: rgba(255,124,139,.5); } +.intent-status { border: 1px solid currentColor; border-radius: 999px; padding: 5px 8px; color: var(--warning); font-size: 10px; font-weight: 800; } +.intent-match .intent-status { color: var(--accent); } +.intent-mismatch .intent-status { color: var(--danger); } +.intent-grid { display: grid; grid-template-columns: 118px minmax(0,1fr); gap: 9px 12px; font-size: 12px; } +.intent-grid span { color: var(--muted); } +.intent-grid strong { line-height: 1.45; word-break: break-word; } .signal-section { margin-top: 18px; } .risk-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; } .risk-list li { display: grid; gap: 3px; background: var(--panel-soft); border-left: 3px solid var(--warning); border-radius: 10px; padding: 10px 12px; color: #dbe5f3; } @@ -157,7 +183,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 { grid-template-columns: 1fr; } + .fusion-grid, .assessment-dimensions { 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/icon.svg b/app/icon.svg new file mode 100644 index 0000000..a45e9bd --- /dev/null +++ b/app/icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/page.tsx b/app/page.tsx index 2a154ba..4c80ef1 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -5,6 +5,9 @@ import { createPublicClient, createWalletClient, custom, http, isAddress, keccak 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 type { XLayerTransaction } from "../lib/chain/transaction-analyzer"; import { judgePresets as presets } from "../lib/presets"; import { currentAnalysisResult, invalidateStaleAnalysis } from "../lib/analysis-state"; @@ -18,20 +21,42 @@ const contractUrl = `${explorerBase}/address/0xf4505A4e8dEca4659b8A2054555788Ddc const verifiedTxUrl = `${explorerBase}/tx/0x1492bc179e98fe5fe79add3528f8f1f26990ab37e189a98d4c4a052d6fd11bcb`; const verifiedTxHash = "0x1492bc179e98fe5fe79add3528f8f1f26990ab37e189a98d4c4a052d6fd11bcb"; type WalletOption = { info: { uuid: string; name: string; icon: string }; provider: WalletProvider }; -type AnalysisResult = RiskResult & { contractIntelligence?: ContractIntelligence }; +type AnalysisResult = RiskResult & { + analysisConfidence: AnalysisConfidence; + analysisVerdict: AnalysisVerdict; + executionStatus: ExecutionStatus; + confidenceReasons: string[]; + contractIntelligence: ContractIntelligence; + consequences: TransactionConsequence[]; + intentComparison: IntentComparison; +}; 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 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"]); function isCurrentAnalysisResult(value: unknown): value is AnalysisResult { if (!value || typeof value !== "object") return false; const candidate = value as Partial; 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))); return typeof candidate.finalScore === "number" && typeof candidate.deterministicScore === "number" + && analysisConfidences.has(String(candidate.analysisConfidence)) + && analysisVerdicts.has(String(candidate.analysisVerdict)) + && executionStatuses.has(String(candidate.executionStatus)) + && Array.isArray(candidate.confidenceReasons) + && candidate.confidenceReasons.every((reason) => typeof reason === "string") && validSignals(candidate.criticalSignals) && validSignals(candidate.advisorySignals) - && Boolean(candidate.contractIntelligence); + && Boolean(candidate.contractIntelligence) + && validConsequences + && validIntent; } export default function Home() { @@ -43,7 +68,7 @@ export default function Home() { const [to, setTo] = useState(""); const [value, setValue] = useState("0"); const [data, setData] = useState("0x"); - const [context, setContext] = useState("Swap on a new token router"); + const [context, setContext] = useState(""); const [result, setResult] = useState(null); const [lastInput, setLastInput] = useState(null); const [analyzing, setAnalyzing] = useState(false); @@ -267,15 +292,15 @@ export default function Home() {
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.

-

Built for X Layer

Network{networkName}
Analysis{modeLabel}
Safety floorDeterministic
SigningAlways user-confirmed
+

What happens if I sign this?

Network{networkName}
Analysis{modeLabel}
Safety floorDeterministic
SigningAlways user-confirmed
Transaction DecoderOn-chain IntelligenceDeterministic Safety FloorAI Risk Analysis
{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.

-
02Unlimited ApprovalExpected: HIGH

Decoded approve(), visible spender, and Unlimited amount.

-
03Suspicious AirdropExpected: HIGH

Demonstrates that AI cannot lower the deterministic floor.

+
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.

✓ Human-readable calldata✓ Deterministic safety floor✓ AI enrichment✓ X Layer intelligence✓ User-controlled signing✓ Verified on-chain receipt
@@ -287,7 +312,7 @@ export default function Home() { setFrom(event.target.value)} /> setTo(event.target.value)} />
setValue(event.target.value)} />
setData(event.target.value)} />
-