Migrating from the official 0G SDKs
If you are already using @0gfoundation/0g-storage-ts-sdk,
@0gfoundation/0g-compute-ts-sdk, or rolling your own DA HTTP client,
0gkit is a drop-in replacement that gives you a uniform
Receipt, a typed error taxonomy, and an
escape hatch to the underlying SDK whenever
you need it.
You can migrate one primitive at a time. The official SDKs continue to work inside 0gkit as the underlying transport — nothing is wrapped that prevents you from reaching the raw client.
Why migrate?
| Pain point | 0gkit fix |
|---|---|
Each SDK has a different signer shape (PrivateKey, ethers.Wallet, broker key, …) | Single Signer interface across every primitive. |
Errors are bare Errors — no codes, no hints, no docs links | Every failure is a ZeroGError with code + hint + helpUrl. |
| No cost estimate before broadcasting | primitive.estimate(input) on storage / compute / DA. |
| No deterministic preview | { dryRun: true } returns the receipt envelope without any tx. |
| Untyped contract calls | Typed contracts with wagmi-style read/write. |
| No browser-safe client | Storage.computeRoot and Storage.exists are pure — no SDK import. |
| No CLI | npx @foundryprotocol/0gkit-cli storage put (or infer, da publish). |
You do not lose anything: storage.raw() returns the loaded
@0gfoundation/0g-storage-ts-sdk module so any feature 0gkit does not surface
yet is still one call away.
1. Storage
Replace @0gfoundation/0g-storage-ts-sdk with @foundryprotocol/0gkit-storage.
The SDK is still installed as an optional peer — 0gkit loads it lazily.
Install
# before
npm install @0gfoundation/0g-storage-ts-sdk ethers
# after — 0gkit + the same peers (kept lazy)
npm install @foundryprotocol/0gkit-storage@latest @foundryprotocol/0gkit-core@latest viem
npm install @0gfoundation/0g-storage-ts-sdk ethers # optional peers
Upload
// before — @0gfoundation/0g-storage-ts-sdk
import { Indexer, ZgFile } from "@0gfoundation/0g-storage-ts-sdk";
import { Wallet, JsonRpcProvider } from "ethers";
const provider = new JsonRpcProvider("https://evmrpc-testnet.0g.ai");
const wallet = new Wallet(process.env.PRIVATE_KEY!, provider);
const indexer = new Indexer("https://indexer-storage-testnet.0g.ai");
const file = ZgFile.fromBytes(new TextEncoder().encode("hello 0G"));
const [tree, err] = await file.merkleTree();
if (err) throw err;
const root = tree!.rootHash();
const [tx, uploadErr] = await indexer.upload(
file,
"https://evmrpc-testnet.0g.ai",
wallet
);
if (uploadErr) throw uploadErr;
console.log("root:", root, "tx:", tx);
// after — @foundryprotocol/0gkit-storage
import { Storage } from "@foundryprotocol/0gkit-storage";
import { fromEnv } from "@foundryprotocol/0gkit-wallet";
const storage = new Storage({ network: "galileo", signer: await fromEnv() });
const { root, tx } = await storage.upload(new TextEncoder().encode("hello 0G"));
console.log("root:", root, "tx:", tx.txHash, `(${tx.latencyMs} ms)`);
What you gain: typed Signer from env/file/private key/KMS, uniform Receipt
({ txHash, latencyMs }), ConfigError with hint when the SDK is missing,
and a { dryRun: true } overload that returns the predicted root + the
gas estimate without broadcasting.
Download / probe / hash locally
// after
const bytes = await storage.download(root); // download by root
const exists = await storage.exists(root); // poll for finality
const localRoot = await storage.computeRoot(bytes); // no SDK, no network
Need the underlying SDK for something not exposed yet?
const raw = await storage.raw(); // the loaded @0gfoundation module
See @foundryprotocol/0gkit-storage for the full API
and the estimate + dry-run concept for cost preflight.
2. Compute (TEE inference)
Replace @0gfoundation/0g-compute-ts-sdk (or @0glabs/0g-serving-broker)
with @foundryprotocol/0gkit-compute.
Install
# before
npm install @0gfoundation/0g-compute-ts-sdk ethers
# after
npm install @foundryprotocol/0gkit-compute@latest @foundryprotocol/0gkit-core@latest viem
npm install @0gfoundation/0g-compute-ts-sdk ethers # optional peer
Inference
// before — @0gfoundation/0g-compute-ts-sdk
import { createZGComputeNetworkBroker } from "@0gfoundation/0g-compute-ts-sdk";
import { Wallet, JsonRpcProvider } from "ethers";
const provider = new JsonRpcProvider("https://evmrpc-testnet.0g.ai");
const wallet = new Wallet(process.env.BROKER_KEY!, provider);
const broker = await createZGComputeNetworkBroker(wallet);
const account = await broker.inference.getAccount(process.env.PROVIDER!);
const { endpoint, model } = await broker.inference.getServiceMetadata(
process.env.PROVIDER!
);
const headers = await broker.inference.getRequestHeaders(
process.env.PROVIDER!,
"hello"
);
const res = await fetch(`${endpoint}/v1/chat/completions`, {
method: "POST",
headers: { "Content-Type": "application/json", ...headers },
body: JSON.stringify({ messages: [{ role: "user", content: "hello" }], model }),
});
const json = await res.json();
const output = json.choices[0].message.content;
// after — @foundryprotocol/0gkit-compute
import { Compute } from "@foundryprotocol/0gkit-compute";
import { fromEnv } from "@foundryprotocol/0gkit-wallet";
const compute = new Compute({
network: "galileo",
signer: await fromEnv(),
provider: process.env.ZEROG_PROVIDER!,
});
const { output, receipt } = await compute.inference({
messages: [{ role: "user", content: "hello" }],
});
console.log(output, receipt.txHash);
What you gain: no manual header dance, no manual broker setup, a typed
ZeroGError taxonomy (COMPUTE_NO_PROVIDER, COMPUTE_INFERENCE_FAILED,
COMPUTE_BAD_ATTESTATION) with one-line fixes, and an
{ dryRun: true } overload that returns a token-count + cost estimate.
See @foundryprotocol/0gkit-compute.
3. DA (Data Availability)
Replace direct HTTP calls to the 0G DA encoder with
@foundryprotocol/0gkit-da.
Install
# after — no upstream SDK install required; DA is HTTP-only
npm install @foundryprotocol/0gkit-da@latest @foundryprotocol/0gkit-core@latest viem
Publish
// before — hand-rolled HTTP
const res = await fetch("https://da-encoder-testnet.0g.ai/v1/publish", {
method: "POST",
headers: { "Content-Type": "application/octet-stream" },
body: payload,
});
if (!res.ok) throw new Error(`DA publish failed: ${res.status}`);
const { digest } = await res.json();
// after — @foundryprotocol/0gkit-da
import { DA } from "@foundryprotocol/0gkit-da";
const da = new DA({ network: "galileo" });
const { digest, raw } = await da.publish(payload);
What you gain: a network preset (no manual URLs), NetworkError with a
hint when the encoder is unreachable, an estimate(payload) for the
expected fee, and a { dryRun: true } overload that returns the digest
without a network call.
See @foundryprotocol/0gkit-da.
What stays the same
- The on-chain receipt.
tx.txHashis the same hash you would have seen before; the explorer link works in both worlds. - The storage root. A blob uploaded via
Storage.uploadhas the same merkle root that@0gfoundation/0g-storage-ts-sdkwould produce for the same bytes — that's what makescomputeRootdeterministic. - The TEE attestation. Inference receipts carry the provider's attestation
unchanged —
@foundryprotocol/0gkit-attestationparses + verifies it.
Hybrid usage
You can mix 0gkit with the underlying SDK indefinitely. storage.raw(),
compute.raw(), and da.raw() return the loaded module so any feature not
yet surfaced through 0gkit's API is one call away. This is also how you
adopt incrementally — keep the old code paths working while you migrate
endpoints one at a time.
Next steps
- Getting started — install + a 60-second end-to-end example.
create-0gkit-app— scaffold a runnable project with the right peers wired in.- Cookbook — end-to-end builds (chat, AI agent, NFT minter).
- CLI reference —
npx @foundryprotocol/0gkit-clifor the same operations from a script.