Files
herolib/lib/threefold/incatokens/simulation.v
2025-08-26 11:36:53 +02:00

175 lines
5.2 KiB
V

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
}