SDK · Reference
The @foundryprotocol/sdk surface, frozen at 1.0.0-rc.1.
One imported class — Foundry — with five namespaces: forge, ingot, inference, revenue, lineage. No surprises, no callback hell, no opaque proxies. Read methods need no wallet; write methods require walletClient.
Foundry client
constructionts
import { Foundry } from "@foundryprotocol/sdk";
import { createWalletClient, custom } from "viem";
// Read-only — no wallet needed.
const foundry = new Foundry({ contracts: "aristotle" });
// Read + write — pass a viem WalletClient.
const wallet = createWalletClient({
transport: custom(window.ethereum),
});
const foundryRW = new Foundry({
contracts: "aristotle",
walletClient: wallet,
});Config options:
| Option | Type | Default |
|---|---|---|
contracts | "aristotle" | "aristotle" |
rpcUrl | string | https://rpc.0g.network |
walletClient | viem.WalletClient | — |
inferenceEndpoint | string | https://api.foundryprotocol.xyz/v1 |
inferenceApiKey | string | — |
forge.*
forge.create()
Opens a new Forge. Requires wallet.
ts
const { txHash } = await foundry.forge.create({
modelSpec: "0x…",
evalSpec: "0x…",
evalCoordinator: "0x…",
contributionWindowEnds: BigInt(Math.floor(Date.now() / 1000) + 7 * 86400),
});forge.contributeData() / contributeCompute() / fundForge()
ts
await foundry.forge.contributeData("forge:0x…", "0x<storageRoot>");
await foundry.forge.contributeCompute("forge:0x…", "0.05"); // 0.05 OG
await foundry.forge.fundForge("forge:0x…", "1.0"); // 1.0 OGforge.state() / forge.list()
ts
const state = await foundry.forge.state("forge:0x…"); // 0|1|2|3|4
const ids = await foundry.forge.list(); // ForgeId[]
// State enum: OPEN=0, TRAINING=1, ATTESTED=2, MINTED=3, FAILED=4ingot.*
ts
const meta = await foundry.ingot.meta(tokenId);
// → { weightsRoot, lineageParent, forge, mintedAt, weightsSet }
const share = await foundry.ingot.shareOf(tokenId, "0x<address>");
// → bigint (basis points, 10000 = 100%)inference.*
ts
const { output, receipt } = await foundry.inference.run(
"ingot:0x…",
{
input: "…",
// — or —
messages: [{ role: "user", content: "…" }],
temperature: 0.7,
maxTokens: 512,
},
);The receipt:
ts
{
output: string,
ingotId: `ingot:0x${string}`,
receipt: {
requestId: string,
inferenceTxHash: `0x${string}` | undefined,
revenueTxHash: `0x${string}` | undefined,
latencyMs: number,
},
}revenue.*
ts
const claimable = await foundry.revenue.claimable(tokenId, "0x<address>");
const { txHash } = await foundry.revenue.claim(tokenId);Pull payments, intentionally
Revenue is never pushed. Smiths claim when they like — gas costs are theirs, and reverts on the recipient side can't grief the splitter. This is the OpenZeppelin PaymentSplitter pattern, adapted for ERC-721 share weights.
lineage.*
ts
const { parent } = await foundry.lineage.get(tokenId);
// parent is the weightsRoot Hex of the parent Ingot, or 0x000…0 if root.Type reference
| Type | Shape |
|---|---|
IngotId | `ingot:0x${string}` |
ForgeId | `forge:0x${string}` |
Address | viem Address |
Hex | viem Hex |
InferenceParams | see inference |
InferenceResult | see inference |
Error handling
All write methods throw a viem-derived error on revert. The SDK wraps inference HTTP errors in InferenceError with the upstream status code and body fragment.
ts
import { InferenceError } from "@foundryprotocol/sdk";
try {
await foundry.inference.run("ingot:0x…", { input: "…" });
} catch (e) {
if (e instanceof InferenceError) {
console.error("proxy returned", e.status, e.body);
} else throw e;
}