Skip to main content

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

ParameterValue
Contract address0xD1F216E872a9ed4b90E364825869c2F377155B29
Chain ID8453 (Base mainnet)
Minimum stake0.001 ETH

KB types

The kbType parameter is a uint8 that declares the structural role of the KB:
ValueType
0Practice
1Feature
2StateMachine
3PromptEngineering
4ComplianceChecklist
5Rubric

Steps

1

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
2

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.
3

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);
4

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.
5

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 };
}