0G integration
Thin, typed wrappers over 0G Compute (attested inference), 0G Storage (root-hash commitments), and 0G Chain (the registry). Each exposes .raw() — one place to absorb SDK churn.
#0G Compute
Inference runs against a TEE-capable (“TeeML”) provider through the 0G Compute broker, which can cryptographically attest the response came from the enclave. The broker is throw-on-error and auto-selects testnet contracts from the signer’s chain id.
async infer(messages): Promise<InferenceResult> {
const broker = await this.getBroker();
await this.ensureFunded(broker);
const provider = this.config.computeProvider;
const { endpoint, model } = await broker.inference.getServiceMetadata(provider);
const content = serialize(messages); // joined role+content; the broker bills on it
const headers = await broker.inference.getRequestHeaders(provider, content); // SINGLE-USE per call
const openai = new OpenAI({ baseURL: endpoint, apiKey: '' });
// .withResponse() exposes raw headers: the TEE signature is keyed by the
// provider's ZG-Res-Key header, NOT completion.id (which 404s).
const { data: completion, response } = await openai.chat.completions
.create({ model, messages }, { headers: { ...headers } })
.withResponse();
const answer = completion.choices[0]?.message?.content;
if (!answer) throw new Error('0G inference returned an empty completion');
const chatId = response.headers.get('ZG-Res-Key') ?? completion.id; // the verification handle
return { answer, chatId, provider, model };
}Storage went green, but compute kept failing the attestation step. processResponsefetches the TEE signature from /v1/proxy/signature/{chatID} — and we were passing completion.id, which 404s. The chatID must be the provider’s ZG-Res-Key response header, only reachable via .withResponse(). One line turned the red cross into “processResponse returned TRUE — the call is sworn.”
Verification is told honestly: processResponse returns boolean | null, and anything other than an explicit true is treated as unverified. We never fabricate a verified state.
#0G Storage
0G Storage turns a sealed memory blob into a public, content-addressed commitment: a merkle root hash. The SDK is tuple-returning — it never throws — the exact inverse of the compute broker, so every call checks the error tuple.
async upload(bytes): Promise<UploadResult> {
const data = new MemData(bytes);
const [tree, treeErr] = await data.merkleTree(); // [result, err] TUPLE — never assume a throw
if (treeErr !== null) throw treeErr;
const expectedRoot = tree?.rootHash() ?? null;
const [res, upErr] = await this.indexer.upload(data, this.evmRpc, signer);
if (upErr !== null) throw upErr;
// upload() is polymorphic: one small object returns { rootHash, txHash }; narrow defensively.
const rootHash = 'rootHash' in res ? res.rootHash : res.rootHashes[0];
if (expectedRoot !== null && rootHash !== expectedRoot)
throw new Error('0G upload root mismatch');
return { rootHash, txHash: res.txHash ?? null };
}Splitting computeRoot from upload lets a receipt surface a real root hash immediately while the upload runs in the background — and the upload’s root is asserted to match. Reads are Node-only and run only on the reconcile path; the 3–5 minute propagation delay is precisely why a user turn never reads from storage.
#0G Chain
Storage proves a memory exists; the chain proves the agent committed to it, permanently, in an order anyone can replay. AgentRegistry is a tiny Solidity contract: an append-only log of each owner’s root hashes, with events the proof feed indexes. It holds no funds and has no admin path to mutate or delete.
function commitMemory(bytes32 rootHash) external returns (uint256 index) {
if (!registered[msg.sender]) revert NotRegistered();
if (rootHash == bytes32(0)) revert ZeroRootHash();
index = _memories[msg.sender].length;
_memories[msg.sender].push(Commitment({ rootHash: rootHash, timestamp: uint64(block.timestamp) }));
emit MemoryCommitted(msg.sender, rootHash, index);
}Phase 3 is wired behind one env var. When a registry address is configured, a successful upload is followed by an on-chain commit whose tx hash flows into the memory receipt — another clickable proof. Eight Foundry tests cover access control, the reverts, append-only immutability, and a fuzz pass.
#SDK reality
The single hardest-won lesson in this project is which packages to install. The 0G SDKs migrated org from @0glabs/* to @0gfoundation/*; the old packages are abandoned and point at the wrong contracts on Galileo (the broker defaults to mainnet addresses). Use these:
| Need | Package |
|---|---|
| Compute | @0gfoundation/0g-compute-ts-sdk@^0.8.4 |
| Storage | @0gfoundation/0g-ts-sdk@^1.2.8 |
Before touching a 0G primitive, run npm pack @0gfoundation/<pkg> and read the .d.ts files. Never trust docs, blogs, or training data for versions or signatures — they are routinely stale for this stack. Galileo’s chain id is 16602 (ChainList still shows the old 16601).