File size: 9,203 Bytes
19fc8d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt
from decimal import Decimal

def simulate_full_bonding_curve_with_fees(
    initial_market_cap_sol, migration_market_cap_sol, total_token_supply,
    token_decimals, quote_decimals,
    migration_fee_percent, creator_migration_fee_percent,
    partner_lp_percentage, creator_lp_percentage,
    partner_locked_lp_percentage, creator_locked_lp_percentage,
    trading_fee_bps, total_trading_volume_sol
):
    total_trading_volume_sol = float(total_trading_volume_sol)
    percentage_supply = Decimal(100)

    migration_quote_amount = Decimal(initial_market_cap_sol) * percentage_supply / Decimal(100)
    migration_quote_threshold = migration_quote_amount * Decimal(100) / (Decimal(100) - Decimal(migration_fee_percent))

    circulating_supply = Decimal(total_token_supply) * percentage_supply / Decimal(100)
    start_price = Decimal(initial_market_cap_sol) / circulating_supply
    end_price = Decimal(migration_market_cap_sol) / circulating_supply

    # Calculate k for the price formula P(x) = k / (C - x)^2
    # S(x) = integral P(x)dx from 0 to x = k/(C-x) - k/C
    # initial_market_cap_sol is the SOL value for 0 tokens sold (conceptually)
    # For the purpose of plotting the amount of SOL raised against tokens sold:
    # Let C = float(circulating_supply)
    # The price at a given number of tokens sold 's' is P(s) = k / (C - s)^2
    # The SOL raised to sell 's' tokens is Integral(P(x)dx) from 0 to s which is k/(C-s) - k/C
    # We use migration_quote_amount as the SOL raised when 0 tokens are sold for the *start* of the curve for simplicity in k calc.
    # This interpretation aligns k with the initial SOL amount rather than price directly.
    C_float = float(circulating_supply)
    if C_float == 0: # Avoid division by zero if circulating supply is zero
        x = np.array([0])
        prices = np.array([0])
        x_end_plot = 0
    else:
        # k is derived from the initial state: initial_market_cap_sol is the SOL value for 0 tokens sold (conceptually)
        # P(x) = k / (C-x)^2. SOL_raised(x) = k/(C-x) - k/C.
        # if initial_market_cap_sol is S(0), then k = initial_market_cap_sol * C_float. This is wrong, initial_market_cap_sol is not S(0).
        # initial_market_cap_sol is effectively the amount of SOL in the pool at the start for pricing calculations.
        # Let's use the definition that migration_quote_amount (SOL before fees) is the target SOL to be in the curve before it migrates.
        # The curve starts with some implicit SOL amount that gives start_price.
        # Price(x) = k / (C-x)^2. So, Price(0) = k / C^2 = start_price.
        # k = start_price * C^2
        k = float(start_price) * (C_float**2)

        if k == 0 or (float(migration_quote_threshold) + k / C_float) == 0: # Handle division by zero or k=0
            x_end_plot = C_float # Sell all tokens if k is 0 or threshold makes denominator 0
        else:
            # Calculate x_end_plot: number of tokens sold to reach migration_quote_threshold SOL
            # SOL_raised(x_end_plot) = migration_quote_threshold
            # migration_quote_threshold = k/(C_float - x_end_plot) - k/C_float
            # k/(C_float - x_end_plot) = migration_quote_threshold + k/C_float
            # C_float - x_end_plot = k / (migration_quote_threshold + k/C_float)
            x_end_plot = C_float - (k / (float(migration_quote_threshold) + k / C_float))
            # Ensure x_end_plot is not negative or greater than C_float
            x_end_plot = max(0, min(x_end_plot, C_float * 0.9999)) # Plot up to 99.99% to avoid infinity

        if x_end_plot <= 1e-9: # If effectively no tokens are sold to reach threshold (e.g. threshold is 0)
            x_end_plot = C_float * 0.01 # Plot a small portion to show something
            if x_end_plot <= 1e-9: # If C_float is also tiny
                 x_end_plot = 1 # Default to 1 token if supply is extremely small

        num_points = 100
        if x_end_plot == 0:
            x = np.array([0]) # Handle case with single point
            prices = np.array([float(start_price)])
        else:
            x = np.linspace(0.0, x_end_plot, num_points) 
            prices = k / (C_float - x + 1e-9)**2 # Add small epsilon to avoid division by zero if x reaches C_float
            prices = [float(p) for p in prices]

    total_fee = float(migration_quote_threshold) * float(migration_fee_percent) / 100
    creator_migration_fee = total_fee * (creator_migration_fee_percent / 100)
    partner_migration_fee = total_fee - creator_migration_fee

    total_lp_tokens = float(migration_quote_threshold)
    creator_lp_tokens = total_lp_tokens * (creator_lp_percentage / 100)
    partner_lp_tokens = total_lp_tokens * (partner_lp_percentage / 100)
    creator_locked_lp = creator_lp_tokens * (creator_locked_lp_percentage / 100)
    partner_locked_lp = partner_lp_tokens * (partner_locked_lp_percentage / 100)

    trading_fee_rate = trading_fee_bps / 10000
    total_trading_fee = total_trading_volume_sol * trading_fee_rate
    creator_trading_fee = total_trading_fee * (creator_lp_percentage / 100)
    partner_trading_fee = total_trading_fee * (partner_lp_percentage / 100)

    fig, ax = plt.subplots()
    ax.plot(x, prices)
    ax.set_xlabel("Tokens Sold")
    ax.set_ylabel("Price (in SOL)")
    ax.set_title("Bonding Curve Simulation (in SOL)")

    note = """
Bonding Curve Unit: SOL

Parameter Explanations:
- Initial Market Cap: Total valuation (in SOL) at curve start.
- Migration Market Cap: Valuation (in SOL) when curve ends and migrates to AMM.
- Migration Quote Amount: Amount of SOL raised before fees.
- Migration Threshold: Total SOL needed to trigger migration (includes fees).
- LP Tokens: Represents user's share in the post-migration AMM liquidity pool. Approximated here as equal to the migration threshold in SOL.
- Trading Fee BPS: The fee rate applied to all swaps post-migration. BPS = Basis Points (e.g., 100 BPS = 1%).
- Creator/Partner Trading Fee: Earnings from swap volume based on LP share.
- All SOL values are approximated assuming quote token = SOL.
    """

    return (
        fig,
        f"Initial Price: {start_price:.8f} SOL",
        f"Migration Price: {end_price:.8f} SOL",
        f"Migration Quote Amount: {migration_quote_amount:.2f} SOL",
        f"Migration Threshold (after fee): {migration_quote_threshold:.2f} SOL",
        f"Bonding Curve Unit: SOL",
        f"Creator Migration Fee: {creator_migration_fee:.2f} SOL",
        f"Partner Migration Fee: {partner_migration_fee:.2f} SOL",
        f"Total LP Tokens: {total_lp_tokens:.2f}",
        f"Creator LP: {creator_lp_tokens:.2f} (Locked: {creator_locked_lp:.2f})",
        f"Partner LP: {partner_lp_tokens:.2f} (Locked: {partner_locked_lp:.2f})",
        f"Creator Trading Fee: {creator_trading_fee:.2f} SOL",
        f"Partner Trading Fee: {partner_trading_fee:.2f} SOL",
        note.strip()
    )

gr.Interface(
    fn=simulate_full_bonding_curve_with_fees,
    inputs=[
        gr.Textbox(label="Initial Market Cap (SOL)", value="1000"),
        gr.Textbox(label="Migration Market Cap (SOL)", value="10000"),
        gr.Textbox(label="Total Token Supply", value="1000000"),
        gr.Textbox(label="Token Decimals", value="6"),
        gr.Textbox(label="Quote Token Decimals", value="9"),
        gr.Slider(label="Migration Fee Percent (%)", minimum=0, maximum=50, step=0.5, value=10),
        gr.Slider(label="Creator Fee Share of Migration Fee (%)", minimum=0, maximum=100, step=1, value=50),
        gr.Slider(label="Partner LP %", minimum=0, maximum=100, step=1, value=50),
        gr.Slider(label="Creator LP %", minimum=0, maximum=100, step=1, value=50),
        gr.Slider(label="Partner Locked LP %", minimum=0, maximum=100, step=1, value=100),
        gr.Slider(label="Creator Locked LP %", minimum=0, maximum=100, step=1, value=100),
        gr.Slider(label="Post-Migration Trading Fee (bps)", minimum=0, maximum=1000, step=5, value=30),
        gr.Textbox(label="Total Trading Volume (SOL)", value="1000"),
    ],
    outputs=[
        gr.Plot(label="Bonding Curve"),
        gr.Textbox(label="Initial Price", lines=1, interactive=False),
        gr.Textbox(label="Migration Price", lines=1, interactive=False),
        gr.Textbox(label="Migration Quote Amount", lines=1, interactive=False),
        gr.Textbox(label="Migration Threshold", lines=1, interactive=False),
        gr.Textbox(label="Bonding Curve Unit", lines=1, interactive=False),
        gr.Textbox(label="Creator Migration Fee", lines=1, interactive=False),
        gr.Textbox(label="Partner Migration Fee", lines=1, interactive=False),
        gr.Textbox(label="Total LP Tokens", lines=1, interactive=False),
        gr.Textbox(label="Creator LP", lines=1, interactive=False),
        gr.Textbox(label="Partner LP", lines=1, interactive=False),
        gr.Textbox(label="Creator Trading Fee", lines=1, interactive=False),
        gr.Textbox(label="Partner Trading Fee", lines=1, interactive=False),
        gr.Textbox(label="Explanation", lines=12, interactive=False),
    ],
    title="Dynamic Bonding Curve Simulator (with Full Fee + LP Breakdown)"
).launch()