module incatokens import freeflowuniverse.herolib.biz.spreadsheet // Initialize default investor rounds pub fn (mut sim Simulation) init_default_rounds() ! { sim.investor_rounds = [ InvestorRound{ name: 'R1' allocation_pct: 0.05 price: 0.005 vesting: VestingSchedule{cliff_months: 6, vesting_months: 24} }, InvestorRound{ name: 'R2' allocation_pct: 0.075 price: 0.009 vesting: VestingSchedule{cliff_months: 6, vesting_months: 24} }, InvestorRound{ name: 'R3' allocation_pct: 0.075 price: 0.0106 vesting: VestingSchedule{cliff_months: 6, vesting_months: 24} } ] sim.team_vesting = VestingSchedule{cliff_months: 12, vesting_months: 36} sim.treasury_vesting = VestingSchedule{cliff_months: 12, vesting_months: 48} } // Run a scenario with given demands and AMM trades pub fn (mut sim Simulation) run_scenario(name string, demands []f64, amm_trades []f64) !&Scenario { mut scenario := &Scenario{ name: name demands: demands amm_trades: amm_trades } // Initialize epochs scenario.epochs = [ Epoch{index: 0, type_: .auction_only, start_month: 0, end_month: 3, auction_share: 1.0, amm_share: 0.0}, Epoch{index: 1, type_: .hybrid, start_month: 3, end_month: 6, auction_share: 0.5, amm_share: 0.5}, Epoch{index: 2, type_: .amm_only, start_month: 6, end_month: 12, auction_share: 0.0, amm_share: 1.0} ] // Track in spreadsheet mut price_row := sim.price_sheet.row_new( name: 'scenario_${name}_price' tags: 'scenario:${name} type:price' descr: 'Token price evolution for ${name} scenario' )! mut treasury_row := sim.investment_sheet.row_new( name: 'scenario_${name}_treasury' tags: 'scenario:${name} type:treasury' descr: 'Treasury raised for ${name} scenario' aggregatetype: .sum )! // Calculate public tokens per epoch total_public := sim.total_supply * sim.public_pct tokens_per_epoch := total_public / 3.0 mut last_auction_price := sim.get_last_investor_price() mut spillover := 0.0 mut treasury_total := 0.0 mut amm_pool := AMMPool{} for mut epoch in scenario.epochs { epoch.tokens_allocated = tokens_per_epoch + spillover epoch.auction_demand = demands[epoch.index] epoch.amm_net_trade = amm_trades[epoch.index] // Run auction if applicable if epoch.auction_share > 0 { auction_tokens := epoch.tokens_allocated * epoch.auction_share floor_price := sim.calculate_floor_price(epoch.index, last_auction_price) auction_result := simulate_auction( demand: epoch.auction_demand min_price: floor_price token_supply: auction_tokens )! epoch.treasury_raised = auction_result.usd_raised treasury_total += auction_result.usd_raised last_auction_price = auction_result.clearing_price epoch.final_price = auction_result.clearing_price spillover = auction_tokens - auction_result.tokens_sold // Record in spreadsheet treasury_row.cells[epoch.start_month].val = auction_result.usd_raised } // Handle AMM if applicable if epoch.amm_share > 0 { amm_tokens := epoch.tokens_allocated * epoch.amm_share + spillover spillover = 0 // Seed AMM pool amm_usdc_to_add := sim.amm_liquidity_depth_factor * epoch.treasury_raised amm_pool.add_liquidity(amm_tokens, amm_usdc_to_add) // Simulate trading if epoch.amm_net_trade != 0 { amm_pool.trade(epoch.amm_net_trade)! } epoch.final_price = amm_pool.get_price() } // Record price in spreadsheet for month in epoch.start_month .. epoch.end_month { price_row.cells[month].val = epoch.final_price } epoch.tokens_spillover = spillover } // Calculate final metrics scenario.final_metrics = sim.calculate_metrics(scenario, treasury_total)! sim.scenarios[name] = scenario return scenario } // Calculate metrics for scenario fn (sim Simulation) calculate_metrics(scenario &Scenario, treasury_total f64) !ScenarioMetrics { final_price := scenario.epochs.last().final_price mut investor_roi := map[string]f64{} for round in sim.investor_rounds { investor_roi[round.name] = final_price / round.price } return ScenarioMetrics{ treasury_total: treasury_total final_price: final_price investor_roi: investor_roi market_cap_final: final_price * sim.total_supply circulating_supply_final: sim.calculate_circulating_supply(12) // at month 12 } } fn (sim Simulation) get_last_investor_price() f64 { mut max_price := 0.0 for round in sim.investor_rounds { if round.price > max_price { max_price = round.price } } return max_price } fn (sim Simulation) calculate_floor_price(epoch_idx int, last_auction_price f64) f64 { last_investor_price := sim.get_last_investor_price() if epoch_idx == 0 { return last_investor_price * sim.epoch1_floor_uplift } return last_auction_price * sim.epochn_floor_uplift } fn (sim Simulation) calculate_circulating_supply(month int) f64 { // Base circulation (non-public allocations) investor_tokens := sim.investor_pct * sim.total_supply team_tokens := sim.team_pct * sim.total_supply treasury_tokens := sim.treasury_pct * sim.total_supply // For simplicity, assume all public tokens are circulating after TGE public_tokens := sim.public_pct * sim.total_supply return investor_tokens + team_tokens + treasury_tokens + public_tokens }