x402-trust-layer 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/DEPLOY.md +53 -0
- package/Dockerfile +30 -0
- package/LICENSE +21 -0
- package/README.md +294 -0
- package/dist/agents/a2a-payment.d.ts +37 -0
- package/dist/agents/a2a-payment.js +105 -0
- package/dist/agents/agent-escrow.d.ts +30 -0
- package/dist/agents/agent-escrow.js +23 -0
- package/dist/agents/agent-verify.d.ts +15 -0
- package/dist/agents/agent-verify.js +112 -0
- package/dist/agents/api-router.d.ts +32 -0
- package/dist/agents/api-router.js +228 -0
- package/dist/agents/attestation-registry.d.ts +35 -0
- package/dist/agents/attestation-registry.js +76 -0
- package/dist/agents/audition-coach.d.ts +45 -0
- package/dist/agents/audition-coach.js +257 -0
- package/dist/agents/bedrock-bridge.d.ts +3 -0
- package/dist/agents/bedrock-bridge.js +60 -0
- package/dist/agents/budget-allocator.d.ts +24 -0
- package/dist/agents/budget-allocator.js +31 -0
- package/dist/agents/compliance-ledger.d.ts +66 -0
- package/dist/agents/compliance-ledger.js +80 -0
- package/dist/agents/dispute-resolver.d.ts +62 -0
- package/dist/agents/dispute-resolver.js +124 -0
- package/dist/agents/evidence-locker.d.ts +30 -0
- package/dist/agents/evidence-locker.js +47 -0
- package/dist/agents/facilitator-failover.d.ts +15 -0
- package/dist/agents/facilitator-failover.js +18 -0
- package/dist/agents/identity-gate.d.ts +20 -0
- package/dist/agents/identity-gate.js +79 -0
- package/dist/agents/mandate-compiler.d.ts +51 -0
- package/dist/agents/mandate-compiler.js +73 -0
- package/dist/agents/mandate-diff.d.ts +41 -0
- package/dist/agents/mandate-diff.js +170 -0
- package/dist/agents/market-buy-advisor.d.ts +65 -0
- package/dist/agents/market-buy-advisor.js +234 -0
- package/dist/agents/merchant-trust.d.ts +38 -0
- package/dist/agents/merchant-trust.js +171 -0
- package/dist/agents/mpp-session-broker.d.ts +27 -0
- package/dist/agents/mpp-session-broker.js +29 -0
- package/dist/agents/mpp-session-v2.d.ts +76 -0
- package/dist/agents/mpp-session-v2.js +269 -0
- package/dist/agents/payment-intent-compiler.d.ts +21 -0
- package/dist/agents/payment-intent-compiler.js +45 -0
- package/dist/agents/pipeline-execute.d.ts +40 -0
- package/dist/agents/pipeline-execute.js +100 -0
- package/dist/agents/pipeline-trust-v2.d.ts +31 -0
- package/dist/agents/pipeline-trust-v2.js +111 -0
- package/dist/agents/pre-x402-guard.d.ts +35 -0
- package/dist/agents/pre-x402-guard.js +84 -0
- package/dist/agents/quality-escrow-semantic.d.ts +88 -0
- package/dist/agents/quality-escrow-semantic.js +137 -0
- package/dist/agents/quality-escrow.d.ts +65 -0
- package/dist/agents/quality-escrow.js +104 -0
- package/dist/agents/quality-monitor.d.ts +32 -0
- package/dist/agents/quality-monitor.js +77 -0
- package/dist/agents/rail-optimizer.d.ts +33 -0
- package/dist/agents/rail-optimizer.js +133 -0
- package/dist/agents/receipt-auditor.d.ts +14 -0
- package/dist/agents/receipt-auditor.js +145 -0
- package/dist/agents/refund-arbiter.d.ts +24 -0
- package/dist/agents/refund-arbiter.js +70 -0
- package/dist/agents/research-brief.d.ts +14 -0
- package/dist/agents/research-brief.js +66 -0
- package/dist/agents/risk-gate.d.ts +11 -0
- package/dist/agents/risk-gate.js +78 -0
- package/dist/agents/settlement-graph.d.ts +16 -0
- package/dist/agents/settlement-graph.js +38 -0
- package/dist/agents/spend-governor.d.ts +2 -0
- package/dist/agents/spend-governor.js +70 -0
- package/dist/agents/trust-network.d.ts +138 -0
- package/dist/agents/trust-network.js +244 -0
- package/dist/agents/x402-proxy.d.ts +32 -0
- package/dist/agents/x402-proxy.js +90 -0
- package/dist/client/demo-alchemy-live.d.ts +1 -0
- package/dist/client/demo-alchemy-live.js +226 -0
- package/dist/client/demo-tail.d.ts +1 -0
- package/dist/client/demo-tail.js +100 -0
- package/dist/client/demo.d.ts +1 -0
- package/dist/client/demo.js +293 -0
- package/dist/config.d.ts +94 -0
- package/dist/config.js +223 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +389 -0
- package/dist/lib/agent-response.d.ts +14 -0
- package/dist/lib/agent-response.js +13 -0
- package/dist/lib/agentic-gateways.d.ts +5 -0
- package/dist/lib/agentic-gateways.js +15 -0
- package/dist/lib/agentic-probes.d.ts +10 -0
- package/dist/lib/agentic-probes.js +49 -0
- package/dist/lib/alchemy-x402-fetch.d.ts +16 -0
- package/dist/lib/alchemy-x402-fetch.js +95 -0
- package/dist/lib/apply-verifier-body.d.ts +7 -0
- package/dist/lib/apply-verifier-body.js +179 -0
- package/dist/lib/attestation.d.ts +30 -0
- package/dist/lib/attestation.js +107 -0
- package/dist/lib/bazaar-extension.d.ts +15 -0
- package/dist/lib/bazaar-extension.js +265 -0
- package/dist/lib/bazaar.d.ts +100 -0
- package/dist/lib/bazaar.js +341 -0
- package/dist/lib/certified-sellers.d.ts +41 -0
- package/dist/lib/certified-sellers.js +129 -0
- package/dist/lib/chains.d.ts +20 -0
- package/dist/lib/chains.js +78 -0
- package/dist/lib/db-persistence.d.ts +7 -0
- package/dist/lib/db-persistence.js +65 -0
- package/dist/lib/db.d.ts +5 -0
- package/dist/lib/db.js +113 -0
- package/dist/lib/discovery-page.d.ts +2 -0
- package/dist/lib/discovery-page.js +71 -0
- package/dist/lib/ecosystem-telemetry.d.ts +20 -0
- package/dist/lib/ecosystem-telemetry.js +80 -0
- package/dist/lib/erc8004/agent-card.d.ts +34 -0
- package/dist/lib/erc8004/agent-card.js +151 -0
- package/dist/lib/erc8004/cache.d.ts +3 -0
- package/dist/lib/erc8004/cache.js +17 -0
- package/dist/lib/erc8004/constants.d.ts +22 -0
- package/dist/lib/erc8004/constants.js +35 -0
- package/dist/lib/erc8004/registry.d.ts +19 -0
- package/dist/lib/erc8004/registry.js +171 -0
- package/dist/lib/erc8004/resolve-agent.d.ts +7 -0
- package/dist/lib/erc8004/resolve-agent.js +70 -0
- package/dist/lib/erc8004/trust-score.d.ts +33 -0
- package/dist/lib/erc8004/trust-score.js +136 -0
- package/dist/lib/escrow-ledger.d.ts +14 -0
- package/dist/lib/escrow-ledger.js +54 -0
- package/dist/lib/escrow-unified.d.ts +15 -0
- package/dist/lib/escrow-unified.js +28 -0
- package/dist/lib/facilitator-extra.d.ts +13 -0
- package/dist/lib/facilitator-extra.js +52 -0
- package/dist/lib/facilitators.d.ts +20 -0
- package/dist/lib/facilitators.js +89 -0
- package/dist/lib/host-policy.d.ts +4 -0
- package/dist/lib/host-policy.js +20 -0
- package/dist/lib/idempotency.d.ts +4 -0
- package/dist/lib/idempotency.js +120 -0
- package/dist/lib/ledger.d.ts +2 -0
- package/dist/lib/ledger.js +17 -0
- package/dist/lib/logger.d.ts +6 -0
- package/dist/lib/logger.js +24 -0
- package/dist/lib/mandate-vc.d.ts +20 -0
- package/dist/lib/mandate-vc.js +25 -0
- package/dist/lib/mandate.d.ts +44 -0
- package/dist/lib/mandate.js +190 -0
- package/dist/lib/marketplace.d.ts +7 -0
- package/dist/lib/marketplace.js +127 -0
- package/dist/lib/migrations.d.ts +2 -0
- package/dist/lib/migrations.js +130 -0
- package/dist/lib/nonce-store.d.ts +6 -0
- package/dist/lib/nonce-store.js +109 -0
- package/dist/lib/openapi-agentcash.d.ts +5 -0
- package/dist/lib/openapi-agentcash.js +288 -0
- package/dist/lib/openapi-meta.d.ts +5 -0
- package/dist/lib/openapi-meta.js +235 -0
- package/dist/lib/otel.d.ts +2 -0
- package/dist/lib/otel.js +25 -0
- package/dist/lib/paid-resource-url.d.ts +6 -0
- package/dist/lib/paid-resource-url.js +47 -0
- package/dist/lib/parse-with-verifier-fallback.d.ts +3 -0
- package/dist/lib/parse-with-verifier-fallback.js +13 -0
- package/dist/lib/payment-request-context.d.ts +10 -0
- package/dist/lib/payment-request-context.js +5 -0
- package/dist/lib/payment-response.d.ts +13 -0
- package/dist/lib/payment-response.js +39 -0
- package/dist/lib/payto-guard.d.ts +10 -0
- package/dist/lib/payto-guard.js +20 -0
- package/dist/lib/probe.d.ts +29 -0
- package/dist/lib/probe.js +157 -0
- package/dist/lib/problem-detail.d.ts +10 -0
- package/dist/lib/problem-detail.js +14 -0
- package/dist/lib/rate-limit.d.ts +12 -0
- package/dist/lib/rate-limit.js +126 -0
- package/dist/lib/replay-middleware.d.ts +3 -0
- package/dist/lib/replay-middleware.js +27 -0
- package/dist/lib/response-guard.d.ts +5 -0
- package/dist/lib/response-guard.js +40 -0
- package/dist/lib/safe-fetch.d.ts +5 -0
- package/dist/lib/safe-fetch.js +19 -0
- package/dist/lib/security.d.ts +13 -0
- package/dist/lib/security.js +61 -0
- package/dist/lib/semantic-judge.d.ts +14 -0
- package/dist/lib/semantic-judge.js +107 -0
- package/dist/lib/semantic-judge.test.d.ts +1 -0
- package/dist/lib/semantic-judge.test.js +11 -0
- package/dist/lib/ssrf.d.ts +10 -0
- package/dist/lib/ssrf.js +130 -0
- package/dist/lib/ssrf.test.d.ts +1 -0
- package/dist/lib/ssrf.test.js +16 -0
- package/dist/lib/suite-catalog.d.ts +83 -0
- package/dist/lib/suite-catalog.js +131 -0
- package/dist/lib/telemetry.d.ts +5 -0
- package/dist/lib/telemetry.js +37 -0
- package/dist/lib/verifier-fast-path.d.ts +10 -0
- package/dist/lib/verifier-fast-path.js +44 -0
- package/dist/lib/verifier-probe-protocol.d.ts +7 -0
- package/dist/lib/verifier-probe-protocol.js +115 -0
- package/dist/lib/verify-examples.d.ts +2 -0
- package/dist/lib/verify-examples.js +438 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.js +2 -0
- package/dist/lib/webhook-auth.d.ts +3 -0
- package/dist/lib/webhook-auth.js +34 -0
- package/dist/lib/webhook-routes.d.ts +2 -0
- package/dist/lib/webhook-routes.js +112 -0
- package/dist/lib/webhooks.d.ts +23 -0
- package/dist/lib/webhooks.js +123 -0
- package/dist/lib/webhooks.test.d.ts +1 -0
- package/dist/lib/webhooks.test.js +16 -0
- package/dist/lib/x402-client-options.d.ts +28 -0
- package/dist/lib/x402-client-options.js +138 -0
- package/dist/lib/x402-headers.d.ts +10 -0
- package/dist/lib/x402-headers.js +27 -0
- package/dist/lib/x402-paid.d.ts +5 -0
- package/dist/lib/x402-paid.js +252 -0
- package/dist/lib/x402-payment-replay.d.ts +22 -0
- package/dist/lib/x402-payment-replay.js +57 -0
- package/dist/lib/x402gle-host-verify.d.ts +3 -0
- package/dist/lib/x402gle-host-verify.js +27 -0
- package/dist/protocol/agent-passport.d.ts +34 -0
- package/dist/protocol/agent-passport.js +44 -0
- package/dist/protocol/compliance-v2.d.ts +21 -0
- package/dist/protocol/compliance-v2.js +19 -0
- package/dist/protocol/credit-bureau.d.ts +18 -0
- package/dist/protocol/credit-bureau.js +44 -0
- package/dist/protocol/crypto.d.ts +6 -0
- package/dist/protocol/crypto.js +41 -0
- package/dist/protocol/escrow-fsm.d.ts +33 -0
- package/dist/protocol/escrow-fsm.js +99 -0
- package/dist/protocol/fraud-engine.d.ts +28 -0
- package/dist/protocol/fraud-engine.js +77 -0
- package/dist/protocol/observability.d.ts +14 -0
- package/dist/protocol/observability.js +21 -0
- package/dist/protocol/pipeline-full-trust.d.ts +40 -0
- package/dist/protocol/pipeline-full-trust.js +96 -0
- package/dist/protocol/proof-of-execution.d.ts +36 -0
- package/dist/protocol/proof-of-execution.js +48 -0
- package/dist/protocol/reasoning-audit.d.ts +27 -0
- package/dist/protocol/reasoning-audit.js +51 -0
- package/dist/protocol/replay-guard.d.ts +28 -0
- package/dist/protocol/replay-guard.js +76 -0
- package/dist/protocol/replay-guard.test.d.ts +1 -0
- package/dist/protocol/replay-guard.test.js +10 -0
- package/dist/protocol/security-audit.d.ts +18 -0
- package/dist/protocol/security-audit.js +45 -0
- package/dist/protocol/store.d.ts +5 -0
- package/dist/protocol/store.js +59 -0
- package/dist/protocol/threat-catalog.d.ts +13 -0
- package/dist/protocol/threat-catalog.js +75 -0
- package/dist/protocol/trust-oracle.d.ts +23 -0
- package/dist/protocol/trust-oracle.js +30 -0
- package/dist/protocol/trust-score-v2.d.ts +33 -0
- package/dist/protocol/trust-score-v2.js +78 -0
- package/dist/protocol/zk-proofs.d.ts +24 -0
- package/dist/protocol/zk-proofs.js +32 -0
- package/dist/routes/a2a-agent-card.d.ts +3 -0
- package/dist/routes/a2a-agent-card.js +28 -0
- package/dist/routes/catalog.d.ts +5 -0
- package/dist/routes/catalog.js +47 -0
- package/dist/routes/register-all.d.ts +3 -0
- package/dist/routes/register-all.js +1240 -0
- package/dist/routes/schemas.d.ts +83 -0
- package/dist/routes/schemas.js +38 -0
- package/dist/routes/shared.d.ts +16 -0
- package/dist/routes/shared.js +27 -0
- package/dist/routes-protocol.d.ts +10 -0
- package/dist/routes-protocol.js +322 -0
- package/dist/routes.d.ts +2 -0
- package/dist/routes.js +2 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.js +1 -0
- package/openapi.json +7940 -0
- package/package.json +124 -0
- package/public/.well-known/ai-plugin.json +12 -0
- package/public/assets/aegis-logo-blue.png +0 -0
- package/public/assets/aegis-logo-gold.png +0 -0
- package/public/assets/aegis-logo-green.png +0 -0
- package/public/assets/aegis-logo-purple.png +0 -0
- package/public/assets/aegis-logo-red.png +0 -0
- package/public/assets/aegis-logo-white.png +0 -0
- package/public/assets/aegis-logo.png +0 -0
- package/public/assets/x402-trustlayer-logo.png +0 -0
- package/public/assets/x402-trustlayer-logo.svg +5 -0
- package/public/data/agents.json +1528 -0
- package/public/index.html +198 -0
- package/public/landing.css +342 -0
- package/public/landing.js +405 -0
- package/public/llms-full.txt +582 -0
- package/public/llms.txt +132 -0
- package/public/skill.md +135 -0
- package/railway.toml +9 -0
- package/scripts/docker-entrypoint.sh +7 -0
- package/scripts/patch-facilitator-timeout.mjs +61 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { agentTrustMeta, withAgentTrust } from "../lib/agent-response.js";
|
|
2
|
+
import { config } from "../config.js";
|
|
3
|
+
// Visa-style reason code families (illustrative mapping for card rails).
|
|
4
|
+
const VISA_REASON_CODE = {
|
|
5
|
+
non_delivery: { code: "13.1", family: "Merchandise/Services Not Received" },
|
|
6
|
+
quality_mismatch: { code: "13.3", family: "Not as Described or Defective" },
|
|
7
|
+
overcharge: { code: "12.5", family: "Incorrect Amount" },
|
|
8
|
+
duplicate: { code: "12.6", family: "Duplicate Processing" },
|
|
9
|
+
unauthorized: { code: "10.4", family: "Fraud — Card Absent Environment" },
|
|
10
|
+
};
|
|
11
|
+
function isCardRail(rail) {
|
|
12
|
+
return rail === "visa-cli" || rail === "card";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Dispute & Chargeback Auto-Resolver.
|
|
16
|
+
* Visa CLI brings chargeback rights to agentic payments — but nobody automates
|
|
17
|
+
* the filing. For card rails this builds a Visa chargeback dossier (reason code,
|
|
18
|
+
* required evidence, filing steps). For final/stablecoin rails (no chargeback)
|
|
19
|
+
* it routes to an escrow/refund claim instead. Bridges card dispute rules with
|
|
20
|
+
* on-chain receipts.
|
|
21
|
+
*/
|
|
22
|
+
export function runDisputeResolve(input) {
|
|
23
|
+
const ev = input.evidence ?? {};
|
|
24
|
+
const card = isCardRail(input.rail);
|
|
25
|
+
// Strength of the dispute (0-100) from evidence.
|
|
26
|
+
let strength = 40;
|
|
27
|
+
const evidenceItems = [];
|
|
28
|
+
const requiredEvidence = [];
|
|
29
|
+
if (input.reason === "non_delivery") {
|
|
30
|
+
if (ev.actualResponseEmpty) {
|
|
31
|
+
strength += 35;
|
|
32
|
+
evidenceItems.push("Empty/absent response captured");
|
|
33
|
+
}
|
|
34
|
+
if (ev.receiptValid === false) {
|
|
35
|
+
strength += 10;
|
|
36
|
+
evidenceItems.push("Settlement receipt could not be validated");
|
|
37
|
+
}
|
|
38
|
+
requiredEvidence.push("Timestamped request/response logs", "Proof endpoint returned no deliverable");
|
|
39
|
+
}
|
|
40
|
+
if (input.reason === "quality_mismatch") {
|
|
41
|
+
if (typeof ev.verificationScore === "number" && ev.verificationScore < 50) {
|
|
42
|
+
strength += 30;
|
|
43
|
+
evidenceItems.push(`Verification score ${ev.verificationScore} below threshold`);
|
|
44
|
+
}
|
|
45
|
+
if (ev.expectedSchema?.length) {
|
|
46
|
+
strength += 10;
|
|
47
|
+
evidenceItems.push(`Expected schema keys: ${ev.expectedSchema.join(", ")}`);
|
|
48
|
+
}
|
|
49
|
+
requiredEvidence.push("Published 'good response' profile vs actual response diff");
|
|
50
|
+
}
|
|
51
|
+
if (input.reason === "overcharge") {
|
|
52
|
+
if (ev.chargedUsdc != null && ev.quotedUsdc != null && ev.chargedUsdc > ev.quotedUsdc) {
|
|
53
|
+
strength += 40;
|
|
54
|
+
evidenceItems.push(`Charged $${ev.chargedUsdc} vs quoted $${ev.quotedUsdc}`);
|
|
55
|
+
}
|
|
56
|
+
requiredEvidence.push("Original 402 quote", "Settlement amount proof");
|
|
57
|
+
}
|
|
58
|
+
if (input.reason === "duplicate") {
|
|
59
|
+
if (ev.duplicateOfTx) {
|
|
60
|
+
strength += 45;
|
|
61
|
+
evidenceItems.push(`Duplicate of tx ${ev.duplicateOfTx}`);
|
|
62
|
+
}
|
|
63
|
+
requiredEvidence.push("Both transaction hashes with identical merchant + amount");
|
|
64
|
+
}
|
|
65
|
+
if (input.reason === "unauthorized") {
|
|
66
|
+
strength += 20;
|
|
67
|
+
requiredEvidence.push("Mandate showing payment outside signed scope", "Agent identity attestation");
|
|
68
|
+
}
|
|
69
|
+
strength = Math.max(0, Math.min(100, strength));
|
|
70
|
+
const likelihood = strength >= 70 ? "strong" : strength >= 45 ? "moderate" : "weak";
|
|
71
|
+
if (card) {
|
|
72
|
+
const rc = VISA_REASON_CODE[input.reason];
|
|
73
|
+
return withAgentTrust({
|
|
74
|
+
path: "card-chargeback",
|
|
75
|
+
rail: input.rail,
|
|
76
|
+
merchant: input.merchant,
|
|
77
|
+
amountUsdc: input.amountUsdc,
|
|
78
|
+
reason: input.reason,
|
|
79
|
+
reasonCode: rc.code,
|
|
80
|
+
reasonFamily: rc.family,
|
|
81
|
+
disputeStrength: strength,
|
|
82
|
+
likelihood,
|
|
83
|
+
autoFileable: strength >= 70,
|
|
84
|
+
requiredEvidence,
|
|
85
|
+
evidenceCaptured: evidenceItems,
|
|
86
|
+
filingSteps: [
|
|
87
|
+
"Compile evidence bundle (logs + receipt + mandate)",
|
|
88
|
+
`File chargeback under Visa reason code ${rc.code} (${rc.family})`,
|
|
89
|
+
"Submit via Visa CLI dispute channel / issuing bank",
|
|
90
|
+
"Track representment window and respond to merchant compelling evidence",
|
|
91
|
+
],
|
|
92
|
+
nextStep: { method: "POST", path: "/api/compliance/ledger", note: "Log disputed item in audit ledger" },
|
|
93
|
+
}, agentTrustMeta(["reason_code_map", "evidence_scoring"], {
|
|
94
|
+
confidence: 0.83,
|
|
95
|
+
sources: ["dispute-resolver", "visa-dispute-rules"],
|
|
96
|
+
accuracy_note: "Reason codes are illustrative; confirm current Visa Dispute Resolution code set before filing.",
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
// Stablecoin / final rails: no chargeback — route to escrow/refund claim.
|
|
100
|
+
return withAgentTrust({
|
|
101
|
+
path: "onchain-refund-claim",
|
|
102
|
+
rail: input.rail,
|
|
103
|
+
merchant: input.merchant,
|
|
104
|
+
amountUsdc: input.amountUsdc,
|
|
105
|
+
reason: input.reason,
|
|
106
|
+
finality: "final (no card chargeback available)",
|
|
107
|
+
disputeStrength: strength,
|
|
108
|
+
likelihood,
|
|
109
|
+
autoFileable: false,
|
|
110
|
+
requiredEvidence,
|
|
111
|
+
evidenceCaptured: evidenceItems,
|
|
112
|
+
recommendedRoute: [
|
|
113
|
+
"Open/settle via /api/agent-escrow so funds are release-gated next time",
|
|
114
|
+
"Score eligibility via /api/refund-arbiter/evaluate",
|
|
115
|
+
"Request merchant refund with receipt proof from /api/receipt-auditor/verify",
|
|
116
|
+
],
|
|
117
|
+
escrowUrl: `${config.publicBaseUrl}/api/agent-escrow`,
|
|
118
|
+
refundArbiterUrl: `${config.publicBaseUrl}/api/refund-arbiter/evaluate`,
|
|
119
|
+
}, agentTrustMeta(["finality_check", "evidence_scoring"], {
|
|
120
|
+
confidence: 0.78,
|
|
121
|
+
sources: ["dispute-resolver", "x402-settlement"],
|
|
122
|
+
accuracy_note: "Stablecoin settlements are irreversible; future spend should be escrow-gated. Use card rails (Visa CLI) when dispute rights matter.",
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type WithAgentTrust } from "../lib/agent-response.js";
|
|
2
|
+
export type SettlementRecord = {
|
|
3
|
+
transactionHash?: string;
|
|
4
|
+
endpoint: string;
|
|
5
|
+
amountUsdc: number;
|
|
6
|
+
payer?: string;
|
|
7
|
+
network: string;
|
|
8
|
+
timestamp?: string;
|
|
9
|
+
};
|
|
10
|
+
export type EvidenceLockerInput = {
|
|
11
|
+
organizationId: string;
|
|
12
|
+
records: SettlementRecord[];
|
|
13
|
+
};
|
|
14
|
+
export type EvidenceLockerResult = {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
bundleId: string;
|
|
17
|
+
organizationId: string;
|
|
18
|
+
generatedAt: string;
|
|
19
|
+
recordCount: number;
|
|
20
|
+
totalUsdc: number;
|
|
21
|
+
checksum: string;
|
|
22
|
+
bundleSignature: string;
|
|
23
|
+
tamperEvident: boolean;
|
|
24
|
+
export: {
|
|
25
|
+
summary: string;
|
|
26
|
+
records: SettlementRecord[];
|
|
27
|
+
complianceNotes: string[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare function runEvidenceLocker(input: EvidenceLockerInput): WithAgentTrust<EvidenceLockerResult>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { agentTrustMeta, withAgentTrust } from "../lib/agent-response.js";
|
|
3
|
+
export function runEvidenceLocker(input) {
|
|
4
|
+
const total = input.records.reduce((s, r) => s + r.amountUsdc, 0);
|
|
5
|
+
const payload = JSON.stringify(input.records);
|
|
6
|
+
const checksum = createHash("sha256").update(payload).digest("hex");
|
|
7
|
+
const bundleId = createHash("sha256")
|
|
8
|
+
.update(`${input.organizationId}:${Date.now()}`)
|
|
9
|
+
.digest("hex")
|
|
10
|
+
.slice(0, 16);
|
|
11
|
+
const bundleSignature = createHash("sha256")
|
|
12
|
+
.update(`${input.organizationId}:${checksum}`)
|
|
13
|
+
.digest("hex");
|
|
14
|
+
const checks = [
|
|
15
|
+
"records_present",
|
|
16
|
+
"checksum_computed",
|
|
17
|
+
"bundle_signature_derived",
|
|
18
|
+
"organization_bound",
|
|
19
|
+
];
|
|
20
|
+
if (input.records.length > 0)
|
|
21
|
+
checks.push("non_empty_export");
|
|
22
|
+
return withAgentTrust({
|
|
23
|
+
ok: true,
|
|
24
|
+
bundleId,
|
|
25
|
+
organizationId: input.organizationId,
|
|
26
|
+
generatedAt: new Date().toISOString(),
|
|
27
|
+
recordCount: input.records.length,
|
|
28
|
+
totalUsdc: Number(total.toFixed(6)),
|
|
29
|
+
checksum,
|
|
30
|
+
bundleSignature,
|
|
31
|
+
tamperEvident: true,
|
|
32
|
+
export: {
|
|
33
|
+
summary: `${input.records.length} x402 settlements totaling $${total.toFixed(4)} USDC`,
|
|
34
|
+
records: input.records,
|
|
35
|
+
complianceNotes: [
|
|
36
|
+
"Immutable checksum covers record ordering and amounts",
|
|
37
|
+
"bundleSignature binds organizationId to checksum for tamper detection",
|
|
38
|
+
"Attach Receipt Auditor verification output per transaction for audit trail",
|
|
39
|
+
"Suitable for internal finance review — not legal advice",
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
}, agentTrustMeta(checks, {
|
|
43
|
+
confidence: input.records.length > 0 ? 0.94 : 0.72,
|
|
44
|
+
sources: ["x402-agent-suite-pro", "evidence-locker"],
|
|
45
|
+
accuracy_note: "Compliance export bundle — checksum and signature are deterministic; not a legal attestation.",
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { rankFacilitators } from "../lib/facilitators.js";
|
|
2
|
+
import { probeEndpoint } from "../lib/probe.js";
|
|
3
|
+
export type FailoverInput = {
|
|
4
|
+
targetUrl: string;
|
|
5
|
+
preferNetwork?: string;
|
|
6
|
+
fastProbe?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type FailoverResult = {
|
|
9
|
+
targetUrl: string;
|
|
10
|
+
recommendedFacilitator: string;
|
|
11
|
+
facilitators: Awaited<ReturnType<typeof rankFacilitators>>;
|
|
12
|
+
targetProbe: Awaited<ReturnType<typeof probeEndpoint>>;
|
|
13
|
+
routingNote: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function runFacilitatorFailover(input: FailoverInput): Promise<FailoverResult>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { rankFacilitators } from "../lib/facilitators.js";
|
|
2
|
+
import { probeEndpoint } from "../lib/probe.js";
|
|
3
|
+
export async function runFacilitatorFailover(input) {
|
|
4
|
+
const facilitators = await rankFacilitators(input.preferNetwork, input.fastProbe === true);
|
|
5
|
+
const targetProbe = await probeEndpoint(input.targetUrl, {
|
|
6
|
+
fastSynthetic: input.fastProbe === true,
|
|
7
|
+
});
|
|
8
|
+
const best = facilitators.find((f) => f.healthy) ?? facilitators[0];
|
|
9
|
+
return {
|
|
10
|
+
targetUrl: input.targetUrl,
|
|
11
|
+
recommendedFacilitator: best?.id ?? "dexter",
|
|
12
|
+
facilitators,
|
|
13
|
+
targetProbe,
|
|
14
|
+
routingNote: best?.id === "dexter"
|
|
15
|
+
? "Use Dexter facilitator (https://x402.dexter.cash) for settlement. Client should wrapFetch with facilitatorUrl pointing to the recommended host."
|
|
16
|
+
: `Primary facilitator ${best?.id} is healthy. Fall back to Dexter if settlement fails.`,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type TrustTier } from "../lib/erc8004/constants.js";
|
|
2
|
+
export type IdentityGateInput = {
|
|
3
|
+
walletAddress: string;
|
|
4
|
+
maxTierSpendUsdc?: number;
|
|
5
|
+
requireMainnet?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type IdentityGateResult = {
|
|
8
|
+
allowed: boolean;
|
|
9
|
+
tier: "trusted" | "standard" | "restricted";
|
|
10
|
+
riskScore: number;
|
|
11
|
+
maxSpendUsdc: number;
|
|
12
|
+
reasons: string[];
|
|
13
|
+
erc8004?: {
|
|
14
|
+
trustScore: number;
|
|
15
|
+
tier: TrustTier;
|
|
16
|
+
agentId: string | null;
|
|
17
|
+
registered: boolean;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export declare function runIdentityGate(input: IdentityGateInput): Promise<IdentityGateResult>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { isEvmAddress } from "../lib/erc8004/constants.js";
|
|
2
|
+
import { computeTrustScore } from "../lib/erc8004/trust-score.js";
|
|
3
|
+
const BLOCKED_PATTERNS = ["test", "burn", "11111111111111111111111111111111"];
|
|
4
|
+
const BLOCKED_EXACT = new Set([
|
|
5
|
+
"0x0000000000000000000000000000000000000000",
|
|
6
|
+
"11111111111111111111111111111111",
|
|
7
|
+
]);
|
|
8
|
+
function isSolanaAddress(addr) {
|
|
9
|
+
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(addr);
|
|
10
|
+
}
|
|
11
|
+
export async function runIdentityGate(input) {
|
|
12
|
+
const reasons = [];
|
|
13
|
+
let riskScore = 10;
|
|
14
|
+
const addr = input.walletAddress.trim();
|
|
15
|
+
if (!isSolanaAddress(addr) && !isEvmAddress(addr)) {
|
|
16
|
+
return {
|
|
17
|
+
allowed: false,
|
|
18
|
+
tier: "restricted",
|
|
19
|
+
riskScore: 100,
|
|
20
|
+
maxSpendUsdc: 0,
|
|
21
|
+
reasons: ["Invalid wallet address format"],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (BLOCKED_EXACT.has(addr) || BLOCKED_EXACT.has(addr.toLowerCase())) {
|
|
25
|
+
return {
|
|
26
|
+
allowed: false,
|
|
27
|
+
tier: "restricted",
|
|
28
|
+
riskScore: 100,
|
|
29
|
+
maxSpendUsdc: 0,
|
|
30
|
+
reasons: ["Blocked sentinel wallet address"],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const lower = addr.toLowerCase();
|
|
34
|
+
for (const p of BLOCKED_PATTERNS) {
|
|
35
|
+
if (lower.includes(p)) {
|
|
36
|
+
reasons.push(`Matched blocked pattern: ${p}`);
|
|
37
|
+
riskScore += 60;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (addr.length < 32) {
|
|
41
|
+
reasons.push("Address suspiciously short");
|
|
42
|
+
riskScore += 30;
|
|
43
|
+
}
|
|
44
|
+
let erc8004;
|
|
45
|
+
if (isEvmAddress(addr)) {
|
|
46
|
+
const trust = await computeTrustScore({ walletAddress: addr });
|
|
47
|
+
erc8004 = {
|
|
48
|
+
trustScore: trust.trustScore,
|
|
49
|
+
tier: trust.tier,
|
|
50
|
+
agentId: trust.agentId,
|
|
51
|
+
registered: trust.registered,
|
|
52
|
+
};
|
|
53
|
+
if (trust.registered && trust.tier !== "UNVERIFIED" && trust.tier !== "UNKNOWN") {
|
|
54
|
+
riskScore = Math.max(0, riskScore - 15);
|
|
55
|
+
reasons.push(`ERC-8004 ${trust.tier} (score ${trust.trustScore})`);
|
|
56
|
+
}
|
|
57
|
+
else if (!trust.registered) {
|
|
58
|
+
reasons.push("No ERC-8004 registration — consider POST /api/agent/verify");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
let tier = "standard";
|
|
62
|
+
if (riskScore < 25)
|
|
63
|
+
tier = "trusted";
|
|
64
|
+
if (riskScore >= 50)
|
|
65
|
+
tier = "restricted";
|
|
66
|
+
const maxSpend = tier === "trusted"
|
|
67
|
+
? (input.maxTierSpendUsdc ?? 50)
|
|
68
|
+
: tier === "standard"
|
|
69
|
+
? Math.min(input.maxTierSpendUsdc ?? 10, 10)
|
|
70
|
+
: 0;
|
|
71
|
+
return {
|
|
72
|
+
allowed: tier !== "restricted",
|
|
73
|
+
tier,
|
|
74
|
+
riskScore,
|
|
75
|
+
maxSpendUsdc: maxSpend,
|
|
76
|
+
reasons: reasons.length ? reasons : ["Wallet passed baseline checks"],
|
|
77
|
+
...(erc8004 ? { erc8004 } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type MandateCheck } from "../lib/mandate.js";
|
|
2
|
+
export type MandateCompileInput = {
|
|
3
|
+
principal: string;
|
|
4
|
+
agentId: string;
|
|
5
|
+
intent: string;
|
|
6
|
+
maxPerTxUsdc: number;
|
|
7
|
+
dailyCapUsdc: number;
|
|
8
|
+
allowedMerchants?: string[];
|
|
9
|
+
allowedCategories?: string[];
|
|
10
|
+
allowedRails?: string[];
|
|
11
|
+
ttlMinutes?: number;
|
|
12
|
+
mandateVersion?: "ap2/v1";
|
|
13
|
+
validUntil?: number;
|
|
14
|
+
currency?: "USDC" | "USDT";
|
|
15
|
+
network?: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* AP2-style Mandate Compiler + Verifiable Intent Notary.
|
|
19
|
+
* Converts a human intent + guardrails into a cryptographically signed, scoped
|
|
20
|
+
* mandate (the "tamper-resistant intent" layer that Google AP2 and Visa CLI
|
|
21
|
+
* governance both require). Agents present the mandate; merchants/fleets verify
|
|
22
|
+
* the proposed payment fits the signed scope before money moves.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runMandateCompile(input: MandateCompileInput): Promise<{
|
|
25
|
+
mandate: import("../lib/mandate.js").MandateRecord;
|
|
26
|
+
verifiableCredential: import("../lib/mandate-vc.js").MandateVC;
|
|
27
|
+
ap2: {
|
|
28
|
+
mandateVersion: "ap2/v1";
|
|
29
|
+
validFrom: number;
|
|
30
|
+
validUntil: number;
|
|
31
|
+
currency: "USDC" | "USDT";
|
|
32
|
+
network: string;
|
|
33
|
+
};
|
|
34
|
+
verifyUrl: string;
|
|
35
|
+
usage: string;
|
|
36
|
+
} & import("../lib/agent-response.js").AgentTrustMeta>;
|
|
37
|
+
export type MandateVerifyInput = {
|
|
38
|
+
mandateId: string;
|
|
39
|
+
proposed?: MandateCheck;
|
|
40
|
+
};
|
|
41
|
+
export declare function runMandateVerify(input: MandateVerifyInput): Promise<{
|
|
42
|
+
ok: boolean;
|
|
43
|
+
allowed: boolean;
|
|
44
|
+
valid: boolean;
|
|
45
|
+
withinScope: boolean;
|
|
46
|
+
reason: string;
|
|
47
|
+
record: import("../lib/mandate.js").MandateRecord | null;
|
|
48
|
+
violations: string[];
|
|
49
|
+
mandateId: string;
|
|
50
|
+
proposed: MandateCheck | null;
|
|
51
|
+
} & import("../lib/agent-response.js").AgentTrustMeta>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { issueMandate, verifyMandate } from "../lib/mandate.js";
|
|
2
|
+
import { mandateToVC } from "../lib/mandate-vc.js";
|
|
3
|
+
import { agentTrustMeta, withAgentTrust } from "../lib/agent-response.js";
|
|
4
|
+
import { config } from "../config.js";
|
|
5
|
+
/**
|
|
6
|
+
* AP2-style Mandate Compiler + Verifiable Intent Notary.
|
|
7
|
+
* Converts a human intent + guardrails into a cryptographically signed, scoped
|
|
8
|
+
* mandate (the "tamper-resistant intent" layer that Google AP2 and Visa CLI
|
|
9
|
+
* governance both require). Agents present the mandate; merchants/fleets verify
|
|
10
|
+
* the proposed payment fits the signed scope before money moves.
|
|
11
|
+
*/
|
|
12
|
+
export async function runMandateCompile(input) {
|
|
13
|
+
const ttl = input.ttlMinutes ?? 1440;
|
|
14
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
15
|
+
const validUntilSec = input.validUntil ?? nowSec + ttl * 60;
|
|
16
|
+
const maxExpiry = nowSec + 86400 * 30;
|
|
17
|
+
if (validUntilSec > maxExpiry) {
|
|
18
|
+
throw new Error("AP2 mandate cannot exceed 30 days validity");
|
|
19
|
+
}
|
|
20
|
+
const scope = {
|
|
21
|
+
maxPerTxUsdc: input.maxPerTxUsdc,
|
|
22
|
+
dailyCapUsdc: input.dailyCapUsdc,
|
|
23
|
+
allowedMerchants: input.allowedMerchants ?? [],
|
|
24
|
+
allowedCategories: input.allowedCategories ?? [],
|
|
25
|
+
allowedRails: input.allowedRails ?? [],
|
|
26
|
+
expiresAt: new Date(validUntilSec * 1000).toISOString(),
|
|
27
|
+
};
|
|
28
|
+
const record = await issueMandate({
|
|
29
|
+
principal: input.principal,
|
|
30
|
+
agentId: input.agentId,
|
|
31
|
+
intent: input.intent,
|
|
32
|
+
scope,
|
|
33
|
+
});
|
|
34
|
+
return withAgentTrust({
|
|
35
|
+
mandate: record,
|
|
36
|
+
verifiableCredential: mandateToVC(record, input.principal.startsWith("did:") ? input.principal : undefined),
|
|
37
|
+
ap2: {
|
|
38
|
+
mandateVersion: input.mandateVersion ?? "ap2/v1",
|
|
39
|
+
validFrom: nowSec,
|
|
40
|
+
validUntil: validUntilSec,
|
|
41
|
+
currency: input.currency ?? "USDC",
|
|
42
|
+
network: input.network ?? "eip155:8453",
|
|
43
|
+
},
|
|
44
|
+
verifyUrl: `${config.publicBaseUrl}/api/mandate/verify`,
|
|
45
|
+
usage: "Present mandateId to merchants/fleet controllers; they POST it to /api/mandate/verify with the proposed payment to confirm scope.",
|
|
46
|
+
}, agentTrustMeta(["intent_hashed", "scope_bound", "hmac_signed"], {
|
|
47
|
+
confidence: 0.92,
|
|
48
|
+
sources: ["mandate-notary", "ap2-aligned"],
|
|
49
|
+
accuracy_note: "Mandate is HMAC-signed and tamper-evident; binding to a real cardholder/Visa CLI principal is the integrator's responsibility.",
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
export async function runMandateVerify(input) {
|
|
53
|
+
const result = await verifyMandate(input.mandateId, input.proposed);
|
|
54
|
+
const allowed = result.valid && result.withinScope;
|
|
55
|
+
return withAgentTrust({
|
|
56
|
+
ok: true,
|
|
57
|
+
allowed,
|
|
58
|
+
valid: result.valid,
|
|
59
|
+
withinScope: result.withinScope,
|
|
60
|
+
reason: result.reason,
|
|
61
|
+
record: result.record,
|
|
62
|
+
violations: result.violations,
|
|
63
|
+
mandateId: input.mandateId,
|
|
64
|
+
proposed: input.proposed ?? null,
|
|
65
|
+
}, agentTrustMeta(result.valid
|
|
66
|
+
? result.withinScope
|
|
67
|
+
? ["signature_ok", "scope_ok", "not_expired"]
|
|
68
|
+
: ["signature_ok", "scope_violation"]
|
|
69
|
+
: ["signature_or_lookup_failed"], {
|
|
70
|
+
confidence: result.valid ? 0.93 : 0.6,
|
|
71
|
+
sources: ["mandate-notary", "hmac-verify"],
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type MandateCheck } from "../lib/mandate.js";
|
|
2
|
+
export type ToolCallTrace = {
|
|
3
|
+
name: string;
|
|
4
|
+
url?: string;
|
|
5
|
+
amountUsdc?: number;
|
|
6
|
+
merchant?: string;
|
|
7
|
+
category?: string;
|
|
8
|
+
rail?: string;
|
|
9
|
+
argsSummary?: string;
|
|
10
|
+
};
|
|
11
|
+
export type MandateDiffInput = {
|
|
12
|
+
mandateId: string;
|
|
13
|
+
toolCalls: ToolCallTrace[];
|
|
14
|
+
/** Optional aggregate payment the agent is about to authorize */
|
|
15
|
+
proposed?: MandateCheck;
|
|
16
|
+
/** Human-readable task for semantic drift checks */
|
|
17
|
+
task?: string;
|
|
18
|
+
};
|
|
19
|
+
type DiffViolation = {
|
|
20
|
+
code: string;
|
|
21
|
+
severity: "block" | "step_up";
|
|
22
|
+
message: string;
|
|
23
|
+
evidence?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Intent Diff Engine — compares a signed mandate scope to the actual MCP/tool trace
|
|
27
|
+
* before x402 payment. Rules-first (auditable); complements t54 behavioral risk.
|
|
28
|
+
*/
|
|
29
|
+
export declare function runMandateDiff(input: MandateDiffInput): Promise<{
|
|
30
|
+
ok: boolean;
|
|
31
|
+
allowed: boolean;
|
|
32
|
+
liabilityTier: string;
|
|
33
|
+
mandateValid: boolean;
|
|
34
|
+
withinMandateScope: boolean;
|
|
35
|
+
violations: DiffViolation[];
|
|
36
|
+
signals: string[];
|
|
37
|
+
mandateId: string;
|
|
38
|
+
toolCallCount: number;
|
|
39
|
+
summary: string;
|
|
40
|
+
} & import("../lib/agent-response.js").AgentTrustMeta>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { verifyMandate } from "../lib/mandate.js";
|
|
2
|
+
import { hostOf } from "../lib/probe.js";
|
|
3
|
+
import { agentTrustMeta, withAgentTrust } from "../lib/agent-response.js";
|
|
4
|
+
const AFFILIATE_HINTS = /[?&](aff|ref|utm_|affiliate)=/i;
|
|
5
|
+
const SUSPICIOUS_DOMAINS = /scam|phish|invalid|fake-wallet/i;
|
|
6
|
+
function tierFromViolations(violations) {
|
|
7
|
+
if (violations.some((v) => v.severity === "block"))
|
|
8
|
+
return "block";
|
|
9
|
+
if (violations.length > 0)
|
|
10
|
+
return "step_up";
|
|
11
|
+
return "allow";
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Intent Diff Engine — compares a signed mandate scope to the actual MCP/tool trace
|
|
15
|
+
* before x402 payment. Rules-first (auditable); complements t54 behavioral risk.
|
|
16
|
+
*/
|
|
17
|
+
export async function runMandateDiff(input) {
|
|
18
|
+
const violations = [];
|
|
19
|
+
const signals = [];
|
|
20
|
+
const mandateResult = await verifyMandate(input.mandateId, input.proposed);
|
|
21
|
+
if (!mandateResult.valid) {
|
|
22
|
+
violations.push({
|
|
23
|
+
code: "mandate_invalid",
|
|
24
|
+
severity: "block",
|
|
25
|
+
message: mandateResult.reason,
|
|
26
|
+
});
|
|
27
|
+
return withAgentTrust({
|
|
28
|
+
ok: true,
|
|
29
|
+
allowed: false,
|
|
30
|
+
liabilityTier: "block",
|
|
31
|
+
mandateValid: false,
|
|
32
|
+
withinMandateScope: false,
|
|
33
|
+
violations,
|
|
34
|
+
signals,
|
|
35
|
+
mandateId: input.mandateId,
|
|
36
|
+
toolCallCount: input.toolCalls.length,
|
|
37
|
+
summary: "Mandate invalid — do not pay",
|
|
38
|
+
}, agentTrustMeta(["mandate_invalid"], { confidence: 0.95, sources: ["mandate-diff"] }));
|
|
39
|
+
}
|
|
40
|
+
if (!mandateResult.withinScope && input.proposed) {
|
|
41
|
+
for (const v of mandateResult.violations) {
|
|
42
|
+
violations.push({ code: "scope_violation", severity: "block", message: v });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const scope = mandateResult.record?.scope;
|
|
46
|
+
const allowedMerchants = scope?.allowedMerchants ?? [];
|
|
47
|
+
const allowedCategories = scope?.allowedCategories ?? [];
|
|
48
|
+
const allowedRails = scope?.allowedRails ?? [];
|
|
49
|
+
const maxPerTx = scope?.maxPerTxUsdc ?? Infinity;
|
|
50
|
+
for (const [i, call] of input.toolCalls.entries()) {
|
|
51
|
+
const label = `toolCalls[${i}]`;
|
|
52
|
+
if (call.url) {
|
|
53
|
+
if (SUSPICIOUS_DOMAINS.test(call.url)) {
|
|
54
|
+
violations.push({
|
|
55
|
+
code: "suspicious_url",
|
|
56
|
+
severity: "block",
|
|
57
|
+
message: `${label}: URL matches suspicious pattern`,
|
|
58
|
+
evidence: call.url,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (AFFILIATE_HINTS.test(call.url)) {
|
|
62
|
+
violations.push({
|
|
63
|
+
code: "affiliate_redirect",
|
|
64
|
+
severity: "step_up",
|
|
65
|
+
message: `${label}: affiliate/tracking params in URL — possible prompt-injected routing`,
|
|
66
|
+
evidence: call.url,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const host = hostOf(call.url);
|
|
70
|
+
if (allowedMerchants.length > 0 &&
|
|
71
|
+
host &&
|
|
72
|
+
!allowedMerchants.some((m) => host.includes(m.toLowerCase()) || call.url.toLowerCase().includes(m.toLowerCase()))) {
|
|
73
|
+
violations.push({
|
|
74
|
+
code: "merchant_not_in_mandate",
|
|
75
|
+
severity: "block",
|
|
76
|
+
message: `${label}: host ${host} not in allowedMerchants`,
|
|
77
|
+
evidence: call.url,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (call.merchant && allowedMerchants.length > 0) {
|
|
82
|
+
if (!allowedMerchants.some((m) => call.merchant.toLowerCase().includes(m.toLowerCase()))) {
|
|
83
|
+
violations.push({
|
|
84
|
+
code: "merchant_not_in_mandate",
|
|
85
|
+
severity: "block",
|
|
86
|
+
message: `${label}: merchant ${call.merchant} not in allowedMerchants`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (call.category && allowedCategories.length > 0 && !allowedCategories.includes(call.category)) {
|
|
91
|
+
violations.push({
|
|
92
|
+
code: "category_not_in_mandate",
|
|
93
|
+
severity: "block",
|
|
94
|
+
message: `${label}: category ${call.category} not in allowedCategories`,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (call.rail && allowedRails.length > 0 && !allowedRails.includes(call.rail)) {
|
|
98
|
+
violations.push({
|
|
99
|
+
code: "rail_not_in_mandate",
|
|
100
|
+
severity: "block",
|
|
101
|
+
message: `${label}: rail ${call.rail} not in allowedRails`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (typeof call.amountUsdc === "number" && call.amountUsdc > maxPerTx) {
|
|
105
|
+
violations.push({
|
|
106
|
+
code: "amount_exceeds_mandate",
|
|
107
|
+
severity: "block",
|
|
108
|
+
message: `${label}: amount ${call.amountUsdc} exceeds maxPerTxUsdc ${maxPerTx}`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (call.argsSummary && /prefer store|rewrite url|ignore mandate|override/i.test(call.argsSummary)) {
|
|
112
|
+
violations.push({
|
|
113
|
+
code: "instruction_tampering",
|
|
114
|
+
severity: "block",
|
|
115
|
+
message: `${label}: tool args suggest non-mandated instruction override`,
|
|
116
|
+
evidence: call.argsSummary.slice(0, 120),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (input.task && mandateResult.record?.intent) {
|
|
121
|
+
const intent = mandateResult.record.intent.toLowerCase();
|
|
122
|
+
const task = input.task.toLowerCase();
|
|
123
|
+
const intentTokens = intent.split(/\W+/).filter((t) => t.length > 3);
|
|
124
|
+
const overlap = intentTokens.filter((t) => task.includes(t)).length;
|
|
125
|
+
if (intentTokens.length >= 3 && overlap < Math.ceil(intentTokens.length * 0.2)) {
|
|
126
|
+
violations.push({
|
|
127
|
+
code: "task_intent_drift",
|
|
128
|
+
severity: "step_up",
|
|
129
|
+
message: "Current task text diverges from signed mandate intent — human confirm recommended",
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
signals.push("Task text loosely aligns with mandate intent");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const liabilityTier = tierFromViolations(violations);
|
|
137
|
+
const allowed = liabilityTier === "allow";
|
|
138
|
+
const withinMandateScope = mandateResult.withinScope && violations.every((v) => v.severity !== "block");
|
|
139
|
+
return withAgentTrust({
|
|
140
|
+
ok: true,
|
|
141
|
+
allowed,
|
|
142
|
+
liabilityTier,
|
|
143
|
+
mandateValid: true,
|
|
144
|
+
withinMandateScope,
|
|
145
|
+
mandateId: input.mandateId,
|
|
146
|
+
toolCallCount: input.toolCalls.length,
|
|
147
|
+
violations,
|
|
148
|
+
signals,
|
|
149
|
+
mandateIntent: mandateResult.record?.intent ?? null,
|
|
150
|
+
proposed: input.proposed ?? null,
|
|
151
|
+
summary: liabilityTier === "allow"
|
|
152
|
+
? "Tool trace within mandate scope — proceed to x402 payment"
|
|
153
|
+
: liabilityTier === "step_up"
|
|
154
|
+
? "Non-blocking drift detected — step-up auth before payment"
|
|
155
|
+
: "Blocking violations — do not pay",
|
|
156
|
+
nextStep: liabilityTier === "block"
|
|
157
|
+
? { method: "POST", path: "/api/mandate/verify", note: "Re-compile mandate or fix tool trace" }
|
|
158
|
+
: liabilityTier === "step_up"
|
|
159
|
+
? { method: "POST", path: "/api/attestation/issue", note: "Issue fresh attestation after human confirm" }
|
|
160
|
+
: null,
|
|
161
|
+
}, agentTrustMeta(allowed
|
|
162
|
+
? ["mandate_ok", "trace_ok"]
|
|
163
|
+
: liabilityTier === "step_up"
|
|
164
|
+
? ["mandate_ok", "trace_drift"]
|
|
165
|
+
: ["mandate_ok", "trace_blocked"], {
|
|
166
|
+
confidence: 0.9,
|
|
167
|
+
sources: ["mandate-diff", "ap2-aligned"],
|
|
168
|
+
accuracy_note: "Diff is rules-based on supplied toolCalls; integrator must capture faithful MCP/browser traces.",
|
|
169
|
+
}));
|
|
170
|
+
}
|