175 lines
5.2 KiB
V
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
|
|
} |