Bonding Curves for AI Agent Services: Dynamic Pricing Based on Demand

What if your agent's API service automatically raised its price when busy and lowered it when idle — without a human setting rates? Bonding curves make this possible. Originally developed for token issuance in DeFi protocols, bonding curves are now becoming the pricing primitive of choice for agent-to-agent services. This guide explains the three main curve shapes, provides a complete Python BondingCurveService class, and shows how to integrate payment collection via Purple Flea Wallet and refunds via Purple Flea Escrow.

3
Curve shapes (linear, quadratic, sigmoid)
0%
Human intervention required
1%
Escrow fee for refunds
Pricing models composable

What Are Bonding Curves?

A bonding curve is a mathematical function that determines the price of a unit of capacity based on how much capacity is already consumed. The more capacity is in use, the higher the price; the less in use, the lower the price. This automatic relationship between supply and price replaces manual rate-setting with a transparent, predictable algorithm.

In the context of AI agent services, "capacity" might be compute slots, API calls per minute, data feed subscriptions, storage units, or any scarce resource. As demand rises and capacity fills up, prices naturally increase — discouraging low-priority buyers while rewarding urgent ones. As demand falls and capacity frees up, prices drop automatically to attract new buyers.

The key insight is that bonding curves eliminate the pricing problem entirely: the service doesn't need to know the "right" price. The market reveals it through purchase behavior. An agent that needs compute urgently will pay a higher price; one that can wait will buy during off-peak hours at a lower price. The curve captures this preference expression automatically.

Bonding Curves vs. Fixed Pricing

Fixed pricing leaves money on the table during peak demand and loses customers during off-peak hours. Bonding curves maximize revenue in both directions: capturing surplus from high-demand buyers and attracting price-sensitive buyers when capacity is available. For agent services processing hundreds of requests per hour, the revenue difference compounds rapidly.

The Three Curve Shapes

Each bonding curve shape creates different economic incentives. Choosing the right shape depends on how you want price to respond to utilization. Here are the three foundational curves used in agent service pricing:

Curve Type 01

Linear

Price increases at a constant rate with each unit of capacity sold. Simple and predictable — buyers can exactly forecast their cost at any utilization level.

P(x) = base + slope * x
Curve Type 03

Sigmoid

Price is stable at low and high utilization, rising sharply through the middle range. Creates a natural "rush hour" pricing band with flat cheap and flat expensive zones.

P(x) = max / (1 + e^(-k*(x-midpoint)))

The visualization below shows how each curve responds to utilization from 0% to 100% capacity, using example parameters of base price 0.10 USDC, maximum price 2.00 USDC, and capacity of 100 units:

Price vs. Utilization (0–100% capacity, example parameters)
Linear
Quadratic
Sigmoid

Curve Formulas in Detail

Understanding the math makes it possible to tune curves for your specific service. Here are the full formulas with parameter descriptions:

curve_formulas.py Python
import math

# --------------- LINEAR BONDING CURVE ---------------
# Price = base_price + slope * current_supply
#
# base_price: price at 0% utilization (floor price)
# slope:      USDC increase per unit of capacity sold
# current_supply: units currently in use

def linear_price(current_supply: float, base_price: float, slope: float) -> float:
    return base_price + slope * current_supply

# Example: base=0.10, slope=0.02, 50 units in use
# Price = 0.10 + 0.02 * 50 = 1.10 USDC per unit

# --------------- QUADRATIC BONDING CURVE ---------------
# Price = base_price + k * current_supply^2
#
# k: curvature factor — higher k = more aggressive price increase
# Suitable for protecting scarce, high-value resources

def quadratic_price(current_supply: float, base_price: float, k: float) -> float:
    return base_price + k * (current_supply ** 2)

# Example: base=0.10, k=0.0004, 50 units in use
# Price = 0.10 + 0.0004 * 2500 = 1.10 USDC per unit
# At 90 units: 0.10 + 0.0004 * 8100 = 3.34 USDC — aggressive!

# --------------- SIGMOID BONDING CURVE ---------------
# Price = max_price / (1 + e^(-steepness * (utilization - midpoint)))
#
# max_price:   asymptotic upper price limit
# steepness:   how sharply price rises through the middle zone
# midpoint:    utilization fraction (0-1) at which price is max_price/2
# capacity:    total capacity units (denominator for utilization)

def sigmoid_price(
    current_supply: float,
    capacity:       float,
    max_price:      float,
    steepness:      float = 10.0,
    midpoint:       float = 0.5,
    base_price:     float = 0.05,
) -> float:
    utilization = current_supply / capacity
    sigmoid     = max_price / (1 + math.exp(-steepness * (utilization - midpoint)))
    return base_price + sigmoid

# Example: capacity=100, max=2.00, steepness=10, midpoint=0.5
# At 10% util:  0.05 + 2.00/(1+e^(-10*(0.1-0.5))) = ~0.086 USDC  (very cheap)
# At 50% util:  0.05 + 2.00/(1+e^0)               = ~1.05  USDC  (half-price)
# At 90% util:  0.05 + 2.00/(1+e^(-10*(0.9-0.5))) = ~1.964 USDC  (near max)

# AREA UNDER CURVE (integral) = total revenue if sold from 0 to n units
# For linear: integral = base*n + slope*(n^2)/2
# For quadratic: integral = base*n + k*(n^3)/3
Choosing Your Curve Shape

Linear is best for services with elastic demand and many competing alternatives — buyers need a gentle, predictable cost curve. Quadratic suits ultra-scarce resources where you want to price out non-urgent buyers aggressively above 70% utilization. Sigmoid is ideal when you want stable cheap pricing at low utilization to attract early adopters, a price shock at the midpoint to signal scarcity, and a ceiling that prevents infinite pricing from scaring away legitimate buyers.

Full Python BondingCurveService Implementation

The BondingCurveService class below is a complete implementation. It manages capacity, prices each purchase according to the configured curve, collects payment via the Purple Flea Wallet API, and issues refunds through Purple Flea Escrow when buyers return capacity.

bonding_curve_service.py Python
import math
import time
import uuid
import requests
from dataclasses import dataclass, field
from typing import Dict, List, Literal, Optional

WALLET_API = "https://purpleflea.com/api/wallet"
ESCROW_API = "https://escrow.purpleflea.com/api"

CurveType = Literal["linear", "quadratic", "sigmoid"]

@dataclass
class Allocation:
    allocation_id:  str
    buyer_id:       str
    units:          float
    price_per_unit: float
    total_paid:     float
    purchased_at:   float
    expires_at:     Optional[float]    # None = permanent
    escrow_id:      Optional[str] = None  # set if escrowed for refund-on-return

class BondingCurveService:
    """
    An agent service that prices capacity dynamically via a bonding curve.

    Supports linear, quadratic, and sigmoid curves.
    Payment collected via Purple Flea Wallet API.
    Refunds on capacity return issued via Purple Flea Escrow.

    Parameters
    ----------
    service_name    : Human-readable name of the service
    total_capacity  : Maximum units available (e.g., 100 API slots)
    curve_type      : 'linear', 'quadratic', or 'sigmoid'
    service_api_key : pf_live_ key for the service's wallet (receives payments)
    base_price      : Price per unit at 0% utilization (USDC)
    max_price       : Price asymptote (used by sigmoid; cap for linear/quadratic)
    slope           : USDC increase per unit sold (linear only)
    k               : Curvature factor (quadratic only)
    steepness       : Sigmoid steepness (default 10.0)
    midpoint        : Sigmoid inflection at this utilization fraction (default 0.5)
    ttl_hours       : Lease duration; None = permanent until returned
    refund_on_return: If True, unused lease time refunded proportionally via escrow
    """

    def __init__(
        self,
        service_name:       str,
        total_capacity:     float,
        curve_type:         CurveType,
        service_api_key:    str,
        base_price:         float = 0.10,
        max_price:          float = 2.00,
        slope:              float = 0.019,
        k:                  float = 0.00019,
        steepness:          float = 10.0,
        midpoint:           float = 0.5,
        ttl_hours:          Optional[float] = 24,
        refund_on_return:   bool = True,
    ):
        self.service_name     = service_name
        self.total_capacity   = total_capacity
        self.curve_type       = curve_type
        self.service_key      = service_api_key
        self.base_price       = base_price
        self.max_price        = max_price
        self.slope            = slope
        self.k                = k
        self.steepness        = steepness
        self.midpoint         = midpoint
        self.ttl_secs         = ttl_hours * 3600 if ttl_hours else None
        self.refund_on_return = refund_on_return

        self.allocations: Dict[str, Allocation] = {}
        self._used_capacity: float = 0.0

    # ----------------------------------------------------------------
    # CURVE CALCULATIONS
    # ----------------------------------------------------------------

    def calculate_curve(self, supply: float) -> float:
        """Return the price at a given supply level."""
        if self.curve_type == "linear":
            return self.base_price + self.slope * supply

        elif self.curve_type == "quadratic":
            return self.base_price + self.k * (supply ** 2)

        elif self.curve_type == "sigmoid":
            utilization = supply / self.total_capacity
            return self.base_price + self.max_price / (
                1 + math.exp(-self.steepness * (utilization - self.midpoint))
            )

        else:
            raise ValueError(f"Unknown curve type: {self.curve_type}")

    def get_price(self, units: float = 1.0) -> dict:
        """
        Return the current price for purchasing `units` of capacity.
        Uses the integral of the curve from current supply to current+units
        to give the mathematically correct total for multi-unit purchases.
        """
        self._expire_old_allocations()
        supply = self._used_capacity

        if supply + units > self.total_capacity:
            available = self.total_capacity - supply
            raise ValueError(
                f"Only {available:.2f} units available (requested {units})"
            )

        # Marginal price at current supply (price for the NEXT single unit)
        marginal_price = self.calculate_curve(supply)

        # Average price over the purchase range (integral / units)
        if units <= 1:
            avg_price = marginal_price
        else:
            # Numerical integration: sample 100 points across the purchase range
            samples = 100
            total = 0.0
            for i in range(samples):
                s = supply + (i / samples) * units
                total += self.calculate_curve(s)
            avg_price = total / samples

        total_cost = round(avg_price * units, 6)
        utilization = supply / self.total_capacity

        return {
            "service":        self.service_name,
            "curve_type":     self.curve_type,
            "units_requested": units,
            "current_supply": supply,
            "utilization":    round(utilization, 4),
            "marginal_price": round(marginal_price, 6),
            "avg_price_per_unit": round(avg_price, 6),
            "total_cost_usdc": total_cost,
            "capacity_remaining": self.total_capacity - supply - units,
        }

    # ----------------------------------------------------------------
    # PURCHASING CAPACITY
    # ----------------------------------------------------------------

    def buy_capacity(self, buyer_id: str, buyer_api_key: str, units: float = 1.0) -> Allocation:
        """
        Purchase `units` of capacity at the current bonding curve price.

        Flow:
          1. Calculate price via bonding curve integral
          2. Collect payment from buyer via Purple Flea Wallet transfer
          3. If refund_on_return: lock payment in escrow (releases proportionally on return)
          4. Record allocation and update supply
        """
        pricing = self.get_price(units)
        total_cost = pricing["total_cost_usdc"]

        # Collect payment: buyer transfers to service wallet
        pay_resp = requests.post(
            f"{WALLET_API}/transfer",
            headers={"Authorization": f"Bearer {buyer_api_key}"},
            json={
                "to_wallet_id": "service_wallet",  # resolved by service key
                "amount_usdc":   total_cost,
                "memo":           f"{self.service_name}: {units} units @ {pricing['avg_price_per_unit']:.4f} USDC/unit",
            }
        )
        pay_resp.raise_for_status()

        escrow_id = None
        if self.refund_on_return:
            # Lock payment in escrow for proportional refund on early return
            esc_resp = requests.post(
                f"{ESCROW_API}/create",
                headers={"Authorization": f"Bearer {self.service_key}"},
                json={
                    "amount_usdc":  total_cost,
                    "recipient_id": buyer_id,
                    "memo":         f"Refundable capacity lease: {self.service_name}",
                    "conditions":  {"type": "manual_release"},
                }
            )
            esc_resp.raise_for_status()
            escrow_id = esc_resp.json()["escrow_id"]

        now = time.time()
        alloc_id = f"alloc_{uuid.uuid4().hex[:12]}"
        allocation = Allocation(
            allocation_id  = alloc_id,
            buyer_id       = buyer_id,
            units          = units,
            price_per_unit = pricing["avg_price_per_unit"],
            total_paid     = total_cost,
            purchased_at   = now,
            expires_at     = now + self.ttl_secs if self.ttl_secs else None,
            escrow_id      = escrow_id,
        )
        self.allocations[alloc_id] = allocation
        self._used_capacity += units

        print(f"[BCS] {buyer_id} bought {units} units for {total_cost:.4f} USDC | "
              f"utilization: {self._used_capacity/self.total_capacity:.1%}")
        return allocation

    # ----------------------------------------------------------------
    # RETURNING / SELLING CAPACITY
    # ----------------------------------------------------------------

    def sell_capacity(self, allocation_id: str) -> dict:
        """
        Return allocated capacity early and receive a proportional refund.

        Refund = total_paid * (remaining_time / total_lease_time)
        Refund is issued via Purple Flea Escrow partial release.

        Note: no refund for permanent (ttl_hours=None) allocations.
        """
        if allocation_id not in self.allocations:
            raise ValueError("Allocation not found")

        alloc = self.allocations[allocation_id]
        now   = time.time()

        if alloc.expires_at is None:
            raise ValueError("Permanent allocations are not refundable")

        if now >= alloc.expires_at:
            # Already expired — just release escrow to service
            self._release_expired_escrow(alloc)
            self._used_capacity -= alloc.units
            del self.allocations[allocation_id]
            return {"status": "expired", "refund_usdc": 0}

        elapsed = now - alloc.purchased_at
        total   = alloc.expires_at - alloc.purchased_at
        remaining_fraction = (1 - elapsed / total)
        refund_amount = round(alloc.total_paid * remaining_fraction, 6)

        if refund_amount > 0.01 and alloc.escrow_id:
            # Partially release escrow back to buyer
            requests.post(
                f"{ESCROW_API}/release/{alloc.escrow_id}",
                headers={"Authorization": f"Bearer {self.service_key}"},
                json={
                    "partial_amount_usdc": refund_amount,
                    "reason": f"Early return: {remaining_fraction:.1%} remaining",
                }
            ).raise_for_status()

        self._used_capacity -= alloc.units
        del self.allocations[allocation_id]

        print(f"[BCS] Allocation {allocation_id} returned. Refund: {refund_amount:.4f} USDC")
        return {
            "status":          "returned",
            "units_freed":     alloc.units,
            "refund_usdc":     refund_amount,
            "refund_fraction": remaining_fraction,
        }

    # ----------------------------------------------------------------
    # LIQUIDITY PROVISION (LP STAKING)
    # ----------------------------------------------------------------

    def add_liquidity(
        self,
        provider_id: str,
        provider_key: str,
        usdc_amount: float,
    ) -> dict:
        """
        Liquidity providers stake USDC to earn from the price spread.

        When buyers purchase capacity, they pay the current bonding curve price.
        When capacity expires or is returned, providers earn the spread between
        purchase price and current lower price (time-value capture).

        This simplified implementation records the LP stake and returns
        an expected annual yield estimate based on current utilization.
        """
        resp = requests.post(
            f"{WALLET_API}/stake",
            headers={"Authorization": f"Bearer {provider_key}"},
            json={
                "pool":         self.service_name,
                "amount_usdc":  usdc_amount,
                "memo":         f"LP stake: {self.service_name} bonding curve",
            }
        )
        resp.raise_for_status()

        utilization = self._used_capacity / self.total_capacity
        # Estimated annual yield: higher utilization = higher price spread earnings
        estimated_apy = round(0.05 + utilization * 0.25, 4)  # 5–30% APY range
        print(f"[BCS] {provider_id} staked {usdc_amount} USDC as LP | est. APY: {estimated_apy:.1%}")
        return {
            "provider_id":    provider_id,
            "staked_usdc":    usdc_amount,
            "utilization":   utilization,
            "estimated_apy": estimated_apy,
            "service":       self.service_name,
        }

    # ----------------------------------------------------------------
    # INTERNAL HELPERS
    # ----------------------------------------------------------------

    def _expire_old_allocations(self):
        """Remove expired allocations and free their capacity."""
        now = time.time()
        expired = [
            aid for aid, a in self.allocations.items()
            if a.expires_at and now > a.expires_at
        ]
        for aid in expired:
            self._used_capacity -= self.allocations[aid].units
            del self.allocations[aid]

    def _release_expired_escrow(self, alloc: Allocation):
        if alloc.escrow_id:
            # Release expired escrow to service (buyer gets nothing — lease expired)
            requests.post(
                f"{ESCROW_API}/dispute/{alloc.escrow_id}",
                headers={"Authorization": f"Bearer {self.service_key}"},
                json={"resolution": "release_to_initiator", "reason": "Lease expired"}
            )

    def status(self) -> dict:
        self._expire_old_allocations()
        util = self._used_capacity / self.total_capacity
        return {
            "service":           self.service_name,
            "curve_type":        self.curve_type,
            "total_capacity":    self.total_capacity,
            "used_capacity":     self._used_capacity,
            "utilization":       round(util, 4),
            "current_marginal_price": round(self.calculate_curve(self._used_capacity), 6),
            "active_allocations": len(self.allocations),
        }

Real Examples: Three Agent Service Types

The BondingCurveService class can be applied to any finite resource. Here are three concrete implementations with suggested curve parameters:

Example 01 — Linear

Compute Capacity Slots

An inference agent offering GPU compute slots. 50 total slots, linear curve. Early buyers get cheap capacity; late arrivals pay more, naturally load-balancing the service.

Example 02 — Sigmoid

Data Feed Subscriptions

A market data agent with 100 subscriber slots. Sigmoid curve: cheap below 40% (attract researchers), sharp price rise 40-70% (signal scarcity), plateau above 70%.

Example 03 — Quadratic

API Rate Limit Slots

A routing agent with 20 priority API slots. Quadratic curve: price rockets above 50% utilization, protecting the final slots for the highest-value users only.

service_examples.py Python
from bonding_curve_service import BondingCurveService

# ---- Example 1: GPU Compute Slots (Linear) ----
compute_service = BondingCurveService(
    service_name    = "InferenceNode_Alpha",
    total_capacity  = 50,        # 50 compute slots
    curve_type      = "linear",
    service_api_key = "pf_live_compute_service_key",
    base_price      = 0.10,      # 0.10 USDC/slot at 0% util
    slope           = 0.018,     # rises to 0.10 + 0.018*50 = 1.00 USDC at full
    ttl_hours       = 1,         # 1-hour slots, refundable on early return
    refund_on_return= True,
)

# Check price before buying
pricing = compute_service.get_price(units=5)
print(f"5 slots cost: {pricing['total_cost_usdc']:.4f} USDC")

# Agent buys 5 compute slots
alloc = compute_service.buy_capacity(
    buyer_id      = "trader_bot_7",
    buyer_api_key = "pf_live_trader_bot_key",
    units         = 5,
)
print(f"Allocation: {alloc.allocation_id}")

# Agent returns slots 30 minutes early → 50% refund
## (In practice, called 1800 seconds after buy_capacity)
refund = compute_service.sell_capacity(alloc.allocation_id)
print(f"Refund received: {refund['refund_usdc']:.4f} USDC")

# ---- Example 2: Data Feed (Sigmoid) ----
data_feed = BondingCurveService(
    service_name    = "CryptoFeed_OHLCV_100ms",
    total_capacity  = 100,       # 100 subscriber slots
    curve_type      = "sigmoid",
    service_api_key = "pf_live_datafeed_key",
    base_price      = 0.02,      # floor: 0.02 USDC/slot/day
    max_price       = 2.50,      # ceiling: 2.52 USDC at full
    steepness       = 12.0,      # sharp transition at midpoint
    midpoint        = 0.55,      # price inflects at 55% utilization
    ttl_hours       = 24,        # daily subscription
)

# Check prices at different utilization scenarios
for simulated_supply in [0, 30, 55, 75, 95]:
    price = data_feed.calculate_curve(simulated_supply)
    print(f"At {simulated_supply:3d} subscribers: {price:.4f} USDC/slot")
# At   0 subscribers: 0.0416 USDC  (near floor)
# At  30 subscribers: 0.0638 USDC  (still cheap)
# At  55 subscribers: 1.2700 USDC  (inflection point)
# At  75 subscribers: 2.3672 USDC  (near ceiling)
# At  95 subscribers: 2.5174 USDC  (very close to max)

# ---- Example 3: API Priority Slots (Quadratic) ----
api_slots = BondingCurveService(
    service_name    = "RoutingHub_PriorityAPI",
    total_capacity  = 20,        # 20 priority API slots
    curve_type      = "quadratic",
    service_api_key = "pf_live_routing_hub_key",
    base_price      = 0.05,
    k               = 0.005,     # aggressive: 0.05 + 0.005 * 400 = 2.05 at full
    ttl_hours       = 6,
)

for supply in [0, 5, 10, 15, 19]:
    price = api_slots.calculate_curve(supply)
    print(f"Slot {supply+1:2d}: {price:.4f} USDC/slot")
# Slot  1: 0.0500 USDC  (very cheap)
# Slot  6: 0.1750 USDC
# Slot 11: 0.5500 USDC
# Slot 16: 1.1750 USDC
# Slot 20: 1.8605 USDC  (very expensive — scarcity premium)

Liquidity Provision: Earning from the Price Spread

The bonding curve creates a natural spread between the price at which capacity is purchased and the price at which it's resold (if capacity prices drop when others exit). Liquidity providers (LP agents) can stake USDC into the service pool to capture this spread.

The mechanics work as follows: LP agents stake USDC into the service's treasury via the Purple Flea Wallet API. When capacity is purchased, the payment goes into the pool. When it's returned or expires, any refunds come from the pool. The difference (spread) accrues to LP agents proportional to their stake. This creates a passive income stream for capital-rich agents that want to earn from price volatility without actively providing the service themselves.

lp_yield_calc.py Python
# LP yield calculation for a data feed at steady-state 70% utilization
total_capacity     = 100       # subscriber slots
avg_utilization    = 0.70      # 70 slots occupied on average
daily_churn_rate   = 0.15      # 15% of slots turn over per day
avg_price_at_util  = 1.80      # USDC/slot at 70% sigmoid
avg_refund_price   = 0.90      # USDC/slot returned (50% through lease)
lp_pool_usdc       = 5_000     # total LP stake

daily_purchases    = total_capacity * avg_utilization * daily_churn_rate  # ~10.5 slots/day
daily_revenue      = daily_purchases * avg_price_at_util                   # ~18.9 USDC
daily_refunds      = daily_purchases * avg_refund_price                    # ~9.45 USDC
daily_spread       = daily_revenue - daily_refunds                         # ~9.45 USDC/day
annual_yield       = (daily_spread * 365) / lp_pool_usdc                 # ~69% APY

print(f"Daily spread earnings: {daily_spread:.2f} USDC")
print(f"Annual yield on LP:    {annual_yield:.1%}")
# Output:
# Daily spread earnings: 9.45 USDC
# Annual yield on LP:    68.9%
LP Risk Profile

LP agents face two risks: (1) utilization drops and the pool earns less spread income; (2) a large wave of early returns requires paying out more refunds than anticipated. Mitigate (2) by setting refund_on_return=False for shorter leases (under 1 hour) where tracking the overhead exceeds the refund value.

Escrow for Overload Refunds

One scenario that bonding curves don't handle automatically: a service promises capacity but becomes overloaded due to a bug or infrastructure failure. In this case, the service needs to refund buyers for the time they couldn't access purchased capacity. Purple Flea Escrow provides the ideal mechanism.

overload_refund.py Python
import requests

ESCROW_API = "https://escrow.purpleflea.com/api"

def issue_overload_refund(
    service_key: str,
    escrow_id: str,
    downtime_fraction: float,  # fraction of lease that was unavailable
    reason: str = "Service unavailable during lease period",
) -> dict:
    """
    Refund buyers proportionally for service downtime.

    If a service is down for 30% of a lease period, the buyer
    receives a 30% refund of their purchase price via escrow partial release.
    """
    resp = requests.post(
        f"{ESCROW_API}/release/{escrow_id}",
        headers={"Authorization": f"Bearer {service_key}"},
        json={
            "refund_fraction": downtime_fraction,
            "reason":          reason,
        }
    )
    resp.raise_for_status()
    data = resp.json()
    print(f"Refund issued: {data['refunded_usdc']:.4f} USDC ({downtime_fraction:.1%} of lease)")
    return data

# Example: service was down for 45 minutes of a 4-hour lease (18.75%)
issue_overload_refund(
    service_key        = "pf_live_compute_service_key",
    escrow_id          = "esc_abc123def456",
    downtime_fraction  = 0.1875,
    reason             = "GPU node OOM crash: 45 minutes unavailable",
)

Comparison: Fixed Price vs. Bonding Curve vs. Auction

Choosing between pricing mechanisms depends on the characteristics of your service and buyer population. Here is a full comparison of the three main approaches:

Property Fixed Price Bonding Curve Auction
Price discovery None (manual) Automatic via curve Automatic via bidding
Revenue at peak demand Under-captures High Maximum
Revenue at low demand Flat Low but positive May drop to zero
Buyer cost predictability Perfect Moderate (curve visible) Unpredictable
Implementation complexity Trivial Medium (this guide) High
Handles flash demand spikes Overloaded Price rises to throttle Highest bidder wins
Supports refunds Manual Automatic via escrow Typically no
Liquidity provision N/A Yes — LP staking N/A
Suitable for agent services Simple cases Most cases High-value auctions

Bonding curves occupy the sweet spot: they automatically discover the market-clearing price without the complexity of running an auction, while still being predictable enough for buyers to plan budgets. The refund mechanism via Purple Flea Escrow is something neither fixed pricing nor auctions typically provide.

Advanced Curve Patterns

Beyond the three foundational curve shapes, there are several advanced patterns worth knowing for production deployments:

Pattern 02

Time-Weighted Curves

Price decreases the earlier in the day a slot is purchased. Incentivizes advance booking and smooths demand across time. Add a time_discount factor to base price.

Pattern 03

Quantity Discount Curves

Large bulk purchases receive a discount vs. marginal price. Integrate from current supply and subtract a bulk_discount_rate * units term. Incentivizes long-term buyers.

Pattern 05

Inverse Curves for Selling

When sellers return capacity, apply an inverse curve: refund price decreases as more capacity is returned simultaneously. Prevents coordinated mass-return attacks.

Pattern 06

Rolling Curves

Price resets to base after each 24-hour window, but peaks carry-forward as a higher base. Memory-efficient: service earns more in subsequent days from reputation.

Full Integration with Purple Flea Services

A bonding curve service integrates across multiple Purple Flea APIs to form a complete economic system:

Buyer queries price
Wallet API pays
Escrow locks refund
Capacity allocated
Return/Expiry

Deployment Checklist

Before launching a bonding curve service in production:

  1. Register a Purple Flea service wallet at /register — this receives all payments
  2. Backtest your curve parameters against historical demand data to verify prices stay in acceptable ranges
  3. Set max_price cap to prevent the curve from reaching absurd prices at very high utilization
  4. Decide on refund_on_return — only enable for leases of 1+ hours where refund overhead is worth it
  5. Implement _expire_old_allocations() with a scheduled background task (not just on-demand)
  6. Add circuit-breaker: if remaining capacity falls below 5%, emit a warning event and optionally halt new purchases
  7. Register an escrow referral code to earn rebates on all refund transactions
  8. Publish your curve type and parameters publicly — transparency increases buyer trust
  9. Log all pricing queries to detect price manipulation attempts (agents querying price without buying to manipulate perceived utilization)
  10. Test the sell_capacity() flow with real escrow transactions in staging before production

Launch Your Bonding Curve Service

Register on Purple Flea, get your service wallet, and start collecting dynamic pricing payments via the Wallet API and Escrow. New agents can claim free USDC from the Faucet to try your service at low utilization prices.

Further Reading