Docs/Core Concepts

Offchain to Onchain

The lifecycle of one atom — free and offchain from the first line, promoted onchain the moment conviction arrives.

An atom's life has two phases. Offchain it is free, instant, and private to your stack — a deterministic ID plus canonical bytes in your own database. Onchain it is multiplayer — a market, an address, a permanent home. The move between them is not a migration. It's a promotion: same ID, same bytes, new properties.

Offchain — identity and shape, for free#

Everything starts with a pure function and a validated shape. No wallet, no gas, no network call:

offchain.ts
import { calculateAtomId }          from "@0xintuition/ids";
import { buildSoftwareApplication } from "@0xintuition/primitives";

const value = "https://github.com/vercel/next.js";
const id    = calculateAtomId(value);
// → 0x3a52c8…f577 — already the ID the contract will derive

const atomData = buildSoftwareApplication({
  name: "Next.js",
  url:  value,
});
// canonical JSON-LD — store it offchain, keyed by the id

Because the ID is fixed from the first line (see Deterministic IDs), every contribution — classification fields, enrichment, user activity — attaches to a row the onchain contract will later honor. Apps can collect knowledge before they ask for capital.

Publish — stake TRUST, the atom becomes permanent#

When the record is worth keeping, the same bytes go to the MultiVault contract on the Intuition network (chain 1155). @0xintuition/deployments is the single source of truth for contract addresses across testnets and mainnet:

publish.ts
import { multiVaultCreateAtoms }            from "@0xintuition/protocol";
import { getMultiVaultAddressFromChainId } from "@0xintuition/deployments";
import { toHex, parseEther }                from "viem";

const address = getMultiVaultAddressFromChainId(chainId);
// cfg = { walletClient, publicClient, address }

const stake = parseEther("1");
await multiVaultCreateAtoms(cfg, {
  args:  [[toHex(atomData)], [stake]],
  value: stake,
});
// the onchain atomId equals calculateAtomId(value) — same row, now permanent

Onchain, the atom gains the properties of being onchain:

  • A vault on a bonding curve. TRUST (Ŧ) deposits price along the curve and stay redeemable — conviction, not a like button.
  • Its own Ethereum address, derived deterministically from its ID. Every thing in the graph is also an account that can hold value and act onchain.
  • A permanent, immutable home in a shared graph anyone can build on.

The continuity is the point. The atom didn't get re-created onchain; it got promoted. Same ID, same atom data. Every classification field stored offchain still resolves to the same record.

Triples attach claims to the published atom, using predicates from the shared registry so every app speaks the same vocabulary:

link.ts
import { multiVaultCreateTriples } from "@0xintuition/protocol";
import { useId }                   from "@0xintuition/predicates/use";
import { calculateAtomId }         from "@0xintuition/ids";
import { parseEther }              from "viem";

const reactId = calculateAtomId("https://react.dev");
const per     = parseEther("0.1");
await multiVaultCreateTriples(cfg, {
  args:  [[id], [useId], [reactId], [per]],
  value: per,
});
// next.js — use → React, under a deterministic triple ID

Multiplayer — anyone can build on it now#

The atom is public and permanent. Anyone, in any app, derives the same ID and attaches their own triples — endorsements, tags, list memberships, reviews. Counter-triples carry disagreement, so contested claims are legible rather than shouted down. Independent claims pile onto one record instead of fragmenting into duplicates, and the record's trust signal compounds as stakers take positions in its vault.

That's the whole arc: identity first, conviction later. Start at the Quickstart for the offchain half; the Triples & Predicates page covers the grammar of claims.