kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
137 lines (134 loc) • 5.04 kB
JavaScript
import {
HostedFunnel,
resolveCopyToken,
resolveSimBase
} from "./bin-69rn2kv7.js";
import {
parseArgs
} from "./bin-1gc4zavq.js";
import {
CliError,
EXIT
} from "./bin-t9ggwnv5.js";
import {
GRADE_SIGN_PREFIX,
ROOT_HASH_PREFIX,
certifiedRoot
} from "./bin-2ywrx58g.js";
// src/cli/commands/verify.ts
import { createPublicKey, verify as ed25519Verify } from "node:crypto";
var VERDICT_EXIT = {
VERIFIED: 0,
UNVERIFIED: EXIT.GENERIC,
KEY_RETIRED: EXIT.GENERIC,
NOT_FOUND: EXIT.NOT_FOUND
};
function parseProofRef(input) {
const trimmed = input.trim();
if (trimmed === "")
throw new CliError({ code: "USAGE", exit: EXIT.USAGE, message: "verify needs a proof URL or id" });
const m = /\/proof\/([^/?#]+)/.exec(trimmed);
if (m !== null)
return decodeURIComponent(m[1]);
if (/^https?:\/\//i.test(trimmed))
throw new CliError({
code: "USAGE",
exit: EXIT.USAGE,
message: `not a proof URL: ${JSON.stringify(trimmed)}`,
hint: "pass a proof URL (https://kestrel.markets/proof/<id>) or a bare proof id"
});
return trimmed;
}
function verifyProofSignature(proof, keys) {
const key = keys.find((k) => k.kid === proof.kid);
if (key === undefined)
return "KEY_RETIRED";
try {
const publicKey = createPublicKey({ key: { ...key.public_jwk }, format: "jwk" });
const signature = Buffer.from(proof.signature, "base64url");
const bareRoot = proof.root.startsWith(ROOT_HASH_PREFIX) ? proof.root.slice(ROOT_HASH_PREFIX.length) : proof.root;
const message = Buffer.from(`${GRADE_SIGN_PREFIX}.${bareRoot}`);
const ok = ed25519Verify(null, message, publicKey, signature);
return ok ? "VERIFIED" : "UNVERIFIED";
} catch {
return "UNVERIFIED";
}
}
async function recomputeNumbersBindRoot(proof) {
if (proof.coveredFields === undefined)
return "unknown";
try {
const bareRoot = proof.root.startsWith(ROOT_HASH_PREFIX) ? proof.root.slice(ROOT_HASH_PREFIX.length) : proof.root;
const recomputed = await certifiedRoot(proof.coveredFields);
return recomputed === bareRoot ? "yes" : "no";
} catch {
return "unknown";
}
}
function needsVerifyKeyUrl(verdict) {
return verdict === "UNVERIFIED" || verdict === "KEY_RETIRED";
}
function emit(ctx, report, notice) {
if (ctx.mode === "json") {
process.stdout.write(JSON.stringify({ schema: "kestrel.verify/v1", ...notice !== undefined ? { notice } : {}, ...report }) + `
`);
return;
}
if (notice !== undefined)
process.stdout.write(`note: ${notice}
`);
const parts = [report.verdict, `proof=${report.proof_id}`];
if (report.kid !== undefined)
parts.push(`kid=${report.kid}`);
if (report.epoch !== undefined)
parts.push(`epoch=${report.epoch}`);
if (report.verdict === "UNVERIFIED" && report.numbers_bind_root === "no")
parts.push("note=published-numbers-do-not-rebuild-the-signed-root");
else if (report.verdict === "UNVERIFIED" && report.claimed_verified === true)
parts.push("note=the-proof-claimed-verified-but-its-signature-did-not-re-verify");
if (report.numbers_bind_root !== undefined)
parts.push(`numbers-bind-root=${report.numbers_bind_root}`);
if (needsVerifyKeyUrl(report.verdict) && report.verify_key_url !== undefined)
parts.push(`verify-key=${report.verify_key_url}`);
process.stdout.write(parts.join("\t") + `
`);
}
async function runVerify(client, id, ctx, forward, notice) {
const proof = await client.publishedProof(id, forward);
if (proof === null) {
emit(ctx, { verdict: "NOT_FOUND", proof_id: id }, notice);
return VERDICT_EXIT.NOT_FOUND;
}
const keys = await client.verifyKeys(forward);
const signatureVerdict = verifyProofSignature(proof, keys);
const numbersBind = await recomputeNumbersBindRoot(proof);
const verdict = numbersBind === "no" ? "UNVERIFIED" : signatureVerdict;
emit(ctx, {
verdict,
proof_id: proof.proof_id,
kid: proof.kid,
epoch: proof.epoch,
claimed_verified: proof.verificationClaim,
numbers_bind_root: numbersBind,
...needsVerifyKeyUrl(verdict) ? { verify_key_url: client.verifyKeysUrl } : {}
}, notice);
return VERDICT_EXIT[verdict];
}
async function verifyCommand(argv, ctx, globals, deps = {}) {
const { positionals, flags } = parseArgs(argv, new Set, new Set(["copy-token"]));
if (positionals.length === 0)
throw new CliError({
code: "USAGE",
exit: EXIT.USAGE,
message: "verify needs a proof URL or id",
hint: "usage: kestrel verify <https://kestrel.markets/proof/<id> | <id>>"
});
const env = deps.env ?? process.env;
const id = parseProofRef(positionals[0]);
const copyToken = resolveCopyToken(flags, env);
const forward = copyToken !== undefined ? { copyToken } : {};
const base = resolveSimBase(globals, env);
const client = new HostedFunnel({ baseUrl: base, ...deps.fetch !== undefined ? { fetch: deps.fetch } : {} });
return runVerify(client, id, ctx, forward);
}
export { parseProofRef, verifyProofSignature, recomputeNumbersBindRoot, runVerify, verifyCommand };