@oracle-agent/oracle 0.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/CONTRIBUTING.md +98 -0
- package/LICENSE +202 -0
- package/README.md +384 -0
- package/SECURITY.md +89 -0
- package/SETUP.md +235 -0
- package/artifacts/inscription/oracle-was-here-preview.png +0 -0
- package/artifacts/inscription/oracle-was-here.svg +1 -0
- package/artifacts/specialist-packs/oracle-full-crypto.json +273 -0
- package/bin/desk-server.mjs +438 -0
- package/bin/oracle-data-mcp.mjs +603 -0
- package/bin/oracle-init.mjs +423 -0
- package/bin/oracle-public-server.mjs +36 -0
- package/bin/oracle-route.mjs +254 -0
- package/bin/oracle-scan.mjs +192 -0
- package/docs/adding-a-chain.md +229 -0
- package/docs/architecture.md +135 -0
- package/docs/profiles.md +132 -0
- package/examples/add-a-chain.mjs +65 -0
- package/examples/research-a-token.mjs +70 -0
- package/package.json +90 -0
- package/profiles/_template/SOUL.md +47 -0
- package/profiles/_template/profile.json +22 -0
- package/profiles/bitcoin-agent/SOUL.md +31 -0
- package/profiles/bitcoin-agent/profile.json +32 -0
- package/profiles/hyperliquid-agent/SOUL.md +34 -0
- package/profiles/hyperliquid-agent/profile.json +37 -0
- package/profiles/oracle/SOUL.md +65 -0
- package/profiles/oracle/profile.json +35 -0
- package/profiles/polymarket-agent/SOUL.md +35 -0
- package/profiles/polymarket-agent/profile.json +34 -0
- package/profiles/profile.schema.json +90 -0
- package/profiles/protocol-builder/SOUL.md +50 -0
- package/profiles/protocol-builder/profile.json +37 -0
- package/profiles/robinhood-agent/SOUL.md +45 -0
- package/profiles/robinhood-agent/profile.json +39 -0
- package/profiles/solana-agent/SOUL.md +37 -0
- package/profiles/solana-agent/profile.json +37 -0
- package/profiles/stable-agent/SOUL.md +43 -0
- package/profiles/stable-agent/profile.json +37 -0
- package/public/oracle-console/app.js +272 -0
- package/public/oracle-console/bitcoin-wallets.js +206 -0
- package/public/oracle-console/index.html +91 -0
- package/public/oracle-console/styles.css +239 -0
- package/public/oracle-splash/index.html +931 -0
- package/scripts/build-inscription.py +230 -0
- package/scripts/check-test-count.mjs +105 -0
- package/scripts/e2e-hl-markets.mjs +21 -0
- package/scripts/e2e-hl-perps.mjs +48 -0
- package/scripts/e2e-hypercore-staking.mjs +128 -0
- package/scripts/e2e-solana-bitcoin.mjs +183 -0
- package/scripts/public-api-scan.mjs +23 -0
- package/scripts/secret-scan.mjs +181 -0
- package/scripts/verify-v3-venues.mjs +192 -0
- package/skills/oracle-best-execution/SKILL.md +127 -0
- package/skills/oracle-bitcoin/SKILL.md +53 -0
- package/skills/oracle-chain-graphs-telegram-cards/SKILL.md +59 -0
- package/skills/oracle-circuit-breaker/SKILL.md +51 -0
- package/skills/oracle-contract-research/SKILL.md +55 -0
- package/skills/oracle-desk/SKILL.md +58 -0
- package/skills/oracle-dex-launch/SKILL.md +38 -0
- package/skills/oracle-grants/SKILL.md +69 -0
- package/skills/oracle-hypercore-staking/SKILL.md +57 -0
- package/skills/oracle-hyperliquid/SKILL.md +56 -0
- package/skills/oracle-meme-token-sniper/SKILL.md +73 -0
- package/skills/oracle-nft-gacha-launch/SKILL.md +48 -0
- package/skills/oracle-nft-mint-gas-war/SKILL.md +63 -0
- package/skills/oracle-polymarket/SKILL.md +60 -0
- package/skills/oracle-protocol-builder/SKILL.md +38 -0
- package/skills/oracle-protocol-security/SKILL.md +60 -0
- package/skills/oracle-public-product/SKILL.md +44 -0
- package/skills/oracle-receipts/SKILL.md +52 -0
- package/skills/oracle-rfq-tokenized-assets/SKILL.md +69 -0
- package/skills/oracle-smart-wallet-scanner/SKILL.md +49 -0
- package/skills/oracle-solana/SKILL.md +65 -0
- package/skills/oracle-solana-nft/SKILL.md +54 -0
- package/skills/oracle-token-research/SKILL.md +67 -0
- package/src/agent-auth.mjs +191 -0
- package/src/approval-guard.mjs +282 -0
- package/src/attestation-secret.mjs +88 -0
- package/src/audit-log.mjs +196 -0
- package/src/auto-slippage.mjs +378 -0
- package/src/capability-posture.mjs +125 -0
- package/src/chains.mjs +62 -0
- package/src/data/catalog.mjs +495 -0
- package/src/data/desk-data.mjs +623 -0
- package/src/data/http.mjs +200 -0
- package/src/data/provider-endpoint.mjs +94 -0
- package/src/data/providers/aerodrome.mjs +244 -0
- package/src/data/providers/balancer.mjs +208 -0
- package/src/data/providers/bitcoin-esplora.mjs +230 -0
- package/src/data/providers/bitcoin-meta.mjs +378 -0
- package/src/data/providers/blockscout.mjs +14 -0
- package/src/data/providers/bridges.mjs +241 -0
- package/src/data/providers/cowswap.mjs +501 -0
- package/src/data/providers/curve.mjs +200 -0
- package/src/data/providers/defillama.mjs +88 -0
- package/src/data/providers/dexscreener.mjs +43 -0
- package/src/data/providers/evm-rpc.mjs +203 -0
- package/src/data/providers/geckoterminal.mjs +34 -0
- package/src/data/providers/gmx.mjs +495 -0
- package/src/data/providers/hl-info.mjs +102 -0
- package/src/data/providers/hl-markets.mjs +210 -0
- package/src/data/providers/hl-perps.mjs +382 -0
- package/src/data/providers/hl-staking.mjs +352 -0
- package/src/data/providers/hl-ws.mjs +119 -0
- package/src/data/providers/hyperevm-dex.mjs +49 -0
- package/src/data/providers/jupiter.mjs +182 -0
- package/src/data/providers/lifi.mjs +150 -0
- package/src/data/providers/magiceden-sol.mjs +355 -0
- package/src/data/providers/morpho.mjs +173 -0
- package/src/data/providers/odos.mjs +155 -0
- package/src/data/providers/oneinch.mjs +173 -0
- package/src/data/providers/opensea-multichain.mjs +136 -0
- package/src/data/providers/opensea-nft.mjs +99 -0
- package/src/data/providers/paraswap.mjs +117 -0
- package/src/data/providers/pendle.mjs +187 -0
- package/src/data/providers/poly-public.mjs +96 -0
- package/src/data/providers/poly-ws.mjs +103 -0
- package/src/data/providers/rh-agent.mjs +59 -0
- package/src/data/providers/satflow.mjs +336 -0
- package/src/data/providers/solana-rpc.mjs +186 -0
- package/src/data/providers/uniswap-v3.mjs +303 -0
- package/src/data/providers/zerox.mjs +166 -0
- package/src/data/public-api-scan.mjs +61 -0
- package/src/data/quote-placeholder.mjs +31 -0
- package/src/exact-integer.mjs +72 -0
- package/src/exec-policy.mjs +444 -0
- package/src/flags.mjs +15 -0
- package/src/fresh-window.mjs +76 -0
- package/src/gmx-attestation.mjs +175 -0
- package/src/index.mjs +50 -0
- package/src/nft-gas-war-guard.mjs +139 -0
- package/src/onboarding/agent-keys.mjs +157 -0
- package/src/onboarding/index.mjs +18 -0
- package/src/onboarding/tiers.mjs +139 -0
- package/src/oracle-env.mjs +38 -0
- package/src/protocol-execution.mjs +84 -0
- package/src/public-api/buzz-integration.mjs +256 -0
- package/src/public-api/connect-agent.mjs +397 -0
- package/src/public-api/grants.mjs +142 -0
- package/src/public-api/http.mjs +374 -0
- package/src/public-control/aa-adapter.mjs +402 -0
- package/src/public-control/build-registry.mjs +227 -0
- package/src/public-control/bundler-client.mjs +372 -0
- package/src/public-control/grant-indexer.mjs +296 -0
- package/src/public-control/policy-render.mjs +69 -0
- package/src/public-control/policy-schema.mjs +318 -0
- package/src/public-control/runtime-config.mjs +265 -0
- package/src/public-control/session-key-model.mjs +374 -0
- package/src/public-control/session-orchestrator.mjs +412 -0
- package/src/route-attestation.mjs +132 -0
- package/src/router/best-execution.mjs +221 -0
- package/src/router/index.mjs +185 -0
- package/src/router/prepare-bridge.mjs +288 -0
- package/src/router/prepare-route.mjs +341 -0
- package/src/router/proposal.mjs +311 -0
- package/src/router/risk-classifier.mjs +119 -0
- package/src/router/route-sources.mjs +292 -0
- package/src/scanner/chains.config.mjs +381 -0
- package/src/scanner/contract.mjs +270 -0
- package/src/scanner/evm-scanner.mjs +394 -0
- package/src/scanner/index.mjs +9 -0
- package/src/scanner/v2-venue.mjs +335 -0
- package/src/scanner/v3-venue.mjs +290 -0
- package/src/scopes.mjs +44 -0
- package/src/sell-simulation.mjs +167 -0
- package/src/token-transfer-guard.mjs +188 -0
- package/src/vault-attestation.mjs +145 -0
- package/src/venues.mjs +206 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
export const ORACLE_CONFIG_DIR = join(homedir(), ".config", "oracle");
|
|
6
|
+
// Legacy config dir from before the rename. Kept so existing installs keep
|
|
7
|
+
// working; new installs only ever see ~/.config/oracle.
|
|
8
|
+
export const LEGACY_CONFIG_DIR = join(homedir(), ".config", "mad-desk");
|
|
9
|
+
|
|
10
|
+
export function env(primary, legacy, fallback = "") {
|
|
11
|
+
const pv = process.env[primary];
|
|
12
|
+
if (pv != null && String(pv).trim() !== "") return pv;
|
|
13
|
+
const lv = legacy ? process.env[legacy] : undefined;
|
|
14
|
+
if (lv != null && String(lv).trim() !== "") return lv;
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function envFlag(primary, legacy, defaultValue = false) {
|
|
19
|
+
const fallback = defaultValue ? "1" : "";
|
|
20
|
+
return String(env(primary, legacy, fallback)).trim() === "1";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function envEnabled(primary, legacy, defaultValue = true) {
|
|
24
|
+
const fallback = defaultValue ? "1" : "0";
|
|
25
|
+
return String(env(primary, legacy, fallback)).trim() !== "0";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function csvEnv(primary, legacy) {
|
|
29
|
+
return String(env(primary, legacy, ""));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function configPath(file, primary, legacy) {
|
|
33
|
+
const explicit = env(primary, legacy, "");
|
|
34
|
+
if (explicit) return explicit;
|
|
35
|
+
const oraclePath = join(ORACLE_CONFIG_DIR, file);
|
|
36
|
+
if (existsSync(oraclePath)) return oraclePath;
|
|
37
|
+
return join(LEGACY_CONFIG_DIR, file);
|
|
38
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { isAddress } from "ethers";
|
|
2
|
+
import { assertAutoSlippageGuard } from "./auto-slippage.mjs";
|
|
3
|
+
|
|
4
|
+
export const EXECUTABLE_PROTOCOL_PROVIDERS = Object.freeze([
|
|
5
|
+
"lifi",
|
|
6
|
+
"relay",
|
|
7
|
+
"uniswap-v3",
|
|
8
|
+
"aerodrome",
|
|
9
|
+
"zerox",
|
|
10
|
+
"paraswap",
|
|
11
|
+
"odos",
|
|
12
|
+
"oneinch",
|
|
13
|
+
"pendle",
|
|
14
|
+
"balancer",
|
|
15
|
+
"curve",
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
function hexData(value) {
|
|
19
|
+
const data = String(value || "");
|
|
20
|
+
return /^0x(?:[0-9a-fA-F]{2})*$/.test(data);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function sameAddress(left, right) {
|
|
24
|
+
return String(left || "").toLowerCase() === String(right || "").toLowerCase();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Validate a provider-produced executable route before it may cross into the
|
|
29
|
+
* generic signer. This function accepts no caller-supplied destination/calldata;
|
|
30
|
+
* those must come from the provider's freshly generated route.
|
|
31
|
+
*/
|
|
32
|
+
export function assertPreparedProtocolRoute(
|
|
33
|
+
route,
|
|
34
|
+
{ provider, chainId, from, nowMs = Date.now() } = {}
|
|
35
|
+
) {
|
|
36
|
+
// `calldataReady` means the provider assembled real calldata from a fresh
|
|
37
|
+
// quote. It deliberately does NOT mean "cleared to execute" — the user's
|
|
38
|
+
// wallet is still the only authority. The old flag name was `executionReady`,
|
|
39
|
+
// which read as permission and trained agents to treat a quote as authority.
|
|
40
|
+
const prepared = route && (route.calldataReady === true || route.executionReady === true);
|
|
41
|
+
if (!prepared) {
|
|
42
|
+
throw new Error(`${provider || "protocol"}: executable provider preparation required`);
|
|
43
|
+
}
|
|
44
|
+
if (provider && route.provider !== provider) {
|
|
45
|
+
throw new Error(`protocol provider mismatch: expected ${provider}, got ${route.provider || "unknown"}`);
|
|
46
|
+
}
|
|
47
|
+
if (Number(route.chainId) !== Number(chainId)) {
|
|
48
|
+
throw new Error(`protocol route chain mismatch: expected ${chainId}, got ${route.chainId}`);
|
|
49
|
+
}
|
|
50
|
+
const raw = Array.isArray(route.transactions) ? route.transactions : [route.transaction];
|
|
51
|
+
if (!raw.length || raw.some((tx) => !tx)) throw new Error("protocol route has no executable transaction");
|
|
52
|
+
|
|
53
|
+
return raw.map((tx, index) => {
|
|
54
|
+
if (Number(tx.chainId ?? route.chainId) !== Number(chainId)) {
|
|
55
|
+
throw new Error(`protocol transaction ${index} chain mismatch`);
|
|
56
|
+
}
|
|
57
|
+
if (!isAddress(String(tx.to || ""))) throw new Error(`protocol transaction ${index} target must be an address`);
|
|
58
|
+
if (!hexData(tx.data) || String(tx.data).length < 10) {
|
|
59
|
+
throw new Error(`protocol transaction ${index} requires non-empty hex calldata`);
|
|
60
|
+
}
|
|
61
|
+
if (from && tx.from && !sameAddress(tx.from, from)) {
|
|
62
|
+
throw new Error(`protocol transaction ${index} sender mismatch`);
|
|
63
|
+
}
|
|
64
|
+
const guard = tx.slippageGuard || tx.madSlippage || route.autoSlippage || route.quote?.autoSlippage;
|
|
65
|
+
// Same bar as enforceTxPolicy sign/broadcast: a prepare helper must not
|
|
66
|
+
// become a second, softer gate that trusts caller-bound unsigned guards.
|
|
67
|
+
assertAutoSlippageGuard(guard, {
|
|
68
|
+
nowMs,
|
|
69
|
+
chainId,
|
|
70
|
+
venue: tx.to,
|
|
71
|
+
tx: { ...tx, chainId: Number(chainId), to: tx.to, data: tx.data },
|
|
72
|
+
requireSigned: true,
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
chainId: Number(chainId),
|
|
76
|
+
to: tx.to,
|
|
77
|
+
data: tx.data,
|
|
78
|
+
value: tx.value == null ? "0x0" : String(tx.value),
|
|
79
|
+
...(tx.gasLimit != null || tx.gas != null ? { gasLimit: String(tx.gasLimit ?? tx.gas) } : {}),
|
|
80
|
+
...(tx.nonce != null ? { nonce: Number(tx.nonce) } : {}),
|
|
81
|
+
slippageGuard: guard,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// Oracle ↔ Buzz integration API (public plane).
|
|
2
|
+
//
|
|
3
|
+
// Buzz should integrate Oracle **via HTTP**, not by embedding our private
|
|
4
|
+
// executor. This module is the contract Buzz (or any partner) can call:
|
|
5
|
+
//
|
|
6
|
+
// 1) Discovery GET /public/buzz
|
|
7
|
+
// 2) Grants existing /public/connect/* + /public/grants/*
|
|
8
|
+
// 3) Shared auth POST /public/buzz/auth/verify (capability tokens)
|
|
9
|
+
// 4) Shared audit POST /public/buzz/audit/{append,verify,entries}
|
|
10
|
+
//
|
|
11
|
+
// Hard boundaries (same as the rest of the public plane):
|
|
12
|
+
// - No private keys, no bearer mint, no broadcast.
|
|
13
|
+
// - Minting capabilities stays client-side (owner wallet signs).
|
|
14
|
+
// - Audit detail is scanned for secret shapes before append/response.
|
|
15
|
+
// - Fail closed on unknown fields / bad capability tags.
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
verifyCapability,
|
|
19
|
+
authPreimage,
|
|
20
|
+
AUTH_DOMAIN,
|
|
21
|
+
} from "../agent-auth.mjs";
|
|
22
|
+
import {
|
|
23
|
+
appendAudit,
|
|
24
|
+
verifyChain,
|
|
25
|
+
getEntries,
|
|
26
|
+
AUDIT_ACTIONS,
|
|
27
|
+
GENESIS_HASH,
|
|
28
|
+
} from "../audit-log.mjs";
|
|
29
|
+
import { assertNoSecretMaterial, SecretLeakError } from "./connect-agent.mjs";
|
|
30
|
+
|
|
31
|
+
export const BUZZ_API_VERSION = 1;
|
|
32
|
+
export const BUZZ_INTEGRATION_ID = "oracle-buzz-http-v1";
|
|
33
|
+
|
|
34
|
+
/** Public-safe audit actions partners may append. */
|
|
35
|
+
export const BUZZ_PUBLIC_AUDIT_ACTIONS = Object.freeze([
|
|
36
|
+
AUDIT_ACTIONS.AUTH_GRANT,
|
|
37
|
+
AUDIT_ACTIONS.AUTH_OK,
|
|
38
|
+
AUDIT_ACTIONS.AUTH_FAIL,
|
|
39
|
+
"connect.assemble",
|
|
40
|
+
"connect.bound",
|
|
41
|
+
"grant.revoke",
|
|
42
|
+
"grant.active",
|
|
43
|
+
"buzz.ping",
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
export function buildBuzzCatalog({ baseUrl = null } = {}) {
|
|
47
|
+
const base = baseUrl || "";
|
|
48
|
+
return Object.freeze({
|
|
49
|
+
ok: true,
|
|
50
|
+
integration: BUZZ_INTEGRATION_ID,
|
|
51
|
+
version: BUZZ_API_VERSION,
|
|
52
|
+
plane: "public",
|
|
53
|
+
unsigned: true,
|
|
54
|
+
custody: "user-signs",
|
|
55
|
+
defaultPosture: "DISARMED",
|
|
56
|
+
summary:
|
|
57
|
+
"Oracle exposes grants, capability verify, and audit over HTTP so Buzz (or any client) can integrate without house keys.",
|
|
58
|
+
doAll: {
|
|
59
|
+
api: true,
|
|
60
|
+
sharedAuth: true,
|
|
61
|
+
sharedAudit: true,
|
|
62
|
+
note: "One surface — not three separate products. Buzz calls these routes; user still signs grants/capabilities.",
|
|
63
|
+
},
|
|
64
|
+
endpoints: Object.freeze([
|
|
65
|
+
{
|
|
66
|
+
method: "GET",
|
|
67
|
+
path: `${base}/public/buzz`,
|
|
68
|
+
purpose: "Discovery catalog for Buzz integrators",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
method: "GET",
|
|
72
|
+
path: `${base}/public/health`,
|
|
73
|
+
purpose: "Liveness",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
method: "GET",
|
|
77
|
+
path: `${base}/public/config`,
|
|
78
|
+
purpose: "Public custody config (Privy flags, no secrets)",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
method: "POST",
|
|
82
|
+
path: `${base}/public/connect/request`,
|
|
83
|
+
purpose: "Build human-readable connect request",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
method: "POST",
|
|
87
|
+
path: `${base}/public/connect/assemble`,
|
|
88
|
+
purpose: "Assemble unsigned grant for user personal_sign",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
method: "POST",
|
|
92
|
+
path: `${base}/public/grants/active`,
|
|
93
|
+
purpose: "List active grants from injected store",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
method: "POST",
|
|
97
|
+
path: `${base}/public/grants/get`,
|
|
98
|
+
purpose: "Get one grant by id",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
method: "POST",
|
|
102
|
+
path: `${base}/public/buzz/auth/verify`,
|
|
103
|
+
purpose: "Verify owner-signed capability token (shared auth)",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
method: "POST",
|
|
107
|
+
path: `${base}/public/buzz/auth/preimage`,
|
|
108
|
+
purpose: "Build exact capability signing preimage (client mints)",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
method: "POST",
|
|
112
|
+
path: `${base}/public/buzz/audit/append`,
|
|
113
|
+
purpose: "Append public audit event to shared hash chain",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
method: "POST",
|
|
117
|
+
path: `${base}/public/buzz/audit/verify`,
|
|
118
|
+
purpose: "Verify audit chain integrity",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
method: "POST",
|
|
122
|
+
path: `${base}/public/buzz/audit/entries`,
|
|
123
|
+
purpose: "Read audit entries (paginated)",
|
|
124
|
+
},
|
|
125
|
+
]),
|
|
126
|
+
auth: Object.freeze({
|
|
127
|
+
domain: AUTH_DOMAIN,
|
|
128
|
+
format: '["auth", ownerAddress, conditions, signature]',
|
|
129
|
+
mint: "client-side only — owner wallet personal_sign(preimage)",
|
|
130
|
+
verify: "POST /public/buzz/auth/verify",
|
|
131
|
+
clauses: ["chain=<id>", "action=<scope>", "expires<unix", "notbefore>unix"],
|
|
132
|
+
}),
|
|
133
|
+
audit: Object.freeze({
|
|
134
|
+
model: "sha256 hash-chain",
|
|
135
|
+
genesis: GENESIS_HASH,
|
|
136
|
+
publicActions: BUZZ_PUBLIC_AUDIT_ACTIONS,
|
|
137
|
+
streamDefault: "buzz-public",
|
|
138
|
+
}),
|
|
139
|
+
never: Object.freeze([
|
|
140
|
+
"private-executor-broadcast",
|
|
141
|
+
"server-side-capability-mint-with-house-key",
|
|
142
|
+
"raw-private-keys-in-responses",
|
|
143
|
+
]),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function handleBuzzAuthPreimage(body = {}) {
|
|
148
|
+
const agentAddress = body.agentAddress;
|
|
149
|
+
const conditions = body.conditions == null ? "" : String(body.conditions);
|
|
150
|
+
if (!agentAddress || typeof agentAddress !== "string") {
|
|
151
|
+
const err = new Error("agentAddress required");
|
|
152
|
+
err.code = "invalid-auth-preimage";
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
const preimage = authPreimage(agentAddress, conditions);
|
|
156
|
+
return {
|
|
157
|
+
ok: true,
|
|
158
|
+
domain: AUTH_DOMAIN,
|
|
159
|
+
agentAddress,
|
|
160
|
+
conditions,
|
|
161
|
+
preimage,
|
|
162
|
+
note: "Owner personal_sign(preimage). Server never mints with a house key.",
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function handleBuzzAuthVerify(body = {}) {
|
|
167
|
+
const tag = body.capability ?? body.tag ?? body.auth;
|
|
168
|
+
const agentAddress = body.agentAddress;
|
|
169
|
+
if (tag == null) {
|
|
170
|
+
const err = new Error("capability tag required");
|
|
171
|
+
err.code = "invalid-capability";
|
|
172
|
+
throw err;
|
|
173
|
+
}
|
|
174
|
+
if (!agentAddress) {
|
|
175
|
+
const err = new Error("agentAddress required");
|
|
176
|
+
err.code = "invalid-capability";
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
const result = verifyCapability(tag, {
|
|
180
|
+
agentAddress,
|
|
181
|
+
chainId: body.chainId ?? null,
|
|
182
|
+
action: body.action ?? null,
|
|
183
|
+
now: body.now ?? null,
|
|
184
|
+
});
|
|
185
|
+
if (!result || result.ok !== true) {
|
|
186
|
+
return {
|
|
187
|
+
ok: false,
|
|
188
|
+
valid: false,
|
|
189
|
+
reason: (result && (result.reason || result.error)) || "invalid",
|
|
190
|
+
result,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
ok: true,
|
|
195
|
+
valid: true,
|
|
196
|
+
result,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function assertPublicAuditAction(action) {
|
|
201
|
+
if (!BUZZ_PUBLIC_AUDIT_ACTIONS.includes(action)) {
|
|
202
|
+
const err = new Error(
|
|
203
|
+
`action not allowed on public buzz audit: ${action}`
|
|
204
|
+
);
|
|
205
|
+
err.code = "audit-action-forbidden";
|
|
206
|
+
throw err;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function handleBuzzAuditAppend(body = {}, { path } = {}) {
|
|
211
|
+
const action = body.action;
|
|
212
|
+
if (!action) {
|
|
213
|
+
const err = new Error("action required");
|
|
214
|
+
err.code = "invalid-audit";
|
|
215
|
+
throw err;
|
|
216
|
+
}
|
|
217
|
+
assertPublicAuditAction(action);
|
|
218
|
+
const detail = body.detail ?? null;
|
|
219
|
+
try {
|
|
220
|
+
assertNoSecretMaterial(detail);
|
|
221
|
+
} catch (e) {
|
|
222
|
+
if (e instanceof SecretLeakError || e?.name === "SecretLeakError") {
|
|
223
|
+
const err = new Error("audit detail blocked: secret-shaped material");
|
|
224
|
+
err.code = "secret-leak-blocked";
|
|
225
|
+
throw err;
|
|
226
|
+
}
|
|
227
|
+
throw e;
|
|
228
|
+
}
|
|
229
|
+
const entry = await appendAudit({
|
|
230
|
+
action,
|
|
231
|
+
actor: body.actor ?? null,
|
|
232
|
+
objectId: body.objectId ?? null,
|
|
233
|
+
detail,
|
|
234
|
+
stream: body.stream || "buzz-public",
|
|
235
|
+
path,
|
|
236
|
+
});
|
|
237
|
+
return { ok: true, entry };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function handleBuzzAuditVerify(body = {}, { path } = {}) {
|
|
241
|
+
const out = verifyChain({
|
|
242
|
+
stream: body.stream || "buzz-public",
|
|
243
|
+
path,
|
|
244
|
+
});
|
|
245
|
+
return { ok: true, ...out };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function handleBuzzAuditEntries(body = {}, { path } = {}) {
|
|
249
|
+
const entries = getEntries({
|
|
250
|
+
stream: body.stream || "buzz-public",
|
|
251
|
+
fromSeq: body.fromSeq ?? 1,
|
|
252
|
+
limit: Math.min(Number(body.limit || 100), 500),
|
|
253
|
+
path,
|
|
254
|
+
});
|
|
255
|
+
return { ok: true, count: entries.length, entries };
|
|
256
|
+
}
|