Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f0fefe6
Validate complex issuance reader payloads
HardlyDifficult Jul 10, 2026
2147d62
Merge branch 'codex/decoder-backed-adjustment-readers' into codex/dec…
HardlyDifficult Jul 10, 2026
4f1051f
Reject unsafe issuance integer encodings
HardlyDifficult Jul 10, 2026
20241b7
Merge commit '78fb05c47bf97e52445e5d2d7b5fd9c4bc867deb' into codex/de…
HardlyDifficult Jul 11, 2026
2f6c381
Harden complex issuance readers
HardlyDifficult Jul 11, 2026
a2c45af
Reject lossy stock-class issuance fields
HardlyDifficult Jul 11, 2026
f7b900a
fix: enforce DAML Int termination periods
HardlyDifficult Jul 11, 2026
4aedfd8
fix: validate complex issuance numerics
HardlyDifficult Jul 11, 2026
fd87bea
fix: harden complex issuance numeric writers
HardlyDifficult Jul 11, 2026
b998550
fix: preserve issuance writer error paths
HardlyDifficult Jul 11, 2026
d99be7e
fix: harden complex issuance boundaries
HardlyDifficult Jul 11, 2026
ac6ce2f
fix: make issuance boundaries trap-safe
HardlyDifficult Jul 11, 2026
c5f276b
fix: bound diagnostics and preflight ledger envelopes
HardlyDifficult Jul 11, 2026
1f0ac13
fix: harden issuance boundary validation
HardlyDifficult Jul 11, 2026
fb2b186
fix: bound convertible semantic traversal
HardlyDifficult Jul 11, 2026
9a94adc
Merge commit '3920d54c186984f67d18c40fa4f65f9347e8c036' into codex/de…
HardlyDifficult Jul 12, 2026
883b35a
feat: complete typed issuance boundaries
HardlyDifficult Jul 12, 2026
bfdbb8f
Merge commit '25e9678cfcd99612bd48c92d76221de2a3d5fe1a' into codex/de…
HardlyDifficult Jul 12, 2026
425a2dd
fix: reconcile typed issuance boundaries
HardlyDifficult Jul 12, 2026
f67ac18
fix: address issuance review feedback
HardlyDifficult Jul 12, 2026
f075f38
Merge commit '9cf559303245b69dcd80fa4c1eed194fcc8d59b0' into codex/de…
HardlyDifficult Jul 12, 2026
4419c46
fix: harden issuance boundaries and generic writers
HardlyDifficult Jul 12, 2026
e661867
Merge adjustment reader hardening into issuance readers
HardlyDifficult Jul 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/functions/OpenCapTable/capTable/batchTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,17 @@ export type DamlDataTypeFor<EntityType extends OcfEntityType> = Extract<
{ tag: OcfOperationTagFor<EntityType, 'edit'> }
>['value'];

/** Recursively readonly view used for immutable generated DAML writer output. */
export type DeepReadonly<T> =
T extends ReadonlyArray<infer Item>
? ReadonlyArray<DeepReadonly<Item>>
: T extends object
? { readonly [Key in keyof T]: DeepReadonly<T[Key]> }
: T;

/** Exact immutable generated DAML entity-data payload for one SDK entity kind. */
export type ReadonlyDamlDataTypeFor<EntityType extends OcfEntityType> = DeepReadonly<DamlDataTypeFor<EntityType>>;

/** Correlated entity-kind and generated DAML-data tuples accepted by the read dispatcher. */
export type DamlEntityArguments = {
[EntityType in OcfEntityType]: readonly [type: EntityType, damlData: DamlDataTypeFor<EntityType>];
Expand Down
16 changes: 16 additions & 0 deletions src/functions/OpenCapTable/capTable/damlEntityData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import {
} from './batchTypes';
import { extractAndDecodeCancellationData, isCancellationEntityType } from './cancellationContractData';
import { decodeLosslessGeneratedDamlValue, type ReadonlyGeneratedDaml } from './damlCodecLosslessness';
import {
decodeComplexIssuanceDamlData,
extractAndDecodeComplexIssuanceData,
isComplexIssuanceEntityType,
validateComplexIssuanceDamlDataInput,
} from './issuanceContractData';
import {
extractAndDecodeTransferData,
isTransferEntityType,
Expand Down Expand Up @@ -122,6 +128,9 @@ function createEntityDataDecoder<const EntityType extends OcfEntityType>(
if (isVestingEntityType(entityType)) {
validateVestingDamlDataInput(entityType, decoderInput);
}
if (isComplexIssuanceEntityType(entityType)) {
validateComplexIssuanceDamlDataInput(entityType, decoderInput);
}
assertCanonicalJsonGraph(decoderInput, entityType);
preflightSemanticDamlEntityData(entityType, decoderInput);
const decoderResult = codec.decoder.run(decoderInput);
Expand Down Expand Up @@ -348,6 +357,9 @@ export function decodeDamlEntityData(
input: unknown
): ReadonlyDamlDataTypeFor<OcfEntityType> {
assertSupportedOcfEntityType(entityType, 'damlToOcf.decodeDamlEntityData.entityType');
if (isComplexIssuanceEntityType(entityType)) {
return decodeComplexIssuanceDamlData(entityType, input);
}
return ENTITY_DATA_DECODER_MAP[entityType](input);
}

Expand All @@ -364,6 +376,10 @@ export function extractAndDecodeDamlEntityData(
return extractAndDecodeAdministrativeAdjustmentData(entityType, createArgument);
}

if (isComplexIssuanceEntityType(entityType)) {
return extractAndDecodeComplexIssuanceData(entityType, createArgument);
}

if (isAcceptanceEntityType(entityType)) {
return extractAndDecodeAcceptanceData(entityType, createArgument);
}
Expand Down
27 changes: 17 additions & 10 deletions src/functions/OpenCapTable/capTable/damlToOcf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,23 @@ export function convertToOcf(
);
}

// Issuance converters run their correlated generated-codec preflight first,
// preserving one parse-error family across direct, dispatcher, and ledger reads.
if (type === 'convertibleIssuance') {
return damlConvertibleIssuanceDataToNative(data as Parameters<typeof damlConvertibleIssuanceDataToNative>[0]);
}
if (type === 'equityCompensationIssuance') {
return damlEquityCompensationIssuanceDataToNative(
data as Parameters<typeof damlEquityCompensationIssuanceDataToNative>[0]
);
}
if (type === 'stockIssuance') {
return damlStockIssuanceDataToNative(data as Parameters<typeof damlStockIssuanceDataToNative>[0]);
}
if (type === 'warrantIssuance') {
return damlWarrantIssuanceDataToNative(data as Parameters<typeof damlWarrantIssuanceDataToNative>[0]);
}

assertCanonicalJsonGraph(data, type);
switch (type) {
// ===== Core objects =====
Expand All @@ -191,16 +208,6 @@ export function convertToOcf(
case 'stockPlan':
return damlStockPlanDataToNative(data);

// ===== Issuance types =====
case 'convertibleIssuance':
return damlConvertibleIssuanceDataToNative(data);
case 'equityCompensationIssuance':
return damlEquityCompensationIssuanceDataToNative(data);
case 'stockIssuance':
return damlStockIssuanceDataToNative(data as Parameters<typeof damlStockIssuanceDataToNative>[0]);
case 'warrantIssuance':
return damlWarrantIssuanceDataToNative(data);

// ===== Acceptance types =====
case 'stockAcceptance':
return damlStockAcceptanceToNative(data as Parameters<typeof damlStockAcceptanceToNative>[0]);
Expand Down
Loading