Skip to content

Instantly share code, notes, and snippets.

@sambacha
Created March 28, 2025 18:35
Show Gist options
  • Save sambacha/7848abbfe75cf7aeecec0ed05c16d165 to your computer and use it in GitHub Desktop.
Save sambacha/7848abbfe75cf7aeecec0ed05c16d165 to your computer and use it in GitHub Desktop.

Mathematical Formalization of Prize-Linked Savings Accounts

1. Notation and Definitions

  • t: Time period (can be discrete, e.g., days, weeks, or continuous)
  • u: Index for user, u = 1, 2, ..., N, where N is the number of users
  • V(t): Total value of assets deposited in the underlying ERC-4626 Vault at time t
  • D_u(t): Deposit amount of user u at time t. We assume deposits are cumulative, so D_u(t) represents the total deposited amount by user u up to time t
  • S_u(t): Vault Shares (ERC-4626 tokens) held by user u at time t
  • Y_R(t): Yield Rate of the underlying ERC-4626 Vault during time period t. This can be expressed as a percentage or a factor
  • Y(t): Total yield generated by the ERC-4626 Vault during time period t
  • P_R: Prize Rate – the percentage of the total yield allocated to the prize pool
  • P(t): Prize Pool size for the prize draw at time t
  • W: Number of winners selected in each prize draw
  • Prize_i: Value of the i-th prize in a prize draw, where i = 1, 2, ..., W. Prizes can be tiered
  • ∑Prize = ∑_{i=1}^{W} Prize_i: Total value of prizes distributed in a single draw
  • Prob_u(t): Probability of user u winning any prize in a draw at time t
  • Prob_u,i(t): Probability of user u winning the i-th prize in a draw at time t
  • EV_u(t): Expected Value of prizes for user u in a draw at time t

2. Core Equations

2.1. Total Deposited Value

The total value of assets in the vault at time t is the sum of all user deposits (after accounting for yield generation and potential exchange rate changes within the ERC-4626 vault). However, for simplicity in prize calculation based on shares, we often work with shares as the representation of deposit size within the Prize Vault logic. Assuming a 1:1 initial share ratio for the Prize Vault:

$$V(t) \approx \sum_{u=1}^{N} D_u(t)$$

and also S_u(t) is approximately proportional to D_u(t) in terms of prize probability contribution.

2.2. Yield Generation

The total yield generated by the ERC-4626 Vault during time period t is calculated based on the total value in the vault and the yield rate:

$$Y(t) = V(t-1) * Y_R(t)$$

Where V(t-1) is the vault value at the beginning of the time period t, and Y_R(t) is the yield rate for period t.

2.3. Prize Pool Calculation

The prize pool for the draw at time t is a percentage of the generated yield:

$$P(t) = Y(t) * P_R$$

2.4. Probability of Winning

Total Vault Shares in Prize Vault:

$$S_{Total}(t) = \sum_{u=1}^{N} S_u(t)$$

For tiered prizes with W winners drawn without replacement, the approximate probability of winning at least one prize:

$$Prob_u(t) \approx 1 - (1 - (S_u(t) / S_{Total}(t)))^W$$

For each individual prize Prize_i, the simplified probability:

$$Prob_{u,i}(t) \approx S_u(t) / S_{Total}(t)$$

2.5. Expected Value of Prizes

The expected value for user u:

$$EV_u(t) = \sum_{i=1}^{W} Prob_{u,i}(t) * Prize_i$$

Using the simplified probability:

$$EV_u(t) \approx (S_u(t) / S_{Total}(t)) * \sum Prize$$

3. Invariant Calculations for Implementation

Total Vault Shares Invariant

$$\sum_{u=1}^{N} S_u(t) = \text{Total Vault Shares}$$

Prize Pool Allocation Invariant

$$P(t) = Y(t) * P_R$$

Prize Distribution Invariant

$$\sum_{i=1}^{W} Prize_i \leq P(t)$$

Probability Bounds Invariant

$$0 \leq Prob_u(t) \leq 1$$

Withdrawal and Deposit Invariant

For any withdrawal at time t: $$\text{Withdrawn Assets}_u(t) \approx \text{Initial Deposit}_u * \text{ERC4626 Exchange Rate}(t)$$

Expected Value Invariant

Over time period T: $$\text{Average Prize Payout}(T) \approx \text{Expected Prize Payout}(T)$$

Figure_21

Calculating deadweight loss of credit card fees

# A I generated slop

import matplotlib.pyplot as plt
import numpy as np

def generate_dwl_graph(p0, q0, fee_rate, edemand, esupply):
    """
    Generates a Deadweight Loss (DWL) graph similar to the provided image,
    using the elasticity-based approximation for DWL calculation.

    Args:
        p0: Equilibrium Price without fees.
        q0: Equilibrium Quantity without fees.
        fee_rate: Credit card transaction fee rate (as a decimal).
        edemand: Price elasticity of demand (absolute value, positive).
        esupply: Price elasticity of supply (positive).
    """

    # --- Calculate DWL and Price/Quantity Changes ---

    # DWL calculation (same as before)
    dwl = 0.5 * p0 * q0 * (fee_rate**2) * (edemand * esupply / (edemand + esupply))

    # Calculate change in quantity (delta Q) using elasticity approximation
    delta_q = -q0 * fee_rate * (edemand * esupply / (edemand + esupply))
    qd = q0 + delta_q  # Quantity demanded after the fee

    # Calculate price changes for consumers (Pc) and producers (Pp)
    delta_pc = fee_rate * p0 * (esupply / (edemand + esupply))
    delta_pp = -fee_rate * p0 * (edemand / (edemand + esupply))
    pc = p0 + delta_pc  # Price consumers pay
    pp = p0 + delta_pp  # Price producers receive
    qs = q0 + (delta_pp/p0) * esupply *q0 #Simplified for demonstration.  More accurate Qs is complex.
    
    # --- Create the Plot ---

    plt.figure(figsize=(8, 6))  # Adjust figure size as needed


    # Demand Curve (Original)
    q_values_demand = np.array([0, q0 * 1.5])  # Extend beyond equilibrium for visualization
    p_values_demand = p0 - (q_values_demand - q0) * (p0 / (edemand * q0))  # Linear approx.
    plt.plot(q_values_demand, p_values_demand, label='Demand', color='green')

    # Supply Curve (Original)
    q_values_supply = np.array([0, q0 * 1.5])  # Extend for visualization
    p_values_supply = p0 + (q_values_supply - q0) * (p0 / (esupply * q0))  # Linear approx.
    plt.plot(q_values_supply, p_values_supply, label='Supply', color='blue')


    # 2.  Points and Labels (A, B, C, D, P1, P2, Q1, Qd, Qs)

    # Point A (Original Equilibrium)
    plt.plot(q0, p0, 'ko')  # 'ko' = black circle
    plt.text(q0 + 0.02*q0, p0 - 0.03*p0, 'A', fontsize=12)

    # Point B (New Consumer Price Intersection)
    plt.plot(qd, pc, 'ko')
    plt.text(qd + 0.02*q0 , pc + 0.02*p0, 'B', fontsize=12)

    # Point C (New Producer Price Intersection)
    plt.plot(qd, pp, 'ko')
    plt.text(qd - 0.1*q0, pp - 0.03*p0, 'C', fontsize=12)

    # Point D: Intersection of supply and new price
    plt.plot(qs, pc, 'ko')  # Intersection of the original supply and new consumer price.
    plt.text(qs+0.02*q0, pc+0.01*p0, 'D', fontsize=12)
    # Horizontal dashed lines for P1 and P2
    plt.hlines(y=p0, xmin=0, xmax=q0, linestyles='dashed', color='black')
    plt.hlines(y=pc, xmin=0, xmax=qs, linestyles='dashed', color='black')
    plt.hlines(y=pp, xmin=0, xmax=qd, linestyles='dashed', color='black')

    # Vertical dashed lines for Q1, Qd, and Qs
    plt.vlines(x=q0, ymin=0, ymax=p0, linestyles='dashed', color='black')
    plt.vlines(x=qd, ymin=0, ymax=pc, linestyles='dashed', color='black')
    plt.vlines(x=qs, ymin=0, ymax=pc, linestyles='dashed', color='black')

    # Label axes, prices and quantities
    plt.text(-0.07*q0, p0, r'$P_1$', fontsize=12) #using Latex
    plt.text(-0.07*q0, pc, r'$P_2$', fontsize=12)
    plt.text(q0, -0.07*p0, r'$Q_1$', fontsize=12)
    plt.text(qd, -0.07*p0, r'$Q_d$', fontsize=12)
    plt.text(qs, -0.07*p0, r'$Q_s$', fontsize=12)

    # 3.  Shaded DWL Triangle

    # Fill the triangle ABC
    plt.fill_between([qd, q0], [pc, p0], [pp, p0], color='red', alpha=0.5)


    # 4.  Axis Labels and Title

    plt.xlabel('Q')
    plt.ylabel('P')
    plt.title('Deadweight Loss from Credit Card Fees')


    plt.legend(handles=[plt.Line2D([], [], color='green', label='D'),
                         plt.Line2D([], [], color='blue', label='S')],
               loc='upper left', frameon=False)
    plt.text(0.1*q0,0.95*p_values_demand[0], r'$D_L$', color='green')
    plt.text(0.1*q0,0.1*p_values_supply[0], r'$S_L$', color='blue')


    plt.xlim(0, q0 * 1.3)  # Extend x-axis slightly
    plt.ylim(0, p_values_demand[0] * 1.1)  # Extend y-axis to accommodate labels
    plt.tight_layout() # Prevents overlapping
    plt.show()



def main():
    # Example parameters (you can change these)
    p0 = 100  # Equilibrium price
    q0 = 1000  # Equilibrium quantity
    fee_rate = 0.03  # 3% fee
    edemand = 0.8  # Absolute value of demand elasticity
    esupply = 1.2  # Supply elasticity
    generate_dwl_graph(p0, q0, fee_rate, edemand, esupply)

if __name__ == "__main__":
    main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment