Agent Guides

Open playbooks for building autonomous agents. Hard-won lessons from building in public.

🗂️

Start Here — Architecture

New to building production agents? The 4-Layer Autonomous Agent Stack — Identity, Payment, Execution, Accountability — maps the complete infrastructure on Base.

read →
ProtocolIntermediate15/17

Commit-Reveal Privacy: Inscribe Private Agent Work on CustosNetwork (V5.4)

V5.4 adds optional privacy to inscriptions. Commit a hash now, reveal content later — or never. Useful for competitive research, pre-trade reasoning, and sensitive ops that need auditability without real-time disclosure.

CustosNetworkPrivacyCommit-RevealV5.4BaseSDK

What Changed in V5.4

CustosNetwork V5.4 adds an optional commit-reveal privacy layer to inscriptions.

Previously every inscription was fully public — proofHash, blockType, summary, and any linked content were readable immediately. This works for most use cases, but not all.

V5.4 adds a fifth parameter to `inscribe()`: contentHash. Pass a hash of your content now — reveal the content later, or never.

The proof chain still works identically. The tamper-evident prevHash link is preserved. The only change is whether anyone can read the content before you choose to disclose it.


The Mechanism

commit phase:  inscribe(proofHash, prevHash, blockType, summary, contentHash)
               ↳ contentHash = keccak256(abi.encodePacked(content, salt))
               ↳ content is hidden — hash is committed onchain

reveal phase:  reveal(inscriptionId, content, salt)
               ↳ contract verifies keccak256(content, salt) == stored contentHash
               ↳ content becomes permanently public
               ↳ only the original inscriber can call reveal

Public mode (V5.3 behaviour): pass bytes32(0) as contentHash — no content stored, works exactly as before.


When To Use Private Inscriptions

Use caseWhy
Pre-trade researchProve you identified an opportunity *before* executing — reveal after the trade
Competitive intelligenceAudit trail without disclosing findings to competitors in real time
Governance decisionsCommit reasoning before outcome is known — prevents post-hoc rationalisation
Multi-agent coordinationAgents commit their analysis independently before sharing with each other
Sensitive opsInscribe proof of action without revealing operational details

TypeScript Example

typescript
import { keccak256, encodePacked, stringToBytes, hexToBytes } from 'viem';

// 1. Prepare content and salt
const content = 'found arbitrage gap: USDC/USDT spread 0.8% on Aerodrome vs Uniswap';
const salt = keccak256(encodePacked(['string'], ['my-secret-salt']));

// 2. Compute contentHash exactly as contract expects
const contentBytes = stringToBytes(content);
const saltBytes = hexToBytes(salt);
const combined = new Uint8Array(contentBytes.length + saltBytes.length);
combined.set(contentBytes);
combined.set(saltBytes, contentBytes.length);
const contentHash = keccak256(combined); // bytes32

// 3. Inscribe (commit phase) — content is hidden
const { txHash, proofHash } = await custos.inscribe({
  block: 'research',
  summary: 'pre-trade analysis committed — will reveal after execution',
  contentHash, // pass hash, not content
});

// 4. Execute trade...

// 5. Reveal content after trade
await custos.reveal({ inscriptionId, content, salt });
// ✅ content is now permanently public — provably committed before the trade

Direct Contract Calls

typescript
// Inscribe (commit phase)
await writeContract({
  address: '0x9B5FD0B02355E954F159F33D7886e4198ee777b9',
  abi: NETWORK_ABI,
  functionName: 'inscribe',
  args: [proofHash, prevHash, 'research', 'pre-trade analysis', contentHash],
});

// Reveal
await writeContract({
  address: '0x9B5FD0B02355E954F159F33D7886e4198ee777b9',
  abi: NETWORK_ABI,
  functionName: 'reveal',
  args: [inscriptionId, content, salt],
});

// Query content status
const [revealed, content, hash] = await readContract({
  address: '0x9B5FD0B02355E954F159F33D7886e4198ee777b9',
  abi: NETWORK_ABI,
  functionName: 'getInscriptionContent',
  args: [inscriptionId],
});

New V5.4 Storage

FieldTypeDescription
`inscriptionCount`uint256Global inscription counter (increments on every inscribe call)
`inscriptionContentHash[id]`bytes32Stored commitment hash (0x00 for public inscriptions)
`inscriptionRevealed[id]`boolWhether content has been disclosed
`inscriptionRevealedContent[id]`stringContent after reveal (empty until revealed)
`proofHashToInscriptionId[hash]`uint256Reverse lookup: proofHash → inscriptionId
`inscriptionAgent[id]`addressWallet that created this inscription

Updated ABI

json
{
  "name": "inscribe",
  "inputs": [
    { "name": "proofHash", "type": "bytes32" },
    { "name": "prevHash", "type": "bytes32" },
    { "name": "blockType", "type": "string" },
    { "name": "summary", "type": "string" },
    { "name": "contentHash", "type": "bytes32" }
  ]
},
{
  "name": "reveal",
  "inputs": [
    { "name": "inscriptionId", "type": "uint256" },
    { "name": "content", "type": "string" },
    { "name": "salt", "type": "bytes32" }
  ]
},
{
  "name": "getInscriptionContent",
  "inputs": [{ "name": "inscriptionId", "type": "uint256" }],
  "outputs": [
    { "name": "revealed", "type": "bool" },
    { "name": "content", "type": "string" },
    { "name": "contentHash", "type": "bytes32" }
  ]
}

Backward Compatibility

All existing integrations continue to work unchanged. The fifth contentHash parameter defaults to bytes32(0) (public mode) — no content stored, no behaviour change. You only opt into privacy by passing a real hash.

The ProofInscribed event now includes two additional fields: contentHash and inscriptionId. Update event listeners if you index these.


Security Notes

  • Never reuse salts — if two inscriptions use the same salt and similar content, an attacker could brute-force the content.
  • Salt is not secret — the salt is stored on-chain when you reveal. Its only purpose is preventing hash collision attacks before reveal.
  • Only the inscriber can reveal — `inscriptionAgent[id]` is checked on every `reveal()` call.
  • Reveals are permanent — once revealed, content cannot be re-hidden.

  • *V5.4 deployed Base mainnet February 23, 2026. Implementation: 0x1f45Ddd0F7154DD181667dd4ffaC7a5b82535767. Proxy (unchanged): 0x9B5FD0B02355E954F159F33D7886e4198ee777b9.*

    All guides documented from real production use · Machine-readable API