Skip to content

OpenCapTable Module

Cursor Agent edited this page Jun 16, 2026 · 10 revisions

OpenCapTable Module

This module contains the Open Cap Table Protocol (OpenCapTable) DAML implementation for the Canton Network. It mirrors the concepts and schema defined by the Open Cap Format (OCF) and is organized around the same core building blocks: objects and transactions using the schema's types and enums.

For shared coding guidelines that apply to all OCP DAML packages, see the Home wiki page.

Current version: OpenCapTable-v34

Companion NFT and other non-OCP packages are maintained in fairmint/daml; see Contract-Diagram and Home (@fairmint/daml-js). dars/ in this repo backs up OpenCapTable DARs only (#217); non-OCP DAR history lives with fairmint/daml.

Contract Architecture

See Contract-Diagram for visual documentation of the contract hierarchy and relationships.

Key components:

  • OcpFactoryIssuerAuthorizationCapTable (factory chain)
  • CapTable maintains Map Text (ContractId T) for all OCF objects (O(1) lookup)
  • All OCF contracts use dual signatories: issuer + system_operator

Schema Guidance

Source of Truth: Schema (@schema)

The single source of truth for all data structures is the JSON Schema under Open-Cap-Format-OCF/schema/ (@schema).

  • Strict adherence: All models, types, events, and files must strictly match the schema definitions
  • No drift: Do not introduce fields, values, or shapes that are not defined in the schema
  • Validation first: Any produced or ingested JSON must validate against the relevant schema

Implementation Guidance

  • Deprecated fields: Exclude deprecated schema fields from DAML. The SDK is responsible for mapping deprecated inputs to the latest standard.
  • Signatories: All OCP objects must use both the issuer and system operator as signatories.
  • Required numbers may be zero: A required numeric field may validly be 0 unless the schema specifies otherwise.
  • Code comments: Each non-test file starts with a one-line summary; the OCF object block (title, description, raw $id URL) sits immediately after module ... where, before imports. Field-level comments follow Home (DAML coding standards).

Package-Specific Notes

  • In DAML we exclude the object_type field since it is implied from the template used.
  • In StockIssuance, the schema requires stock_legend_ids with minItems: 1. Our implementation temporarily allows an empty array for stock_legend_ids to support existing data that lacks legends.

Field Ordering

All types/records in this package must follow the field ordering rule:

data Example = Example
  with
    -- Identifier for the object
    id: Text

    -- Required fields (alphabetical)
    ---------------------------------
    required_a: Text
    required_b: Int

    -- Arrays (alphabetical)
    ---------------------------------
    items: [Text]

    -- Optional fields (alphabetical)
    ---------------------------------
    optional_a: Optional Text
    optional_b: Optional Int
  deriving (Eq, Show)

Declaration Order Within Template Files

After imports, use: template block first, then the main OCF data record for that template, then subtype/helper data and validators. See Home for the full header/import layout.

Field-Level Comments

For every field, add high-signal comments derived from the schema: field title, then description, then $comment if present. Include constraints like -- minItems: 1 for arrays when relevant.

Example for ObjectReference:

-- Type - Object Reference
-- A type representing a reference to any kind of OCF object
-- OCF: https://raw.githubusercontent.com/Open-Cap-Table-Coalition/Open-Cap-Format-OCF/main/schema/types/ObjectReference.schema.json
data OcfObjectReference = OcfObjectReference
  with
    -- Identifier of the referenced object
    object_id: Text
    -- Type of the referenced object
    object_type: OcfObjectType
  deriving (Eq, Show)

Optional Text Validation

For every Optional Text field, validate with validateOptionalText in the record validator. This ensures that when a value is provided it is non-empty.

Usage Guidance

  • CapTable authority: The CapTable contract is the authority for all OCF objects (per ADR-002-Stateful-Issuer). Issuer is a plain OCF object stored in the CapTable maps, not a factory or entry point.
  • Edits: Use UpdateCapTable batch operations — archive the old contract and create the replacement in a single atomic transaction via the generated edit choices, not ad-hoc ArchiveByIssuer calls.

Clone this wiki locally