Technical Architecture

LBP Platform Architecture

BioFoundry's LBP platform is built on a modular contract architecture with three primary components:

Factory Contract ──────► LBP Pool Instances ──────► Treasury
     │                         │                      │
     ▼                         ▼                      ▼
Pool Deployment        Trading Execution         Fee Management

The pool implementation uses a proxy pattern with immutable arguments to optimize gas costs while maintaining isolation between pools.

Core Components

  1. Factory Contract: Handles pool creation, initializes parameters, and manages deployment

  2. LBP Pool Implementation: Core logic for handling trades, calculating weights, and managing lifecycle

  3. Treasury System: Collects and distributes platform fees

For concepts and mathematical foundations, see our LBP as Funding Engine document.

Weight Calculation Implementation

The internal weight calculation algorithm linearly interpolates between the start and end weights based on the current timestamp:

function _currentAssetWeight() internal view returns (uint256) {
    uint256 _saleStart = saleStart();
    uint256 _saleEnd = saleEnd();
    uint256 _now = block.timestamp;
    
    if (_now <= _saleStart) return weightStart();
    if (_now >= _saleEnd) return weightEnd();
    
    return weightStart() + 
           ((_now - _saleStart) * (weightEnd() - weightStart())) / 
           (_saleEnd - _saleStart);
}

When executing a swap, the implementation follows this flow:

  1. Validate constraints (timing, amounts, caps)

  2. Calculate current weights based on timestamp

  3. Compute trade amounts using weighted math formulas

  4. Apply fees to the calculated amounts

  5. Transfer tokens and update reserves

  6. Emit swap events

Advanced Features

The platform supports several advanced features:

  • Merkle-based Whitelisting: Configurable access control using merkle proofs

  • Vesting Integration: Optional linear vesting for purchased tokens

  • Redemption Controls: Configurable delay periods for token redemption

Integration Guide

Trading Functions

The pool supports multiple trading functions depending on what parameters are being specified:

// Buy tokens with exact amount of asset in (e.g., USDC)
pool.swapExactAssetsForShares(
    uint256 assetsIn,              // Exact amount to spend
    uint256 minSharesOut,          // Minimum tokens to receive
    address recipient              // Who receives the tokens
) -> uint256 sharesOut            // Actual tokens received

// Buy exact amount of tokens with maximum asset limit
pool.swapAssetsForExactShares(
    uint256 sharesOut,            // Exact amount to receive
    uint256 maxAssetsIn,          // Maximum amount to spend
    address recipient             // Who receives the tokens
) -> uint256 assetsIn            // Actual amount spent

// Sell tokens with exact amount of shares in
pool.swapExactSharesForAssets(
    uint256 sharesIn,             // Exact tokens to sell
    uint256 minAssetsOut,         // Minimum amount to receive
    address recipient             // Who receives the assets
) -> uint256 assetsOut           // Actual amount received

// Sell tokens for exact amount of assets out
pool.swapSharesForExactAssets(
    uint256 assetsOut,            // Exact amount to receive
    uint256 maxSharesIn,          // Maximum tokens to sell
    address recipient             // Who receives the assets
) -> uint256 sharesIn            // Actual tokens sold

Price Estimation Functions

The pool provides functions to estimate trade outcomes before execution:

// Preview trades (without executing)
pool.previewAssetsIn(uint256 sharesOut) -> uint256 // How much to pay for X tokens
pool.previewSharesOut(uint256 assetsIn) -> uint256 // How many tokens for X assets
pool.previewSharesIn(uint256 assetsOut) -> uint256 // How many tokens to sell for X assets
pool.previewAssetsOut(uint256 sharesIn) -> uint256 // How much received for selling X tokens

Reading Pool State

// Core pool information
pool.asset() -> address              // Asset token address (e.g., USDC)
pool.share() -> address              // Share token address (project token) 
pool.closed() -> bool                // Whether pool is closed
pool.cancelled() -> bool             // Whether pool was cancelled

// Current state
pool.reservesAndWeights() -> (                   
    uint256 assetReserve,            // Current asset token reserve
    uint256 shareReserve,            // Current share token reserve 
    uint256 assetWeight,             // Current asset token weight
    uint256 shareWeight              // Current share token weight
)

Events

The LBP protocol emits events for all major operations to enable proper tracking and integration:

// Trading events
event Buy(
    address indexed caller,     // Who initiated the purchase
    uint256 assets,            // Amount of assets spent
    uint256 shares,            // Amount of shares received 
    uint256 swapFee            // Fee amount charged
);

event Sell(
    address indexed caller,     // Who initiated the sale
    uint256 shares,            // Amount of shares sold
    uint256 assets,            // Amount of assets received
    uint256 swapFee            // Fee amount charged
);

// Redemption events
event Redeem(
    address indexed caller,     // Who redeemed tokens
    uint256 indexed streamID,   // Sablier stream ID (if vesting enabled)
    uint256 shares              // Amount of shares redeemed
);

// Pool lifecycle events
event Close(
    uint256 assets,             // Final asset balance
    uint256 platformFees,       // Fees collected for platform
    uint256 swapFeesAsset,      // Swap fees in asset token
    uint256 swapFeesShare       // Swap fees in share token
);

event Cancelled(
    uint256 assets,             // Amount of assets returned
    uint256 shares              // Amount of shares returned
);

These events provide a complete record of all trading activity and lifecycle changes for LBP pools.

Last updated