Documentation Index
Fetch the complete documentation index at: https://docs.xandrlabs.ai/llms.txt
Use this file to discover all available pages before exploring further.
Publishing a Knowledge Block makes it permanently discoverable on-chain and eligible for query fee settlement. The registry contract on Base mainnet stores the KB’s identity hash, IPFS content address, type, parent lineage, and royalty configuration. Once published, a KB’s identity is immutable — there is no on-chain mechanism to edit or retract a published record.
Prerequisites
Before you publish, make sure you have:
- Node.js with
ethers v6 and @alx/protocol installed
- A wallet with at least 0.001 ETH on Base mainnet (chain ID 8453) to cover the minimum stake
- An IPFS CID for your artifact — upload the artifact before calling the registry
- The
kbHash for your artifact (see Compute a Knowledge Block identity with kbHash)
Contract reference
| Parameter | Value |
|---|
| Contract address | 0xD1F216E872a9ed4b90E364825869c2F377155B29 |
| Chain ID | 8453 (Base mainnet) |
| Minimum stake | 0.001 ETH |
KB types
The kbType parameter is a uint8 that declares the structural role of the KB:
| Value | Type |
|---|
0 | Practice |
1 | Feature |
2 | StateMachine |
3 | PromptEngineering |
4 | ComplianceChecklist |
5 | Rubric |
Steps
Compute the kbHash
Derive the kbHash for your artifact. This becomes the on-chain kbId. See Compute a Knowledge Block identity with kbHash for the full derivation flow.import { kbHashFromEnvelope } from "@alx/protocol";
const { kbHash: _excluded, metadata: _m, curator: _c, createdAt: _d, ...envelope } = artifact;
const kbHash = kbHashFromEnvelope(envelope);
// "0x" + 64 hex chars
Upload the artifact to IPFS
Upload your artifact JSON to IPFS and record the resulting CID. The registry stores the CID as a string — use CIDv1 in base32 format for forward compatibility.// Using the web3.storage client or any IPFS HTTP API.
// This example shows a generic fetch-based upload; use your preferred IPFS library.
const artifactJson = JSON.stringify(artifact, null, 2) + "\n";
// Example with web3.storage (kubo-rpc-client, Pinata, NFT.storage, etc.):
// const cid = await client.put([new File([artifactJson], "artifact.json")]);
const rootCid = "bafybeig..."; // your CIDv1 string
The registry stores the CID as an opaque string. Use a pinning service to keep the artifact retrievable. A CID without an active IPFS pin should be treated as at-risk for unavailability.
Connect to the registry contract
Instantiate the registry with the contract address, ABI, and a signer.import { ethers } from "ethers";
import { REGISTRY_ABI } from "@alx/protocol";
const CONTRACT_ADDRESS = "0xD1F216E872a9ed4b90E364825869c2F377155B29";
// Connect to Base mainnet (chain ID 8453)
const provider = new ethers.JsonRpcProvider("https://mainnet.base.org");
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const registry = new ethers.Contract(CONTRACT_ADDRESS, REGISTRY_ABI, wallet);
Call publishKB
Submit the transaction with all required parameters and the 0.001 ETH minimum stake.const kbType = 0; // Practice
const parentIds: string[] = []; // bytes32[] of parent kbHashes, max 8
const royaltyBps = 500; // 5% royalty in basis points (500 / 10000)
const tx = await registry.publishKB(
kbHash, // bytes32 — the KB identity hash
rootCid, // string — IPFS CID of the artifact
kbType, // uint8 — KB type from the table above
parentIds, // bytes32[] — parent KB hashes (max 8)
royaltyBps, // uint16 — royalty in basis points (0–10000)
{ value: ethers.parseEther("0.001") }
);
const receipt = await tx.wait();
console.log("Published in block:", receipt.blockNumber);
The minimum stake is 0.001 ETH per KB. Transactions that supply less than this amount will revert. The stake is held by the contract and is subject to the reference deployment’s staking and slashing rules.
Verify the published artifact hash
After the transaction confirms, read back the artifact hash stored on-chain and compare it with your locally computed value to confirm the registration is consistent.import { createHash } from "crypto";
// Re-derive the artifact hash locally
const artifactJson = JSON.stringify(artifact, null, 2) + "\n";
const localArtifactHash = "0x" + createHash("sha256")
.update(artifactJson)
.digest("hex");
// Read from the contract (pass the kbHash as the kbId)
const onChainArtifactHash = await registry.getArtifactHash(kbHash);
console.log("Match:", localArtifactHash === onChainArtifactHash);
Parent lineage and royalties
The parentIds array encodes the attribution graph for derived KBs. Each entry is a bytes32 kbHash of a parent KB that must already be registered on-chain.
- Maximum 8 parent IDs per KB.
royaltyBps sets the basis-point share of query fees that flows to parent KB curators via the settlement mechanism. A value of 500 means 5%.
- The sum of
royaltyShareBps across all attribution links in a settlement call must not exceed 10000 (100%). See Settle query fees across the attribution graph for details.
Full example
import { ethers } from "ethers";
import { REGISTRY_ABI, kbHashFromEnvelope } from "@alx/protocol";
import { createHash } from "crypto";
const CONTRACT_ADDRESS = "0xD1F216E872a9ed4b90E364825869c2F377155B29";
async function publishKnowledgeBlock(artifact: Record<string, unknown>) {
// 1. Compute identity hash
const { kbHash: _k, metadata: _m, curator: _c, createdAt: _d, ...envelope } = artifact;
const kbHash = kbHashFromEnvelope(envelope);
// 2. Derive artifact hash for verification
const artifactJson = JSON.stringify(artifact, null, 2) + "\n";
const artifactHash = "0x" + createHash("sha256").update(artifactJson).digest("hex");
// 3. Upload to IPFS (implementation depends on your pinning provider)
const rootCid = await uploadToIPFS(artifactJson);
// 4. Connect to registry
const provider = new ethers.JsonRpcProvider("https://mainnet.base.org");
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const registry = new ethers.Contract(CONTRACT_ADDRESS, REGISTRY_ABI, wallet);
// 5. Publish
const tx = await registry.publishKB(
kbHash,
rootCid,
0, // Practice
[], // no parents
500, // 5% royalty
{ value: ethers.parseEther("0.001") }
);
const receipt = await tx.wait();
// 6. Verify
const onChainHash = await registry.getArtifactHash(kbHash);
if (onChainHash !== artifactHash) {
throw new Error("On-chain artifact hash does not match local computation");
}
return { kbHash, rootCid, blockNumber: receipt.blockNumber };
}