Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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.18
version: 0.0.19
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.18.dar
- ../OpenCapTable-v34/.daml/dist/OpenCapTable-v34-0.0.19.dar
build-options:
- -Wno-template-interface-depends-on-daml-script
32 changes: 30 additions & 2 deletions Test/daml/OpenCapTable/TestBalanceSecurityReferences.daml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ testBalanceSecurityReferences_EditCanCreateStockSuccessorInSameBatch = script do
let cancellation = StockCancellationOcfData with
id = "TX-STOCK-EDIT-BALANCE"
date = defaultTestDate
quantity = 10.0
quantity = 100.0
reason_text = "Partial cancellation"
security_id = "SEC-STOCK-1"
comments = []
Expand All @@ -147,6 +147,7 @@ testBalanceSecurityReferences_EditCanCreateStockSuccessorInSameBatch = script do
exerciseCmd created.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateStockIssuance balanceIssuance]
edits = [CT.OcfEditStockCancellation (cancellation with
quantity = 10.0
balance_security_id = Some "SEC-STOCK-EDIT-BALANCE-SUCCESSOR")]
deletes = []
pure ()
Expand All @@ -158,7 +159,7 @@ testBalanceSecurityReferences_EditMissingStockSuccessorFails = script do
let cancellation = StockCancellationOcfData with
id = "TX-STOCK-EDIT-MISSING-BALANCE"
date = defaultTestDate
quantity = 10.0
quantity = 100.0
reason_text = "Partial cancellation"
security_id = "SEC-STOCK-1"
comments = []
Expand All @@ -174,5 +175,32 @@ testBalanceSecurityReferences_EditMissingStockSuccessorFails = script do
exerciseCmd created.updatedCapTableCid CT.UpdateCapTable with
creates = []
edits = [CT.OcfEditStockCancellation (cancellation with
quantity = 10.0
balance_security_id = Some "SEC-STOCK-EDIT-MISSING-BALANCE")]
deletes = []

testTerminalTransactionCompleteness_EditFullCancellationToPartialWithoutBalanceFails = script do
TestOcp{issuer, cap_table} <- setupTestOcp
capTableCid <- addPrerequisites issuer cap_table
capTableCid <- addDefaultStockIssuance issuer capTableCid
let cancellation = StockCancellationOcfData with
id = "TX-STOCK-EDIT-PARTIAL-NO-BALANCE"
date = defaultTestDate
quantity = 100.0
reason_text = "Initially a full cancellation"
security_id = "SEC-STOCK-1"
comments = []
balance_security_id = None

created <- submit issuer do
exerciseCmd capTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateStockCancellation cancellation]
edits = []
deletes = []

submitMustFail issuer do
exerciseCmd created.updatedCapTableCid CT.UpdateCapTable with
creates = []
edits = [CT.OcfEditStockCancellation (cancellation with
quantity = 10.0)]
deletes = []
19 changes: 19 additions & 0 deletions Test/daml/OpenCapTable/TestConvertibleCancellation.daml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,25 @@ testConvertibleCancellation_Create = script do
deletes = []
pure ()

testConvertibleCancellation_PartialWithoutBalanceSecurityFails = script do
TestOcp{issuer, cap_table} <- setupTestOcp
capTableCid <- addDefaultStakeholder issuer cap_table
let securityId = "SEC-CONVERTIBLE-PARTIAL-NO-BALANCE"
result <- createConvertibleIssuance issuer capTableCid securityId 100000.0 (DT.time (DA.date 2022 Jun 01) 0 0 0)

submitMustFail issuer do
exerciseCmd result.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateConvertibleCancellation ConvertibleCancellationOcfData with
id = "TX-CONVERTIBLE-CANCEL-PARTIAL-NO-BALANCE"
date = DT.time (DA.date 2022 Nov 03) 0 0 0
security_id = securityId
amount = OcfMonetary with amount = 40000.0, currency = "USD"
reason_text = "Invalid partial cancellation"
balance_security_id = None
comments = []]
edits = []
deletes = []

testConvertibleCancellation_PartialWithOptionals = script do
TestOcp{system_operator, issuer, ctx, cap_table} <- setupTestOcp
capTableCid <- addDefaultStakeholder issuer cap_table
Expand Down
34 changes: 26 additions & 8 deletions Test/daml/OpenCapTable/TestConvertibleConversion.daml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ testConvertibleConversion_FullFixedUsesCurrentPrincipal = script do
capTableCid <- addPrerequisites issuer cap_table
capTableCid <- addPreferredStockClass issuer capTableCid
let securityId = "CONV-SEC-FULL-CURRENT-PRINCIPAL"
reducedSecurityId = "CONV-SEC-FULL-CURRENT-PRINCIPAL-BALANCE"
reductionDate = DT.time (DA.date 2025 Nov 09) 0 0 0
conversionDate = DT.time (DA.date 2025 Nov 10) 0 0 0
sourceResult <- createConvertibleIssuanceWithMechanism
Expand All @@ -258,13 +259,21 @@ testConvertibleConversion_FullFixedUsesCurrentPrincipal = script do
(DT.time (DA.date 2023 Mar 15) 0 0 0)
(OcfConvMechFixedAmount (OcfFixedAmountConversionMechanism with converts_to_quantity = 10000.0))
(Some "SC_PREFERRED")
reducedSourceResult <- createConvertibleIssuanceWithMechanism
issuer
sourceResult.updatedCapTableCid
reducedSecurityId
80000.0
reductionDate
(OcfConvMechFixedAmount (OcfFixedAmountConversionMechanism with converts_to_quantity = 8000.0))
(Some "SC_PREFERRED")
reductionResult <- submit issuer do
exerciseCmd sourceResult.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateConvertibleCancellation (convertibleCancellation
exerciseCmd reducedSourceResult.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateConvertibleCancellation ((convertibleCancellation
"TX-CONV-CANCEL-BEFORE-FULL-CONVERSION"
securityId
20000.0
reductionDate)]
reductionDate) with balance_security_id = Some reducedSecurityId)]
edits = []
deletes = []

Expand All @@ -275,7 +284,7 @@ testConvertibleConversion_FullFixedUsesCurrentPrincipal = script do
, CT.OcfCreateConvertibleConversion ConvertibleConversionOcfData with
id = "TX-CONV-CONVERSION-FULL-CURRENT-PRINCIPAL"
date = conversionDate
security_id = securityId
security_id = reducedSecurityId
trigger_id = "equity-financing-trigger"
reason_text = "Convert the remaining principal after an earlier reduction"
resulting_security_ids = ["SSEC-CONV-FULL-CURRENT-PRINCIPAL"]
Expand All @@ -293,6 +302,7 @@ testConvertibleConversion_PartialFixedUsesCurrentPrincipal = script do
capTableCid <- addPrerequisites issuer cap_table
capTableCid <- addPreferredStockClass issuer capTableCid
let securityId = "CONV-SEC-PARTIAL-CURRENT-PRINCIPAL"
reducedSecurityId = "CONV-SEC-PARTIAL-CURRENT-PRINCIPAL-AFTER-REDUCTION"
balanceSecurityId = "CONV-SEC-PARTIAL-CURRENT-PRINCIPAL-BALANCE"
reductionDate = DT.time (DA.date 2025 Nov 09) 0 0 0
conversionDate = DT.time (DA.date 2025 Nov 10) 0 0 0
Expand All @@ -304,13 +314,21 @@ testConvertibleConversion_PartialFixedUsesCurrentPrincipal = script do
(DT.time (DA.date 2023 Mar 15) 0 0 0)
(OcfConvMechFixedAmount (OcfFixedAmountConversionMechanism with converts_to_quantity = 10000.0))
(Some "SC_PREFERRED")
reducedSourceResult <- createConvertibleIssuanceWithMechanism
issuer
sourceResult.updatedCapTableCid
reducedSecurityId
80000.0
reductionDate
(OcfConvMechFixedAmount (OcfFixedAmountConversionMechanism with converts_to_quantity = 8000.0))
(Some "SC_PREFERRED")
reductionResult <- submit issuer do
exerciseCmd sourceResult.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateConvertibleCancellation (convertibleCancellation
exerciseCmd reducedSourceResult.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateConvertibleCancellation ((convertibleCancellation
"TX-CONV-CANCEL-BEFORE-PARTIAL-CONVERSION"
securityId
20000.0
reductionDate)]
reductionDate) with balance_security_id = Some reducedSecurityId)]
edits = []
deletes = []
balanceResult <- createConvertibleIssuanceWithMechanism
Expand All @@ -329,7 +347,7 @@ testConvertibleConversion_PartialFixedUsesCurrentPrincipal = script do
, CT.OcfCreateConvertibleConversion ConvertibleConversionOcfData with
id = "TX-CONV-CONVERSION-PARTIAL-CURRENT-PRINCIPAL"
date = conversionDate
security_id = securityId
security_id = reducedSecurityId
trigger_id = "equity-financing-trigger"
reason_text = "Partially convert the remaining principal after an earlier reduction"
resulting_security_ids = ["SSEC-CONV-PARTIAL-CURRENT-PRINCIPAL"]
Expand Down
27 changes: 27 additions & 0 deletions Test/daml/OpenCapTable/TestConvertibleTransfer.daml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,33 @@ testConvertibleTransfer_PartialSAFE = script do
deletes = []
pure ()

testConvertibleTransfer_PartialWithoutBalanceSecurityFails = script do
TestOcp{issuer, cap_table} <- setupTestOcp
capTableCid <- addDefaultStakeholder issuer cap_table
(capTableCid, assigneeId) <- setupStakeholderWithId issuer capTableCid "SH-CONVERTIBLE-PARTIAL-NO-BALANCE" "Convertible Assignee"
let securityId = "CSEC-PARTIAL-NO-BALANCE"
transferDate = DT.time (DA.date 2025 Oct 15) 0 0 0
result <- createConvertibleIssuance issuer capTableCid securityId 100000.0 (DT.time (DA.date 2024 Mar 01) 0 0 0)

submitMustFail issuer do
exerciseCmd result.updatedCapTableCid CT.UpdateCapTable with
creates =
[ CT.OcfCreateConvertibleIssuance (convertibleTransferIssuance
"CV-ISS-PARTIAL-NO-BALANCE" "CSEC-PARTIAL-NO-BALANCE-RESULT" assigneeId 40000.0
transferDate OcfConvertibleSafe (DT.time (DA.date 2025 Dec 31) 0 0 0))
, CT.OcfCreateConvertibleTransfer ConvertibleTransferOcfData with
id = "TX-CONVERTIBLE-TRANSFER-PARTIAL-NO-BALANCE"
date = transferDate
amount = OcfMonetary with amount = 40000.0, currency = "USD"
security_id = securityId
resulting_security_ids = ["CSEC-PARTIAL-NO-BALANCE-RESULT"]
comments = []
balance_security_id = None
consideration_text = None
]
edits = []
deletes = []

-- Test: Convertible note transfer with full assignment
testConvertibleTransfer_NoteFullAssignment = script do
TestOcp{system_operator, issuer, ctx, cap_table} <- setupTestOcp
Expand Down
34 changes: 33 additions & 1 deletion Test/daml/OpenCapTable/TestEquityCompensationCancellation.daml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module OpenCapTable.TestEquityCompensationCancellation where
import Fairmint.OpenCapTable.OCF.EquityCompensationIssuance
import Fairmint.OpenCapTable.OCF.EquityCompensationCancellation
import Fairmint.OpenCapTable.OCF.EquityCompensationExercise
import Fairmint.OpenCapTable.Types.Monetary (OcfMonetary(..))
import Fairmint.OpenCapTable.Types.Vesting (OcfCompensationType(..))
import qualified Fairmint.OpenCapTable.CapTable as CT
Expand Down Expand Up @@ -62,7 +63,19 @@ testEquityCompensationCancellation_CreateAndArchiveByIssuer = script do
capTableCid <- addPrerequisites issuer cap_table
let securityId = "db5a26d6-3912-4400-87b0-bda74de361af"
result <- createEquityCompensationIssuance issuer capTableCid securityId 250000.0 (DT.time (DA.date 2020 Jan 15) 0 0 0)
_ <- createEquityCompensationCancellation issuer result.updatedCapTableCid securityId 214200.0
exerciseResult <- submit issuer do
exerciseCmd result.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateEquityCompensationExercise EquityCompensationExerciseOcfData with
id = "TX_EC_EX_BEFORE_CANCEL"
date = DT.time (DA.date 2021 Nov 30) 0 0 0
security_id = securityId
quantity = 35800.0
consideration_text = None
resulting_security_ids = []
comments = []]
edits = []
deletes = []
_ <- createEquityCompensationCancellation issuer exerciseResult.updatedCapTableCid securityId 214200.0
pure ()

-- Archive with built-in choice (requires both signatories)
Expand All @@ -85,6 +98,25 @@ testEquityCompensationCancellation_CreateAndArchiveBuiltIn = script do
deletes = []
pure ()

testEquityCompensationCancellation_PartialWithoutBalanceSecurityFails = script do
TestOcp{issuer, cap_table} <- setupTestOcp
capTableCid <- addPrerequisites issuer cap_table
let securityId = "SEC-EC-PARTIAL-NO-BALANCE"
result <- createEquityCompensationIssuance issuer capTableCid securityId 100.0 (DT.time (DA.date 2020 Jan 15) 0 0 0)

submitMustFail issuer do
exerciseCmd result.updatedCapTableCid CT.UpdateCapTable with
creates = [CT.OcfCreateEquityCompensationCancellation EquityCompensationCancellationOcfData with
id = "TX-EC-CANCEL-PARTIAL-NO-BALANCE"
date = DT.time (DA.date 2024 Mar 15) 0 0 0
security_id = securityId
quantity = 40.0
reason_text = "Invalid partial cancellation"
balance_security_id = None
comments = []]
edits = []
deletes = []

-- Partial cancellation with optional fields populated
testEquityCompensationCancellation_PartialWithOptionals = script do
TestOcp{system_operator, issuer, ctx, cap_table} <- setupTestOcp
Expand Down
25 changes: 25 additions & 0 deletions Test/daml/OpenCapTable/TestEquityCompensationTransfer.daml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,31 @@ testEquityCompensationTransfer_ResultQuantityMustMatchTransfer = script do
edits = []
deletes = []

testEquityCompensationTransfer_PartialWithoutBalanceSecurityFails = script do
TestOcp{issuer, cap_table} <- setupTestOcp
capTableCid <- addDefaultStakeholder issuer cap_table
(capTableCid, transfereeId) <- setupStakeholderWithId issuer capTableCid "SH-EC-PARTIAL-NO-BALANCE" "EC Transferee"
let securityId = "ESEC-TRANSFER-PARTIAL-NO-BALANCE"
transferDate = DT.time (DA.date 2025 Jun 01) 0 0 0
result <- createEquityCompensationIssuance issuer capTableCid securityId 100.0 (DT.time (DA.date 2022 Jan 15) 0 0 0)

submitMustFail issuer do
exerciseCmd result.updatedCapTableCid CT.UpdateCapTable with
creates =
[ equityCompensationSuccessorIssuance "EC-ISS-PARTIAL-NO-BALANCE" "ESEC-PARTIAL-NO-BALANCE-RESULT" transfereeId transferDate 40.0 (Some equityCompensationExpiration)
, CT.OcfCreateEquityCompensationTransfer EquityCompensationTransferOcfData with
id = "TX-EC-TRANSFER-PARTIAL-NO-BALANCE"
date = transferDate
quantity = 40.0
security_id = securityId
resulting_security_ids = ["ESEC-PARTIAL-NO-BALANCE-RESULT"]
comments = []
balance_security_id = None
consideration_text = None
]
edits = []
deletes = []

testEquityCompensationTransfer_BalanceMustKeepSourceStakeholder = script do
TestOcp{issuer, cap_table} <- setupTestOcp
capTableCid <- addDefaultStakeholder issuer cap_table
Expand Down
2 changes: 1 addition & 1 deletion Test/daml/OpenCapTable/TestFinalReferenceValidation.daml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ stockTransferData transferId securityId = StockTransferOcfData with
security_id = securityId
quantity = 10.0
resulting_security_ids = ["SEC-TRANSFER-RESULT"]
balance_security_id = None
balance_security_id = Some "SEC-TRANSFER-BALANCE"
consideration_text = None
comments = []

Expand Down
12 changes: 8 additions & 4 deletions Test/daml/OpenCapTable/TestLifecycleInvariants.daml
Original file line number Diff line number Diff line change
Expand Up @@ -518,18 +518,20 @@ testStockBalanceSuccessorIncludesPriorMaterializedReduction = script do
(capTableWithClass, stockClassId) <- setupStockClassWith issuer cap_table (limitedStockClass "SC_STOCK_UNMATERIALIZED_HISTORY" 1_000.0)
(capTableReady, stakeholderId) <- setupStakeholderWithId issuer capTableWithClass "SH_STOCK_UNMATERIALIZED_HISTORY" "Stock Unmaterialized History Holder"
let sourceSecurityId = "SEC_STOCK_UNMATERIALIZED_HISTORY_SOURCE"
let transferBalanceSecurityId = "SEC_STOCK_UNMATERIALIZED_HISTORY_TRANSFER_BALANCE"
issued <- createStockIssuanceWith issuer capTableReady (defaultStockIssuance "TX_STOCK_UNMATERIALIZED_HISTORY_SOURCE" sourceSecurityId stakeholderId stockClassId)
transferred <- submit issuer do
exerciseCmd issued CT.UpdateCapTable with
creates =
[ CT.OcfCreateStockTransfer (lifecycleStockTransfer "TX_STOCK_UNMATERIALIZED_HISTORY_TRANSFER" sourceSecurityId 30.0 None ["SEC_STOCK_UNMATERIALIZED_HISTORY_MISSING"])
[ CT.OcfCreateStockTransfer (lifecycleStockTransfer "TX_STOCK_UNMATERIALIZED_HISTORY_TRANSFER" sourceSecurityId 30.0 (Some transferBalanceSecurityId) ["SEC_STOCK_UNMATERIALIZED_HISTORY_MISSING"])
, stockSuccessorIssuance "TX_STOCK_UNMATERIALIZED_HISTORY_RESULT" "SEC_STOCK_UNMATERIALIZED_HISTORY_MISSING" stakeholderId stockClassId defaultTestDate 30.0
, stockSuccessorIssuance "TX_STOCK_UNMATERIALIZED_HISTORY_TRANSFER_BALANCE" transferBalanceSecurityId stakeholderId stockClassId defaultTestDate 70.0
]
edits = []
deletes = []

let balanceSecurityId = "SEC_STOCK_UNMATERIALIZED_HISTORY_BALANCE"
let cancellation = (stockCancellation "TX_STOCK_UNMATERIALIZED_HISTORY_CANCEL" sourceSecurityId 20.0) with
let cancellation = (stockCancellation "TX_STOCK_UNMATERIALIZED_HISTORY_CANCEL" transferBalanceSecurityId 20.0) with
balance_security_id = Some balanceSecurityId
submitMustFail issuer do
exerciseCmd transferred.updatedCapTableCid CT.UpdateCapTable with
Expand All @@ -545,6 +547,7 @@ testEquityBalanceSuccessorIncludesPriorMaterializedReduction = script do
(capTableWithClass, stockClassId) <- setupStockClassWith issuer cap_table (limitedStockClass "SC_EQUITY_UNMATERIALIZED_HISTORY" 1_000.0)
(capTableReady, stakeholderId) <- setupStakeholderWithId issuer capTableWithClass "SH_EQUITY_UNMATERIALIZED_HISTORY" "Equity Unmaterialized History Holder"
let sourceSecurityId = "ESEC_UNMATERIALIZED_HISTORY_SOURCE"
let transferBalanceSecurityId = "ESEC_UNMATERIALIZED_HISTORY_TRANSFER_BALANCE"
issued <- submit issuer do
exerciseCmd capTableReady CT.UpdateCapTable with
creates = [CT.OcfCreateEquityCompensationIssuance (lifecycleEquityIssuance "TX_EQUITY_UNMATERIALIZED_HISTORY_SOURCE" sourceSecurityId stakeholderId stockClassId 100.0)]
Expand All @@ -553,8 +556,9 @@ testEquityBalanceSuccessorIncludesPriorMaterializedReduction = script do
transferred <- submit issuer do
exerciseCmd issued.updatedCapTableCid CT.UpdateCapTable with
creates =
[ CT.OcfCreateEquityCompensationTransfer (lifecycleEquityTransfer "TX_EQUITY_UNMATERIALIZED_HISTORY_TRANSFER" sourceSecurityId 30.0 None ["ESEC_UNMATERIALIZED_HISTORY_MISSING"])
[ CT.OcfCreateEquityCompensationTransfer (lifecycleEquityTransfer "TX_EQUITY_UNMATERIALIZED_HISTORY_TRANSFER" sourceSecurityId 30.0 (Some transferBalanceSecurityId) ["ESEC_UNMATERIALIZED_HISTORY_MISSING"])
, CT.OcfCreateEquityCompensationIssuance (lifecycleEquityIssuance "TX_EQUITY_UNMATERIALIZED_HISTORY_RESULT" "ESEC_UNMATERIALIZED_HISTORY_MISSING" stakeholderId stockClassId 30.0)
, CT.OcfCreateEquityCompensationIssuance (lifecycleEquityIssuance "TX_EQUITY_UNMATERIALIZED_HISTORY_TRANSFER_BALANCE" transferBalanceSecurityId stakeholderId stockClassId 70.0)
]
edits = []
deletes = []
Expand All @@ -563,7 +567,7 @@ testEquityBalanceSuccessorIncludesPriorMaterializedReduction = script do
submitMustFail issuer do
exerciseCmd transferred.updatedCapTableCid CT.UpdateCapTable with
creates =
[ CT.OcfCreateEquityCompensationCancellation (lifecycleEquityCancellation "TX_EQUITY_UNMATERIALIZED_HISTORY_CANCEL" sourceSecurityId 20.0 balanceSecurityId)
[ CT.OcfCreateEquityCompensationCancellation (lifecycleEquityCancellation "TX_EQUITY_UNMATERIALIZED_HISTORY_CANCEL" transferBalanceSecurityId 20.0 balanceSecurityId)
, CT.OcfCreateEquityCompensationIssuance (lifecycleEquityIssuance "TX_EQUITY_UNMATERIALIZED_HISTORY_BALANCE" balanceSecurityId stakeholderId stockClassId 80.0)
]
edits = []
Expand Down
Loading
Loading