Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions app/contracts/deployments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* Local mirror of the deployment registry in modeltrace-contract.
*
* The canonical registry lives in the contracts repository as
* `deployments/{testnet,mainnet}.json` (tracked in modeltrace-contract#62).
* This file is shaped to be a straight copy of that record — contract id,
* WASM hash, build commit, deploy timestamp — so that when the registry lands,
* updating this page is a data swap, not a rewrite.
*
* Until the contracts are actually deployed, every address and hash below is
* `null` and the page renders the honest "not yet deployed" state. This file
* must never be filled with unverified values: the entire point of the page
* is that a reader can verify the deployed bytes against the source, so an
* unverifiable address would be worse than none.
*/

export type ContractSlug = "audit-registry" | "usage-meter" | "payment-router";
export type ContractRole = "Attestation" | "Metering" | "Settlement";

export interface ContractMeta {
slug: ContractSlug;
name: string;
role: ContractRole;
/** What the contract holds on-chain. */
holds: string;
/** Why this contract exists separately from the other two. */
rationale: string;
/** Direct link to the crate source in modeltrace-contract. */
sourceUrl: string;
}

export const CONTRACT_META: Record<ContractSlug, ContractMeta> = {
"audit-registry": {
slug: "audit-registry",
name: "Audit Registry",
role: "Attestation",
holds: "Signed inference events — model version, policy ref, timestamp, submitter.",
rationale:
"Attestation is the hottest path in the system: every inference a gateway logs becomes a record. It must be cheap, append-only, and safe to call at volume, so it stays free of money-moving logic that would force it to be conservative.",
sourceUrl:
"https://github.com/FinesseStudioLab/modeltrace-contract/tree/main/audit-registry",
},
"usage-meter": {
slug: "usage-meter",
name: "Usage Meter",
role: "Metering",
holds: "Usage units, quota buckets, pricing tiers.",
rationale:
"Metering converts raw attestations into billable units. It reads attestations and prices them against tiers, but it holds no funds — keeping it between the two extremes lets it change pricing without touching either escrow or the audit trail.",
sourceUrl:
"https://github.com/FinesseStudioLab/modeltrace-contract/tree/main/usage-meter",
},
"payment-router": {
slug: "payment-router",
name: "Payment Router",
role: "Settlement",
holds: "Escrow, dispute windows, payout release.",
rationale:
"Settlement moves money, so it must be the most conservative contract in the system: slow to act, gated by dispute windows, and rare by design. Isolating it means an upgrade or audit of money movement never touches the attestation rail.",
sourceUrl:
"https://github.com/FinesseStudioLab/modeltrace-contract/tree/main/payment-router",
},
};

/** One row of the deployment registry, mirroring the contracts repo record. */
export interface DeployedContract {
slug: ContractSlug;
/** Soroban contract id (C…). `null` until the registry lands. */
address: string | null;
/** SHA-256 of the deployed WASM bytes. `null` until the registry lands. */
wasmHash: string | null;
/** Source commit the deployed WASM was built from. */
commit: string | null;
/** ISO-8601 deploy timestamp. */
deployedAt: string | null;
}

export interface NetworkDeployments {
network: "testnet" | "mainnet";
label: string;
/** Explorer prefix; the contract address is appended to build the link. */
explorerUrl: string;
contracts: DeployedContract[];
}

/**
* Read by the page — never hardcode an address in JSX. When
* modeltrace-contract#62 lands, copy the registry values in here.
*/
export const DEPLOYMENTS: NetworkDeployments[] = [
{
network: "testnet",
label: "Testnet",
explorerUrl: "https://stellar.expert/explorer/testnet/contract/",
contracts: [
{ slug: "audit-registry", address: null, wasmHash: null, commit: null, deployedAt: null },
{ slug: "usage-meter", address: null, wasmHash: null, commit: null, deployedAt: null },
{ slug: "payment-router", address: null, wasmHash: null, commit: null, deployedAt: null },
],
},
{
network: "mainnet",
label: "Mainnet",
explorerUrl: "https://stellar.expert/explorer/public/contract/",
contracts: [
{ slug: "audit-registry", address: null, wasmHash: null, commit: null, deployedAt: null },
{ slug: "usage-meter", address: null, wasmHash: null, commit: null, deployedAt: null },
{ slug: "payment-router", address: null, wasmHash: null, commit: null, deployedAt: null },
],
},
];

/** True once any contract on any network carries a real address. */
export function hasLiveDeployments(): boolean {
return DEPLOYMENTS.some((network) =>
network.contracts.some((c) => c.address !== null),
);
}
143 changes: 143 additions & 0 deletions app/contracts/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,146 @@
import type { Metadata } from "next";
import Link from "next/link";
import { CONTRACT_META, hasLiveDeployments } from "./deployments";
import { DeploymentTable } from "@/components/deployment-table";
import { FlowDiagram } from "@/components/flow-diagram";

export const metadata: Metadata = {
title: "Contracts",
description:
"The three ModelTrace contracts — audit-registry, usage-meter, payment-router — why they are separate, where they are deployed, and how to verify the deployed bytes yourself.",
};

const CONTRACT_ORDER = ["audit-registry", "usage-meter", "payment-router"] as const;

const REGISTRY_ISSUE_URL =
"https://github.com/FinesseStudioLab/modeltrace-contract/issues/62";
const CONTRACTS_REPO_URL = "https://github.com/FinesseStudioLab/modeltrace-contract";
const CONTRACTS_STATUS_URL =
"https://github.com/FinesseStudioLab/modeltrace-contract#current-status";

export default function Page() {
const live = hasLiveDeployments();

return (
<section className="section">
<span className="tag">Contracts</span>
<h2>The contracts behind ModelTrace</h2>
<p className="contracts-lead">
ModelTrace&apos;s rules live in three Soroban contracts on Stellar:
attestation, metering, and settlement. They are deliberately separate —
attestation is cheap and frequent, settlement is conservative and rare —
so each one can be reasoned about and audited on its own.
</p>

{/* Why three contracts */}
<div className="contracts-grid">
{CONTRACT_ORDER.map((slug) => {
const meta = CONTRACT_META[slug];
return (
<article className="card contract-card" key={slug}>
<span className="contract-role">{meta.role}</span>
<h3>{meta.name}</h3>
<p>{meta.holds}</p>
<p className="contract-rationale">{meta.rationale}</p>
<a className="contract-source" href={meta.sourceUrl} target="_blank" rel="noreferrer">
Read the source →
</a>
</article>
);
})}
</div>
<p className="contracts-separation">
One rule of thumb ties the design together: the closer a contract gets
to moving money, the slower and more careful it must be. Attestations
are written on every inference and never cost anything to dispute;
settlements move funds, so they wait out a dispute window and only fire
when the case is clear.
</p>

{/* Live deployments */}
<div className="contracts-block">
<h3>Deployed addresses</h3>
<p className="contracts-sub">
Addresses and WASM hashes below are read from the deployment registry,
not hardcoded in this page. Each address links to its explorer entry.
</p>
{!live ? (
<div className="deploy-notice" role="status">
<strong>Not yet deployed.</strong> The contracts are compiling
scaffolds today, and the deployment registry they will be published
in is tracked in{" "}
<a href={REGISTRY_ISSUE_URL} target="_blank" rel="noreferrer">
modeltrace-contract#62
</a>
. This page goes live the moment that registry lands — no page
rewrite needed.
</div>
) : null}
<DeploymentTable />
</div>

{/* Verify it yourself */}
<div className="contracts-block">
<h3>Verify it yourself</h3>
<p className="contracts-sub">
The WASM hash next to each address is a SHA-256 of the deployed
bytes. Rebuild from source and compare — if the hashes match, the
deployed contract is exactly what the source says it is.
</p>
<ol className="contracts-steps">
<li>
Clone and build the contracts with the pinned toolchain (requires
Rust 1.84+ and the Soroban WASM target):
{/* Scrolls on narrow screens (unbreakable command lines), so it
needs a tab stop to satisfy axe's scrollable-region-focusable. */}
<pre className="contracts-code" tabIndex={0}>{`git clone https://github.com/FinesseStudioLab/modeltrace-contract
cd modeltrace-contract
rustup target add wasm32v1-none
cargo build --release --target wasm32v1-none`}</pre>
</li>
<li>
Hash the artifact for the contract you want to check. The release
profile in the workspace (opt-level z, LTO, stripped) is what makes
the output reproducible:
<pre className="contracts-code" tabIndex={0}>{`sha256sum target/wasm32v1-none/release/audit_registry.wasm
sha256sum target/wasm32v1-none/release/usage_meter.wasm
sha256sum target/wasm32v1-none/release/payment_router.wasm`}</pre>
</li>
<li>
Compare each result with the WASM hash in the table above. A match
means the bytes on-chain were built from this source at the
recorded commit. Use the Soroban WASM target{" "}
<code>wasm32v1-none</code> — <code>wasm32-unknown-unknown</code>{" "}
produces bytes the network rejects.
</li>
</ol>
</div>

{/* Flow */}
<div className="contracts-block">
<h3>How an inference flows through</h3>
<FlowDiagram />
</div>

{/* Source & audit status */}
<div className="contracts-block">
<h3>Source and audit status</h3>
<p className="contracts-sub">
The contracts are open source under Apache-2.0. They are currently
compiling scaffolds — real domain entrypoints, authorization, and
tests are tracked as open issues in the contracts repository.
</p>
<div className="contracts-links">
<a className="cta-secondary" href={CONTRACTS_REPO_URL} target="_blank" rel="noreferrer">
modeltrace-contract on GitHub
</a>
<a className="cta-secondary" href={CONTRACTS_STATUS_URL} target="_blank" rel="noreferrer">
Audit status
</a>
<Link className="cta-secondary" href="/roadmap">
Production milestones
</Link>
</div>
import { Address, Hash } from "@/components/address-hash";

// Synthetic but realistic-length values for the demo.
Expand Down
Loading