04 — Mechanism Post-Mortem¶

Cross-cutting analysis of how the ABC + Conviction Voting mechanisms performed under various market and social pressures.

Central thesis to evaluate:¶

The TEC deployed an Augmented Bonding Curve (primary market) feeding a Common Pool governed by Conviction Voting (fund allocation). This analysis evaluates whether these mechanisms achieved their design goals and what broke down.

In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import seaborn as sns
import datetime

sns.set_theme(style='whitegrid', palette='deep')
plt.rcParams['figure.figsize'] = (14, 6)
plt.rcParams['figure.dpi'] = 100

DATA = '../data/onchain'

# Load all data
proposals = pd.read_csv(f'{DATA}/cv_proposals.csv')
stakes = pd.read_csv(f'{DATA}/cv_stakes.csv')
common = pd.read_csv(f'{DATA}/dune_common_pool.csv')
reserve = pd.read_csv(f'{DATA}/dune_reserve_pool.csv')
balances = pd.read_csv(f'{DATA}/dune_token_balances_usd.csv')

# Parse dates - strip timezone info for consistent comparison
common['date'] = pd.to_datetime(common['day'], utc=True).dt.tz_localize(None)
reserve['date'] = pd.to_datetime(reserve['day'], utc=True).dt.tz_localize(None)
balances['date'] = pd.to_datetime(balances['day'], utc=True).dt.tz_localize(None)

# Approximate dates for on-chain events
genesis_block = 20086944
genesis_date = datetime.datetime(2022, 1, 19)

def block_to_date(block):
    return genesis_date + datetime.timedelta(seconds=(block - genesis_block) * 5)

proposals['date'] = proposals['block'].apply(block_to_date)
stakes['date'] = stakes['block'].apply(block_to_date)

print('Data loaded. Analysis period:')
print(f'  CV proposals: {proposals["date"].min().date()} to {proposals["date"].max().date()}')
print(f'  Common pool: {common["date"].min().date()} to {common["date"].max().date()}')
print(f'  Reserve pool: {reserve["date"].min().date()} to {reserve["date"].max().date()}')
print(f'  Token balances: {balances["date"].min().date()} to {balances["date"].max().date()}')
Data loaded. Analysis period:
  CV proposals: 2022-01-19 to 2023-08-17
  Common pool: 2022-01-19 to 2023-12-19
  Reserve pool: 2022-01-19 to 2023-12-19
  Token balances: 2023-12-20 to 2025-12-10

1. The Fundamental Loop: ABC → Common Pool → CV → Grants¶

Did the system achieve a self-sustaining funding cycle?

  • ABC tributes (entry/exit fees) replenish the common pool
  • CV allocates common pool funds to proposals
  • Funded proposals should create value → attract new participants → ABC buys → more tributes
In [2]:
# Compare inflow (tributes) vs outflow (grants) on common pool
cp_monthly = common.set_index('date').resample('ME').agg({
    'inflow': 'sum',
    'outflow': lambda x: x.abs().sum(),
    'balance': 'last'
})
cp_monthly['net'] = cp_monthly['inflow'] - cp_monthly['outflow']
cp_monthly['cumulative_net'] = cp_monthly['net'].cumsum()

fig, axes = plt.subplots(2, 1, figsize=(16, 10))

# Inflow vs Outflow
ax = axes[0]
width = 15
ax.bar(cp_monthly.index - pd.Timedelta(days=8), cp_monthly['inflow'],
       width=width, color='#2ecc71', alpha=0.7, label='Inflow (tributes + other)')
ax.bar(cp_monthly.index + pd.Timedelta(days=8), cp_monthly['outflow'],
       width=width, color='#e74c3c', alpha=0.7, label='Outflow (grants)')
ax.set_ylabel('Amount')
ax.set_title('Common Pool: Monthly Inflow vs Outflow — Was the loop sustainable?')
ax.legend()

# Cumulative net position
ax = axes[1]
ax.fill_between(cp_monthly.index, cp_monthly['cumulative_net'],
                where=cp_monthly['cumulative_net'] >= 0,
                color='#2ecc71', alpha=0.3, label='Net positive')
ax.fill_between(cp_monthly.index, cp_monthly['cumulative_net'],
                where=cp_monthly['cumulative_net'] < 0,
                color='#e74c3c', alpha=0.3, label='Net negative')
ax.plot(cp_monthly.index, cp_monthly['cumulative_net'], 'k-', linewidth=1.5)
ax.axhline(y=0, color='black', linewidth=0.5)
ax.set_ylabel('Cumulative Net Flow')
ax.set_title('Cumulative Net Position — When did outflows exceed inflows?')
ax.legend()

for ax in axes:
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))

plt.tight_layout()
plt.savefig(f'{DATA}/../snapshots/mechanism_sustainability.png', dpi=150, bbox_inches='tight')
plt.show()

total_in = cp_monthly['inflow'].sum()
total_out = cp_monthly['outflow'].sum()
print(f'\nFunding Loop Analysis:')
print(f'  Total inflows: {total_in:,.0f}')
print(f'  Total outflows: {total_out:,.0f}')
print(f'  Coverage ratio: {total_in/total_out:.2f}x (1.0 = break even)')
print(f'  Net deficit: {total_in - total_out:,.0f}')
No description has been provided for this image
Funding Loop Analysis:
  Total inflows: 1,195,952
  Total outflows: 1,195,952
  Coverage ratio: 1.00x (1.0 = break even)
  Net deficit: -0

2. Governance Activity vs Treasury Health¶

Did governance participation correlate with treasury health? As the treasury declined, did participation wane (death spiral) or intensify (crisis response)?

In [3]:
# Monthly governance activity
stakes_monthly = stakes.set_index('date').resample('ME').agg(
    num_stakes=('proposal_id', 'count'),
    unique_stakers=('staker', 'nunique'),
    total_staked=('tokens_staked', 'sum'),
)

# Proposals per month
props_monthly = proposals[proposals['id'] > 1].set_index('date').resample('ME').agg(
    num_proposals=('id', 'count'),
    total_requested=('amount_requested', 'sum'),
)

fig, axes = plt.subplots(3, 1, figsize=(16, 14), sharex=True)

# Treasury balance
ax = axes[0]
ax.plot(common['date'], common['balance'], color='#2ecc71', linewidth=1.5, label='Common Pool')
ax.plot(reserve['date'], reserve['balance'], color='#3498db', linewidth=1.5, label='Reserve Pool')
ax.set_ylabel('Balance')
ax.set_title('Treasury Health')
ax.legend()

# Active stakers
ax = axes[1]
if len(stakes_monthly) > 0:
    ax.bar(stakes_monthly.index, stakes_monthly['unique_stakers'], width=20, color='teal', alpha=0.7)
ax.set_ylabel('Unique Stakers')
ax.set_title('Monthly Governance Participation')

# New proposals
ax = axes[2]
if len(props_monthly) > 0:
    ax.bar(props_monthly.index, props_monthly['num_proposals'], width=20, color='coral', alpha=0.7)
ax.set_ylabel('New Proposals')
ax.set_title('Monthly Proposal Submissions')
ax.set_xlabel('Date')

for ax in axes:
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))

plt.tight_layout()
plt.savefig(f'{DATA}/../snapshots/governance_vs_treasury.png', dpi=150, bbox_inches='tight')
plt.show()
No description has been provided for this image

3. Conviction Voting Parameter Stress Test¶

The TEC used these CV parameters:

  • Conviction Growth: 7 days
  • Minimum Conviction: 4%
  • Spending Limit: 11%

Were these appropriate? How did they interact with the actual dynamics?

In [4]:
# Analyze request sizes relative to common pool
funded = proposals[(proposals['status'] == 'executed') & (proposals['amount_requested'] > 0)].copy()

# For each funded proposal, estimate what % of the pool it represented
# We need to match proposal dates to pool balance dates
# Use the common pool daily balance
cp_daily = common.set_index('date')['balance'].resample('D').last().ffill()

request_pcts = []
for _, row in funded.iterrows():
    prop_date = row['date']
    # Find closest pool balance
    mask = cp_daily.index <= prop_date
    if mask.any():
        pool_bal = cp_daily[mask].iloc[-1]
        if pool_bal > 0:
            pct = row['amount_requested'] / pool_bal
            request_pcts.append({
                'id': row['id'],
                'name': row['link'][:40],
                'amount': row['amount_requested'],
                'pool_balance': pool_bal,
                'pct_of_pool': pct,
                'date': prop_date
            })

if request_pcts:
    rp_df = pd.DataFrame(request_pcts)

    fig, axes = plt.subplots(1, 2, figsize=(16, 6))

    # Request as % of pool
    ax = axes[0]
    ax.bar(range(len(rp_df)), rp_df['pct_of_pool'] * 100, color='steelblue')
    ax.axhline(y=11, color='red', linestyle='--', label='Spending Limit (11%)')
    ax.axhline(y=4, color='orange', linestyle='--', label='Min Conviction (4%)')
    ax.set_xlabel('Proposal (chronological)')
    ax.set_ylabel('% of Common Pool')
    ax.set_title('Proposal Size Relative to Common Pool')
    ax.legend()

    # Over time
    ax = axes[1]
    ax.scatter(rp_df['date'], rp_df['pct_of_pool'] * 100, c='steelblue', s=rp_df['amount']/100, alpha=0.6)
    ax.axhline(y=11, color='red', linestyle='--', label='Spending Limit (11%)')
    ax.set_xlabel('Date')
    ax.set_ylabel('% of Common Pool')
    ax.set_title('Request Size Relative to Pool Over Time\n(bubble size = absolute amount)')
    ax.legend()

    plt.tight_layout()
    plt.savefig(f'{DATA}/../snapshots/cv_parameters.png', dpi=150, bbox_inches='tight')
    plt.show()

    print(f'\nSpending limit analysis:')
    over_limit = (rp_df['pct_of_pool'] > 0.11).sum()
    print(f'  Proposals exceeding 11% spending limit: {over_limit}/{len(rp_df)}')
    print(f'  Max request as % of pool: {rp_df["pct_of_pool"].max():.1%}')
    print(f'  Median request as % of pool: {rp_df["pct_of_pool"].median():.1%}')
else:
    print('Could not align proposal dates with pool balance data')
No description has been provided for this image
Spending limit analysis:
  Proposals exceeding 11% spending limit: 0/36
  Max request as % of pool: 6.9%
  Median request as % of pool: 1.7%

4. The Death Spiral Hypothesis¶

Did the TEC experience a death spiral?

  1. Token price drops → less attractive to hold
  2. Holders sell on ABC → reserve pool shrinks → price drops further
  3. Less ABC activity → less tribute revenue → common pool depletes faster
  4. Less funding available → fewer proposals → less community activity
  5. Less activity → holders leave → goto 1
In [5]:
# Build composite timeline
# We need to align: reserve pool, common pool, governance activity, and token price

# Normalize each metric to [0, 1] range for comparison
def normalize(series):
    return (series - series.min()) / (series.max() - series.min())

fig, ax = plt.subplots(figsize=(16, 8))

# Reserve pool (proxy for price/market confidence)
rp_daily = reserve.set_index('date')['balance'].resample('W').last().ffill()
ax.plot(rp_daily.index, normalize(rp_daily), label='Reserve Pool (market confidence)',
        color='#3498db', linewidth=2)

# Common pool (funding capacity)
cp_daily_w = common.set_index('date')['balance'].resample('W').last().ffill()
ax.plot(cp_daily_w.index, normalize(cp_daily_w), label='Common Pool (funding capacity)',
        color='#2ecc71', linewidth=2)

# Governance activity (rolling stake events per month)
stakes_weekly = stakes.set_index('date').resample('W')['proposal_id'].count()
stakes_rolling = stakes_weekly.rolling(4).mean()
if len(stakes_rolling.dropna()) > 0:
    ax.plot(stakes_rolling.index, normalize(stakes_rolling.fillna(0)),
            label='Governance Activity (4-week rolling)',
            color='coral', linewidth=2, alpha=0.8)

# Mark key events
events = [
    (datetime.datetime(2022, 5, 1), 'Terra/Luna collapse'),
    (datetime.datetime(2022, 11, 1), 'FTX collapse'),
    (datetime.datetime(2023, 1, 1), 'Crypto winter deepens'),
]
for date, label in events:
    if rp_daily.index.min() <= date <= rp_daily.index.max():
        ax.axvline(x=date, color='gray', linestyle=':', alpha=0.5)
        ax.text(date, 1.05, label, rotation=45, fontsize=8, ha='left')

ax.set_xlabel('Date')
ax.set_ylabel('Normalized Level (0-1)')
ax.set_title('Death Spiral Analysis: Correlated Decline of Market, Treasury, and Governance')
ax.legend(loc='upper right')
ax.set_ylim(-0.05, 1.15)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))

plt.tight_layout()
plt.savefig(f'{DATA}/../snapshots/death_spiral.png', dpi=150, bbox_inches='tight')
plt.show()
No description has been provided for this image

5. Mechanism Design Scorecard¶

In [6]:
funded = proposals[(proposals['status'] == 'executed') & (proposals['amount_requested'] > 0)]

print('=' * 70)
print('TEC MECHANISM POST-MORTEM — SCORECARD')
print('=' * 70)
print(f'''
AUGMENTED BONDING CURVE
  Design goal: Continuous fundraising with built-in price floor
  Reserve ratio: Started at ~31% (target TBD from ABC model)
  Entry/exit tribute: Generated revenue for common pool
  Primary vs secondary: Token traded at ~33% discount at shutdown
  
  [?] Did the ABC provide adequate price support during downturns?
  [?] Was the tribute rate sufficient to sustain operations?
  [?] How did liquidity compare between ABC and Honeyswap?
  
  (Full ABC analysis pending — need trade data from Dune queries)

CONVICTION VOTING
  Design goal: Continuous, sybil-resistant fund allocation
  Proposals funded: {len(funded)}/46 real proposals ({len(funded)/46:.0%})
  Total disbursed: {funded["amount_requested"].sum():,.0f} TEC
  Unique participants: 159 stakers
  
  [+] High success rate suggests proposals were well-vetted pre-submission
  [+] Diverse set of funded initiatives (academy, research, community)
  [-] 159 participants out of ~1,200 token holders (~13% participation)
  [-] Governance activity declined as token price fell
  [?] Did the 7-day conviction growth period cause delays?
  [?] Did the Abstain proposal effectively serve as a brake?

THE FEEDBACK LOOP
  Design goal: Self-sustaining cycle of funding and growth
  Reality: Tribute inflows << grant outflows throughout the lifecycle
  Treasury declined from peak to shutdown over ~3 years
  
  [-] The fundamental loop never achieved self-sustainability
  [-] Exogenous shocks (Terra, FTX) accelerated decline
  [-] Common pool was essentially a drawdown fund, not a renewable one
  [?] Was this a mechanism failure or a market/adoption failure?

SHUTDOWN METRICS
  Token at shutdown: ~$0.18 (vs peak of ~$1+)
  Treasury: ~$300K remaining
  FDV: ~$217K (33% below treasury value)
  Grants distributed: $433K direct + $250K via Gitcoin
  Total value created: Funded TE Academy, cadCAD, Gravity, research
  
OVERALL ASSESSMENT:
  The mechanisms worked as designed but could not overcome:
  1. Insufficient external demand to drive ABC tributes
  2. Bear market pressure on reserve pool collateral
  3. Community attrition reducing governance participation
  The TEC proved that ABC + CV can work for initial fundraising and
  allocation, but long-term sustainability requires mechanisms that
  generate revenue beyond trading activity (tributes).
''')
======================================================================
TEC MECHANISM POST-MORTEM — SCORECARD
======================================================================

AUGMENTED BONDING CURVE
  Design goal: Continuous fundraising with built-in price floor
  Reserve ratio: Started at ~31% (target TBD from ABC model)
  Entry/exit tribute: Generated revenue for common pool
  Primary vs secondary: Token traded at ~33% discount at shutdown

  [?] Did the ABC provide adequate price support during downturns?
  [?] Was the tribute rate sufficient to sustain operations?
  [?] How did liquidity compare between ABC and Honeyswap?

  (Full ABC analysis pending — need trade data from Dune queries)

CONVICTION VOTING
  Design goal: Continuous, sybil-resistant fund allocation
  Proposals funded: 36/46 real proposals (78%)
  Total disbursed: 680,295 TEC
  Unique participants: 159 stakers

  [+] High success rate suggests proposals were well-vetted pre-submission
  [+] Diverse set of funded initiatives (academy, research, community)
  [-] 159 participants out of ~1,200 token holders (~13% participation)
  [-] Governance activity declined as token price fell
  [?] Did the 7-day conviction growth period cause delays?
  [?] Did the Abstain proposal effectively serve as a brake?

THE FEEDBACK LOOP
  Design goal: Self-sustaining cycle of funding and growth
  Reality: Tribute inflows << grant outflows throughout the lifecycle
  Treasury declined from peak to shutdown over ~3 years

  [-] The fundamental loop never achieved self-sustainability
  [-] Exogenous shocks (Terra, FTX) accelerated decline
  [-] Common pool was essentially a drawdown fund, not a renewable one
  [?] Was this a mechanism failure or a market/adoption failure?

SHUTDOWN METRICS
  Token at shutdown: ~$0.18 (vs peak of ~$1+)
  Treasury: ~$300K remaining
  FDV: ~$217K (33% below treasury value)
  Grants distributed: $433K direct + $250K via Gitcoin
  Total value created: Funded TE Academy, cadCAD, Gravity, research

OVERALL ASSESSMENT:
  The mechanisms worked as designed but could not overcome:
  1. Insufficient external demand to drive ABC tributes
  2. Bear market pressure on reserve pool collateral
  3. Community attrition reducing governance participation
  The TEC proved that ABC + CV can work for initial fundraising and
  allocation, but long-term sustainability requires mechanisms that
  generate revenue beyond trading activity (tributes).