Skip to main content

Contract Architecture & Patterns

File structure

plutus/
├── core/
│   ├── VaultFactory.hs        # Creates vault instances
│   ├── VaultRegistry.hs       # Global vault tracking
│   ├── FractionalizedVault.hs # Core vault functionality
│   └── VaultValidator.hs      # Main validation logic
├── governance/
│   ├── ProposalValidator.hs   # Governance validation
│   ├── ExecutorValidator.hs   # Proposal execution
│   └── VotingValidator.hs     # Vote handling
├── tokens/
│   ├── FractionalPolicy.hs    # Fractional token minting
│   └── GovernancePolicy.hs    # Governance token minting
├── windows/
│   ├── AssetWindowValidator.hs     # Asset contribution period
│   └── InvestmentWindowValidator.hs # Investment period
├── types/
│   ├── VaultTypes.hs          # Core type definitions
│   ├── GovernanceTypes.hs     # Governance related types 
│   └── WindowTypes.hs         # Window related types
└── utils/
   ├── Validators.hs          # Common validation functions
   └── Scripts.hs             # Script utilities

Core Contracts

VaultFactory

data VaultParams = VaultParams
    { vaultType :: VaultType
    , assetTypes :: [AssetType]
    , settings :: VaultSettings
    }

newtype VaultFactory = VaultFactory
    { createVault :: VaultParams -> Contract w s Text VaultId
    }

mkVaultValidator :: VaultParams -> TypedValidator VaultSchema
mkVaultValidator params = mkTypedValidator @VaultSchema
    ($$(PlutusTx.compile [|| validateVault ||])
        `PlutusTx.applyCode` PlutusTx.liftCode params)
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = wrapValidator @VaultDatum @VaultRedeemer

VaultRegistry

data RegistryDatum = RegistryDatum
    { vaults :: Map VaultId VaultInfo
    , totalVaults :: Integer
    }

data VaultInfo = VaultInfo
    { vaultState :: VaultState
    , assetIds :: [AssetId]
    , tokenPolicy :: CurrencySymbol
    }

mkRegistryValidator :: TypedValidator RegistrySchema
mkRegistryValidator = mkTypedValidator @RegistrySchema
    $$(PlutusTx.compile [|| validateRegistry ||])
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = wrapValidator @RegistryDatum @RegistryRedeemer

FractionalizedVault

data VaultDatum = VaultDatum
    { assets :: [AssetDetails]
    , fractionalization :: FractionalizationParams
    , state :: VaultState
    }

data AssetDetails = AssetDetails
    { assetId :: AssetId
    , amount :: Integer
    , locked :: Bool
    }

mkVaultScript :: VaultParams -> Scripts.TypedValidator VaultSchema
mkVaultScript params = Scripts.mkTypedValidator @VaultSchema
    ($$(PlutusTx.compile [|| validateVault ||])
        `PlutusTx.applyCode` PlutusTx.liftCode params)
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = Scripts.wrapValidator @VaultDatum @VaultRedeemer

Governance Module

data ProposalDatum = ProposalDatum
    { proposalId :: Integer
    , description :: BuiltinByteString
    , startTime :: POSIXTime
    , endTime :: POSIXTime
    , votes :: Map PubKeyHash Integer
    , status :: ProposalStatus
    }

data VoteRedeemer = 
    Vote Integer |
    Execute |
    Cancel

mkGovernanceValidator :: TypedValidator GovernanceSchema
mkGovernanceValidator = mkTypedValidator @GovernanceSchema
    $$(PlutusTx.compile [|| validateGovernance ||])
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = wrapValidator @ProposalDatum @VoteRedeemer

Token Minting

data FractionalTokenParams = FractionalTokenParams
    { tokenName :: TokenName
    , decimals :: Integer
    , totalSupply :: Integer
    }

mkTokenPolicy :: FractionalTokenParams -> MintingPolicy
mkTokenPolicy params = mkMintingPolicyScript
    ($$(PlutusTx.compile [|| validateMinting ||])
        `PlutusTx.applyCode` PlutusTx.liftCode params)

PlutusTx.makeLift ''FractionalTokenParams

Asset Window

data WindowDatum = WindowDatum
    { windowStart :: POSIXTime
    , windowEnd :: POSIXTime
    , contributions :: Map AssetId Contribution
    }

data WindowRedeemer =
    Contribute AssetContribution |
    CloseWindow

mkWindowValidator :: TypedValidator WindowSchema
mkWindowValidator = mkTypedValidator @WindowSchema
    $$(PlutusTx.compile [|| validateWindow ||])
    $$(PlutusTx.compile [|| wrap ||])
  where
    wrap = wrapValidator @WindowDatum @WindowRedeemer

Example Validator Logic

validateVault :: VaultParams -> VaultDatum -> VaultRedeemer -> ScriptContext -> Bool
validateVault params datum redeemer ctx = 
    traceIfFalse "Invalid operation" $ case redeemer of
        AddAsset asset -> validateAssetAddition asset datum ctx
        RemoveAsset asset -> validateAssetRemoval asset datum ctx
        Lock -> validateLocking datum ctx
        Unlock -> validateUnlocking datum ctx

validateGovernance :: ProposalDatum -> VoteRedeemer -> ScriptContext -> Bool
validateGovernance datum redeemer ctx =
    traceIfFalse "Invalid governance action" $ case redeemer of
        Vote amount -> validateVoting datum amount ctx
        Execute -> validateExecution datum ctx
        Cancel -> validateCancellation datum ctx


Each contract follows Cardano/Plutus best practices:

  1. Strong typing
  2. Explicit datum/redeemer structures
  3. Proper validator patterns
  4. Clear state transitions
  5. Efficient UTXO management