Data Structures
Detailed specifications for all RevvFi data structures and storage patterns.
Core Structures
LaunchConfig
Purpose: Immutable configuration for each launch, set at creation time
struct LaunchConfig {
// Token Identity
string tokenName; // ERC20 token name
string tokenSymbol; // ERC20 ticker symbol
uint256 totalSupply; // Total tokens minted (fixed, permanent)
// Token Allocations (must sum to totalSupply)
uint256 liquidityAllocation; // For Uniswap V2 pair
uint256 creatorVestingAmount; // Creator's tokens (with cliff/vesting)
uint256 treasuryAmount; // LP-governed treasury
uint256 strategicReserveAmount; // LP-governed strategic fund
uint256 rewardsAmount; // Community rewards distribution
// Raise Parameters
uint256 raiseWindowDuration; // Seconds deposit window stays open
uint256 targetLiquidityETH; // Minimum ETH required to launch
uint256 hardCapETH; // Maximum ETH accepted (0 = no cap)
// Lock Period
uint256 lockDuration; // Seconds LPs must wait after launch
// Validates: 30 days ≤ lockDuration ≤ 730 days
// Creator Vesting
uint256 creatorCliffDuration; // Cliff period (no release)
uint256 creatorVestingDuration; // Linear vesting after cliff
// Metadata
uint8 templateId; // Token type: 0=Community, 1=Utility, 2=Meme
string tokenURI; // IPFS/Arweave metadata link
}Immutability:
- Set once in
RevvFiFactory.createLaunch() - Stored in bootstrapper contract
- Cannot be modified after creation
Validation:
require(
liquidityAllocation + creatorVestingAmount + treasuryAmount +
strategicReserveAmount + rewardsAmount == totalSupply,
"Allocations must sum to totalSupply"
);
require(targetLiquidityETH > 0, "Target must be positive");
require(hardCapETH == 0 || hardCapETH >= targetLiquidityETH, "Cap < target");
require(lockDuration >= 30 days && lockDuration <= 730 days, "Invalid lock");LaunchMetadata
Purpose: Registry entry for each launch
struct LaunchMetadata {
uint256 launchId; // Unique launch identifier
address creator; // Creator's address
address bootstrapper; // RevvFiBootstrapper contract address
address tokenAddress; // Deployed ERC20 token address
uint256 createdAt; // Block timestamp of creation
// Status Flags
bool active; // True if launch not completed/failed
bool launched; // True after liquidity deployed
bool failed; // True if target not reached
// Key Dates
uint256 raiseEndTime; // When deposit window closes
uint256 maturityTime; // When LPs can withdraw
// Deposit Tracking
uint256 targetLiquidityETH; // Minimum required
uint256 totalDepositedETH; // Current/final amount
uint256 totalShares; // Shares outstanding
// Popular Oracle
uint256 popularityScore; // 0-100 score
uint256 lastScoreUpdate; // Timestamp of last update
}Stored in:
mapping(uint256 => LaunchMetadata) public launches;
mapping(address => LaunchMetadata) public launchesByBootstrapper;RevvFiBootstrapper State
Purpose: Per-launch contract holding all LP funds and state
contract RevvFiBootstrapper {
// Immutable Config
address public creator;
address public revvToken;
address public weth;
address public uniswapRouter;
address public uniswapPair;
// Deposits & Shares
mapping(address => uint256) public shares; // LP → share count
uint256 public totalShares; // Sum of all shares
mapping(address => uint256) public deposits; // LP → ETH deposited (for history)
uint256 public totalDepositedETH; // Total ETH pooled
// Uniswap Integration
uint256 public uniLPTokenAmount; // Uniswap LP tokens held
// Launch Parameters
uint256 public targetLiquidityETH; // From LaunchConfig
uint256 public hardCapETH; // From LaunchConfig
uint256 public raiseEndTime; // Deposit window closes
uint256 public lockDuration; // LP lock period
uint256 public maturityTime; // raiseEndTime + lockDuration
// State Flags
bool public launched; // Launch executed
bool public failed; // Target not reached
bool public paused; // Emergency pause
// Refund Tracking
mapping(address => bool) public refundClaimed; // LP refund status
// Vaults
address public creatorVestingVault;
address public treasuryVault;
address public strategicReserveVault;
address public rewardsDistributor;
}VestingSchedule
Purpose: Track creator’s token vesting with cliff and linear release
struct VestingSchedule {
uint256 totalAmount; // Total tokens to vest
uint256 releasedAmount; // Already released to creator
uint256 startTime; // Vesting start (launch time)
uint256 cliffDuration; // Time before any release (e.g., 1 year)
uint256 vestingDuration; // Time for full vesting after cliff
}Calculation:
function releasableAmount(VestingSchedule storage vs)
public view returns (uint256)
{
// During cliff: nothing
if (block.timestamp < vs.startTime + vs.cliffDuration) {
return 0;
}
// After full vesting: everything
if (block.timestamp >= vs.startTime + vs.cliffDuration + vs.vestingDuration) {
return vs.totalAmount - vs.releasedAmount;
}
// During vesting: proportional
uint256 elapsed = block.timestamp - (vs.startTime + vs.cliffDuration);
uint256 vested = (vs.totalAmount * elapsed) / vs.vestingDuration;
return vested - vs.releasedAmount;
}Storage:
mapping(address => VestingSchedule) public vesting; // Creator → scheduleProposal
Purpose: Governance proposal with voting tracking
struct Proposal {
uint256 proposalId; // Unique proposal ID
uint8 proposalType; // 0=Treasury, 1=Strategic, 2=LockReduction, 3=Emergency
address proposer; // LP who created proposal
address target; // Contract being modified (vault, etc)
bytes data; // Encoded function call
string description; // Human-readable description
// Voting
uint256 votesFor; // Sum of shares voting FOR
uint256 votesAgainst; // Sum of shares voting AGAINST
mapping(address => bool) hasVoted; // LP vote tracking
// Timing
uint256 createdAt; // Block timestamp
uint256 votingEndTime; // When voting closes
uint256 timelockExpires; // When execution allowed
// Status
bool executed; // True if executed
bool vetoed; // True if creator rejected (for lock reductions)
}Storage:
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCounter;
mapping(uint256 => mapping(address => bool)) public hasVoted;CreatorProfile
Purpose: Track creator reputation and metadata
struct CreatorProfile {
// Identity
string name; // Human name
string website; // Project website URL
string twitter; // Twitter handle
string github; // GitHub username
// Verification
bool kycVerified; // KYC completion status
bool twitterVerified; // Twitter blue check
bool githubVerified; // GitHub account verified
// Reputation
uint256 successfulLaunches; // Number of successful launches
uint256 failedLaunches; // Number of failed launches
uint256 reputationScore; // 0-100 derived from success rate
// Metadata
uint256 firstLaunchTime; // Timestamp of first launch
uint256 lastUpdateTime; // Last profile update
}Storage:
mapping(address => CreatorProfile) public creators;Reputation Calculation:
reputationScore = (successfulLaunches * 100) / (successfulLaunches + failedLaunches)PopularityMetrics
Purpose: Track metrics for popularity scoring
struct PopularityMetrics {
uint256 totalDeposited; // Total ETH deposited
uint256 uniqueDepositers; // Count of distinct addresses
uint256 depositVelocity; // ETH per day
uint256 timeTo50Percent; // Days to reach 50% of target
// Score Components
uint256 velocityScore; // 0-100
uint256 uniquenessScore; // 0-100
uint256 socialScore; // 0-100
uint256 reputationScore; // 0-100
uint256 speedScore; // 0-100
// Final Score
uint256 compositeScore; // 0-100 weighted sum
uint256 lastUpdated; // Timestamp
}Storage:
mapping(address => PopularityMetrics) public metrics; // Bootstrapper → metricsScore Calculation:
compositeScore =
(velocityScore * 30) / 100 +
(uniquenessScore * 25) / 100 +
(socialScore * 20) / 100 +
(reputationScore * 15) / 100 +
(speedScore * 10) / 100;Storage Layout & Optimization
Bootstrapper Slot Packing
// Slot 0: Creator Address
address public creator; // 20 bytes
// Slot 1: Token Addresses
address public revvToken; // 20 bytes
// 12 bytes unused
// Slot 2: Protocol Addresses
address public weth; // 20 bytes
// 12 bytes unused
// Slot 3: Uniswap Contracts
address public uniswapRouter; // 20 bytes
address public uniswapPair; // 20 bytes packed together? No, separate slot
// 12 bytes unused
// Slot 4: Counters (packed)
uint256 public totalDepositedETH; // 32 bytes
uint256 public totalShares; // 32 bytes (Slot 5)
// Slot 6-8: Time Parameters
uint256 public raiseEndTime; // 32 bytes
uint256 public lockDuration; // 32 bytes
uint256 public maturityTime; // 32 bytes
// Slot 9: Uniswap LP Tokens
uint256 public uniLPTokenAmount; // 32 bytes
// Slot 10: Targets (packed)
uint256 public targetLiquidityETH; // 32 bytes
uint256 public hardCapETH; // 32 bytes
// Slot 11: Booleans (packed)
bool public launched; // 1 byte
bool public failed; // 1 byte
bool public paused; // 1 byte
// 29 bytes unused
// Slot 12+: Mappings
mapping(address => uint256) public shares; // Start Slot 12
mapping(address => bool) public refundClaimed; // Start Slot 13
// ... more mappingsGas-Efficient Access
// BAD: Multiple SLOAD operations
if (totalShares > 0 && totalDepositedETH > 0) {
// totalShares → SLOAD #1
// totalDepositedETH → SLOAD #2
}
// GOOD: Cache in memory
uint256 _totalShares = totalShares; // SLOAD #1
uint256 _totalDeposited = totalDepositedETH; // SLOAD #2
if (_totalShares > 0 && _totalDeposited > 0) {
// MLOAD operations (cheap)
}Mappings & Lookup Patterns
Factory Registry
mapping(uint256 => address) public bootstrappers; // ID → contract
mapping(address => uint256) public bootstrapperIds; // contract → ID
mapping(address => bool) public isDeployed; // contract → is valid
// Lookup: Find launch ID for bootstrapper
function getLaunchId(address bootstrapper) public view returns (uint256) {
require(isDeployed[bootstrapper], "Not a valid bootstrapper");
return bootstrapperIds[bootstrapper];
}Creator Launches
mapping(address => uint256[]) public creatorLaunches; // creator → launch IDs
// Lookup: All launches by creator
function getCreatorLaunches(address creator)
public view returns (uint256[] memory)
{
return creatorLaunches[creator];
}Share Lookups
// Direct: shares[lp] → balance
function getShareBalance(address lp) public view returns (uint256) {
return shares[lp];
}
// Aggregate: totalShares = sum of all shares
function getTotalShares() public view returns (uint256) {
return totalShares;
}
// Percentage: LP's percentage of pool
function getSharePercentage(address lp) public view returns (uint256) {
return (shares[lp] * 1e18) / totalShares; // 18 decimals
}Next Steps
- Review Smart Contracts for implementation
- Check Deployment for network configs
- Explore Mechanics for usage patterns