IYK · YK Tokenomics Simulator

This simulator models the four core economic variables of the IYK/YK system: NFT auction mechanics, IYK ERC-20 distribution, swap signal economics, and the corrected content coin stream model (YK treasury streams content coins, not IYK).

How to run (no install required)

The fastest path is Google Colab — opens in your browser, runs in the cloud, no Python needed locally.

  1. Go to https://colab.research.google.com
  2. Click File → New notebook
  3. Paste the launcher cell below into the first code cell and run it
  4. Click the localhost tunnel link that appears — the full Streamlit app opens in a new tab
# ── IYK Sim Colab launcher ──
!pip install streamlit plotly numpy pandas pyngrok -q

import threading, time
from pyngrok import ngrok

# Write the app file
app_code = '''
import streamlit as st
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots

st.set_page_config(page_title="IYK Tokenomics Simulator", layout="wide")
st.title("IYK · YK Tokenomics Simulator")
st.caption("NFT auction · IYK ERC-20 · Swap signals · Content streams")

tab1, tab2, tab3, tab4 = st.tabs(["NFT Auction", "IYK ERC-20", "Swap Signals", "Content Streams"])

with tab1:
    st.info("Paste full iyk_sim.py content here — see Notion page for full source.")
'''

with open('iyk_sim.py', 'w') as f:
    f.write(app_code)

# Start streamlit in background
def run():
    import subprocess
    subprocess.run(['streamlit', 'run', 'iyk_sim.py', '--server.port', '8501', '--server.headless', 'true'])

t = threading.Thread(target=run)
t.daemon = True
t.start()
time.sleep(4)

# Open tunnel
public_url = ngrok.connect(8501)
print(f'\\n\\n✅ Open the simulator here: {public_url}\\n')

Note: Replace the stub app_code in the launcher with the full source from the code block below before running.


Local install (30 seconds)

pip install streamlit plotly numpy pandas
streamlit run iyk_sim.py

Opens at http://localhost:8501


Full source — iyk_sim.py

Copy this entire block into a file called iyk_sim.py:

"""
IYK Tokenomics Simulator
Run: streamlit run iyk_sim.py
Requires: pip install streamlit plotly numpy pandas
"""

import streamlit as st
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots

st.set_page_config(
    page_title="IYK Tokenomics Simulator",
    page_icon="📊",
    layout="wide",
    initial_sidebar_state="expanded",
)

st.markdown("""
<style>
.critique { background: #fff8e1; border-left: 4px solid #f9a825;
            padding: 10px 14px; border-radius: 4px; font-size: 0.9rem; margin: 8px 0; }
.good    { background: #e8f5e9; border-left: 4px solid #2e7d32;
            padding: 10px 14px; border-radius: 4px; font-size: 0.9rem; margin: 8px 0; }
</style>
""", unsafe_allow_html=True)

st.title("IYK · YK Tokenomics Simulator")
st.caption("Explore auction mechanics, IYK ERC-20 distribution, swap signal economics, and content coin stream dynamics.")

tab1, tab2, tab3, tab4 = st.tabs([
    "NFT Auction", "IYK ERC-20", "Swap Signals", "Content Streams"
])

# ── TAB 1: NFT AUCTION ───────────────────────────────────────────────────────
with tab1:
    st.header("YK NFT Auction Parameters")
    col_ctrl, col_out = st.columns([1, 1.6])
    with col_ctrl:
        cadence_h   = st.slider("Auction cadence (hours)", 1, 168, 24, 1)
        reserve_eth = st.slider("Reserve price (ETH)", 0.001, 2.0, 0.05, 0.001, format="%.3f ETH")
        bid_mult    = st.slider("Expected avg bid (x reserve)", 1.0, 10.0, 2.0, 0.1)
        total_nfts  = st.slider("Founding NFTs (total)", 20, 300, 100, 1)
        st.markdown("---")
        ordao_pct   = st.slider("ORDAO Respect Council (%)", 0, 50, 30, 1)
        founder_pct = st.slider("Founder allocation (%)", 0, 30, 10, 1)
        airdrop_pct = st.slider("Founding airdrop (%)", 0, 30, 10, 1)
        auction_pct = 100 - ordao_pct - founder_pct - airdrop_pct
        lp_seed_eth = st.slider("IYK LP seed ETH", 0.01, 5.0, 0.5, 0.01)
    with col_out:
        auction_nfts    = max(0, int(total_nfts * auction_pct / 100))
        avg_bid         = reserve_eth * bid_mult
        auctions_per_wk = 7 * 24 / cadence_h
        weeks           = np.arange(1, 53)
        cum_eth         = np.minimum(weeks * auctions_per_wk, auction_nfts) * avg_bid
        fig = go.Figure()
        fig.add_trace(go.Scatter(x=weeks, y=cum_eth, fill='tozeroy',
                                  line=dict(color='#3266ad'), name='Treasury ETH'))
        fig.add_hline(y=lp_seed_eth, line_dash='dash', line_color='#c47c2f',
                      annotation_text=f'LP seed ({lp_seed_eth:.2f} ETH)')
        fig.update_layout(title='Treasury ETH build-up (52 weeks)',
                           xaxis_title='Week', yaxis_title='ETH', height=300)
        st.plotly_chart(fig, use_container_width=True)
        days_to_lp = next((((i+1)*7) for i, e in enumerate(cum_eth) if e >= lp_seed_eth), None)
        c1,c2,c3,c4 = st.columns(4)
        c1.metric("Auction NFTs", auction_nfts)
        c2.metric("Avg bid", f"{avg_bid:.3f} ETH")
        c3.metric("Treasury at sellout", f"{auction_nfts*avg_bid:.2f} ETH")
        c4.metric("Days to LP seed", f"{days_to_lp}d" if days_to_lp else ">1yr")
        if auction_pct < 20:
            st.warning(f"Open auction only {auction_pct}% — thin community price discovery.")
        if ordao_pct + founder_pct > 50:
            st.warning(f"ORDAO + founder = {ordao_pct+founder_pct}% — centralization risk at launch.")

# ── TAB 2: IYK ERC-20 ────────────────────────────────────────────────────────
with tab2:
    st.header("IYK ERC-20 (Creator Coin)")
    col_ctrl, col_out = st.columns([1, 1.6])
    with col_ctrl:
        supply_m     = st.slider("Total supply (millions)", 100, 10_000, 1_000, 100)
        lp_pct       = st.slider("LP allocation (%)", 5, 60, 20, 1)
        lock_months  = st.slider("Vault lock (months)", 0, 24, 1, 1)
        vest_months  = st.slider("Linear vest (months)", 6, 72, 48, 1)
        lp_seed_eth2 = st.slider("ETH seeded into LP", 0.01, 5.0, 0.5, 0.01)
        eth_price    = st.number_input("ETH price (USD)", value=3000, step=100)
        epoch_m      = st.slider("Sablier epoch (M tokens/qtr)", 0.5, 100.0, 10.0, 0.5)
    with col_out:
        supply       = supply_m * 1e6
        lp_tokens    = supply * lp_pct / 100
        vault_tokens = supply * (1 - lp_pct/100)
        token_price_usd = (lp_seed_eth2 * eth_price) / lp_tokens if lp_tokens > 0 else 0
        months = np.arange(0, vest_months + lock_months + 1)
        def circ(m):
            if m <= lock_months: return lp_tokens
            return lp_tokens + min((m-lock_months)/vest_months, 1.0) * vault_tokens
        circulating = np.array([circ(m) for m in months])
        fig2 = go.Figure()
        fig2.add_trace(go.Scatter(x=months, y=circulating/1e6, fill='tozeroy',
                                   line=dict(color='#3266ad'), name='Circulating'))
        fig2.add_hline(y=lp_tokens/1e6, line_dash='dash', line_color='#c47c2f',
                        annotation_text='LP floor')
        fig2.update_layout(title='Circulating supply over vest schedule',
                            xaxis_title='Month', yaxis_title='IYK (M)', height=300)
        st.plotly_chart(fig2, use_container_width=True)
        vault_qtr_pct = (epoch_m*1e6/vault_tokens*100) if vault_tokens > 0 else 0
        c1,c2,c3,c4 = st.columns(4)
        c1.metric("Token price", f"${token_price_usd:.6f}")
        c2.metric("Mkt cap", f"${supply*token_price_usd:,.0f}")
        c3.metric("Stream rate", f"{vault_qtr_pct:.2f}%/qtr")
        c4.metric("Vault runway", f"{vault_tokens/(epoch_m*1e6)/4:.1f} yrs")
        if lp_pct < 15:
            st.warning(f"LP at {lp_pct}% — thin float, expect high early volatility.")
        if lock_months < 3:
            st.warning(f"{lock_months}-month lock is short. Vault unlocks before community is bootstrapped.")

# ── TAB 3: SWAP SIGNALS ──────────────────────────────────────────────────────
with tab3:
    st.header("Swap Signal Economics")
    st.markdown("Users swap IYK → ContentCoin to vote within programs. Swap volume = stated interest signal.")
    col_ctrl, col_out = st.columns([1, 1.6])
    with col_ctrl:
        swappers      = st.slider("Monthly active swappers", 10, 5000, 200, 10)
        swap_size     = st.slider("Avg IYK per swap", 100, 100_000, 5_000, 100)
        fee_bps       = st.slider("LP swap fee (bps)", 10, 300, 100, 5)
        iyk_price_usd = st.slider("IYK price (USD)", 0.0001, 0.10, 0.005, 0.0001, format="%.4f")
        outflow_pct   = st.slider("% IYK routed to content coins / mo", 1, 80, 15, 1)
        growth_rate   = st.slider("Monthly swapper growth (%)", 0, 50, 10, 1)
        supply_m3     = st.number_input("Total IYK supply (M)", value=1000, step=100)
    with col_out:
        monthly_vol   = swappers * swap_size
        fee_rev_usd   = monthly_vol * fee_bps/10_000 * iyk_price_usd
        outflow_pct_supply = (monthly_vol * outflow_pct/100) / (supply_m3*1e6) * 100
        g = 1 + growth_rate/100
        months_p = np.arange(1,13)
        vol_series = monthly_vol * g**(months_p-1) * iyk_price_usd / 1000
        fee_series = monthly_vol * fee_bps/10_000 * iyk_price_usd * g**(months_p-1)
        fig3 = make_subplots(specs=[[{"secondary_y": True}]])
        fig3.add_trace(go.Bar(x=months_p, y=vol_series, name='Vol (K USD)',
                               marker_color='#3266ad', opacity=0.7), secondary_y=False)
        fig3.add_trace(go.Scatter(x=months_p, y=fee_series, name='Fee USD',
                                   line=dict(color='#c47c2f'), mode='lines+markers'), secondary_y=True)
        fig3.update_layout(title='Swap volume & fees (12mo projection)', height=300)
        st.plotly_chart(fig3, use_container_width=True)
        c1,c2,c3,c4 = st.columns(4)
        c1.metric("Monthly vol", f"${monthly_vol*iyk_price_usd:,.0f}")
        c2.metric("Monthly fees", f"${fee_rev_usd:,.2f}")
        c3.metric("Outflow/supply", f"{outflow_pct_supply:.4f}%/mo")
        c4.metric("Annual fees", f"${fee_rev_usd*12:,.0f}")
        if outflow_pct_supply > 0.5:
            st.warning(f"Monthly outflow {outflow_pct_supply:.3f}% of supply — sustained selling creates IYK price drag.")
        if swappers < 50:
            st.warning(f"Only {swappers} swappers — signal statistically weak, whale manipulation risk.")

# ── TAB 4: CONTENT STREAMS ───────────────────────────────────────────────────
with tab4:
    st.header("Content Coin Stream Model")
    st.markdown("""
    **Correct model:** YK treasury custodies content coins (WTM, CANON) at program approval.
    Treasury streams a % of those content coins to program recipients via Sablier.
    Recipients hold (vote), sell into ContentCoin/IYK LP, or add to LP.
    Selling into LP removes IYK from the pool (IYK price up) and adds ContentCoins (ContentCoin price down).
    """)
    col_ctrl, col_out = st.columns([1, 1.6])
    with col_ctrl:
        content_supply       = st.number_input("Content coin total supply", value=10_000_000, step=500_000)
        treasury_custody_pct = st.slider("% custodied by YK treasury", 0, 100, 50, 1)
        stream_pct_qtr       = st.slider("Stream rate (% of custody / qtr)", 0.5, 25.0, 5.0, 0.5)
        qtrs                 = st.slider("Quarters to simulate", 1, 20, 8)
        iyk_in_lp            = st.slider("IYK in ContentCoin/IYK LP at launch (M)", 0.1, 50.0, 5.0, 0.1)
        content_in_lp        = st.slider("Content coins in LP at launch (M)", 0.01, 5.0, 0.5, 0.01)
        iyk_price_cc         = st.slider("IYK price (USD)", 0.0001, 0.10, 0.005, 0.0001,
                                          format="%.4f", key="cc_price")
        sell_pct             = st.slider("Recipient sell to LP (%)", 0, 100, 30, 5)
        lp_dep_pct           = st.slider("Recipient add to LP (%)", 0, 100, 20, 5)
        hold_pct             = 100 - sell_pct - lp_dep_pct
        st.caption(f"Hold / vote: {hold_pct}%" if hold_pct >= 0 else "⚠️ Exceeds 100%")
    with col_out:
        if hold_pct < 0:
            st.error("Sell + LP > 100%. Adjust sliders.")
        else:
            treasury_coins = content_supply * treasury_custody_pct / 100
            coins_per_qtr  = treasury_coins * stream_pct_qtr / 100
            qtrs_arr       = np.arange(1, qtrs+1)
            # AMM simulation
            iyk_lp_r, cc_lp_r = iyk_in_lp, content_in_lp
            k = iyk_lp_r * cc_lp_r
            cc_price_s, iyk_removed_s = [], []
            for _ in range(qtrs):
                dcc_sell = (coins_per_qtr * sell_pct / 100) / 1e6
                dcc_lp   = (coins_per_qtr * lp_dep_pct / 100) / 1e6
                if sell_pct > 0:
                    new_cc = cc_lp_r + dcc_sell
                    new_iyk = k / new_cc
                    iyk_removed_s.append(max(iyk_lp_r - new_iyk, 0))
                    cc_lp_r, iyk_lp_r = new_cc, new_iyk
                else:
                    iyk_removed_s.append(0)
                if lp_dep_pct > 0:
                    ratio = iyk_lp_r / cc_lp_r if cc_lp_r > 0 else 1
                    cc_lp_r += dcc_lp
                    iyk_lp_r += dcc_lp * ratio
                k = iyk_lp_r * cc_lp_r
                cc_price_s.append(iyk_lp_r / cc_lp_r if cc_lp_r > 0 else 0)
            cc_price_s = np.array(cc_price_s)
            iyk_removed_s = np.array(iyk_removed_s)
            fig4 = make_subplots(rows=2, cols=1,
                                  subplot_titles=("ContentCoin price (IYK/token)",
                                                  "IYK removed from LP per quarter (M)"),
                                  shared_xaxes=True, vertical_spacing=0.15)
            fig4.add_trace(go.Scatter(x=qtrs_arr, y=cc_price_s,
                                       line=dict(color='#3266ad'), mode='lines+markers'), row=1, col=1)
            fig4.add_trace(go.Bar(x=qtrs_arr, y=iyk_removed_s,
                                   marker_color='#e05c45'), row=2, col=1)
            fig4.update_layout(height=380, showlegend=False)
            st.plotly_chart(fig4, use_container_width=True)
            qtr_exhaust = treasury_coins / coins_per_qtr if coins_per_qtr > 0 else 999
            price_delta = (cc_price_s[-1]/cc_price_s[0]-1)*100 if len(cc_price_s)>1 and cc_price_s[0]>0 else 0
            c1,c2,c3,c4 = st.columns(4)
            c1.metric("Treasury custody", f"{treasury_coins/1e6:.1f}M coins")
            c2.metric("Per-qtr stream", f"{coins_per_qtr/1e6:.2f}M")
            c3.metric("Exhausted in", f"Q{qtr_exhaust:.0f}")
            c4.metric(f"Price delta (Q{qtrs})", f"{price_delta:+.1f}%")
            if sell_pct > 50:
                st.warning(f"{sell_pct}% sell pressure steadily depresses ContentCoin/IYK pool.")
            if iyk_removed_s.sum() > iyk_in_lp * 1e6 * 0.3:
                st.warning(f"Sell pressure removed {iyk_removed_s.sum()/1e6:.1f}M IYK from LP — pool becoming thin.")
            if hold_pct < 20:
                st.warning(f"Only {hold_pct}% held for voting — low governance engagement signal.")

st.markdown("---")
st.caption("IYK · YK Tokenomics Simulator v0.1 — all models are approximations.")

Changelog