Contract Architecture & Patterns
Technical Implementation Guide
Overview
This documentation outlines the implementation of a real-world asset tokenization system on Cardano, utilizing the Agora protocol for governance. The system enables the creation of fractionalized ownership of physical assets through secure smart contracts, with built-in governance mechanisms for collective decision-making.
The implementation combines vault management for asset handling, Agora's three-phase governance system, token policies for both fractional ownership and governance rights, and managed contribution windows. All components work together to create a secure, compliant, and flexible tokenization platform.
System Architecture
File structureStructure
plutus/
├── core/
│ ├── VaultFactory.hs # Creates vault instances
│ ├── VaultRegistry.hs # Global vault tracking
│ ├── FractionalizedVault.hs # Core vault functionality
│ └── VaultValidator.hs # Main validation logic
├── governance/agora/
│ ├── ProposalValidator.hs # GovernanceProposal validation logic
│ ├── ExecutorValidator.LockPhase.hs # ProposalLock executionphase implementation
│ ├── VotingPhase.hs # Voting phase logic
│ ├── ExecutionPhase.hs # Execution phase handling
│ └── VotingValidator.ThresholdValidator.hs # VoteGovernance handlingthresholds
├── tokens/
│ ├── FractionalPolicy.hs # Fractional token minting
│ └── GovernancePolicy.hs # GovernanceAgora governance token minting
├── windows/
│ ├── AssetWindowValidator.hs # Asset contribution period
│ └── InvestmentWindowValidator.hs # Investment period
├── types/
│ ├── VaultTypes.hs # Core type definitions
│ ├── GovernanceTypes.AgoraTypes.hs # GovernanceAgora relatedgovernance types
│ └── WindowTypes.hs # Window related types
├── effects/
│ ├── ProposalEffects.hs # Proposal action execution
│ └── RequirementEffects.hs # Requirement modifications
└── utils/
├── Validators.hs # Common validation functions
└── Scripts.hs # Script utilities
Core ContractsVault Components
The vault system manages the fundamental asset tokenization functionality.
VaultFactoryVault Factory
Responsible for creating new vault instances with proper initialization:
data VaultParams = VaultParams {
vaultType :: 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
VaultRegistryVault Registry
Maintains the global state of all vaults:
data RegistryDatum = RegistryDatum {
vaults :: Map VaultId VaultInfo
,VaultInfo,
totalVaults :: Integer
}
data VaultInfo = VaultInfo {
vaultState :: VaultState
,VaultState,
assetIds :: [AssetId]
,
tokenPolicy :: CurrencySymbol
}
mkRegistryValidator :: TypedValidator RegistrySchema
mkRegistryValidator = mkTypedValidator @RegistrySchema
$$(PlutusTx.compile [|| validateRegistry ||])
$$(PlutusTx.compile [|| wrap ||])
where
wrap = wrapValidator @RegistryDatum @RegistryRedeemer
FractionalizedVaultFractionalized Vault
Manages the core vault operations and state:
data VaultDatum = VaultDatum {
assets :: [AssetDetails]
,
fractionalization :: FractionalizationParams
,FractionalizationParams,
state :: VaultState
}
data AssetDetails = AssetDetails {
assetId :: AssetId
,AssetId,
amount :: Integer
,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
Agora Governance ModuleIntegration
The Agora protocol provides a structured governance system with three distinct phases.
Core Governance Structures
data ProposalDatumGovernanceSettings = ProposalDatumGovernanceSettings {
creationThreshold :: Percentage, -- Min FT % to create proposal
startThreshold :: Percentage, -- Min FT % to start voting
voteThreshold :: Percentage, -- Min staked FT for valid vote
executionThreshold :: Percentage, -- Min votes for execution
cosigningThreshold :: Percentage, -- Min FT for cosigning
lockDuration :: POSIXTime -- Lock phase duration
}
data ProposalPhase =
LockPhase
| VotingPhase
| ExecutionPhase
Proposal Management
data ProposalParams = ProposalParams {
description :: Text,
votingDuration :: POSIXTime,
lockDuration :: POSIXTime,
executionDuration :: POSIXTime,
requiredCosigners :: [PubKeyHash],
effects :: [ProposalEffect]
}
createProposal :: VaultId -> ProposalParams -> Contract w s Text ProposalId
createProposal vaultId params = do
validateCreatorStake
proposalId <- submitTx $ mustPayToScript proposalValidator (proposalDatum params)
emitEvent $ ProposalCreated proposalId
pure proposalId
Phase Transitions
data PhaseTransition =
StartVoting
| StartLockPhase
| StartExecution
validatePhaseTransition :: ProposalDatum -> PhaseTransition -> ScriptContext -> Bool
validatePhaseTransition datum transition ctx = case transition of
StartVoting ->
meetStartThreshold &&
timeToVote
StartLockPhase ->
votingComplete &&
sufficientVotes
StartExecution ->
lockPhaseComplete &&
cosignersSigned
Token Management
Governance Token
data GovernanceToken = GovernanceToken {
policyId :: CurrencySymbol,
tokenName :: TokenName,
totalSupply :: Integer
,}
descriptionvalidateGovernanceToken :: BuiltinByteStringAssetParams ,-> startTimeGovernanceToken ::-> POSIXTimeScriptContext ,-> endTimeBool
::validateGovernanceToken POSIXTimeparams ,token votes :: Map PubKeyHash Integer
, status :: ProposalStatus
}
data VoteRedeemerctx =
VotecorrectSupply Integer&&
|correctDistribution Execute&&
|
Cancel
mkGovernanceValidator :: TypedValidator GovernanceSchema
mkGovernanceValidator = mkTypedValidator @GovernanceSchema
$$(PlutusTx.compile [|| validateGovernance ||])
$$(PlutusTx.compile [|| wrap ||])
where
wrap = wrapValidator @ProposalDatum @VoteRedeemerhasGovernanceMetadata
Fractional Token Minting
data FractionalTokenParams = FractionalTokenParams {
tokenName :: TokenName
,TokenName,
decimals :: Integer
,Integer,
totalSupply :: Integer
}
mkTokenPolicy :: FractionalTokenParams -> MintingPolicy
mkTokenPolicy params = mkMintingPolicyScript
($$(PlutusTx.compile [|| validateMinting ||])
`PlutusTx.applyCode` PlutusTx.liftCode params)
PlutusTx.makeLift ''FractionalTokenParams
Window Management
Asset Window
data WindowDatum = WindowDatum {
windowStart :: POSIXTime
,POSIXTime,
windowEnd :: POSIXTime
,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
ExampleTypes 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
Other filesSystem
ValidatorsVault Types
VaultValidator.hs
Main validation logic for vault operationsHandles state transitionsValidates transaction constraintsEnsures proper authorizationCoordinates with other validators
Validators.hs
Scripts.hs
Script compilation utilitiesScript optimization functionsOn-chain code helpersParameterization utilities
Types Files
VaultTypes.hs
data VaultState =
Draft
| Active
| Locked
| Terminated
data VaultParams = VaultParams {
vaultType :: VaultType,
assetTypes :: [AssetType],
contributorPolicy :: PolicyId,
investorPolicy :: PolicyId,
settings :: VaultSettings
}
data VaultAction =
Initialize VaultParams
| AddAsset AssetDetails
| RemoveAsset AssetId
| LockAssets
| UnlockAssets
GovernanceTypes.hs
Governance Types
data ProposalState =
Pending
| VotingActive
| Locked
| Executed
| Failed
data VoteType =
Approve
| Reject
data ProposalAction =
CreateProposal ProposalParams
| CastVote VoteDetails
| ExecuteProposal
| CancelProposal
Implementation Notes
Best Practices
WindowTypes.hsThe implementation adheres to several key principles:
data
WindowState- Strong
=typing NotStartedensures |that Activeinvalid |states Completedare |unrepresentable Failedin datathe WindowParamstype =system. WindowParamsEvery {operation startTimehas ::explicit POSIXTime,type durationdefinitions ::that Integer,capture allowedAssetsits ::requirements [AssetId],and minimumValueconstraints.
::- Explicit
Integerdatum }and
redeemer Instructures conclusion
clearly define the state transitions and valid operations. Each validator precisely specifies what constitutes a valid state change.
Security Considerations
EachThe contractimplementation followsincludes Cardano/Plutusseveral bestsecurity practices:measures:
- Multiple validation layers verify all operations
- Strong typing
Explicitpreventsdatum/redeemer structuresProper validator patternsClearinvalid state transitionsEfficientExplicitUTXOaccessmanagementcontrol through stake-based governance- Comprehensive audit trail of all operations
- Time-locked phases prevent rushed decisions
Integration Points
The system's main integration points are:
- Asset registration and verification
- Governance token distribution
- Proposal creation and execution
- Time Window management and transitions
- Effect implementation and validation