diff --git a/Test/daml/OpenCapTable/TestWarrantIssuance.daml b/Test/daml/OpenCapTable/TestWarrantIssuance.daml index fea17c9d..19d9a8a3 100644 --- a/Test/daml/OpenCapTable/TestWarrantIssuance.daml +++ b/Test/daml/OpenCapTable/TestWarrantIssuance.daml @@ -6,7 +6,7 @@ import Fairmint.OpenCapTable.Types.Stock (OcfQuantitySourceType(..), OcfSecurity import Fairmint.OpenCapTable.Types.Vesting (OcfVesting(..)) import qualified Fairmint.OpenCapTable.CapTable as CT import OpenCapTable.Setup -import OpenCapTable.TestHelpers (addDefaultStakeholder) +import OpenCapTable.TestHelpers (addDefaultStakeholder, defaultVestingTerms) import qualified DA.Date as DA import DA.Date (Month(..)) import qualified DA.Time as DT @@ -57,25 +57,28 @@ testWarrantIssuance_OptionalsSome_ArraysNonEmpty = script do capTableCid <- addDefaultStakeholder issuer cap_table _ <- submit issuer do exerciseCmd capTableCid CT.UpdateCapTable with - creates = [CT.OcfCreateWarrantIssuance WarrantIssuanceOcfData with - id = "TX_WARRANT_SOME" - date = DT.time (DA.date 2024 Feb 01) 0 0 0 - security_id = "WSEC-3" - custom_id = "W-3" - stakeholder_id = "SH-1" - board_approval_date = Some (DT.time (DA.date 2024 Jan 15) 0 0 0) - stockholder_approval_date = Some (DT.time (DA.date 2024 Jan 20) 0 0 0) - consideration_text = Some "Cash" - security_law_exemptions = [ OcfSecurityExemption with description = "Reg D", jurisdiction = "US-DE" ] - quantity = Some 100.0 - quantity_source = Some OcfQuantityInstrumentFixed - exercise_price = Some (OcfMonetary with amount = 1.5, currency = "USD") - purchase_price = OcfMonetary with amount = 0.1, currency = "USD" - exercise_triggers = [ ocfTriggerElectiveAtWill ] - warrant_expiration_date = Some (DT.time (DA.date 2025 Jan 01) 0 0 0) - vesting_terms_id = Some "VT_W" - vestings = [ OcfVesting with date = DT.time (DA.date 2024 Mar 01) 0 0 0, amount = 10.0 ] - comments = ["Issued"]] + creates = + [ CT.OcfCreateVestingTerms (defaultVestingTerms "VT_W") + , CT.OcfCreateWarrantIssuance WarrantIssuanceOcfData with + id = "TX_WARRANT_SOME" + date = DT.time (DA.date 2024 Feb 01) 0 0 0 + security_id = "WSEC-3" + custom_id = "W-3" + stakeholder_id = "SH-1" + board_approval_date = Some (DT.time (DA.date 2024 Jan 15) 0 0 0) + stockholder_approval_date = Some (DT.time (DA.date 2024 Jan 20) 0 0 0) + consideration_text = Some "Cash" + security_law_exemptions = [ OcfSecurityExemption with description = "Reg D", jurisdiction = "US-DE" ] + quantity = Some 100.0 + quantity_source = Some OcfQuantityInstrumentFixed + exercise_price = Some (OcfMonetary with amount = 1.5, currency = "USD") + purchase_price = OcfMonetary with amount = 0.1, currency = "USD" + exercise_triggers = [ ocfTriggerElectiveAtWill ] + warrant_expiration_date = Some (DT.time (DA.date 2025 Jan 01) 0 0 0) + vesting_terms_id = Some "VT_W" + vestings = [ OcfVesting with date = DT.time (DA.date 2024 Mar 01) 0 0 0, amount = 10.0 ] + comments = ["Issued"] + ] edits = [] deletes = [] pure () diff --git a/Test/daml/OpenCapTable/TestWarrantIssuanceReferences.daml b/Test/daml/OpenCapTable/TestWarrantIssuanceReferences.daml new file mode 100644 index 00000000..9c880a92 --- /dev/null +++ b/Test/daml/OpenCapTable/TestWarrantIssuanceReferences.daml @@ -0,0 +1,89 @@ +module OpenCapTable.TestWarrantIssuanceReferences where + +import qualified Fairmint.OpenCapTable.CapTable as CT +import Fairmint.OpenCapTable.OCF.WarrantIssuance (WarrantIssuanceOcfData(..)) +import Fairmint.OpenCapTable.Types.Monetary (OcfMonetary(..)) +import Fairmint.OpenCapTable.Types.Stock (OcfQuantitySourceType(..)) +import OpenCapTable.HelpersTriggers (ocfTriggerElectiveAtWill) +import OpenCapTable.Setup +import OpenCapTable.TestHelpers +import Daml.Script + +warrantIssuance : Text -> Text -> Text -> WarrantIssuanceOcfData +warrantIssuance issuanceId securityId stakeholderId = WarrantIssuanceOcfData with + id = issuanceId + date = defaultTestDate + security_id = securityId + custom_id = "W-" <> issuanceId + stakeholder_id = stakeholderId + board_approval_date = None + stockholder_approval_date = None + consideration_text = None + security_law_exemptions = [] + quantity = Some 100.0 + quantity_source = Some OcfQuantityUnspecified + 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 = [] + +createReferencedWarrantIssuance : + Party -> + ContractId CT.CapTable -> + Script (ContractId CT.CapTable, WarrantIssuanceOcfData, Text) +createReferencedWarrantIssuance issuer capTableCid = do + (capTableWithStakeholder, stakeholderId) <- setupStakeholderWithId issuer capTableCid "SH_WARRANT_REF" "Warrant Holder" + let vestingTermsId = "VT_WARRANT_REF" + let issuance = (warrantIssuance "TX_WARRANT_REF" "WARRANT-REF" stakeholderId) with + vesting_terms_id = Some vestingTermsId + + result <- submit issuer do + exerciseCmd capTableWithStakeholder CT.UpdateCapTable with + creates = + [ CT.OcfCreateVestingTerms (defaultVestingTerms vestingTermsId) + , CT.OcfCreateWarrantIssuance issuance + ] + edits = [] + deletes = [] + pure (result.updatedCapTableCid, issuance, vestingTermsId) + +testWarrantIssuance_MissingVestingTermsReferenceFails = script do + TestOcp{issuer, cap_table} <- setupTestOcp + (capTableCid, stakeholderId) <- setupStakeholderWithId issuer cap_table "SH_WARRANT_MISSING_VESTING" "Warrant Holder" + let issuance = (warrantIssuance "TX_WARRANT_MISSING_VESTING" "WARRANT-MISSING-VESTING" stakeholderId) with + vesting_terms_id = Some "VT_MISSING_WARRANT" + + submitMustFail issuer do + exerciseCmd capTableCid CT.UpdateCapTable with + creates = [CT.OcfCreateWarrantIssuance issuance] + edits = [] + deletes = [] + +testWarrantIssuance_VestingTermsCreatedInSameBatchSucceeds = script do + TestOcp{issuer, cap_table} <- setupTestOcp + _ <- createReferencedWarrantIssuance issuer cap_table + pure () + +testWarrantIssuance_EditMissingVestingTermsReferenceFails = script do + TestOcp{issuer, cap_table} <- setupTestOcp + (capTableCid, issuance, _) <- createReferencedWarrantIssuance issuer cap_table + let editedIssuance = issuance with vesting_terms_id = Some "VT_MISSING_WARRANT_ON_EDIT" + + submitMustFail issuer do + exerciseCmd capTableCid CT.UpdateCapTable with + creates = [] + edits = [CT.OcfEditWarrantIssuance editedIssuance] + deletes = [] + +testWarrantIssuance_DeleteReferencedVestingTermsFails = script do + TestOcp{issuer, cap_table} <- setupTestOcp + (capTableCid, _, vestingTermsId) <- createReferencedWarrantIssuance issuer cap_table + + submitMustFail issuer do + exerciseCmd capTableCid CT.UpdateCapTable with + creates = [] + edits = [] + deletes = [CT.OcfDeleteVestingTerms vestingTermsId] diff --git a/dars/OpenCapTable-v34/0.0.2/OpenCapTable-v34.dar b/dars/OpenCapTable-v34/0.0.2/OpenCapTable-v34.dar index 0fe143d7..d3db91ee 100644 --- a/dars/OpenCapTable-v34/0.0.2/OpenCapTable-v34.dar +++ b/dars/OpenCapTable-v34/0.0.2/OpenCapTable-v34.dar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d0222d7116f1a8278cf65cf7d4d9318ac62c7bf5c30f6bf830fe040fe177ba0 -size 2509005 +oid sha256:c89b11662c56c40d0ff7e8bfc03e9f4b863e84ad7b5711a338070a30ed84c08d +size 2510816 diff --git a/dars/dars.lock b/dars/dars.lock index 6158a6bb..acc9a0a9 100644 --- a/dars/dars.lock +++ b/dars/dars.lock @@ -12,8 +12,8 @@ ] }, "OpenCapTable-v34/0.0.2/OpenCapTable-v34.dar": { - "sha256": "5d0222d7116f1a8278cf65cf7d4d9318ac62c7bf5c30f6bf830fe040fe177ba0", - "size": 2509005, + "sha256": "c89b11662c56c40d0ff7e8bfc03e9f4b863e84ad7b5711a338070a30ed84c08d", + "size": 2510816, "sdkVersion": "3.4.10", "uploadedAt": "2026-07-07T21:50:59.634Z", "networks": [] diff --git a/scripts/codegen/captable-config.yaml b/scripts/codegen/captable-config.yaml index 976afd60..0a3052c3 100644 --- a/scripts/codegen/captable-config.yaml +++ b/scripts/codegen/captable-config.yaml @@ -88,14 +88,9 @@ validations: 'vesting_terms_id?:vesting_terms', ] EquityCompensationIssuance: - [ - stakeholder_id, - 'stock_class_id?:stock_classes', - 'stock_plan_id?:stock_plans', - 'vesting_terms_id?:vesting_terms', - ] + [stakeholder_id, 'stock_class_id?:stock_classes', 'stock_plan_id?:stock_plans', 'vesting_terms_id?:vesting_terms'] ConvertibleIssuance: [stakeholder_id] - WarrantIssuance: [stakeholder_id] + WarrantIssuance: [stakeholder_id, 'vesting_terms_id?:vesting_terms'] # Stakeholder events - validate stakeholder exists StakeholderRelationshipChangeEvent: [stakeholder_id] StakeholderStatusChangeEvent: [stakeholder_id] diff --git a/scripts/codegen/templates/CapTable.daml.template b/scripts/codegen/templates/CapTable.daml.template index 33ec12b3..fb5555cf 100644 --- a/scripts/codegen/templates/CapTable.daml.template +++ b/scripts/codegen/templates/CapTable.daml.template @@ -363,6 +363,14 @@ validateEquityCompensationIssuanceReferences maps = validateOptionalReference "Equity compensation vesting terms" maps.vesting_terms issuance.issuance_data.vesting_terms_id) (Map.values maps.equity_compensation_issuances) +validateWarrantIssuanceReferences : CapTableMaps -> Update () +validateWarrantIssuanceReferences maps = + mapA_ + (\issuanceCid -> do + issuance <- fetch issuanceCid + validateOptionalReference "Warrant vesting terms" maps.vesting_terms issuance.issuance_data.vesting_terms_id) + (Map.values maps.warrant_issuances) + -- | Get the processing tier for a create operation getCreateTier : OcfCreateData -> Int getCreateTier createData = case createData of @@ -502,6 +510,7 @@ template CapTable validateWarrantConversionRightReferences finalMaps validateValuationStockClassReferences finalMaps validateEquityCompensationIssuanceReferences finalMaps + validateWarrantIssuanceReferences finalMaps validateIssuerAuthorizedShares finalMaps newIssuerCid -- Create new CapTable with updated maps and potentially new issuer