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,171 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { config } from "../../config.js";
|
|
3
|
+
import { DEFAULT_IDENTITY_REGISTRY, DEFAULT_REPUTATION_REGISTRY, ERC8004_CHAIN_ID, } from "./constants.js";
|
|
4
|
+
const identityRegistryAbi = [
|
|
5
|
+
{
|
|
6
|
+
inputs: [{ name: "tokenId", type: "uint256" }],
|
|
7
|
+
name: "ownerOf",
|
|
8
|
+
outputs: [{ name: "", type: "address" }],
|
|
9
|
+
stateMutability: "view",
|
|
10
|
+
type: "function",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
inputs: [{ name: "tokenId", type: "uint256" }],
|
|
14
|
+
name: "tokenURI",
|
|
15
|
+
outputs: [{ name: "", type: "string" }],
|
|
16
|
+
stateMutability: "view",
|
|
17
|
+
type: "function",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
inputs: [{ name: "agentId", type: "uint256" }],
|
|
21
|
+
name: "getAgentWallet",
|
|
22
|
+
outputs: [{ name: "", type: "address" }],
|
|
23
|
+
stateMutability: "view",
|
|
24
|
+
type: "function",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
inputs: [{ name: "owner", type: "address" }],
|
|
28
|
+
name: "balanceOf",
|
|
29
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
30
|
+
stateMutability: "view",
|
|
31
|
+
type: "function",
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
const reputationRegistryAbi = [
|
|
35
|
+
{
|
|
36
|
+
inputs: [
|
|
37
|
+
{ name: "agentId", type: "uint256" },
|
|
38
|
+
{ name: "clientAddresses", type: "address[]" },
|
|
39
|
+
{ name: "tag1", type: "string" },
|
|
40
|
+
{ name: "tag2", type: "string" },
|
|
41
|
+
],
|
|
42
|
+
name: "getSummary",
|
|
43
|
+
outputs: [
|
|
44
|
+
{ name: "count", type: "uint64" },
|
|
45
|
+
{ name: "summaryValue", type: "int128" },
|
|
46
|
+
{ name: "summaryValueDecimals", type: "uint8" },
|
|
47
|
+
],
|
|
48
|
+
stateMutability: "view",
|
|
49
|
+
type: "function",
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
async function ethCall(to, data) {
|
|
53
|
+
const res = await fetch(config.baseRpcUrl, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: { "content-type": "application/json" },
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
jsonrpc: "2.0",
|
|
58
|
+
id: 1,
|
|
59
|
+
method: "eth_call",
|
|
60
|
+
params: [{ to, data }, "latest"],
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
if (!res.ok)
|
|
64
|
+
return null;
|
|
65
|
+
const json = (await res.json());
|
|
66
|
+
if (!json.result || json.result === "0x")
|
|
67
|
+
return null;
|
|
68
|
+
return json.result;
|
|
69
|
+
}
|
|
70
|
+
function decodeAddress(result) {
|
|
71
|
+
if (result.length < 66)
|
|
72
|
+
return null;
|
|
73
|
+
return `0x${result.slice(-40)}`;
|
|
74
|
+
}
|
|
75
|
+
function decodeUint256(result) {
|
|
76
|
+
return BigInt(result);
|
|
77
|
+
}
|
|
78
|
+
function decodeString(result) {
|
|
79
|
+
try {
|
|
80
|
+
const hex = result.slice(2);
|
|
81
|
+
if (hex.length < 128)
|
|
82
|
+
return null;
|
|
83
|
+
const offset = Number(BigInt(`0x${hex.slice(0, 64)}`)) * 2;
|
|
84
|
+
const len = Number(BigInt(`0x${hex.slice(offset, offset + 64)}`));
|
|
85
|
+
const data = hex.slice(offset + 64, offset + 64 + len * 2);
|
|
86
|
+
const bytes = new Uint8Array(len);
|
|
87
|
+
for (let i = 0; i < len; i++) {
|
|
88
|
+
bytes[i] = parseInt(data.slice(i * 2, i * 2 + 2), 16);
|
|
89
|
+
}
|
|
90
|
+
return new TextDecoder().decode(bytes);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function decodeSummary(result) {
|
|
97
|
+
try {
|
|
98
|
+
const hex = result.slice(2);
|
|
99
|
+
if (hex.length < 192)
|
|
100
|
+
return null;
|
|
101
|
+
const count = BigInt(`0x${hex.slice(0, 64)}`);
|
|
102
|
+
const summaryValue = BigInt(`0x${hex.slice(64, 128)}`);
|
|
103
|
+
const summaryValueDecimals = Number(BigInt(`0x${hex.slice(128, 192)}`));
|
|
104
|
+
return { count, summaryValue, summaryValueDecimals };
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export function identityRegistryAddress() {
|
|
111
|
+
return (config.erc8004IdentityRegistry || DEFAULT_IDENTITY_REGISTRY);
|
|
112
|
+
}
|
|
113
|
+
export function reputationRegistryAddress() {
|
|
114
|
+
return (config.erc8004ReputationRegistry || DEFAULT_REPUTATION_REGISTRY);
|
|
115
|
+
}
|
|
116
|
+
export async function readOwnerOf(agentId) {
|
|
117
|
+
const data = encodeFunctionData({
|
|
118
|
+
abi: identityRegistryAbi,
|
|
119
|
+
functionName: "ownerOf",
|
|
120
|
+
args: [agentId],
|
|
121
|
+
});
|
|
122
|
+
const result = await ethCall(identityRegistryAddress(), data);
|
|
123
|
+
return result ? decodeAddress(result) : null;
|
|
124
|
+
}
|
|
125
|
+
export async function readTokenUri(agentId) {
|
|
126
|
+
const data = encodeFunctionData({
|
|
127
|
+
abi: identityRegistryAbi,
|
|
128
|
+
functionName: "tokenURI",
|
|
129
|
+
args: [agentId],
|
|
130
|
+
});
|
|
131
|
+
const result = await ethCall(identityRegistryAddress(), data);
|
|
132
|
+
return result ? decodeString(result) : null;
|
|
133
|
+
}
|
|
134
|
+
export async function readAgentWallet(agentId) {
|
|
135
|
+
const data = encodeFunctionData({
|
|
136
|
+
abi: identityRegistryAbi,
|
|
137
|
+
functionName: "getAgentWallet",
|
|
138
|
+
args: [agentId],
|
|
139
|
+
});
|
|
140
|
+
const result = await ethCall(identityRegistryAddress(), data);
|
|
141
|
+
const wallet = result ? decodeAddress(result) : null;
|
|
142
|
+
if (!wallet || wallet === "0x0000000000000000000000000000000000000000")
|
|
143
|
+
return null;
|
|
144
|
+
return wallet;
|
|
145
|
+
}
|
|
146
|
+
export async function readBalanceOf(wallet) {
|
|
147
|
+
const data = encodeFunctionData({
|
|
148
|
+
abi: identityRegistryAbi,
|
|
149
|
+
functionName: "balanceOf",
|
|
150
|
+
args: [wallet],
|
|
151
|
+
});
|
|
152
|
+
const result = await ethCall(identityRegistryAddress(), data);
|
|
153
|
+
return result ? decodeUint256(result) : 0n;
|
|
154
|
+
}
|
|
155
|
+
export async function readReputationSummary(agentId) {
|
|
156
|
+
const data = encodeFunctionData({
|
|
157
|
+
abi: reputationRegistryAbi,
|
|
158
|
+
functionName: "getSummary",
|
|
159
|
+
args: [agentId, [], "", ""],
|
|
160
|
+
});
|
|
161
|
+
const result = await ethCall(reputationRegistryAddress(), data);
|
|
162
|
+
return result ? decodeSummary(result) : null;
|
|
163
|
+
}
|
|
164
|
+
export function chainMeta() {
|
|
165
|
+
return {
|
|
166
|
+
caip2: "eip155:8453",
|
|
167
|
+
chainId: ERC8004_CHAIN_ID,
|
|
168
|
+
identityRegistry: identityRegistryAddress(),
|
|
169
|
+
reputationRegistry: reputationRegistryAddress(),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
export type AgentResolution = {
|
|
3
|
+
agentId: bigint | null;
|
|
4
|
+
source: "body" | "alchemy" | "none";
|
|
5
|
+
guidance: string | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function resolveAgentId(wallet: Address, agentIdInput?: string | number | bigint): Promise<AgentResolution>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { config } from "../../config.js";
|
|
2
|
+
import { identityRegistryAddress, readBalanceOf, readOwnerOf } from "./registry.js";
|
|
3
|
+
async function resolveViaAlchemy(wallet) {
|
|
4
|
+
const apiKey = config.alchemyApiKey;
|
|
5
|
+
if (!apiKey)
|
|
6
|
+
return null;
|
|
7
|
+
const registry = identityRegistryAddress();
|
|
8
|
+
const url = new URL(`https://base-mainnet.g.alchemy.com/nft/v3/${apiKey}/getNFTsForOwner`);
|
|
9
|
+
url.searchParams.set("owner", wallet);
|
|
10
|
+
url.searchParams.append("contractAddresses[]", registry);
|
|
11
|
+
url.searchParams.set("withMetadata", "false");
|
|
12
|
+
const res = await fetch(url.toString(), { signal: AbortSignal.timeout(8000) });
|
|
13
|
+
if (!res.ok)
|
|
14
|
+
return null;
|
|
15
|
+
const json = (await res.json());
|
|
16
|
+
const first = json.ownedNfts?.[0];
|
|
17
|
+
if (!first?.tokenId)
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
return BigInt(first.tokenId);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function resolveAgentId(wallet, agentIdInput) {
|
|
27
|
+
if (agentIdInput != null && agentIdInput !== "") {
|
|
28
|
+
try {
|
|
29
|
+
const agentId = BigInt(agentIdInput);
|
|
30
|
+
const owner = await readOwnerOf(agentId);
|
|
31
|
+
if (owner && owner.toLowerCase() === wallet.toLowerCase()) {
|
|
32
|
+
return { agentId, source: "body", guidance: null };
|
|
33
|
+
}
|
|
34
|
+
if (owner) {
|
|
35
|
+
return {
|
|
36
|
+
agentId: null,
|
|
37
|
+
source: "body",
|
|
38
|
+
guidance: `agentId ${agentId} is owned by ${owner}, not ${wallet}`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
agentId: null,
|
|
43
|
+
source: "body",
|
|
44
|
+
guidance: `agentId ${agentId} not found on ERC-8004 IdentityRegistry`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return { agentId: null, source: "body", guidance: "Invalid agentId in request body" };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const balance = await readBalanceOf(wallet);
|
|
52
|
+
if (balance === 0n) {
|
|
53
|
+
return {
|
|
54
|
+
agentId: null,
|
|
55
|
+
source: "none",
|
|
56
|
+
guidance: config.alchemyApiKey
|
|
57
|
+
? "No ERC-8004 agent NFT found for this wallet on Base mainnet"
|
|
58
|
+
: "Provide agentId in body or set ALCHEMY_API_KEY for wallet→agentId NFT lookup",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const fromAlchemy = await resolveViaAlchemy(wallet);
|
|
62
|
+
if (fromAlchemy != null) {
|
|
63
|
+
return { agentId: fromAlchemy, source: "alchemy", guidance: null };
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
agentId: null,
|
|
67
|
+
source: "none",
|
|
68
|
+
guidance: "Wallet holds ERC-8004 NFT(s) but agentId could not be resolved — pass agentId explicitly or configure ALCHEMY_API_KEY",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type TrustTier } from "./constants.js";
|
|
2
|
+
import { chainMeta } from "./registry.js";
|
|
3
|
+
export type TrustScoreBreakdown = {
|
|
4
|
+
onChainRegistration: number;
|
|
5
|
+
reputation: number;
|
|
6
|
+
walletVerified: number;
|
|
7
|
+
agentCard: number;
|
|
8
|
+
domainWellKnown: number;
|
|
9
|
+
paymentHistory: number;
|
|
10
|
+
};
|
|
11
|
+
export type TrustScoreResult = {
|
|
12
|
+
walletAddress: string;
|
|
13
|
+
agentId: string | null;
|
|
14
|
+
chain: ReturnType<typeof chainMeta>;
|
|
15
|
+
trustScore: number;
|
|
16
|
+
tier: TrustTier;
|
|
17
|
+
breakdown: TrustScoreBreakdown;
|
|
18
|
+
registered: boolean;
|
|
19
|
+
owner: string | null;
|
|
20
|
+
agentWallet: string | null;
|
|
21
|
+
agentUri: string | null;
|
|
22
|
+
reputationCount: number;
|
|
23
|
+
resolutionSource: "body" | "alchemy" | "none";
|
|
24
|
+
guidance: string | null;
|
|
25
|
+
cached: boolean;
|
|
26
|
+
flags: string[];
|
|
27
|
+
};
|
|
28
|
+
export declare function computeTrustScore(input: {
|
|
29
|
+
walletAddress: string;
|
|
30
|
+
agentId?: string | number;
|
|
31
|
+
skipCache?: boolean;
|
|
32
|
+
}): Promise<TrustScoreResult>;
|
|
33
|
+
export declare function meetsMinTier(current: TrustTier, required: TrustTier): boolean;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { config } from "../../config.js";
|
|
2
|
+
import { fetchAgentCard, scoreAgentCard, verifyWellKnown, } from "./agent-card.js";
|
|
3
|
+
import { cacheGet, cacheKey, cacheSet } from "./cache.js";
|
|
4
|
+
import { isEvmAddress, tierForScore, TRUST_SCORE_WEIGHTS, } from "./constants.js";
|
|
5
|
+
import { chainMeta, readAgentWallet, readOwnerOf, readReputationSummary, readTokenUri, } from "./registry.js";
|
|
6
|
+
import { resolveAgentId } from "./resolve-agent.js";
|
|
7
|
+
function reputationPoints(summary) {
|
|
8
|
+
if (!summary || summary.count === 0n)
|
|
9
|
+
return 0;
|
|
10
|
+
const max = TRUST_SCORE_WEIGHTS.reputation;
|
|
11
|
+
const decimals = summary.summaryValueDecimals;
|
|
12
|
+
const raw = Number(summary.summaryValue);
|
|
13
|
+
const normalized = decimals > 0 ? raw / 10 ** decimals : raw;
|
|
14
|
+
// ERC-8004 feedback is typically 0–100; clamp and scale to 0–25.
|
|
15
|
+
const clamped = Math.max(0, Math.min(100, normalized));
|
|
16
|
+
const volumeBoost = summary.count >= 5n ? 1 : Number(summary.count) / 5;
|
|
17
|
+
return Math.round((clamped / 100) * max * volumeBoost);
|
|
18
|
+
}
|
|
19
|
+
export async function computeTrustScore(input) {
|
|
20
|
+
const wallet = input.walletAddress.trim();
|
|
21
|
+
if (!isEvmAddress(wallet)) {
|
|
22
|
+
return {
|
|
23
|
+
walletAddress: wallet,
|
|
24
|
+
agentId: null,
|
|
25
|
+
chain: chainMeta(),
|
|
26
|
+
trustScore: 0,
|
|
27
|
+
tier: "UNKNOWN",
|
|
28
|
+
breakdown: {
|
|
29
|
+
onChainRegistration: 0,
|
|
30
|
+
reputation: 0,
|
|
31
|
+
walletVerified: 0,
|
|
32
|
+
agentCard: 0,
|
|
33
|
+
domainWellKnown: 0,
|
|
34
|
+
paymentHistory: 0,
|
|
35
|
+
},
|
|
36
|
+
registered: false,
|
|
37
|
+
owner: null,
|
|
38
|
+
agentWallet: null,
|
|
39
|
+
agentUri: null,
|
|
40
|
+
reputationCount: 0,
|
|
41
|
+
resolutionSource: "none",
|
|
42
|
+
guidance: "Invalid or missing EVM wallet address",
|
|
43
|
+
cached: false,
|
|
44
|
+
flags: ["invalid_wallet"],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const ttl = config.trustScoreCacheTtlSec;
|
|
48
|
+
const key = cacheKey(["trustscore", wallet.toLowerCase(), input.agentId ?? ""]);
|
|
49
|
+
if (!input.skipCache) {
|
|
50
|
+
const hit = cacheGet(key);
|
|
51
|
+
if (hit)
|
|
52
|
+
return { ...hit, cached: true };
|
|
53
|
+
}
|
|
54
|
+
const flags = [];
|
|
55
|
+
const resolved = await resolveAgentId(wallet, input.agentId);
|
|
56
|
+
const agentId = resolved.agentId;
|
|
57
|
+
let onChainRegistration = 0;
|
|
58
|
+
let owner = null;
|
|
59
|
+
let agentWallet = null;
|
|
60
|
+
let agentUri = null;
|
|
61
|
+
let reputationCount = 0;
|
|
62
|
+
let reputation = 0;
|
|
63
|
+
let walletVerified = 0;
|
|
64
|
+
let agentCardPts = 0;
|
|
65
|
+
let domainPts = 0;
|
|
66
|
+
if (agentId != null) {
|
|
67
|
+
onChainRegistration = TRUST_SCORE_WEIGHTS.onChainRegistration;
|
|
68
|
+
owner = (await readOwnerOf(agentId)) ?? null;
|
|
69
|
+
if (owner && owner.toLowerCase() !== wallet.toLowerCase()) {
|
|
70
|
+
flags.push("wallet_not_owner");
|
|
71
|
+
onChainRegistration = Math.round(TRUST_SCORE_WEIGHTS.onChainRegistration * 0.5);
|
|
72
|
+
}
|
|
73
|
+
const verifiedWallet = await readAgentWallet(agentId);
|
|
74
|
+
agentWallet = verifiedWallet;
|
|
75
|
+
if (verifiedWallet &&
|
|
76
|
+
verifiedWallet.toLowerCase() === wallet.toLowerCase()) {
|
|
77
|
+
walletVerified = TRUST_SCORE_WEIGHTS.walletVerified;
|
|
78
|
+
}
|
|
79
|
+
const rep = await readReputationSummary(agentId);
|
|
80
|
+
reputationCount = rep ? Number(rep.count) : 0;
|
|
81
|
+
reputation = reputationPoints(rep);
|
|
82
|
+
agentUri = await readTokenUri(agentId);
|
|
83
|
+
if (agentUri) {
|
|
84
|
+
const card = await fetchAgentCard(agentUri);
|
|
85
|
+
const cardScore = scoreAgentCard(card, agentUri);
|
|
86
|
+
agentCardPts = cardScore.points;
|
|
87
|
+
if (!cardScore.valid)
|
|
88
|
+
flags.push("incomplete_agent_card");
|
|
89
|
+
const wellKnown = await verifyWellKnown(cardScore.domain);
|
|
90
|
+
domainPts = wellKnown.points;
|
|
91
|
+
if (!wellKnown.verified && cardScore.domain)
|
|
92
|
+
flags.push("domain_not_verified");
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
flags.push("missing_agent_uri");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (resolved.guidance) {
|
|
99
|
+
flags.push("unregistered");
|
|
100
|
+
}
|
|
101
|
+
// Phase 2 — payment history from Trust Layer ledger (stub 0).
|
|
102
|
+
const paymentHistory = 0;
|
|
103
|
+
const breakdown = {
|
|
104
|
+
onChainRegistration,
|
|
105
|
+
reputation,
|
|
106
|
+
walletVerified,
|
|
107
|
+
agentCard: agentCardPts,
|
|
108
|
+
domainWellKnown: domainPts,
|
|
109
|
+
paymentHistory,
|
|
110
|
+
};
|
|
111
|
+
const trustScore = Object.values(breakdown).reduce((a, b) => a + b, 0);
|
|
112
|
+
const tier = tierForScore(trustScore);
|
|
113
|
+
const result = {
|
|
114
|
+
walletAddress: wallet,
|
|
115
|
+
agentId: agentId != null ? agentId.toString() : null,
|
|
116
|
+
chain: chainMeta(),
|
|
117
|
+
trustScore,
|
|
118
|
+
tier,
|
|
119
|
+
breakdown,
|
|
120
|
+
registered: agentId != null,
|
|
121
|
+
owner,
|
|
122
|
+
agentWallet,
|
|
123
|
+
agentUri,
|
|
124
|
+
reputationCount,
|
|
125
|
+
resolutionSource: resolved.source,
|
|
126
|
+
guidance: resolved.guidance,
|
|
127
|
+
cached: false,
|
|
128
|
+
flags,
|
|
129
|
+
};
|
|
130
|
+
cacheSet(key, result, ttl);
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
export function meetsMinTier(current, required) {
|
|
134
|
+
const order = ["PLATINUM", "GOLD", "SILVER", "BRONZE", "UNVERIFIED", "UNKNOWN"];
|
|
135
|
+
return order.indexOf(current) <= order.indexOf(required);
|
|
136
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type EscrowRecord = {
|
|
2
|
+
id: string;
|
|
3
|
+
payerAgentId: string;
|
|
4
|
+
payeeAgentId: string;
|
|
5
|
+
amountUsdc: number;
|
|
6
|
+
status: "pending" | "released" | "cancelled";
|
|
7
|
+
releaseCondition: string;
|
|
8
|
+
createdAt: string;
|
|
9
|
+
releasedAt: string | null;
|
|
10
|
+
metadata?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
export declare function createEscrow(input: Omit<EscrowRecord, "id" | "status" | "createdAt" | "releasedAt">): Promise<EscrowRecord>;
|
|
13
|
+
export declare function getEscrow(id: string): Promise<EscrowRecord | null>;
|
|
14
|
+
export declare function releaseEscrow(id: string): Promise<EscrowRecord | null>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { getEscrowFromDb, saveEscrowToDb, } from "./db-persistence.js";
|
|
5
|
+
import { syncLedgerEscrow } from "./escrow-unified.js";
|
|
6
|
+
const DATA_DIR = path.join(process.cwd(), "data");
|
|
7
|
+
async function readStore() {
|
|
8
|
+
await mkdir(DATA_DIR, { recursive: true });
|
|
9
|
+
const file = path.join(DATA_DIR, "escrow-ledger.json");
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(await readFile(file, "utf8"));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function writeStore(store) {
|
|
18
|
+
const file = path.join(DATA_DIR, "escrow-ledger.json");
|
|
19
|
+
await writeFile(file, JSON.stringify(store, null, 2), "utf8");
|
|
20
|
+
}
|
|
21
|
+
export async function createEscrow(input) {
|
|
22
|
+
const store = await readStore();
|
|
23
|
+
const record = {
|
|
24
|
+
...input,
|
|
25
|
+
id: randomUUID(),
|
|
26
|
+
status: "pending",
|
|
27
|
+
createdAt: new Date().toISOString(),
|
|
28
|
+
releasedAt: null,
|
|
29
|
+
};
|
|
30
|
+
store[record.id] = record;
|
|
31
|
+
await writeStore(store);
|
|
32
|
+
saveEscrowToDb(record);
|
|
33
|
+
syncLedgerEscrow(record);
|
|
34
|
+
return record;
|
|
35
|
+
}
|
|
36
|
+
export async function getEscrow(id) {
|
|
37
|
+
const fromDb = getEscrowFromDb(id);
|
|
38
|
+
if (fromDb)
|
|
39
|
+
return fromDb;
|
|
40
|
+
const store = await readStore();
|
|
41
|
+
return store[id] ?? null;
|
|
42
|
+
}
|
|
43
|
+
export async function releaseEscrow(id) {
|
|
44
|
+
const store = await readStore();
|
|
45
|
+
const record = store[id];
|
|
46
|
+
if (!record || record.status !== "pending")
|
|
47
|
+
return null;
|
|
48
|
+
record.status = "released";
|
|
49
|
+
record.releasedAt = new Date().toISOString();
|
|
50
|
+
await writeStore(store);
|
|
51
|
+
saveEscrowToDb(record);
|
|
52
|
+
syncLedgerEscrow(record);
|
|
53
|
+
return record;
|
|
54
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EscrowState } from "../protocol/escrow-fsm.js";
|
|
2
|
+
import type { EscrowRecord } from "./escrow-ledger.js";
|
|
3
|
+
export declare function syncProtocolEscrow(input: {
|
|
4
|
+
escrowId: string;
|
|
5
|
+
payerAgentId: string;
|
|
6
|
+
payeeId: string;
|
|
7
|
+
amountUsdc: number;
|
|
8
|
+
state: EscrowState | string;
|
|
9
|
+
resourceHash?: string;
|
|
10
|
+
sessionId?: string;
|
|
11
|
+
stateProof: string;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}): void;
|
|
14
|
+
export declare function recordEscrowTransition(escrowId: string, fromState: string, toState: string, note?: string, proof?: string): void;
|
|
15
|
+
export declare function syncLedgerEscrow(record: EscrowRecord): void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { db } from "./db.js";
|
|
2
|
+
const upsertEscrow = db.prepare(`
|
|
3
|
+
INSERT INTO escrows (
|
|
4
|
+
escrow_id, payer_agent_id, payee_id, amount_usdc, state,
|
|
5
|
+
resource_hash, session_id, release_condition, quality_score,
|
|
6
|
+
state_proof, metadata, updated_at
|
|
7
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, unixepoch())
|
|
8
|
+
ON CONFLICT(escrow_id) DO UPDATE SET
|
|
9
|
+
state = excluded.state,
|
|
10
|
+
state_proof = excluded.state_proof,
|
|
11
|
+
metadata = excluded.metadata,
|
|
12
|
+
updated_at = unixepoch(),
|
|
13
|
+
settled_at = CASE WHEN excluded.state = 'SETTLED' THEN unixepoch() ELSE settled_at END
|
|
14
|
+
`);
|
|
15
|
+
const insertTransition = db.prepare(`
|
|
16
|
+
INSERT INTO escrow_transitions (escrow_id, from_state, to_state, note, proof)
|
|
17
|
+
VALUES (?, ?, ?, ?, ?)
|
|
18
|
+
`);
|
|
19
|
+
export function syncProtocolEscrow(input) {
|
|
20
|
+
upsertEscrow.run(input.escrowId, input.payerAgentId, input.payeeId, input.amountUsdc, input.state, input.resourceHash ?? null, input.sessionId ?? null, null, null, input.stateProof, input.metadata ? JSON.stringify(input.metadata) : null);
|
|
21
|
+
}
|
|
22
|
+
export function recordEscrowTransition(escrowId, fromState, toState, note, proof) {
|
|
23
|
+
insertTransition.run(escrowId, fromState, toState, note ?? null, proof ?? null);
|
|
24
|
+
}
|
|
25
|
+
export function syncLedgerEscrow(record) {
|
|
26
|
+
const state = record.status === "released" ? "SETTLED" : record.status === "cancelled" ? "CANCELLED" : "LOCKED";
|
|
27
|
+
upsertEscrow.run(record.id, record.payerAgentId, record.payeeAgentId, record.amountUsdc, state, null, null, record.releaseCondition, null, `ledger:${record.status}`, JSON.stringify(record.metadata ?? {}));
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Load facilitator /supported extras (permit2 on Base, feePayer on Solana, etc.). */
|
|
2
|
+
export declare function refreshFacilitatorExtras(facilitatorUrl?: string): Promise<void>;
|
|
3
|
+
export declare function ensureFacilitatorExtras(): Promise<void>;
|
|
4
|
+
/**
|
|
5
|
+
* Merge facilitator extras into 402 accepts so EVM clients use Permit2 on Base
|
|
6
|
+
* (Dexter facilitator returns 500 if payer signs EIP-712 but settle expects permit2).
|
|
7
|
+
*/
|
|
8
|
+
export declare function enrichAcceptFromFacilitator(accept: {
|
|
9
|
+
network?: string;
|
|
10
|
+
scheme?: string;
|
|
11
|
+
extra?: Record<string, unknown>;
|
|
12
|
+
}): void;
|
|
13
|
+
export declare function startFacilitatorExtrasRefresh(intervalMs?: number): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { config } from "../config.js";
|
|
2
|
+
let extrasByNetworkScheme = new Map();
|
|
3
|
+
let cacheLoadedAt = 0;
|
|
4
|
+
const CACHE_TTL_MS = 60_000;
|
|
5
|
+
function cacheKey(network, scheme) {
|
|
6
|
+
return `${network}|${scheme}`;
|
|
7
|
+
}
|
|
8
|
+
/** Load facilitator /supported extras (permit2 on Base, feePayer on Solana, etc.). */
|
|
9
|
+
export async function refreshFacilitatorExtras(facilitatorUrl = config.facilitatorUrl) {
|
|
10
|
+
const base = facilitatorUrl.replace(/\/$/, "");
|
|
11
|
+
const res = await fetch(`${base}/supported`, {
|
|
12
|
+
signal: AbortSignal.timeout(Number(process.env.X402_FACILITATOR_TIMEOUT_MS ?? 90_000)),
|
|
13
|
+
});
|
|
14
|
+
if (!res.ok) {
|
|
15
|
+
throw new Error(`Facilitator /supported HTTP ${res.status}`);
|
|
16
|
+
}
|
|
17
|
+
const body = (await res.json());
|
|
18
|
+
const next = new Map();
|
|
19
|
+
for (const kind of body.kinds ?? []) {
|
|
20
|
+
if (kind.extra && kind.network && kind.scheme) {
|
|
21
|
+
next.set(cacheKey(kind.network, kind.scheme), kind.extra);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
extrasByNetworkScheme = next;
|
|
25
|
+
cacheLoadedAt = Date.now();
|
|
26
|
+
}
|
|
27
|
+
export async function ensureFacilitatorExtras() {
|
|
28
|
+
if (Date.now() - cacheLoadedAt < CACHE_TTL_MS && extrasByNetworkScheme.size > 0)
|
|
29
|
+
return;
|
|
30
|
+
await refreshFacilitatorExtras();
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Merge facilitator extras into 402 accepts so EVM clients use Permit2 on Base
|
|
34
|
+
* (Dexter facilitator returns 500 if payer signs EIP-712 but settle expects permit2).
|
|
35
|
+
*/
|
|
36
|
+
export function enrichAcceptFromFacilitator(accept) {
|
|
37
|
+
if (!accept.network)
|
|
38
|
+
return;
|
|
39
|
+
const scheme = accept.scheme ?? "exact";
|
|
40
|
+
const facilitatorExtra = extrasByNetworkScheme.get(cacheKey(accept.network, scheme));
|
|
41
|
+
if (!facilitatorExtra)
|
|
42
|
+
return;
|
|
43
|
+
accept.extra = { ...facilitatorExtra, ...accept.extra };
|
|
44
|
+
}
|
|
45
|
+
export function startFacilitatorExtrasRefresh(intervalMs = CACHE_TTL_MS) {
|
|
46
|
+
const tick = () => {
|
|
47
|
+
void refreshFacilitatorExtras().catch((err) => {
|
|
48
|
+
console.warn("[facilitator-extra] refresh failed:", err instanceof Error ? err.message : err);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
setInterval(tick, intervalMs).unref?.();
|
|
52
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type FacilitatorHealth = {
|
|
2
|
+
id: string;
|
|
3
|
+
url: string;
|
|
4
|
+
healthy: boolean;
|
|
5
|
+
latencyMs: number | null;
|
|
6
|
+
supportedNetworks: string[];
|
|
7
|
+
error: string | null;
|
|
8
|
+
synthetic?: boolean;
|
|
9
|
+
note?: string;
|
|
10
|
+
};
|
|
11
|
+
declare const FACILITATORS: readonly [{
|
|
12
|
+
readonly id: "dexter";
|
|
13
|
+
readonly url: "https://x402.dexter.cash";
|
|
14
|
+
}, {
|
|
15
|
+
readonly id: "coinbase";
|
|
16
|
+
readonly url: "https://api.cdp.coinbase.com/platform/v2/x402";
|
|
17
|
+
}];
|
|
18
|
+
export declare function checkFacilitatorHealth(facilitator: (typeof FACILITATORS)[number]): Promise<FacilitatorHealth>;
|
|
19
|
+
export declare function rankFacilitators(preferNetwork?: string, fastCheck?: boolean): Promise<FacilitatorHealth[]>;
|
|
20
|
+
export {};
|