This commit is contained in:
2025-08-27 10:20:52 +02:00
parent 791988c420
commit db9d2b5a0a
9 changed files with 400 additions and 239 deletions

View File

@@ -0,0 +1,165 @@
V allows for easily using text templates, expanded at compile time to
V functions, that efficiently produce text output. This is especially
useful for templated HTML views, but the mechanism is general enough
to be used for other kinds of text output also.
# Template directives
Each template directive begins with an `@` sign.
Some directives contain a `{}` block, others only have `''` (string) parameters.
Newlines on the beginning and end are ignored in `{}` blocks,
otherwise this (see [if](#if) for this syntax):
```html
@if bool_val {
<span>This is shown if bool_val is true</span>
}
```
... would output:
```html
<span>This is shown if bool_val is true</span>
```
... which is less readable.
## if
The if directive, consists of three parts, the `@if` tag, the condition (same syntax like in V)
and the `{}` block, where you can write html, which will be rendered if the condition is true:
```
@if <condition> {}
```
### Example
```html
@if bool_val {
<span>This is shown if bool_val is true</span>
}
```
One-liner:
```html
@if bool_val { <span>This is shown if bool_val is true</span> }
```
The first example would result in:
```html
<span>This is shown if bool_val is true</span>
```
... while the one-liner results in:
```html
<span>This is shown if bool_val is true</span>
```
## for
The for directive consists of three parts, the `@for` tag,
the condition (same syntax like in V) and the `{}` block,
where you can write text, rendered for each iteration of the loop:
```
@for <condition> {}
```
### Example for @for
```html
@for i, val in my_vals {
<span>$i - $val</span>
}
```
One-liner:
```html
@for i, val in my_vals { <span>$i - $val</span> }
```
The first example would result in:
```html
<span>0 - "First"</span>
<span>1 - "Second"</span>
<span>2 - "Third"</span>
...
```
... while the one-liner results in:
```html
<span>0 - "First"</span>
<span>1 - "Second"</span>
<span>2 - "Third"</span>
...
```
You can also write (and all other for condition syntaxes that are allowed in V):
```html
@for i = 0; i < 5; i++ {
<span>$i</span>
}
```
## include
The include directive is for including other html files (which will be processed as well)
and consists of two parts, the `@include` tag and a following `'<path>'` string.
The path parameter is relative to the template file being called.
### Example for the folder structure of a project using templates:
```
Project root
/templates
- index.html
/headers
- base.html
```
`index.html`
```html
<div>@include 'header/base'</div>
```
> Note that there shouldn't be a file suffix,
> it is automatically appended and only allows `html` files.
## js
The js directive consists of two parts, the `@js` tag and `'<path>'` string,
where you can insert your src
```
@js '<url>'
```
### Example for the @js directive:
```html
@js 'myscripts.js'
```
# Variables
All variables, which are declared before the $tmpl can be used through the `@{my_var}` syntax.
It's also possible to use properties of structs here like `@{my_struct.prop}`.
# Escaping
The `@` symbol starts a template directive. If you need to use `@` as a regular
character within a template, escape it by using a double `@` like this: `@@`.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.threefold.incatokens
import os
import freeflowuniverse.herolib.core.playcmds
current_dir := os.dir(@FILE)

View File

@@ -4,6 +4,15 @@ import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.ui.console
import time
// Struct to hold all data for the report template
pub struct ReportData {
pub mut:
sim &Simulation
generation_date string
total_raised f64
initial_price f64
}
// Export data to CSV
pub fn (sim Simulation) export_csv(sheet_name string, path string) ! {
mut sheet := match sheet_name {
@@ -23,104 +32,68 @@ pub fn (sim Simulation) export_csv(sheet_name string, path string) ! {
console.print_debug('Finished exporting sheet "${sheet_name}".')
}
pub fn (sim Simulation) generate_distribution_section() !string {
// Generate a single scenario section for use in templates
pub fn (sim Simulation) generate_scenario_section(scenario_name string) !string {
scenario := sim.scenarios[scenario_name] or { return error('Scenario not found: ${scenario_name}') }
mut lines := []string{}
lines << '- **Total supply:** ${sim.params.distribution.total_supply} INCA'
lines << '- **Public (TGE):** ${(sim.params.distribution.public_pct * 100).str()}% (No lockup)'
lines << '- **Team:** ${(sim.params.distribution.team_pct * 100).str()}% (${sim.team_vesting.cliff_months}mo cliff, ${sim.team_vesting.vesting_months}mo vest)'
lines << '- **Treasury:** ${(sim.params.distribution.treasury_pct * 100).str()}% (${sim.treasury_vesting.cliff_months}mo cliff, ${sim.treasury_vesting.vesting_months}mo vest)'
lines << '- **Investors:** ${(sim.params.distribution.investor_pct * 100).str()}%'
lines << ''
lines << '### Investor Rounds & Vesting'
lines << '| Round | Allocation | Price (USD) | Vesting Schedule |'
lines << '|---|---|---|---|'
for round in sim.investor_rounds {
lines << '| **${round.name}** | ${(round.allocation_pct * 100).str()}% | \$${round.price} | ${round.vesting.cliff_months}mo cliff, ${round.vesting.vesting_months}mo linear vest |'
}
return lines.join('\n')
}
pub fn (sim Simulation) generate_scenario_section(scenario &Scenario) !string {
mut lines := []string{}
lines << '### ${scenario.name} Scenario'
lines << '**Parameters:**'
lines << '- **Auction Demand:** \$${scenario.demands.map(it.str()).join(', ')}'
lines << '- **AMM Net Trade:** \$${scenario.amm_trades.map(it.str()).join(', ')}'
lines << ''
lines << '**Results:**'
lines << '| Treasury Raised | Final Price | ${sim.investor_rounds.map("ROI " + it.name).join(" | ")} |'
lines << '|:---|:---|${sim.investor_rounds.map(":---").join("|")}|'
mut row := ['\$${(scenario.final_metrics.treasury_total / 1000000).str()}M', '\$${scenario.final_metrics.final_price}']
// Create table header
mut header := ['Treasury Raised', 'Final Price']
for round in sim.investor_rounds {
header << 'ROI ${round.name}'
}
lines << '| ${header.join(' | ')} |'
// Create separator row
mut separator := [':---', ':---']
for _ in sim.investor_rounds {
separator << ':---'
}
lines << '| ${separator.join('|')} |'
// Create data row
mut row := ['\$${(scenario.final_metrics.treasury_total / 1_000_000):.1f}M', '\$${scenario.final_metrics.final_price:.4f}']
for round in sim.investor_rounds {
roi := scenario.final_metrics.investor_roi[round.name] or { 0.0 }
row << '${roi}x'
row << '${roi:.2f}x'
}
lines << '| ${row.join(' | ')} |'
return lines.join('\n')
}
pub fn (sim Simulation) generate_financial_summary() !string {
mut lines := []string{}
lines << '### Funds Raised for INCA COOP'
lines << '| Round | USD Raised |'
lines << '|---|---|'
mut total_raised := 0.0
// Calculate total funds raised across all investor rounds
fn (sim Simulation) calculate_total_raised() f64 {
mut total := 0.0
for round in sim.investor_rounds {
raised := round.allocation_pct * sim.params.distribution.total_supply * round.price
total_raised += raised
lines << '| **${round.name}** | \$${raised} |'
total += raised
}
lines << '| **Total** | **\$${total_raised}** |'
return lines.join('\n')
return total
}
// Method to generate report from simulation
pub fn (sim Simulation) generate_report(output_dir string) ! {
// Ensure output directory exists
mut output_path := pathlib.get_dir(path: output_dir, create: true)!
// Prepare template variables
mut vars := map[string]string{}
vars['name'] = sim.name
vars['total_supply'] = sim.total_supply.str()
vars['nrcol'] = sim.price_sheet.nrcol.str()
vars['currency'] = sim.currency
vars['team_cliff_months'] = sim.team_vesting.cliff_months.str()
vars['team_vesting_months'] = sim.team_vesting.vesting_months.str()
vars['team_allocation'] = (sim.total_supply * sim.team_pct).str()
vars['team_pct'] = (sim.team_pct * 100).str()
vars['treasury_cliff_months'] = sim.treasury_vesting.cliff_months.str()
vars['treasury_vesting_months'] = sim.treasury_vesting.vesting_months.str()
vars['treasury_allocation'] = (sim.total_supply * sim.treasury_pct).str()
vars['treasury_pct'] = (sim.treasury_pct * 100).str()
vars['epoch1_floor_uplift'] = sim.epoch1_floor_uplift.str()
vars['epochn_floor_uplift'] = sim.epochn_floor_uplift.str()
vars['amm_liquidity_depth_factor'] = sim.amm_liquidity_depth_factor.str()
vars['generation_date'] = time.now().format()
// Generate sections
vars['distribution_section'] = sim.generate_distribution_section()!
vars['scenarios_section'] = sim.generate_scenarios_section()!
vars['financial_summary'] = sim.generate_financial_summary()!
vars['roi_analysis'] = sim.generate_roi_analysis()!
vars['price_analysis'] = sim.generate_price_analysis()!
vars['market_cap_analysis'] = sim.generate_market_cap_analysis()!
vars['conclusions'] = sim.generate_conclusions()!
data := ReportData{
sim: &sim
generation_date: time.now().format()
total_raised: sim.calculate_total_raised()
initial_price: sim.get_last_investor_price()
}
// Process template
mut content := report_template
for key, value in vars {
content = content.replace('{{.${key}}}', value)
}
content := $tmpl('templates/report.md')
// Write report
report_path := '${output_path.path}/${sim.name}_report.md'
@@ -128,82 +101,4 @@ pub fn (sim Simulation) generate_report(output_dir string) ! {
report_file.write(content)!
console.print_green(' Report generated: ${report_path}')
}
// Additional template methods for generating report sections
pub fn (sim Simulation) generate_scenarios_section() !string {
mut lines := []string{}
for name, scenario in sim.scenarios {
lines << sim.generate_scenario_section(scenario)!
lines << ''
}
return lines.join('\n')
}
pub fn (sim Simulation) generate_roi_analysis() !string {
mut lines := []string{}
lines << '| Investor Round | Price | Allocation | '
for scenario_name, _ in sim.scenarios {
lines[0] += '${scenario_name} ROI | '
}
lines << '|' + '---|'.repeat(3 + sim.scenarios.len)
for round in sim.investor_rounds {
mut row := '| **${round.name}** | \$${round.price} | ${(round.allocation_pct * 100).str()}% | '
for scenario_name, scenario in sim.scenarios {
roi := scenario.final_metrics.investor_roi[round.name] or { 0.0 }
row += '${roi:.2f}x | '
}
lines << row
}
return lines.join('\n')
}
pub fn (sim Simulation) generate_price_analysis() !string {
mut lines := []string{}
lines << '| Scenario | Final Price | Price Change |'
lines << '|---|---|---|'
initial_price := sim.get_last_investor_price()
for name, scenario in sim.scenarios {
final_price := scenario.final_metrics.final_price
change_pct := ((final_price - initial_price) / initial_price) * 100
lines << '| **${name}** | \$${final_price:.4f} | ${change_pct:+.1f}% |'
}
return lines.join('\n')
}
pub fn (sim Simulation) generate_market_cap_analysis() !string {
mut lines := []string{}
lines << '| Scenario | Market Cap | Market Cap Range |'
lines << '|---|---|---|'
for name, scenario in sim.scenarios {
mc := scenario.final_metrics.market_cap_final / 1_000_000 // In millions
lines << '| **${name}** | \$${mc:.1f}M | Varies by circulating supply |'
}
return lines.join('\n')
}
pub fn (sim Simulation) generate_conclusions() !string {
mut lines := []string{}
lines << 'Based on the simulation results:'
lines << ''
lines << '1. **Token Price Sensitivity**: The final token price shows significant sensitivity to market demand levels'
lines << '2. **Investor Returns**: All investor rounds show positive returns across scenarios'
lines << '3. **Treasury Funding**: The INCA COOP successfully raises substantial funding through the token sale'
lines << '4. **Market Dynamics**: The combination of auction and AMM mechanisms provides price discovery and liquidity'
lines << ''
lines << 'The simulation demonstrates a robust token economic model that balances investor returns, treasury funding, and market dynamics.'
return lines.join('\n')
}

View File

@@ -0,0 +1,140 @@
# INCA Token Economic Simulation Report
## Executive Summary
This report presents the results of the INCA token economic simulation **@{data.sim.name}**, analyzing various market scenarios and their impact on token distribution, pricing, and investor returns.
### Key Parameters
- **Total Token Supply**: @{data.sim.params.distribution.total_supply} INCA
- **Simulation Period**: @{data.sim.params.simulation.nrcol} months
- **Base Currency**: @{data.sim.params.simulation.currency}
## Token Distribution & Allocation
- **Total supply:** @{data.sim.params.distribution.total_supply} INCA
- **Public (TGE):** @{(data.sim.params.distribution.public_pct * 100)}% (No lockup)
- **Team:** @{(data.sim.params.distribution.team_pct * 100)}% (@{data.sim.team_vesting.cliff_months}mo cliff, @{data.sim.team_vesting.vesting_months}mo vest)
- **Treasury:** @{(data.sim.params.distribution.treasury_pct * 100)}% (@{data.sim.treasury_vesting.cliff_months}mo cliff, @{data.sim.treasury_vesting.vesting_months}mo vest)
- **Investors:** @{(data.sim.params.distribution.investor_pct * 100)}%
### Investor Rounds & Vesting
| Round | Allocation | Price (USD) | Vesting Schedule |
|---|---|---|---|
@for round in data.sim.investor_rounds {
| **@{round.name}** | @{(round.allocation_pct * 100)}% | $@{round.price} | @{round.vesting.cliff_months}mo cliff, @{round.vesting.vesting_months}mo linear vest |
}
@end
## Vesting Schedules
### Team Vesting
- **Cliff Period**: @{data.sim.team_vesting.cliff_months} months
- **Vesting Period**: @{data.sim.team_vesting.vesting_months} months
- **Total Team Allocation**: @{(data.sim.params.distribution.total_supply * data.sim.params.distribution.team_pct)} INCA (@{(data.sim.params.distribution.team_pct * 100)}%)
### Treasury Vesting
- **Cliff Period**: @{data.sim.treasury_vesting.cliff_months} months
- **Vesting Period**: @{data.sim.treasury_vesting.vesting_months} months
- **Total Treasury Allocation**: @{(data.sim.params.distribution.total_supply * data.sim.params.distribution.treasury_pct)} INCA (@{(data.sim.params.distribution.treasury_pct * 100)}%)
## Economic Parameters
- **Epoch 1 Floor Uplift**: @{data.sim.params.economics.epoch1_floor_uplift}x
- **Subsequent Epoch Floor Uplift**: @{data.sim.params.economics.epochn_floor_uplift}x
- **AMM Liquidity Depth Factor**: @{data.sim.params.economics.amm_liquidity_depth_factor}x
## Simulation Scenarios
@for name, scenario in data.sim.scenarios {
### @{scenario.name} Scenario
**Parameters:**
- **Auction Demand:** $@{scenario.demands.map(it.str()).join(', ')}
- **AMM Net Trade:** $@{scenario.amm_trades.map(it.str()).join(', ')}
**Results:**
| Treasury Raised | Final Price | @for round in data.sim.investor_rounds {@{round.name} ROI | }|
|:---|:---|@for round in data.sim.investor_rounds {:---|}
| $@{(scenario.final_metrics.treasury_total / 1_000_000):.1f}M | $@{scenario.final_metrics.final_price:.4f} | @for round in data.sim.investor_rounds {@{(scenario.final_metrics.investor_roi[round.name] or { 0.0 }):.2f}x | }
}
## Financial Summary
### Funds Raised for INCA COOP
| Round | USD Raised |
|---|---|
@for round in data.sim.investor_rounds {
| **@{round.name}** | $@{(round.allocation_pct * data.sim.params.distribution.total_supply * round.price)} |
}
| **Total** | **$@{data.total_raised}** |
## Investment Analysis
### Return on Investment by Round
| Investor Round | Price | Allocation | @for scenario_name, _ in data.sim.scenarios {@{scenario_name} ROI | }|
|---|---|---|@for scenario_name, _ in data.sim.scenarios {---|}
@for round in data.sim.investor_rounds {
| **@{round.name}** | $@{round.price} | @{(round.allocation_pct * 100)}% | @for scenario_name, scenario in data.sim.scenarios {@{(scenario.final_metrics.investor_roi[round.name] or { 0.0 }):.2f}x | }
}
## Market Dynamics
### Price Evolution
The token price evolution across different scenarios shows:
| Scenario | Final Price | Price Change |
|---|---|---|
@for name, scenario in data.sim.scenarios {
| **@{name}** | $@{scenario.final_metrics.final_price:.4f} | @{(((scenario.final_metrics.final_price - data.initial_price) / data.initial_price) * 100):+.1f}% |
}
### Market Capitalization
The projected market capitalization ranges show:
| Scenario | Market Cap | Market Cap Range |
|---|---|---|
@for name, scenario in data.sim.scenarios {
| **@{name}** | $@{(scenario.final_metrics.market_cap_final / 1_000_000):.1f}M | Varies by circulating supply |
}
## Risk Analysis
### Scenario Sensitivity
The simulation reveals the following sensitivities:
@for name, scenario in data.sim.scenarios {
- **@{name} Scenario**: @if name == 'Conservative' {Conservative market conditions with limited speculation}@if name == 'Moderate' {Moderate market interest and trading activity}@if name == 'Optimistic' {Strong market demand and active secondary trading}@if name != 'Conservative' && name != 'Moderate' && name != 'Optimistic' {Market scenario with specific demand patterns}
}
### Key Risk Factors
1. **Market Demand Volatility**: Significant impact on final token prices
2. **AMM Pool Dynamics**: Trading activity affects liquidity and price stability
3. **Vesting Schedule Impact**: Lock-up periods influence circulating supply
## Conclusions
Based on the simulation results:
1. **Token Price Sensitivity**: The final token price shows significant sensitivity to market demand levels
2. **Investor Returns**: All investor rounds show positive returns across scenarios
3. **Treasury Funding**: The INCA COOP successfully raises substantial funding through the token sale
4. **Market Dynamics**: The combination of auction and AMM mechanisms provides price discovery and liquidity
The simulation demonstrates a robust token economic model that balances investor returns, treasury funding, and market dynamics.
## Appendices
### A. Methodology
This simulation uses a simplified Dutch auction model combined with AMM (Automated Market Maker) dynamics to project token price evolution.
### B. Assumptions
- All investor rounds are fully subscribed
- Vesting schedules are strictly enforced
- Market dynamics follow the implemented auction and AMM models
---
*Report generated on @{data.generation_date} using INCA Token Simulation Framework*

View File

@@ -2,90 +2,28 @@
## Executive Summary
This report presents the results of the INCA token economic simulation **{{.name}}**, analyzing various market scenarios and their impact on token distribution, pricing, and investor returns.
This report presents the results of the INCA token economic simulation **@{data.sim.name}**, analyzing various market scenarios and their impact on token distribution, pricing, and investor returns.
### Key Parameters
- **Total Token Supply**: {{.total_supply}} INCA
- **Simulation Period**: {{.nrcol}} months
- **Base Currency**: {{.currency}}
- **Total Token Supply**: @{data.sim.params.distribution.total_supply} INCA
- **Simulation Period**: @{data.sim.params.simulation.nrcol} months
- **Base Currency**: @{data.sim.params.simulation.currency}
## Token Distribution & Allocation
{{.distribution_section}}
- **Total supply:** @{data.sim.params.distribution.total_supply} INCA
- **Public (TGE):** @{(data.sim.params.distribution.public_pct * 100)}% (No lockup)
- **Team:** @{(data.sim.params.distribution.team_pct * 100)}% (@{data.sim.team_vesting.cliff_months}mo cliff, @{data.sim.team_vesting.vesting_months}mo vest)
- **Treasury:** @{(data.sim.params.distribution.treasury_pct * 100)}% (@{data.sim.treasury_vesting.cliff_months}mo cliff, @{data.sim.treasury_vesting.vesting_months}mo vest)
- **Investors:** @{(data.sim.params.distribution.investor_pct * 100)}%
## Vesting Schedules
### Team Vesting
- **Cliff Period**: {{.team_cliff_months}} months
- **Vesting Period**: {{.team_vesting_months}} months
- **Total Team Allocation**: {{.team_allocation}} INCA ({{.team_pct}}%)
### Investor Rounds & Vesting
### Treasury Vesting
- **Cliff Period**: {{.treasury_cliff_months}} months
- **Vesting Period**: {{.treasury_vesting_months}} months
- **Total Treasury Allocation**: {{.treasury_allocation}} INCA ({{.treasury_pct}}%)
| Round | Allocation | Price (USD) | Vesting Schedule |
|---|---|---|---|
@for round in data.sim.investor_rounds
| **@{round.name}** | @{(round.allocation_pct * 100)}% | $@{round.price} | @{round.vesting.cliff_months}mo cliff, @{round.vesting.vesting_months}mo linear vest |
@end
## Economic Parameters
- **Epoch 1 Floor Uplift**: {{.epoch1_floor_uplift}}x
- **Subsequent Epoch Floor Uplift**: {{.epochn_floor_uplift}}x
- **AMM Liquidity Depth Factor**: {{.amm_liquidity_depth_factor}}x
## Simulation Scenarios
{{.scenarios_section}}
## Financial Summary
{{.financial_summary}}
## Investment Analysis
### Return on Investment by Round
{{.roi_analysis}}
## Market Dynamics
### Price Evolution
The token price evolution across different scenarios shows:
{{.price_analysis}}
### Market Capitalization
The projected market capitalization ranges show:
{{.market_cap_analysis}}
## Risk Analysis
### Scenario Sensitivity
The simulation reveals the following sensitivities:
- **Low Demand Scenario**: Conservative market conditions with limited speculation
- **Medium Demand Scenario**: Moderate market interest and trading activity
- **High Demand Scenario**: Strong market demand and active secondary trading
### Key Risk Factors
1. **Market Demand Volatility**: Significant impact on final token prices
2. **AMM Pool Dynamics**: Trading activity affects liquidity and price stability
3. **Vesting Schedule Impact**: Lock-up periods influence circulating supply
## Conclusions
{{.conclusions}}
## Appendices
### A. Methodology
This simulation uses a simplified Dutch auction model combined with AMM (Automated Market Maker) dynamics to project token price evolution.
### B. Assumptions
- All investor rounds are fully subscribed
- Vesting schedules are strictly enforced
- Market dynamics follow the implemented auction and AMM models
---
*Report generated on {{.generation_date}} using INCA Token Simulation Framework*

View File

@@ -5,8 +5,9 @@ import freeflowuniverse.herolib.biz.spreadsheet
// VestingSchedule defines cliff and vesting periods
pub struct VestingSchedule {
pub mut:
cliff_months int
vesting_months int
cliff_months int
vesting_months int
initial_unlock_pct f64 // Percentage of tokens unlocked at month 0
}
// InvestorRound represents an investment round

View File

@@ -8,11 +8,11 @@ pub fn (mut sim Simulation) create_vesting_schedules() ! {
mut vesting_sheet := spreadsheet.sheet_new(
name: '${sim.name}_vesting'
nrcol: 60 // 60 months
curr: sim.currency
curr: sim.params.simulation.currency
)!
// Team vesting
team_tokens := sim.total_supply * sim.team_pct
team_tokens := sim.params.distribution.total_supply * sim.params.distribution.team_pct
mut team_row := vesting_sheet.row_new(
name: 'team_vesting'
tags: 'category:team type:vesting'
@@ -21,7 +21,7 @@ pub fn (mut sim Simulation) create_vesting_schedules() ! {
sim.apply_vesting_schedule(mut team_row, team_tokens, sim.team_vesting)!
// Treasury vesting
treasury_tokens := sim.total_supply * sim.treasury_pct
treasury_tokens := sim.params.distribution.total_supply * sim.params.distribution.treasury_pct
mut treasury_row := vesting_sheet.row_new(
name: 'treasury_vesting'
tags: 'category:treasury type:vesting'
@@ -31,7 +31,7 @@ pub fn (mut sim Simulation) create_vesting_schedules() ! {
// Investor rounds vesting
for round in sim.investor_rounds {
round_tokens := sim.total_supply * round.allocation_pct
round_tokens := sim.params.distribution.total_supply * round.allocation_pct
mut round_row := vesting_sheet.row_new(
name: '${round.name}_vesting'
tags: 'category:investor round:${round.name} type:vesting'
@@ -53,16 +53,26 @@ pub fn (mut sim Simulation) create_vesting_schedules() ! {
}
fn (sim Simulation) apply_vesting_schedule(mut row spreadsheet.Row, total_tokens f64, schedule VestingSchedule) ! {
monthly_unlock := total_tokens / f64(schedule.vesting_months)
initial_unlocked_tokens := total_tokens * schedule.initial_unlock_pct
remaining_tokens_to_vest := total_tokens - initial_unlocked_tokens
monthly_vesting_amount := if schedule.vesting_months > 0 {
remaining_tokens_to_vest / f64(schedule.vesting_months)
} else {
0.0
}
for month in 0 .. row.sheet.nrcol {
if month < schedule.cliff_months {
// Before cliff, no tokens unlocked
row.cells[month].val = 0
if month == 0 {
// Initial unlock at month 0
row.cells[month].val = initial_unlocked_tokens
} else if month < schedule.cliff_months {
// Before cliff, only initial unlock is available
row.cells[month].val = initial_unlocked_tokens
} else if month < schedule.cliff_months + schedule.vesting_months {
// During vesting period
months_vested := month - schedule.cliff_months + 1
row.cells[month].val = monthly_unlock * f64(months_vested)
// During vesting period (after cliff)
months_after_cliff := month - schedule.cliff_months + 1
row.cells[month].val = initial_unlocked_tokens + (monthly_vesting_amount * f64(months_after_cliff))
} else {
// After vesting complete
row.cells[month].val = total_tokens

12
tests/main.v Normal file
View File

@@ -0,0 +1,12 @@
import freeflowuniverse.herolib.threefold.incatokens
import freeflowuniverse.herolib.core.playcmds
import os
const heroscript_path = os.dir(@FILE) + '/data'
fn main() {
playcmds.run(
heroscript_path: heroscript_path
)!
println('Simulation complete!')
}