Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
de4daaf
Enforce stock security balance invariants
HardlyDifficult Jul 9, 2026
329a596
Cover non-stock security balances
HardlyDifficult Jul 9, 2026
77d4bed
Merge remote-tracking branch 'origin/codex/ocf-stock-plan-pool-ceilin…
HardlyDifficult Jul 9, 2026
039da67
Keep equity compensation release fixtures valid
HardlyDifficult Jul 9, 2026
c9c1ca6
Address stock balance review edge cases
HardlyDifficult Jul 9, 2026
55f8855
Restack stock security balances on pool ceiling
HardlyDifficult Jul 9, 2026
572b318
Restack security balances on indexed share ceilings
HardlyDifficult Jul 9, 2026
9cfe968
Merge stock plan ceiling base into security balance
HardlyDifficult Jul 9, 2026
0c58319
Restack security balance category
HardlyDifficult Jul 9, 2026
13bf9a4
Fix non-stock balance terminal-event invariants
Copilot Jul 9, 2026
4c47c34
Refine security retraction error details
Copilot Jul 9, 2026
06f31de
Address security balance review comments
HardlyDifficult Jul 9, 2026
1c87d1b
Merge remote security balance review fixes
HardlyDifficult Jul 9, 2026
e448b17
Allow terminal balance reductions to consume remaining source
HardlyDifficult Jul 9, 2026
9df4041
Order same-day terminal balance reductions after deltas
HardlyDifficult Jul 9, 2026
f0cc5a7
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 9, 2026
aaf8d26
Address stock security balance review feedback
HardlyDifficult Jul 9, 2026
6c7da19
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 9, 2026
d1ba8fb
Update stock security DAR backup
HardlyDifficult Jul 9, 2026
a40fd45
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 9, 2026
38a46b2
Refresh security balance DAR after base update
HardlyDifficult Jul 9, 2026
e6f9265
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 9, 2026
088a9e8
Refresh security balance DAR after ceiling update
HardlyDifficult Jul 9, 2026
5191f61
Address security balance review feedback
HardlyDifficult Jul 9, 2026
78ac0f5
Merge schema constraints refresh into security balance
HardlyDifficult Jul 9, 2026
338c33f
Address security balance review feedback
HardlyDifficult Jul 9, 2026
2c3de9c
Merge schema constraints refresh into security balance
HardlyDifficult Jul 9, 2026
d338606
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 9, 2026
8c8e907
Refresh security balance after schema fixes
HardlyDifficult Jul 9, 2026
ecc0662
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 9, 2026
9366344
Refresh security balance DAR after reference fold
HardlyDifficult Jul 9, 2026
66ae157
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 9, 2026
828b971
Refresh security balance DAR after reference updates
HardlyDifficult Jul 9, 2026
0f1547e
Align security balances with lifecycle events
HardlyDifficult Jul 9, 2026
6ee5883
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 9, 2026
d0f399c
Refresh security balance DAR after schema updates
HardlyDifficult Jul 9, 2026
15633ec
fix: index security balance validation events
HardlyDifficult Jul 10, 2026
50eb41d
fix: preserve ceilings when balances are missing
HardlyDifficult Jul 10, 2026
d5870bf
fix: validate stock balance successors
HardlyDifficult Jul 10, 2026
85c7617
Cover missing stock balance successors
HardlyDifficult Jul 10, 2026
0272b6b
Merge schema constraints category into security balance
HardlyDifficult Jul 10, 2026
d985d11
Merge branch 'codex/ocf-schema-constraints-category' into codex/ocf-s…
HardlyDifficult Jul 10, 2026
dcc84ec
fix: enforce non-stock balance successor continuity
HardlyDifficult Jul 10, 2026
67dc05d
Merge branch 'codex/ocf-schema-constraints-category' into codex/ocf-s…
HardlyDifficult Jul 10, 2026
f48b251
Merge commit 'f183dec' into codex/ocf-stock-security-balance
HardlyDifficult Jul 10, 2026
ff46c61
Merge commit '234891a' into codex/ocf-stock-security-balance
HardlyDifficult Jul 10, 2026
7fa6890
Merge schema constraints into security balances
HardlyDifficult Jul 10, 2026
7021f53
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 10, 2026
6a5b0d4
fix: split-adjust classless plan award balances
HardlyDifficult Jul 11, 2026
688a223
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 11, 2026
ef04b92
chore: refresh deterministic security balance DAR
HardlyDifficult Jul 11, 2026
96c8d97
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 11, 2026
a8175ce
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 11, 2026
312eb3c
chore: refresh deterministic security balance DAR
HardlyDifficult Jul 11, 2026
2e032c3
fix: preserve warrant transfer successor continuity
HardlyDifficult Jul 11, 2026
3984866
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 11, 2026
2d04334
chore: refresh security balance DAR after restack
HardlyDifficult Jul 11, 2026
b3d8a79
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 11, 2026
3b4f0f6
fix: enforce nonnegative indexed equity exercises
HardlyDifficult Jul 11, 2026
5007f54
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 11, 2026
447b537
chore: refresh stock balance DAR after parent update
HardlyDifficult Jul 11, 2026
3475dd9
fix: align equity balance event ordering
HardlyDifficult Jul 11, 2026
465cedb
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 11, 2026
c96ffcc
fix: align stock balance event ordering
HardlyDifficult Jul 11, 2026
3be8ce9
fix: preserve fixed warrant conversion ratios
HardlyDifficult Jul 11, 2026
b5674f6
fix: preserve partial warrant economics
HardlyDifficult Jul 11, 2026
6a70c2f
fix: reject unscalable warrant vesting terms
HardlyDifficult Jul 11, 2026
a068d2b
fix: validate reduction and successor vesting terms
HardlyDifficult Jul 11, 2026
c4b536e
Merge remote-tracking branch 'origin/codex/ocf-schema-constraints-cat…
HardlyDifficult Jul 11, 2026
c271839
chore: refresh security balance DAR
HardlyDifficult Jul 11, 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
2 changes: 1 addition & 1 deletion OpenCapTable-v34/daml.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
sdk-version: 3.4.10
name: OpenCapTable-v34
source: daml
version: 0.0.11
version: 0.0.12
build-options:
- -Wno-crypto-text-is-alpha
- --typecheck-upgrades=no
Expand Down
2 changes: 1 addition & 1 deletion Test/daml.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ dependencies:
- daml-stdlib
- daml-script
data-dependencies:
- ../OpenCapTable-v34/.daml/dist/OpenCapTable-v34-0.0.11.dar
- ../OpenCapTable-v34/.daml/dist/OpenCapTable-v34-0.0.12.dar
build-options:
- -Wno-template-interface-depends-on-daml-script
55 changes: 16 additions & 39 deletions Test/daml/OpenCapTable/TestEquityCompensationCancellation.daml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import qualified DA.Time as DT
import Daml.Script

-- Create an equity compensation issuance to cancel (follows real workflow)
createEquityCompensationIssuance issuer capTableCid securityId quantity =
createEquityCompensationIssuance issuer capTableCid securityId quantity issuanceDate =
submit issuer do
exerciseCmd capTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateEquityCompensationIssuance EquityCompensationIssuanceOcfData with
id = "TX_EC_ISS_1"
date = DT.time (DA.date 2020 Jan 15) 0 0 0
id = "TX_EC_ISS_" <> securityId
date = issuanceDate
security_id = securityId
custom_id = "GRANT-001"
stakeholder_id = "SH-1"
Expand Down Expand Up @@ -61,7 +61,7 @@ testEquityCompensationCancellation_CreateAndArchiveByIssuer = script do
TestOcp{system_operator, issuer, ctx, cap_table} <- setupTestOcp
capTableCid <- addPrerequisites issuer cap_table
let securityId = "db5a26d6-3912-4400-87b0-bda74de361af"
result <- createEquityCompensationIssuance issuer capTableCid securityId 250000.0
result <- createEquityCompensationIssuance issuer capTableCid securityId 250000.0 (DT.time (DA.date 2020 Jan 15) 0 0 0)
_ <- createEquityCompensationCancellation issuer result.updatedCapTableCid securityId 214200.0
pure ()

Expand All @@ -70,7 +70,7 @@ testEquityCompensationCancellation_CreateAndArchiveBuiltIn = script do
TestOcp{system_operator, issuer, ctx, cap_table} <- setupTestOcp
capTableCid <- addPrerequisites issuer cap_table
let securityId = "SEC-EC-002"
result <- createEquityCompensationIssuance issuer capTableCid securityId 100000.0
result <- createEquityCompensationIssuance issuer capTableCid securityId 100000.0 (DT.time (DA.date 2020 Jan 15) 0 0 0)
_ <- submit issuer do
exerciseCmd result.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateEquityCompensationCancellation EquityCompensationCancellationOcfData with
Expand All @@ -92,41 +92,18 @@ testEquityCompensationCancellation_PartialWithOptionals = script do
let securityId = "SEC-EC-PARTIAL"
let balanceSecurityId = "SEC-EC-PARTIAL-BAL"
let cancellationDate = DT.time (DA.date 2024 Jun 30) 0 0 0
result <- createEquityCompensationIssuance issuer capTableCid securityId 500000.0
result <- createEquityCompensationIssuance issuer capTableCid securityId 500000.0 (DT.time (DA.date 2020 Jan 15) 0 0 0)
balanceResult <- createEquityCompensationIssuance issuer result.updatedCapTableCid balanceSecurityId 350000.0 cancellationDate
_ <- submit issuer do
exerciseCmd result.updatedCapTableCid CT.UpdateCapTable with
creates =
[ CT.OcfCreateEquityCompensationCancellation EquityCompensationCancellationOcfData with
id = "TX_EC_CANCEL_PARTIAL"
date = cancellationDate
security_id = securityId
quantity = 150000.0
reason_text = "Partial forfeiture due to early departure"
balance_security_id = Some balanceSecurityId
comments = ["Partial cancellation per separation agreement", "Remaining vested options: 350,000"]
, CT.OcfCreateEquityCompensationIssuance EquityCompensationIssuanceOcfData with
id = "TX_EC_CANCEL_PARTIAL_BALANCE"
date = cancellationDate
security_id = balanceSecurityId
custom_id = "GRANT-001-BALANCE"
stakeholder_id = "SH-1"
board_approval_date = None
stockholder_approval_date = None
consideration_text = None
security_law_exemptions = []
stock_plan_id = None
stock_class_id = Some "SC_COMMON"
compensation_type = OcfCompensationTypeOptionNSO
quantity = 350000.0
exercise_price = Some (OcfMonetary with amount = 0.10, currency = "USD")
base_price = None
early_exercisable = Some False
vesting_terms_id = None
vestings = []
expiration_date = None
termination_exercise_windows = []
comments = []
]
exerciseCmd balanceResult.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateEquityCompensationCancellation EquityCompensationCancellationOcfData with
id = "TX_EC_CANCEL_PARTIAL"
date = cancellationDate
security_id = securityId
quantity = 150000.0
reason_text = "Partial forfeiture due to early departure"
balance_security_id = Some balanceSecurityId
comments = ["Partial cancellation per separation agreement", "Remaining vested options: 350,000"]]
edits = []
deletes = []
pure ()
14 changes: 8 additions & 6 deletions Test/daml/OpenCapTable/TestEquityCompensationTransfer.daml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@ testEquityCompensationTransfer_NSOToFamilyTrust = script do
capTableCid <- addDefaultStakeholder issuer cap_table
let securityId = "ESEC-NSO-001"
result <- createEquityCompensationIssuance issuer capTableCid securityId 10000.0 (DT.time (DA.date 2022 Jan 15) 0 0 0)
balanceResult <- createEquityCompensationIssuance issuer result.updatedCapTableCid "ESEC-NSO-REMAIN" 5000.0 (DT.time (DA.date 2025 Jun 01) 0 0 0)
let transferDate = DT.time (DA.date 2025 Jun 01) 0 0 0
balanceResult <- createEquityCompensationIssuance issuer result.updatedCapTableCid "ESEC-NSO-REMAIN" 5000.0 transferDate
_ <- submit issuer do
exerciseCmd balanceResult.updatedCapTableCid CT.UpdateCapTable with
creates = [equityCompensationSuccessorIssuance "EC-ISS-TRANSFERRED-001" "ESEC-NSO-TRANSFERRED-001" "SH-1" (DT.time (DA.date 2025 Jun 01) 0 0 0) 5000.0
creates = [equityCompensationSuccessorIssuance "EC-ISS-TRANSFERRED-001" "ESEC-NSO-TRANSFERRED-001" "SH-1" transferDate 5000.0
, CT.OcfCreateEquityCompensationTransfer EquityCompensationTransferOcfData with
id = "TX_EQUITY_COMP_TRANSFER_1"
date = DT.time (DA.date 2025 Jun 01) 0 0 0
date = transferDate
quantity = 5000.0
security_id = securityId
resulting_security_ids = ["ESEC-NSO-TRANSFERRED-001"]
Expand Down Expand Up @@ -94,13 +95,14 @@ testEquityCompensationTransfer_WithApprovalComments = script do
capTableCid <- addDefaultStakeholder issuer cap_table
let securityId = "ESEC-NSO-APPROVAL"
result <- createEquityCompensationIssuance issuer capTableCid securityId 15000.0 (DT.time (DA.date 2022 Jan 15) 0 0 0)
balanceResult <- createEquityCompensationIssuance issuer result.updatedCapTableCid "ESEC-NSO-REMAINING" 7000.0 (DT.time (DA.date 2025 Nov 01) 0 0 0)
let transferDate = DT.time (DA.date 2025 Nov 01) 0 0 0
balanceResult <- createEquityCompensationIssuance issuer result.updatedCapTableCid "ESEC-NSO-REMAINING" 7000.0 transferDate
_ <- submit issuer do
exerciseCmd balanceResult.updatedCapTableCid CT.UpdateCapTable with
creates = [equityCompensationSuccessorIssuance "EC-ISS-TRUST" "ESEC-NSO-TRUST" "SH-1" (DT.time (DA.date 2025 Nov 01) 0 0 0) 8000.0
creates = [equityCompensationSuccessorIssuance "EC-ISS-TRUST" "ESEC-NSO-TRUST" "SH-1" transferDate 8000.0
, CT.OcfCreateEquityCompensationTransfer EquityCompensationTransferOcfData with
id = "TX_EQUITY_COMP_TRANSFER_APPROVED"
date = DT.time (DA.date 2025 Nov 01) 0 0 0
date = transferDate
quantity = 8000.0
security_id = securityId
resulting_security_ids = ["ESEC-NSO-TRUST"]
Expand Down
10 changes: 5 additions & 5 deletions Test/daml/OpenCapTable/TestFinalReferenceValidation.daml
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,18 @@ testFinalReferenceValidation_DeleteReferencedStockIssuanceFails = script do
TestOcp{issuer, cap_table} <- setupTestOcp
capTable <- addPrerequisites issuer cap_table
capTable <- addStockIssuance issuer capTable "TX-STOCK-FINAL-REF" "SEC-FINAL-REF" "SH-1" "SC_COMMON"
let balanceIssuance = (defaultStockIssuance "TX-STOCK-TRANSFER-BALANCE" "SEC-TRANSFER-BALANCE" "SH-1" "SC_COMMON") with
date = defaultReferenceTestTime
quantity = 90.0
let resultIssuance = (defaultStockIssuance "TX-STOCK-TRANSFER-RESULT" "SEC-TRANSFER-RESULT" "SH-1" "SC_COMMON") with
let resultIssuance = (defaultStockIssuance "TX-STOCK-TRANSFER-FINAL-RESULT" "SEC-TRANSFER-RESULT" "SH-1" "SC_COMMON") with
date = defaultReferenceTestTime
quantity = 10.0
let balanceIssuance = (defaultStockIssuance "TX-STOCK-TRANSFER-FINAL-BALANCE" "SEC-TRANSFER-BALANCE" "SH-1" "SC_COMMON") with
date = defaultReferenceTestTime
quantity = 90.0
result <- submit issuer do
exerciseCmd capTable CT.UpdateCapTable with
creates =
[ CT.OcfCreateStockTransfer (stockTransferData "TX-STOCK-TRANSFER-FINAL-REF" "SEC-FINAL-REF")
, CT.OcfCreateStockIssuance balanceIssuance
, CT.OcfCreateStockIssuance resultIssuance
, CT.OcfCreateStockIssuance balanceIssuance
]
edits = []
deletes = []
Expand Down
60 changes: 54 additions & 6 deletions Test/daml/OpenCapTable/TestHelpers.daml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import Fairmint.OpenCapTable.OCF.VestingTerms (VestingTermsOcfData(..), OcfAlloc
import Fairmint.OpenCapTable.OCF.WarrantIssuance (WarrantIssuanceOcfData(..))
import Fairmint.OpenCapTable.OCF.ConvertibleIssuance (ConvertibleIssuanceOcfData(..), OcfConvertibleConversionTrigger(..))
import Fairmint.OpenCapTable.OCF.EquityCompensationIssuance (EquityCompensationIssuanceOcfData(..))
import Fairmint.OpenCapTable.OCF.EquityCompensationRelease (EquityCompensationReleaseOcfData(..))
import Fairmint.OpenCapTable.Types.Monetary (OcfMonetary(..))
import Fairmint.OpenCapTable.Types.Stock (OcfStockClassType(..), OcfInitialSharesAuthorized(..), OcfRatio(..))
import Fairmint.OpenCapTable.Types.Vesting (OcfCompensationType(..))
import Fairmint.OpenCapTable.Types.Conversion (OcfConvertibleType(..), OcfConversionTriggerType(..), OcfConvertibleConversionRight(..), OcfConvertibleConversionMechanism(..), OcfSAFEConversionMechanism(..))
import qualified Fairmint.OpenCapTable.CapTable as CT
import OpenCapTable.HelpersTriggers (ocfTriggerElectiveAtWill)
import qualified DA.Date as DA
import DA.Date (Month(..))
import qualified DA.Time as DT
Expand Down Expand Up @@ -92,24 +94,32 @@ stockClassAuthorizedSharesAdjustment adjustmentId stockClassId authorizedShares
stockholder_approval_date = None
comments = []

stockCancellation : Text -> Text -> Decimal -> StockCancellationOcfData
stockCancellation cancellationId securityId quantity = StockCancellationOcfData with
stockCancellationOn : Text -> Text -> Decimal -> Time -> StockCancellationOcfData
stockCancellationOn cancellationId securityId quantity date = StockCancellationOcfData with
id = cancellationId
date = defaultTestDate
date = date
security_id = securityId
quantity = quantity
balance_security_id = None
reason_text = "Cancelled shares"
comments = []

stockClassSplit : Text -> Text -> Decimal -> Decimal -> StockClassSplitOcfData
stockClassSplit splitId stockClassId numerator denominator = StockClassSplitOcfData with
stockCancellation : Text -> Text -> Decimal -> StockCancellationOcfData
stockCancellation cancellationId securityId quantity =
stockCancellationOn cancellationId securityId quantity defaultTestDate

stockClassSplitOn : Text -> Text -> Decimal -> Decimal -> Time -> StockClassSplitOcfData
stockClassSplitOn splitId stockClassId numerator denominator date = StockClassSplitOcfData with
id = splitId
date = defaultTestDate
date = date
stock_class_id = stockClassId
split_ratio = OcfRatio with numerator = numerator, denominator = denominator
comments = []

stockClassSplit : Text -> Text -> Decimal -> Decimal -> StockClassSplitOcfData
stockClassSplit splitId stockClassId numerator denominator =
stockClassSplitOn splitId stockClassId numerator denominator defaultTestDate

stockPlanEquityCompensationIssuance : Text -> Text -> Text -> Text -> Text -> Decimal -> EquityCompensationIssuanceOcfData
stockPlanEquityCompensationIssuance issuanceId securityId stakeholderId stockClassId stockPlanId quantity = EquityCompensationIssuanceOcfData with
id = issuanceId
Expand All @@ -134,6 +144,18 @@ stockPlanEquityCompensationIssuance issuanceId securityId stakeholderId stockCla
quantity = quantity
comments = []

equityCompensationRelease : Text -> Text -> Time -> Time -> Decimal -> EquityCompensationReleaseOcfData
equityCompensationRelease releaseId securityId releaseDate settlementDate quantity = EquityCompensationReleaseOcfData with
id = releaseId
date = releaseDate
security_id = securityId
settlement_date = settlementDate
release_price = OcfMonetary with amount = 1.0, currency = "USD"
quantity = quantity
resulting_security_ids = [releaseId <> "_RESULT"]
consideration_text = None
comments = []

-- | Returns valid StakeholderOcfData with sensible defaults.
-- Provide ID and name; all other fields use reasonable test values.
--
Expand Down Expand Up @@ -221,6 +243,32 @@ warrantSuccessorIssuance issuanceId securityId stakeholderId date quantity =
vesting_terms_id = None
warrant_expiration_date = None

createWarrantIssuance : Party -> ContractId CT.CapTable -> Text -> Decimal -> Time -> Script CT.UpdateCapTableResult
createWarrantIssuance issuer capTableCid securityId quantity issuanceDate =
submit issuer do
exerciseCmd capTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateWarrantIssuance WarrantIssuanceOcfData with
id = "TX_WARRANT_ISS_" <> securityId
date = issuanceDate
security_id = securityId
custom_id = "W-1"
stakeholder_id = "SH-1"
board_approval_date = None
stockholder_approval_date = None
consideration_text = None
security_law_exemptions = []
quantity = Some quantity
quantity_source = None
exercise_price = Some (OcfMonetary with amount = 1.0, currency = "USD")
purchase_price = OcfMonetary with amount = 0.0, currency = "USD"
exercise_triggers = [ocfTriggerElectiveAtWill]
warrant_expiration_date = None
vesting_terms_id = None
vestings = []
comments = []]
edits = []
deletes = []

convertibleSuccessorIssuance : Text -> Text -> Text -> Time -> Decimal -> CT.OcfCreateData
convertibleSuccessorIssuance issuanceId securityId stakeholderId date investmentAmount =
CT.OcfCreateConvertibleIssuance ConvertibleIssuanceOcfData with
Expand Down
Loading
Loading