Skip to content

IFIFv2 Contract

The IFIFv2 contract is an enhanced version of the core IFIF crowdfunding project contract that extends the base functionality with advanced features including vested fund claiming, enhanced purchase controls, dynamic distributor configuration, and improved token distribution mechanisms. It maintains full compatibility with the base IFIF interface while adding sophisticated timing and vesting capabilities.

Overview

Contract Address: contracts/src/core/IFIFv2.sol
License: GPL-3.0-only
Solidity Version: 0.8.19

Key Enhancements Over IFIF v1

  • Automatic Stage Transitions: Eliminates manual stage control with time-based automation
  • Enhanced Purchase Controls: Hard caps, soft caps, and minimum weight validations
  • Vested Fund Claiming: Time-based fund release for project owners with nonce-based replay attack prevention
  • Dynamic Distributor Configuration: Flexible fee structures for different distributors with independent nonce tracking
  • Improved Token Claiming: Vesting schedules for gradual token release to investors
  • Asset Sweep Functionality: Recovery of unclaimed assets after expiration periods
  • Multi-signature Enhancements: Optimized signature requirements for general config updates (2 vs 3 signatures) with nonce validation
  • Enhanced Nonce System: Additional signature types with independent nonce sequences for FundClaimConfig and DistributorConfig

Enhanced Data Structures

Config_v2

struct Config_v2 {
    uint256 privateSaleStartEpoch;    // Timestamp when private sale begins automatically
    uint256 purchaseHardCapPercent;   // Maximum purchase limit as % of funding goal (0-100)
    uint256 purchaseSoftCap;          // Minimum purchase amount required per transaction
    uint256 minNFTWeight;             // Minimum weight required for NFT split operations
}

Note: Config_v2 is stored as internal _config_v2 and is not directly accessible via view functions. The configuration is validated during initialization and used internally for purchase validations and automatic stage transitions.

FundClaimConfig

struct FundClaimConfig {
    uint256 startEpoch;     // When project owner can start claiming funds
    uint256 endEpoch;       // When fund vesting period ends
    uint256 periodLength;   // Duration of each vesting period (minimum 1 day)
    uint256 nonce;          // Nonce for replay attack prevention (must match or exceed current nonce)
}

Nonce Field: The nonce field enables signature replay attack prevention for fund claim configuration updates. Read the current nonce via nonces(1, projectOwner) where 1 is the NONCE_FUND_CLAIM_CONFIG constant. Use nonce: 0 for first-time configuration.

DistributorConfig

struct DistributorConfig {
    uint256 distributorFeePercent;     // Fee percentage for distributor (0-100)
    uint256 projectOwnerFeePercent;    // Fee percentage for project owner (0-100)
    uint256 platformFeePercent;        // Fee percentage for platform (0-100)
    uint256 nonce;                     // Nonce for replay attack prevention (must match or exceed current nonce)
}

Nonce Field: The nonce field enables signature replay attack prevention for distributor configuration updates. Read the current nonce via nonces(2, distributor) where 2 is the NONCE_DISTRIBUTOR_CONFIG constant. Each distributor has their own independent nonce sequence. Use nonce: 0 for first-time configuration of a distributor.

ClaimVesting

struct ClaimVesting {
    uint256 lastTime;      // Timestamp of last successful claim
    uint256 leftAmount;    // Remaining amount available for claiming
}

Project Lifecycle (v2 Enhanced)

IFIFv2 maintains the same core lifecycle as IFIF v1 but adds automatic transitions and enhanced configuration:

Enhanced Stage Flow

NONE → INIT → PRIVATE_SALE → PUBLIC_SALE → SALE_SUCCESSED/FAILED → CLAIM
       ↓                ↓                ↓                      ↓
   Time-based      Time-based      Enhanced                 Enhanced
   Transition      Transition       Deposit                  Vesting
   (on purchase)   (on purchase)   (multi-dist)             (claims)

Enhanced Stage Features

INIT (1) - Enhanced

  • Automatic Transition: Transitions to PRIVATE_SALE when purchase() is called after privateSaleStartEpoch
  • Configuration: Enhanced with timing controls and purchase limits
  • Deprecations: startPrivateSale() and startPublicSale() are deprecated and will revert

PRIVATE_SALE (2) - Enhanced

  • Automatic Transition: Transitions to PUBLIC_SALE when purchase() is called after private sale duration expires
  • Purchase Validation: Enforces soft cap minimums and hard cap maximums
  • Timing Control: Based on v2 configuration timestamps rather than manual triggers

PUBLIC_SALE (3) - Enhanced

  • Reduced Grace Period: 30-day grace period for publicEndSales() (vs 60 days in v1)
  • Hard Cap Enforcement: Continued enforcement of individual purchase limits

SALE_SUCCESSED (4) - Enhanced

  • Fund Retention: Funds remain in contract for vesting claims (no immediate transfer)
  • Multiple Deposits: Supports multiple distributor deposits with custom fee structures
  • Vesting Setup: Prepares for both owner fund claiming and investor token claiming

CLAIM (6) - Enhanced

  • Vesting Claims: Time-based gradual release for both funds and tokens
  • Configuration Window: Claiming parameters can be set during early CLAIM stage
  • Sweep Protection: 6-month window before unclaimed assets can be recovered

Enhanced View Functions

V2-Specific State

version() → string

Returns "2" to identify this as the enhanced v2 implementation.

sweept() → bool

Returns whether unclaimed assets have been swept by the project owner.

totalLiquidityAmount() → uint256

Returns the total amount of project tokens available for investor claims.

claimStartEpoch() → uint256

Returns the timestamp when the investor claiming period begins.

claimEndEpoch() → uint256

Returns the timestamp when the investor claiming period ends.

claimPeriodLength() → uint256

Returns the duration of each vesting period in seconds (minimum 1 day).

Vesting State

claimVestings(bytes32 vestingKey) → (uint256 lastTime, uint256 leftAmount)

Returns vesting information for a specific vesting schedule identified by the key.

distributorConfigs(address distributor) → (uint256, uint256, uint256)

Returns the fee configuration for a specific distributor (distributor%, owner%, platform%).

Nonce Management (V2 Enhanced)

nonces(uint8 signatureType, address signer) → uint256

Returns the current nonce value for a specific signature type and signer address.

V2 Signature Types:

  • NONCE_NEXT_CONFIG = 0: For NextConfig struct signatures (inherited from IFIF v1)
  • NONCE_FUND_CLAIM_CONFIG = 1: For FundClaimConfig struct signatures (v2 specific)
  • NONCE_DISTRIBUTOR_CONFIG = 2: For DistributorConfig struct signatures (v2 specific, per-distributor)

Key Differences from V1:

  • V2 adds two additional signature types with independent nonce sequences
  • DistributorConfig nonces are tracked per distributor address, not per project owner
  • Each signature type maintains its own independent nonce counter

Usage Examples:

// Read NextConfig nonce (same as v1)
uint256 nextConfigNonce = ififv2.nonces(0, projectOwner);
 
// Read FundClaimConfig nonce (v2 specific)
uint256 fundClaimNonce = ififv2.nonces(1, projectOwner);
 
// Read DistributorConfig nonce (v2 specific, per distributor)
uint256 distributorNonce = ififv2.nonces(2, distributorAddress);

EIP-712 Type Hashes

CONFIG_V2_TYPEHASH() → bytes32

Returns the EIP-712 typehash for Config_v2 struct signature verification (does not include nonce).

FUNDCLAIM_CONFIG_TYPEHASH() → bytes32

Returns the EIP-712 typehash for FundClaimConfig struct signature verification (includes nonce field).

DISTRIBUTOR_CONFIG_TYPEHASH() → bytes32

Returns the EIP-712 typehash for DistributorConfig struct signature verification (includes nonce field).

Enhanced Core Functions

V2 Initialization

initialize_v2()

function initialize_v2(
    Config_v2 calldata config_v2,
    bytes calldata configV2Signature
) external

Purpose: Initializes version 2 enhanced features with timing controls and purchase limits.

Parameters:

  • config_v2: Enhanced configuration with automatic timing and purchase constraints
  • configV2Signature: EIP-712 signature from manager validating v2 configuration

Access: Factory contract only during deployment (reinitializer version 2)

Validations:

  • Private sale start time must be in the future
  • Hard cap percentage must be ≤ 100%
  • Valid manager signature for v2 configuration

Actions:

  • Sets v2 configuration parameters
  • Calculates hard cap amount based on funding goal
  • Emits ConfigV2Updated event

Enhanced Configuration Management

updateFundClaimConfig()

function updateFundClaimConfig(
    FundClaimConfig calldata fundClaimConfig,
    bytes calldata fundClaimConfigSignature
) external onlyOwner

Purpose: Establishes vesting schedule for project owner fund withdrawals with nonce-based replay attack prevention.

Parameters:

  • fundClaimConfig: Vesting parameters for fund claiming including nonce
  • fundClaimConfigSignature: Manager signature authorizing configuration (includes nonce validation)

Requirements:

  • Only project owner can call
  • Must be called before fund claiming starts
  • Nonce must be greater than or equal to current nonce for FundClaimConfig
  • Start epoch must be in the future
  • End epoch must be after start epoch
  • Period length must be at least 1 day
  • Valid manager signature

Nonce Workflow:

  1. Read current nonce: uint256 currentNonce = ififv2.nonces(1, projectOwner) (1 = NONCE_FUND_CLAIM_CONFIG)
  2. Include nonce in fundClaimConfig: fundClaimConfig.nonce = currentNonce
  3. Create manager signature with nonce-aware digest
  4. Contract validates nonce ≥ current, then sets nonce to providedNonce + 1

Events: Emits FundClaimConfigUpdated event and NonceConsumed(1, projectOwner, providedNonce) event

updateDistributorConfig()

function updateDistributorConfig(
    address distributor,
    DistributorConfig calldata distributorConfig,
    bytes[] calldata signatures
) external onlyOwner

Purpose: Updates fee distribution configuration for a specific distributor with nonce-based replay attack prevention.

Parameters:

  • distributor: Address of distributor to configure
  • distributorConfig: New fee structure parameters including nonce
  • signatures: Array of exactly 3 signatures [manager, distributor, project owner]

Multi-signature Validation with Nonce:

  1. Nonce validation: Validates provided nonce against distributor's current nonce
  2. Manager signature: Validates configuration parameters
  3. Distributor signature: Confirms distributor consent to new terms
  4. Project owner signature: Confirms owner approval of fee structure

Requirements:

  • Nonce must be greater than or equal to current nonce for this distributor
  • Total fee percentages must be < 100%
  • Distributor must have DISTRIBUTOR_ROLE
  • All three signatures must be valid

Nonce Workflow:

  1. Read distributor's current nonce: uint256 currentNonce = ififv2.nonces(2, distributorAddress) (2 = NONCE_DISTRIBUTOR_CONFIG)
  2. Include nonce in distributorConfig: distributorConfig.nonce = currentNonce
  3. Create three signatures with nonce-aware digest
  4. Contract validates nonce ≥ current, then sets nonce to providedNonce + 1

Important: Each distributor has their own independent nonce sequence. Updating one distributor's configuration does not affect other distributors' nonces.

Events: Emits DistributorConfigUpdated event and NonceConsumed(2, distributorAddress, providedNonce) event

updateClaimConfig()

function updateClaimConfig(
    uint256 startEpoch,
    uint256 periodLength
) external onlyFactory

Purpose: Configures investor token claiming schedule during CLAIM stage.

Parameters:

  • startEpoch: When investors can start claiming tokens
  • periodLength: Duration of each vesting period (minimum 1 day)

Access: Factory contract only during CLAIM stage initialization

Automatic Calculations:

  • claimEndEpoch = startEpoch + 60 days (2-month claiming window)
  • sweepableEpoch = claimEndEpoch + 180 days (6-month grace before sweep)

Enhanced Purchase System

purchase() - Enhanced

function purchase(
    uint256 amount,
    bytes32[] calldata proof
) external

Enhanced Features:

  • Automatic Stage Transitions: Moves from INIT → PRIVATE_SALE → PUBLIC_SALE based on timestamps
  • Soft Cap Validation: Purchase amount must meet minimum threshold
  • Hard Cap Enforcement: Individual purchase limits based on percentage of funding goal
  • Smart Timing: Uses v2 configuration for precise timing control

Enhanced Validations:

  • Amount ≥ purchaseSoftCap (minimum purchase requirement)
  • User's total purchases + amount ≤ hard cap limit
  • Automatic stage progression based on configured timestamps

Vested Fund Management

claimFund()

function claimFund() external onlyOwner

Purpose: Allows project owner to claim vested funds according to configured schedule.

Requirements:

  • Only project owner can call
  • Project must be in SALE_SUCCESSED stage
  • Fund claim configuration must be set
  • Current time must be after vesting start

Vesting Logic:

  • Calculates claimable amount based on time elapsed and vesting schedule
  • Updates vesting state to prevent double claiming
  • Transfers calculated amount to project owner
  • Maintains remaining vested balance for future claims

Events: Emits FundClaimed event with claimed amount

Enhanced Token Distribution

deposit() - Enhanced

function deposit(uint256 amount) external

Enhanced Features:

  • Distributor-specific Fees: Uses individual distributor configurations instead of global settings
  • Multi-deposit Support: Allows multiple deposits from different distributors
  • Extended Stage Support: Can be called in both SALE_SUCCESSED and CLAIM stages
  • Timing Validation: Prevents deposits after claiming starts

Requirements:

  • Minimum deposit of 1 ether
  • Caller must be a configured distributor (has fee configuration)
  • Must be before claim start time if in CLAIM stage

claim() - Enhanced

function claim() external

Enhanced Features:

  • Vested Claiming: Gradual token release based on configured vesting schedule
  • Timing Controls: Respects claim start/end epochs and sweep status
  • Progressive Release: Calculates claimable amounts using time-based vesting
  • State Management: Updates vesting state and cleans up fully claimed positions

Vesting Calculations:

  • Uses purchase weight and earnings multiplier for base amount
  • Applies time-based vesting to determine currently claimable portion
  • Updates user's vesting state after each claim

convertNFT() - Enhanced

function convertNFT(uint256 tokenId) external

Enhanced Features:

  • NFT Vesting: Separate vesting schedule for each NFT
  • Partial Conversions: Allows gradual conversion based on vesting schedule
  • Smart Burning: Burns NFT only when fully vested and claimed
  • Weight Preservation: Maintains NFT weight throughout vesting period

Asset Recovery

sweep()

function sweep() external onlyFactory

Purpose: Recovers unclaimed assets after extended grace period.

Access: Factory contract only

Requirements:

  • Can only be called by factory contract
  • Must be at least 6 months after claim period ends
  • Cannot be called if already swept
  • Project must be in CLAIM stage

Actions:

  • Transfers all remaining project tokens to factory
  • Transfers any remaining fund tokens to factory
  • Sets sweep flag to prevent future sweeps
  • Factory can then redistribute assets to project owner

Timeline:

  • Claiming period: 2 months from claim start
  • Grace period: 6 months after claiming ends
  • Total window: 8 months before sweep eligibility

Enhanced Sales Termination

endSales() - Enhanced

function endSales() external onlyFactory

Purpose: Factory-controlled sales termination for v2 projects.

Access: Factory contract only (vs owner-controlled in v1)

Enhanced Behavior:

  • Funds remain in contract for vesting claims (vs immediate transfer in v1)
  • Prepares project for vested fund claiming by project owner
  • Centralizes project lifecycle management through factory

publicEndSales()

function publicEndSales() external

Purpose: Emergency sales termination after extended delay.

Access: Anyone can call after 30-day grace period (vs 60 days in v1)

Enhanced Behavior: Same fund retention logic as endSales()

Enhanced NFT Operations

splitNFT() - Enhanced

function splitNFT(
    uint256 tokenId,
    uint256[] calldata tokenWeights
) external

Enhanced Validation:

  • All new NFT weights must meet minNFTWeight requirement from v2 configuration
  • Prevents creation of NFTs below minimum operational threshold
  • Maintains existing split logic from base IFIF contract

Deprecated Functions

Manual Stage Control

function startPrivateSale() external // Reverts with Deprecated()
function startPublicSale() external  // Reverts with Deprecated()

Reason: V2 uses automatic stage transitions based on configured timestamps, eliminating the need for manual stage control.

Reduced Signature Requirements

updateConfig() - Simplified

function updateConfig(
    NextConfig calldata nextConfig_,
    bytes[] calldata signatures
) external

Simplified Requirements:

  • Only 2 signatures required (vs 3 in v1): [manager, project owner]
  • Distributor signature no longer required for general config updates
  • Nonce validation required (same as v1, using NONCE_NEXT_CONFIG type)
  • Cannot be called during CLAIM stage (additional protection)

Nonce Workflow (Same as V1):

  1. Read current nonce: uint256 currentNonce = ififv2.nonces(0, projectOwner)
  2. Include nonce in nextConfig: nextConfig.nonce = currentNonce
  3. Create two signatures (manager + project owner) with nonce-aware digest
  4. Contract validates nonce ≥ current, then sets nonce to providedNonce + 1

Events: Emits ConfigUpdated event and NonceConsumed(0, projectOwner, providedNonce) event

Enhanced Security Features

Multi-signature Authorization with Nonce Validation

  • Distributor Configuration: Requires manager + distributor + owner signatures with distributor's nonce (3 signatures)
  • Fund Claim Configuration: Requires manager signature with project owner's nonce for vesting setup (1 signature)
  • Config Updates: Simplified to manager + owner signatures with project owner's nonce (2 vs 3 in v1)
  • Independent Nonce Sequences: Each signature type (NextConfig, FundClaimConfig, DistributorConfig) maintains separate nonce counters
  • Per-Distributor Nonces: DistributorConfig nonces are tracked per distributor address, not per project

Timing-based Security

  • Automatic Transitions: Eliminates manual timing manipulation
  • Vesting Protection: Prevents premature fund/token claims
  • Grace Periods: Extended recovery windows for various operations

Enhanced Validation

  • Purchase Limits: Hard and soft caps prevent abuse
  • Minimum Weights: Prevents spam NFT creation
  • Configuration Validation: Comprehensive parameter checking

Events (V2 Enhanced)

New V2 Events

event ConfigV2Updated(Config_v2 config_v2);
event FundClaimConfigUpdated(FundClaimConfig fundClaimConfig);
event FundClaimed(uint256 amount);
event DistributorConfigUpdated(address indexed distributor, DistributorConfig distributorConfig);
event ClaimConfigUpdated(uint256 startEpoch, uint256 endEpoch, uint256 sweepEpoch, uint256 periodLength);
event Sweept(uint256 fundAmount, uint256 tokenAmount);
event NonceConsumed(uint8 indexed signatureType, address indexed signer, uint256 nonce); // Inherited from SignatureNonceManager

V2 Nonce Events

IFIFv2 emits NonceConsumed events for all three signature types:

  • Type 0 (NONCE_NEXT_CONFIG): When updateConfig() is called with project owner's signature
  • Type 1 (NONCE_FUND_CLAIM_CONFIG): When updateFundClaimConfig() is called with project owner's nonce
  • Type 2 (NONCE_DISTRIBUTOR_CONFIG): When updateDistributorConfig() is called with distributor's nonce

Each event tracks which signature type was used, who signed it, and what nonce value was consumed.

Enhanced Existing Events

  • All base IFIF events are maintained with same functionality
  • Enhanced with additional context where applicable

Integration Examples

V2 Project Initialization

// V2 projects are deployed through the same factory but require additional initialization
const factory = await ethers.getContractAt("IFIFFactory", factoryAddress);
 
// First deploy the base project (same as v1)
const deployTx = await factory.deploy(
  baseConfig,
  nextConfig,
  configSignature,
  nextConfigSignature,
  projectName,
  projectSymbol,
  paymentToken
);
 
// Get the deployed project address
const receipt = await deployTx.wait();
const projectAddress = receipt.logs[0].address; // Extract from deployment logs
const projectV2 = await ethers.getContractAt("IFIFv2", projectAddress);
 
// V2 configuration with timing and limits
const config_v2 = {
  privateSaleStartEpoch: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
  purchaseHardCapPercent: 10, // Max 10% of funding goal per user
  purchaseSoftCap: ethers.parseEther("100"), // Minimum 100 USDC per purchase
  minNFTWeight: ethers.parseEther("50") // Minimum NFT weight for operations
};
 
// Initialize v2 features (separate call)
const initV2Tx = await projectV2.initialize_v2(config_v2, v2ConfigSignature);

Enhanced Purchase Flow

const projectV2 = await ethers.getContractAt("IFIFv2", projectAddress);
 
// Note: V2 config is internal, not directly accessible via view function
// Check current stage and validate purchase amount against known limits
const currentStage = await projectV2.stage();
const userPurchases = await projectV2.purchases(userAddress);
 
// Execute purchase (stages transition automatically based on timestamps)
const purchaseTx = await projectV2.purchase(purchaseAmount, merkleProof);

Vested Fund Claiming

// Project owner sets up fund claiming vesting with nonce
const projectOwner = await projectV2.owner();
const currentNonce = await projectV2.nonces(1, projectOwner); // 1 = NONCE_FUND_CLAIM_CONFIG
 
const fundClaimConfig = {
  startEpoch: Math.floor(Date.now() / 1000) + 86400, // 1 day from now
  endEpoch: Math.floor(Date.now() / 1000) + 86400 * 180, // 6 months vesting
  periodLength: 86400 * 7, // Weekly claims
  nonce: currentNonce // Include current nonce for replay attack prevention
};
 
// Create manager signature with nonce-aware digest
const managerSignature = await createFundClaimConfigSignature(
  projectV2.address,
  fundClaimConfig
);
 
const updateTx = await projectV2.updateFundClaimConfig(
  fundClaimConfig,
  managerSignature
);
 
// Check that nonce was incremented
const newNonce = await projectV2.nonces(1, projectOwner);
console.log(`Nonce incremented: ${currentNonce} -> ${newNonce}`);
 
// Project owner claims vested funds periodically
const claimTx = await projectV2.claimFund();

Enhanced Token Claiming

// Configure investor token claiming (called by factory during CLAIM stage)
const claimStartEpoch = Math.floor(Date.now() / 1000) + 86400; // 1 day from now
const periodLength = 86400 * 7; // Weekly vesting
 
// Note: updateClaimConfig is called by factory, not directly by users
const factory = await ethers.getContractAt("IFIFFactory", factoryAddress);
await factory.updateClaimConfig(projectAddress, claimStartEpoch, periodLength);
 
// Investors claim vested tokens
const userClaimTx = await projectV2.connect(investor).claim();
 
// Or convert NFT with vesting
const convertTx = await projectV2.connect(nftOwner).convertNFT(tokenId);

Distributor Configuration with Per-Distributor Nonces

// Each distributor has their own independent nonce sequence
const distributorAddress = "0x...";
const currentNonce = await projectV2.nonces(2, distributorAddress); // 2 = NONCE_DISTRIBUTOR_CONFIG
 
const distributorConfig = {
  distributorFeePercent: 3,
  projectOwnerFeePercent: 5,
  platformFeePercent: 2,
  nonce: currentNonce // Use distributor's current nonce
};
 
// Create three signatures with nonce-aware digest
const signatures = await createDistributorConfigSignatures(
  projectV2.address,
  distributorAddress,
  distributorConfig
);
 
const updateTx = await projectV2.updateDistributorConfig(
  distributorAddress,
  distributorConfig,
  signatures // [manager, distributor, project owner]
);
 
// Verify distributor's nonce was incremented
const newNonce = await projectV2.nonces(2, distributorAddress);
console.log(`Distributor nonce: ${currentNonce} -> ${newNonce}`);
 
// Important: Other distributors' nonces are unaffected
const otherDistributor = "0x...";
const otherNonce = await projectV2.nonces(2, otherDistributor);
console.log(`Other distributor nonce unchanged: ${otherNonce}`);

Asset Recovery

// After 6 months grace period, factory can sweep unclaimed assets
const factory = await ethers.getContractAt("IFIFFactory", factoryAddress);
const sweepTx = await factory.sweep(projectAddress);
 
// Note: After sweep, factory receives the assets and can handle redistribution
// The specific redistribution mechanism depends on factory implementation

Testing Coverage

IFIFv2 maintains comprehensive test coverage including:

  • V2 Initialization: Enhanced configuration validation and signature verification
  • Automatic Transitions: Time-based stage progression testing
  • Vesting Mechanisms: Fund and token vesting calculations and claims
  • Enhanced Purchases: Hard cap, soft cap, and timing validations
  • Multi-signature Operations: Distributor configuration and reduced signature requirements
  • Asset Recovery: Sweep functionality and timing validations
  • Backward Compatibility: Ensures v1 functionality remains intact where applicable

Migration from V1 to V2

Key Differences

  1. Manual → Automatic: Stage transitions become time-based
  2. Immediate → Vested: Fund transfers become vesting-based claims
  3. Global → Individual: Distributor configurations become address-specific
  4. Basic → Enhanced: Purchase controls add caps and minimums

Deployment Considerations

  • V2 projects require additional configuration parameters
  • Enhanced timing precision requires careful timestamp management
  • Vesting schedules need proper configuration for both funds and tokens
  • Multi-signature requirements may need workflow adjustments

For detailed implementation examples and migration guides, see the Examples section.