Skip to content

Reference

OcpClient — Canton entry point for OCP

One namespaced facade over LedgerJsonApiClient / optional ValidatorApiClient — OpenCapTable reads and batch writes, cached context, and createBatch for composing DAML submissions.

OcpClient is the ergonomic entry package surface for @open-captable-protocol/canton. Instantiate it once with your authenticated Canton ledger clients, then drill into OpenCapTable for every cap-table lifecycle action, OpenCapTableReports for valuation artifacts, CantonPayments / PaymentStreams for tokenized movement, and CouponMinter for TPS pacing utilities. context remembers FeaturedAppRight, issuer party, and the active cap-table contract id across calls so integrations do not re-thread disclosures on every invocation.

Reads through OpenCapTable.*.get return ContractResult<T> { data, contractId }, matching OCF payloads with Canton handles—see the per-entity pages under /reference/open-cap-table for one page per get. Stateful writes that mutate embedded cap-table rows run through CapTableBatch (capTable.update) unless you deliberately emit bare commands (issuer.buildCreate) with createBatch for multi-command Canton submissions.


Minimal setup

import { Canton } from '@fairmint/canton-node-sdk';
import { OcpClient, toContractId, toPartyId } from '@open-captable-protocol/canton';

const canton = new Canton({ network: 'localnet' });

const ocp = new OcpClient({
  ledger: canton.ledger,
  validator: canton.validator, // optional for strict cap-table workloads
});

Dependencies (new OcpClient)

ParameterRequirementMeaning
ledgerRequiredCanton LedgerJsonApiClient from new Canton(...). Mandatory for OpenCapTable, CapTableBatch, OpenCapTableReports, and anything that submits JSON API exercises.
validatorOptionalCanton ValidatorApiClient. Needed for PaymentStreams.utils.buildPaymentContext* stacks that hydrate validator + Amulet context. Pure cap-table code can omit this.

If your transport layer changes (localnet preview vs pinned package line), disclose the pinned template ids explicitly through helper params—see capTable.update({ capTableContractDetails }) and IssuerAuthorization flows below.


Namespace overview

OpenCapTable

  • Readers (get) — hydrate any OCF object or transactional record by contract id. Every namespace key matches the OcpClient table in src/OcpClient.ts.
  • issuer.buildCreate — emit CreateCapTable payloads that must ride on ocp.createBatch (addBuiltCommand).
  • issuerAuthorization.authorize / withdraw — authorize an issuer party through the pinned OCP Factory or withdraw from an IssuerAuthorization contract.
  • capTableclassify / getState (pinned-template queries only), update (fluent CapTableBatch), archive (system-operator teardown after empty maps). Package-level helpers (archiveFullCapTable, getSystemOperatorPartyId, buildUpdateCapTableCommand) live on the @open-captable-protocol/canton root export—not nested under OcpClient.

Consult the index at /reference/open-cap-table for the full routing matrix linking each namespace to get pages plus write paths.

OpenCapTableReports.companyValuationReport

Builder + submit helpers (buildCreate, create, update, addObservers) layered on CompanyValuationReport contracts—see /reference/reports/company-valuation-report for full parameters and submission semantics.

CantonPayments & PaymentStreams

Amulet / stream utilities that depend on both ledger and (usually) validator transports. See /reference/payments and /reference/payment-streams for per-builder disclosure requirements.

CouponMinter

TPS-throttled mint helpers (mintWithRateLimit, waitUntilCanMint, etc.). Pure stateless utilities over coupon payloads supplied by Canton.


Cached context (OcpContextManager)

Expose ocp.context accessors:

Set: setFeaturedAppRight, setIssuerParty, setCapTableContractId, setAll, clear.

Lazy helpers: requireFeaturedAppRight, requireIssuerParty, requireCapTableContractId throw OcpValidationError with REQUIRED_FIELD_MISSING when callers forget provisioning. isReadyForBatchOperations is true exactly when FeaturedAppRight + CapTable CID are hydrated—useful for guardrails before chaining CapTableBatch.

Contexts are process-local—not persisted.


createBatch

Signature:

ocp.createBatch({ actAs: string[]; readAs?: string[] }): TransactionBatch

Dependency contract: Canton Node SDK TransactionBatch expects the ledger you injected earlier. Populate actAs with signer parties (issuer rows for UpdateCapTable, system_operator for WithdrawAuthorization or ArchiveCapTable, etc.). Optionally include readAs when contract resolution spans stakeholders.

Purpose: Glue issuer creation, factory exercises, miscellaneous commands, etc., into atomic submissions that also include manually built payloads:

const built = ocp.OpenCapTable.issuer.buildCreate({
  issuerAuthorizationContractDetails,
  issuerParty: ISSUER_PARTY_ID,
  issuerData: ISSUER_OCF_SHAPE,
});

await ocp.createBatch({ actAs: [ISSUER_PARTY_ID] }).addBuiltCommand(built).submitAndWaitForTransactionTree();

For only cap-table row edits, ocp.OpenCapTable.capTable.update(...) remains the ergonomically constrained path (CapTableBatch) issuing a single UpdateCapTable command.


Returns & errors surfaced from the façade

Writes wrap Canton responses with richer errors:

ErrorTypical trigger
OcpValidationErrorMissing actAs, empty CapTableBatch, malformed schema inputs, context.require* misses. Codes include REQUIRED_FIELD_MISSING and INVALID_TYPE.
OcpContractErrorLedger rejects template mismatch, concurrency, or Canton-specific guard rails; CapTableBatch wraps UpdateCapTable failures with CHOICE_FAILED.

Reads may raise OcpParseError or OcpContractError if template ids diverge (SCHEMA_MISMATCH, RESULT_NOT_FOUND).

Always surface cause when inspecting OcpContractError—the SDK attaches batch metadata for UpdateCapTable.


Auth, parties, and disclosure checklist

OcpClient never invents JWT scopes—supply a ledger client backed by Canton credentials that satisfy:

  • UpdateCapTable: signer is issuer.
  • CreateCapTable: exercising party matches issuerParty disclosed on IssuerAuthorization.
  • AuthorizeIssuer: exercised through OCP Factory with appropriate factory admin rights per deployment.
  • WithdrawAuthorization, ArchiveCapTable, IssuerAuthorization admin ops: signer is system_operator (see withdraw, capTable.archive) per DAML privileges.
  • readAs on reads/batches broaden visibility windows for stakeholders when your token cannot otherwise witness contracts.

FeaturedAppRight / IssuerAuthorization disclosures MUST stay consistent with Canton network configuration (staging vs pinned package hashes).



Source