Data Models & Relationships
Overview
This document outlines the updated core data models in the L4VA system,system. theirOur relationships,revised validationarchitecture rules,now supports dynamic vault management and implementationa details.dual-level Ourasset dataclassification. architectureThis supportsdesign not only covers standard use cases (e.g., works of art, real estate, gold bullion, and equity) but also enables the registration of custom vault management, governance processes,and asset handling,types andas usernew interactions.real-world asset classes emerge.
Core Models
1. Vault
The primary entity representing a tokenized asset vault. The vault model now supports both fixed types (e.g., PUBLIC, PRIVATE, SEMI_PRIVATE) and dynamically registered types. It also allows for an open set of supported asset types, which can be expanded via a configuration registry or admin endpoint.
interface Vault {
id: string; // Unique identifier
contractAddress: string; // On-chain vault contract address
// VaultType can be one of the predefined values or a dynamically registered type.
type: VaultType; // e.g., PRIVATE | PUBLIC | SEMI_PRIVATE | custom types
status: VaultStatus; // DRAFT | ACTIVE | LOCKED | TERMINATED
// Asset ConfigurationConfiguration: supports dynamic asset types.
// Defaults include NFT (for unique assets) and CNT (for fractional assets).
assetTypes: AssetType[]; // SINGLE_NFT | MULTI_NFT | ANY_CNT
assetWhitelist: string[]; // Allowed asset addresses
contributorWhitelist: string[]; // Allowed contributor addresses
// Windows Configuration
assetWindow: {
startTime: Date;
duration: string; // Format: "DD:HH:MM"
status: WindowStatus;
};
investmentWindow: {
startTime: Date;
duration: string; // Format: "DD:HH:MM"
status: WindowStatus;
valuationType: 'FIXED' | 'LBE';
};
// Fractionalization Settings
fractionalization: {
percentage: number; // XX.XX%
tokenSupply: number;
tokenDecimals: number; // 1-9
tokenAddress: string; // Fractional token contract address
};
// Investment Settings
investment: {
reserve: number; // XX.XX%
liquidityPool: number; // XX.XX%
};
// Termination Settings
termination: {
type: 'DAO' | 'PROGRAMMED';
fdp: number; // Floor price deviation percentage
};
// MetadataMetadata: provides room for additional dynamic configuration.
createdBy: string; // Admin wallet address
createdAt: Date;
updatedAt: Date;
metadata: Record<string, any>; // Additional configurable fields (e.g., custom vault parameters)
}
type WindowStatus = 'PENDING' | 'ACTIVE' | 'COMPLETED' | 'FAILED';
2. Asset
Represents assets held within vaults. This model introduces a dual-level classification: a primary tokenization method (e.g., NFT for unique items, CNT for fractional assets) and a secondary categorization (via metadata) to define asset-specific classes such as art, real estate, commodities, or equity.
interface Asset {
id: string;
vaultId: string;
// AssetType may be one of the default types (e.g., NFT, CNT) or a dynamically registered type.
type: AssetType;
contractAddress: string;
tokenId?: string; // For NFTs
quantity: number; // For CNTs
// Valuation
floorPrice: number; // For NFTs
dexPrice: number; // For CNTs
lastValuation: Date;
// Status
status: AssetStatus; // PENDING | LOCKED | RELEASED
lockedAt?: Date;
releasedAt?: Date;
// Metadata now includes an additional "category" field.
// This field can capture asset-specific classifications (e.g., art, real_estate, commodity, equity)
metadata: {
name: string;
description: string;
imageUrl: string;
category?: string;
attributes: Record<string, any>;
};
// Tracking
addedBy: string; // Wallet address
addedAt: Date;
updatedAt: Date;
}
type AssetStatus = 'PENDING' | 'LOCKED' | 'RELEASED';
3. Proposal
Governance proposals withinremain vaults.largely unchanged, but note that proposals may reference dynamically registered asset types or custom governance rules based on asset categories.
interface Proposal {
id: string;
vaultId: string;
type: ProposalType; // ASSET_SALE | BUY | STAKE | LIQUIDATE
// Phases
votingPhase: {
duration: string; // Format: "DD:HH:MM"
startTime: Date;
endTime: Date;
status: PhaseStatus;
quorum: number; // Required participation percentage
};
lockPhase: {
duration: string;
startTime: Date;
endTime: Date;
status: PhaseStatus;
};
executionPhase: {
duration: string;
startTime: Date;
endTime: Date;
status: PhaseStatus;
requiredCosigners: number;
};
// Proposal DetailsDetails: can target assets of any supported type.
settings: {
assets: string[]; // Affected asset IDs
effects: ProposalEffect[];
};
// Results
votes: {
approve: number;
reject: number;
totalVoted: number;
uniqueVoters: number;
};
// Status
status: ProposalStatus; // DRAFT | ACTIVE | PASSED | FAILED | EXECUTED
result?: ProposalResult;
// Metadata
createdBy: string; // Proposer wallet address
createdAt: Date;
updatedAt: Date;
}
type PhaseStatus = 'PENDING' | 'ACTIVE' | 'COMPLETED' | 'FAILED';
type ProposalStatus = 'DRAFT' | 'ACTIVE' | 'PASSED' | 'FAILED' | 'EXECUTED';
4. Vote
Individual votes on proposals.proposals used to execute governance decisions. This model remains unchanged.
interface Vote {
id: string;
proposalId: string;
wallet: string; // Voter's wallet address
decision: 'APPROVE' | 'REJECT';
amount: number; // Amount of FTs staked in vote
// Status
status: VoteStatus; // CAST | CONFIRMED | REVOKED
confirmationTx?: string; // Blockchain transaction hash
// Timing
castAt: Date;
confirmedAt?: Date;
revokedAt?: Date;
}
5. Stake
Represents staked fractional tokens.tokens that contribute to voting power. This model remains similar but supports dynamic governance processes tied to various asset classes.
interface Stake {
id: string;
vaultId: string;
wallet: string; // Staker's wallet address
amount: number; // Staked amount
// Status
status: StakeStatus; // ACTIVE | LOCKED | RELEASED
lockedUntil?: Date; // For time-locked stakes
// Voting Power
votingPower: number;
usedPower: number; // Power used in active votes
// Tracking
createdAt: Date;
updatedAt: Date;
transactions: {
stakeHash: string;
unstakeHash?: string;
};
}
Relationships
Entity Relationships Diagram
erDiagram
Vault ||--o{ Asset : contains
Vault ||--o{ Proposal : has
Vault ||--o{ Stake : holds
Proposal ||--o{ Vote : receives
Stake ||--o{ Vote : powers
Key Relationships
1.
Vault → Assets
- One-to-many relationship
- A
Vaultvault can contain multipleassetsassets; Assetseachbelongasset belongs toexactlyaonesinglevaultvault.- Relationship constraints are enforced by
assetTypes
and
assetWhitelist.assetWhitelist
2.
- One-to-many relationship
- Proposals are
boundtied to a single vault and may leverage asset category-specific rules.
3. Proposal creation governed by vault settings
Vault status affects proposal availability
- One-to-many relationship
- Votes
tiedaretoassociated with specificproposalsproposals, Votewith vote weight determined bystakestakedamounttokens.
4. Vote validity constrained by proposal phases
- One-to-many relationship
- Stakes power
multiplevotesvotesand Votinghelp track voting powertrackedrelativeandtolimited by stakethe amount staked.Stakes can be locked during active votes
Validation Rules
1. Vault Validation
const vaultValidation = {
assetWindow: {
minDuration: "01:00:00",
maxDuration: "30:00:00"
},
investmentWindow: {
minDuration: "24:00:00",
maxDuration: "168:00:00"
},
fractionalization: {
minPercentage: 1,
maxPercentage: 100,
minDecimals: 1,
maxDecimals: 9
},
investment: {
minReserve: 5,
maxReserve: 50,
minLiquidity: 1,
maxLiquidity: 20
}
};
2. Asset Validation
const assetValidation = {
nft: {
maxPerVault: 100
},
cnt: {
minQuantity: 1,
maxQuantity: 1000000
},
valuation: {
maxAge: "24:00:00"
}
};
3. Proposal Validation
const proposalValidation = {
voting: {
minDuration: "24:00:00",
maxDuration: "168:00:00",
minQuorum: 10,
maxQuorum: 100
},
lock: {
minDuration: "12:00:00",
maxDuration: "48:00:00"
},
execution: {
minDuration: "24:00:00",
maxDuration: "72:00:00"
}
};
Implementation Guidelines
1. Database Indexes
// Vault Indexes
{
"contractAddress": 1,
"status": 1,
"type": 1,
"createdAt": -1
}
// Asset Indexes
{
"vaultId": 1,
"contractAddress": 1,
"status": 1
}
// Proposal Indexes
{
"vaultId": 1,
"status": 1,
"votingPhase.endTime": 1
}
// Vote Indexes
{
"proposalId": 1,
"wallet": 1,
"status": 1
}
// Stake Indexes
{
"vaultId": 1,
"wallet": 1,
"status": 1
}
2. Cascade Behaviors
// Delete cascade rules
const cascadeRules = {
vault: {
onDelete: ['assets', 'proposals', 'stakes']
},
proposal: {
onDelete: ['votes']
}
};
3. Data Integrity
interface DataIntegrityChecks {
validateStakeBalance: () => Promise<void>;
validateVotingPower: () => Promise<void>;
validateProposalStatus: () => Promise<void>;
validateAssetLocks: () => Promise<void>;
}
Best Practices
1.
Data Access
- Use the repositories
patternpattern. - Implement a caching
strategystrategy. - Handle concurrent
updatesupdates. - Maintain audit
logslogs.
2.
Validation
- Validate at the model
levellevel. ImplementEnforce businessrulesrules.- Check
relationshipsrelationships. - Verify blockchain
statestate.
3.
Performance
- Use appropriate
indexesindexes. - Implement
paginationpagination. - Optimize
queriesqueries. - Monitor database
loadload.
4.
Security
- Encrypt sensitive
datadata. - Validate
permissionspermissions. - Audit data
accessaccess. - Handle PII
properlyproperly.
Note: I recently updated this document to reflect a move toward a dynamic, extensible framework as detailed in our Vault Formation and Data Models & Relationships guidelines, ensuring our platform remains agile in representing any real-world asset.